[Scummvm-git-logs] scummvm master -> 3aacc800a964583641fa25b764f0052bdd199ca9

dreammaster paulfgilbert at gmail.com
Wed Jun 3 01:36:50 UTC 2020


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

Summary:
5d8838005b GLK: COMPREHEND: Skeleton engine
7423561d21 GLK: COMPREHEND: Adding recomprehend source files
8a9ef1a5a1 GLK: COMPREHEND: Adding startup code, cleanup
2ecbd720ea GLK: COMPREHEND: Work on startup
10aa0e48fe GLK: COMPREHEND: Cleaning up some structure dependencies
20533b4a1a GLK: COMPREHEND: Start of sub-classes for each different game
7e7e6a5fab GLK: COMPREHEND: Changing operation methods to virtual methods
2dd367aa6f GLK: COMPREHEND: Adding initialization defaults for game info
16b1713afd GLK: COMPREHEND: Change comprehend_game to ComprehendGame
14cf02cc1b GLK: COMPREHEND: Field renamings
b0fe096225 GLK: COMPREHEND: Making comprehend game derive from game info
fff77194d7 GLK: COMPREHEND: Converting data loading to be endian safe
5023e261ed GLK: COMPREHEND: Removal of redundant struct prefixes
269b83f31e GLK: COMPREHEND: Removal of redundant struct prefixes
ec99b086fc GLK: COMPREHEND: Capitalizing class names
eca27789b1 GLK: COMPREHEND: Data loading fixes
16c36841aa GLK: COMPREHEND: gcc compilation fixes
fbf8e0a23b GLK: COMPREHEND: Fix opcode map definition
e55aaa91da GLK: COMPREHEND: Adding method to print text to text buffer
51ff674d99 GLK: COMPREHEND: Adding method for reading text
7a88a18d47 GLK: COMPREHEND: Implement action line input
21462c57f6 GLK: COMPREHEND: Creating debugger to hold dumping methods
0f411b62dd GLK: COMPREHEND: Improved graphic vs text area setup
0944b7aa6a GLK: COMPREHEND: Implementing some graphic primitives
687ed8be04 GLK: COMPREHEND: Objectifying image file methods
4fc86e1bc9 GLK: COMPREHEND: Refactoring drawing code
207e8f4ba2 GLK: COMPREHEND: Further refactoring of drawing
645b2132d7 GLK: COMPREHEND: Change debug_printf to use debugC
17454429e4 GLK: COMPREHEND: Move floodfill disable to a debugger command
13b4698c83 GLK: COMPREHEND: Skeleton for savegames within ScummVM
e8c47aa747 GLK: COMPREHEND: Implementing savegames
0a2478984f GLK: COMPREHEND: Change _replaceWords to be an Array
6447f64709 GLK: COMPREHEND: Merged string lookups into Game class
744580a3a0 GLK: COMPREHEND: Change fatal_error to use error
093825f759 GLK: COMPREHEND: Changed StringTable to be a Common StringArray
2671e9a071 GLK: COMPREHEND: Shifting DrawSurface to be a single instance of the engine
3c4bcc9790 GLK: COMPREHEND: Hooking up engine save/load methods
b26044de81 GLK: COMPREHEND: Changing _rooms to be a Common::Array
4d5146341a GLK: COMPREHEND: Change _items to Common::Array
6015d9c914 GLK: COMPREHEND: Change _wordMaps to Common::Array
0ed3473e35 GLK: COMPREHEND: Change _actions to Common::Array
f91628971d GLK: COMPREHEND: Change _functions to Common::Array
08de10a9ec GLK: COMPREHEND: Change _replaceWords to a StringArray
0831f0d93c GLK: COMPREHEND: Remove deprecated utils file
604b8f91ca GLK: COMPREHEND: Fix gcc warnings
9609ef72cc GLK: COMPREHEND: Implement engine readChar method
967c6a277e GLK: COMPREHEND: Remove use of printf macro
d59873704c GLK: COMPREHEND: Converting picture drawing to an Archive abstraction
f7e40621ce GLK: COMPREHEND: Finish implementing PIcs archive
ead0a1bdd4 GLK: COMPREHEND: Proper freeing of Pics on exit
088bb3caf4 GLK: COMPREHEND: Draw images doubled-sized to properly fill screen
9a8d5e51d2 GLK: COMPREHEND: Fix drawing of items on-screen
21eb824978 GLK: COMPREHEND: Fix parsing string table
c6346f2db0 GLK: COMPREHEND: Better placement of location images
a06ed9ef2f GLK: COMPREHEND: Added loading of Transylvania title
508a65a02e GLK: COMPREHEND: Renaming constant arrays to be uppercase
243adfe901 GLK: COMPREHEND: Implemented game font
88c1d4ecf1 GLK: COMPREHEND: Cleanup of Crimson Crown code, remove deprecated data
3aacc800a9 GLK: COMPREHEND: Flesh out and fixes for detection code


Commit: 5d8838005b0311dcf6573d78d0f236b41183ac4b
    https://github.com/scummvm/scummvm/commit/5d8838005b0311dcf6573d78d0f236b41183ac4b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:08-07:00

Commit Message:
GLK: COMPREHEND: Skeleton engine

Changed paths:
  A engines/glk/comprehend/comprehend.cpp
  A engines/glk/comprehend/comprehend.h
  A engines/glk/comprehend/detection.cpp
  A engines/glk/comprehend/detection.h
  A engines/glk/comprehend/detection_tables.h
    engines/glk/detection.cpp
    engines/glk/detection.h
    engines/glk/glk_types.h
    engines/glk/module.mk
    engines/glk/quetzal.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
new file mode 100644
index 0000000000..36480e02e6
--- /dev/null
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -0,0 +1,51 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/quetzal.h"
+#include "common/config-manager.h"
+#include "common/translation.h"
+
+namespace Glk {
+namespace Comprehend {
+
+Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
+		_saveSlot(-1) {
+}
+
+void Comprehend::runGame() {
+	initialize();
+	#ifdef TODO
+	_bottomWindow = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
+	if (_bottomWindow == nullptr) {
+		glk_exit();
+		return;
+	}
+	glk_set_window(_bottomWindow);
+#endif
+}
+
+void Comprehend::initialize() {
+}
+
+} // End of namespace Comprehend
+} // End of namespace Glk
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
new file mode 100644
index 0000000000..c4a7797a66
--- /dev/null
+++ b/engines/glk/comprehend/comprehend.h
@@ -0,0 +1,78 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_COMPREHEND_H
+#define GLK_COMPREHEND_COMPREHEND_H
+
+#include "common/scummsys.h"
+#include "glk/glk_api.h"
+
+namespace Glk {
+namespace Comprehend {
+
+/**
+ * Scott Adams game interpreter
+ */
+class Comprehend : public GlkAPI {
+private:
+	int _saveSlot;		 ///< Save slot when loading savegame from launcher
+private:
+	/**
+	 * Initialization code
+	 */
+	void initialize();
+public:
+	/**
+	 * Constructor
+	 */
+	Comprehend(OSystem *syst, const GlkGameDescription &gameDesc);
+
+	/**
+	 * Returns the running interpreter type
+	 */
+	InterpreterType getInterpreterType() const override { return INTERPRETER_SCOTT; }
+
+	/**
+	 * Execute the game
+	 */
+	void runGame() override;
+
+	/**
+	 * Load a savegame from the passed Quetzal file chunk stream
+	 */
+	Common::Error readSaveData(Common::SeekableReadStream *rs) override {
+		return Common::kReadingFailed;
+	}
+
+	/**
+	 * Save the game. The passed write stream represents access to the UMem chunk
+	 * in the Quetzal save file that will be created
+	 */
+	Common::Error writeGameData(Common::WriteStream *ws) override {
+		return Common::kWritingFailed;
+	}
+};
+
+} // End of namespace Comprehend
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/detection.cpp b/engines/glk/comprehend/detection.cpp
new file mode 100644
index 0000000000..ca5074a17c
--- /dev/null
+++ b/engines/glk/comprehend/detection.cpp
@@ -0,0 +1,92 @@
+/* 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 "glk/comprehend/detection.h"
+#include "glk/comprehend/detection_tables.h"
+#include "glk/blorb.h"
+#include "common/file.h"
+#include "common/md5.h"
+#include "engines/game.h"
+
+namespace Glk {
+namespace Comprehend {
+
+void ComprehendMetaEngine::getSupportedGames(PlainGameList &games) {
+	for (const PlainGameDescriptor *pd = COMPREHEND_GAME_LIST; pd->gameId; ++pd)
+		games.push_back(*pd);
+}
+
+GameDescriptor ComprehendMetaEngine::findGame(const char *gameId) {
+	for (const PlainGameDescriptor *pd = COMPREHEND_GAME_LIST; pd->gameId; ++pd) {
+		if (!strcmp(gameId, pd->gameId))
+			return *pd;
+	}
+
+	return GameDescriptor::empty();
+}
+
+bool ComprehendMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
+	// Loop through the files of the folder
+	for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+		// Check for a recognised filename
+		if (file->isDirectory())
+			continue;
+
+		Common::String filename = file->getName();
+		bool hasExt = filename.hasSuffixIgnoreCase(".gda");
+		if (!hasExt)
+			continue;
+
+		// Get the file's MD5
+		Common::File gameFile;
+		if (!gameFile.open(*file))
+			continue;
+		Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000);
+		gameFile.close();
+
+		// Iterate through the known games
+		const ComprehendDetectionEntry *p = COMPREHEND_GAMES;
+		for (; p->_gameId; ++p) {
+			if (filename.equalsIgnoreCase(p->_filename)) {
+				// Check for an md5 match
+				if (p->_md5 == md5) {
+					// Found a match
+					PlainGameDescriptor gameDesc = findGame(p->_gameId);
+					gameList.push_back(GlkDetectedGame(p->_gameId, gameDesc.description, filename));
+				}
+			}
+		}
+	}
+
+	return !gameList.empty();
+}
+
+void ComprehendMetaEngine::detectClashes(Common::StringMap &map) {
+	for (const PlainGameDescriptor *pd = COMPREHEND_GAME_LIST; pd->gameId; ++pd) {
+		if (map.contains(pd->gameId))
+			error("Duplicate game Id found - %s", pd->gameId);
+		map[pd->gameId] = "";
+	}
+}
+
+} // End of namespace Comprehend
+} // End of namespace Glk
diff --git a/engines/glk/comprehend/detection.h b/engines/glk/comprehend/detection.h
new file mode 100644
index 0000000000..9317366592
--- /dev/null
+++ b/engines/glk/comprehend/detection.h
@@ -0,0 +1,60 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_DETECTION
+#define GLK_COMPREHEND_DETECTION
+
+#include "common/fs.h"
+#include "common/hash-str.h"
+#include "engines/game.h"
+#include "glk/detection.h"
+
+namespace Glk {
+namespace Comprehend {
+
+class ComprehendMetaEngine {
+public:
+	/**
+	 * Get a list of supported games
+	 */
+	static void getSupportedGames(PlainGameList &games);
+
+	/**
+	 * Returns a game description for the given game Id, if it's supported
+	 */
+	static GameDescriptor findGame(const char *gameId);
+
+	/**
+	 * Detect supported games
+	 */
+	static bool detectGames(const Common::FSList &fslist, DetectedGames &gameList);
+
+	/**
+	 * Check for game Id clashes with other sub-engines
+	 */
+	static void detectClashes(Common::StringMap &map);
+};
+
+} // End of namespace Comprehend
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/detection_tables.h b/engines/glk/comprehend/detection_tables.h
new file mode 100644
index 0000000000..aa8185eeef
--- /dev/null
+++ b/engines/glk/comprehend/detection_tables.h
@@ -0,0 +1,51 @@
+/* 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 "common/gui_options.h"
+#include "common/language.h"
+#include "engines/game.h"
+
+namespace Glk {
+namespace Comprehend {
+
+const PlainGameDescriptor COMPREHEND_GAME_LIST[] = {
+    {"crimsoncrown", "Crimson Crown"},
+    {"transylvania", "Transylvania"},
+
+    {nullptr, nullptr}};
+
+struct ComprehendDetectionEntry {
+	const char *const _gameId;
+	const char *const _filename;
+	const char *const _md5;
+};
+
+const ComprehendDetectionEntry COMPREHEND_GAMES[] = {
+    // DOS games
+    {"crimsoncrown", "cc1.gda", "f2abf019675ac5c9bcfd81032bc7787b"},
+    {"transylvania", "tr.gda", "22e08633eea02ceee49b909dfd982d22"},
+
+    {nullptr, nullptr, nullptr}
+};
+
+} // End of namespace Comprehend
+} // End of namespace Glk
diff --git a/engines/glk/detection.cpp b/engines/glk/detection.cpp
index c36eb6e261..e3271966e9 100644
--- a/engines/glk/detection.cpp
+++ b/engines/glk/detection.cpp
@@ -35,6 +35,8 @@
 #include "glk/alan3/alan3.h"
 #include "glk/archetype/archetype.h"
 #include "glk/archetype/detection.h"
+#include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/detection.h"
 #include "glk/frotz/detection.h"
 #include "glk/frotz/frotz.h"
 #include "glk/glulxe/detection.h"
@@ -172,6 +174,7 @@ Common::Error GlkMetaEngine::createInstance(OSystem *syst, Engine **engine) cons
 	else if ((*engine = create<Glk::Alan2::Alan2MetaEngine, Glk::Alan2::Alan2>(syst, gameDesc)) != nullptr) {}
 	else if ((*engine = create<Glk::Alan3::Alan3MetaEngine, Glk::Alan3::Alan3>(syst, gameDesc)) != nullptr) {}
 	else if ((*engine = create<Glk::Archetype::ArchetypeMetaEngine, Glk::Archetype::Archetype>(syst, gameDesc)) != nullptr) {}
+	else if ((*engine = create<Glk::Comprehend::ComprehendMetaEngine, Glk::Comprehend::Comprehend>(syst, gameDesc)) != nullptr) {}
 	else if ((*engine = create<Glk::Frotz::FrotzMetaEngine, Glk::Frotz::Frotz>(syst, gameDesc)) != nullptr) {}
 	else if ((*engine = create<Glk::Glulxe::GlulxeMetaEngine, Glk::Glulxe::Glulxe>(syst, gameDesc)) != nullptr) {}
 	else if ((*engine = create<Glk::Hugo::HugoMetaEngine, Glk::Hugo::Hugo>(syst, gameDesc)) != nullptr) {}
@@ -222,6 +225,7 @@ PlainGameList GlkMetaEngine::getSupportedGames() const {
 	Glk::Alan2::Alan2MetaEngine::getSupportedGames(list);
 	Glk::Alan3::Alan3MetaEngine::getSupportedGames(list);
 	Glk::Archetype::ArchetypeMetaEngine::getSupportedGames(list);
+	Glk::Comprehend::ComprehendMetaEngine::getSupportedGames(list);
 	Glk::Frotz::FrotzMetaEngine::getSupportedGames(list);
 	Glk::Glulxe::GlulxeMetaEngine::getSupportedGames(list);
 	Glk::Hugo::HugoMetaEngine::getSupportedGames(list);
@@ -246,6 +250,7 @@ PlainGameDescriptor GlkMetaEngine::findGame(const char *gameId) const {
 	FIND_GAME(AGT);
 	FIND_GAME(Alan3);
 	FIND_GAME(Archetype);
+	FIND_GAME(Comprehend);
 	FIND_GAME(Frotz);
 	FIND_GAME(Glulxe);
 	FIND_GAME(Hugo);
@@ -272,6 +277,7 @@ DetectedGames GlkMetaEngine::detectGames(const Common::FSList &fslist) const {
 	Glk::Alan2::Alan2MetaEngine::detectGames(fslist, detectedGames);
 	Glk::Alan3::Alan3MetaEngine::detectGames(fslist, detectedGames);
 	Glk::Archetype::ArchetypeMetaEngine::detectGames(fslist, detectedGames);
+	Glk::Comprehend::ComprehendMetaEngine::detectGames(fslist, detectedGames);
 	Glk::Frotz::FrotzMetaEngine::detectGames(fslist, detectedGames);
 	Glk::Glulxe::GlulxeMetaEngine::detectGames(fslist, detectedGames);
 	Glk::Hugo::HugoMetaEngine::detectGames(fslist, detectedGames);
@@ -293,6 +299,7 @@ void GlkMetaEngine::detectClashes() const {
 	Glk::Alan2::Alan2MetaEngine::detectClashes(map);
 	Glk::Alan3::Alan3MetaEngine::detectClashes(map);
 	Glk::Archetype::ArchetypeMetaEngine::detectClashes(map);
+	Glk::Comprehend::ComprehendMetaEngine::detectClashes(map);
 	Glk::Frotz::FrotzMetaEngine::detectClashes(map);
 	Glk::Glulxe::GlulxeMetaEngine::detectClashes(map);
 	Glk::Hugo::HugoMetaEngine::detectClashes(map);
diff --git a/engines/glk/detection.h b/engines/glk/detection.h
index 4575b27595..b3328ff264 100644
--- a/engines/glk/detection.h
+++ b/engines/glk/detection.h
@@ -129,6 +129,7 @@ struct GlkDetectionEntry {
 	const char *const _md5;
 	size_t _filesize;
 	Common::Language _language;
+	const char *const _filename;
 };
 
 #define DT_ENTRY0(ID, MD5, FILESIZE) { ID, "", MD5, FILESIZE, Common::EN_ANY }
diff --git a/engines/glk/glk_types.h b/engines/glk/glk_types.h
index 7609a90f24..0824661c13 100644
--- a/engines/glk/glk_types.h
+++ b/engines/glk/glk_types.h
@@ -43,6 +43,7 @@ enum InterpreterType {
 	INTERPRETER_ALAN3,
 	INTERPRETER_ARCHETYPE,
 	INTERPRETER_BOCFEL,
+	INTERPRETER_COMPREHEND,
 	INTERPRETER_FROTZ,
 	INTERPRETER_GEAS,
 	INTERPRETER_GLULXE,
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 66028ea394..edffd13a06 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -166,6 +166,8 @@ MODULE_OBJS := \
 	archetype/sys_object.o \
 	archetype/timestamp.o \
 	archetype/token.o \
+	comprehend/comprehend.o \
+	comprehend/detection.o \
 	frotz/bitmap_font.o \
 	frotz/config.o \
 	frotz/detection.o \
diff --git a/engines/glk/quetzal.cpp b/engines/glk/quetzal.cpp
index 6929a0a8cf..f1cece12c3 100644
--- a/engines/glk/quetzal.cpp
+++ b/engines/glk/quetzal.cpp
@@ -48,6 +48,8 @@ uint32 QuetzalBase::getInterpreterTag(InterpreterType interpType) {
 		return MKTAG('A', 'L', 'N', '3');
 	case INTERPRETER_ARCHETYPE:
 		return MKTAG('A', 'R', 'C', 'H');
+	case INTERPRETER_COMPREHEND:
+		return MKTAG('C', 'O', 'M', 'P');
 	case INTERPRETER_FROTZ:
 		return MKTAG('Z', 'C', 'O', 'D');
 	case INTERPRETER_GEAS:


Commit: 7423561d21c7c73a3ee8418b19c864ed562c2ea1
    https://github.com/scummvm/scummvm/commit/7423561d21c7c73a3ee8418b19c864ed562c2ea1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:08-07:00

Commit Message:
GLK: COMPREHEND: Adding recomprehend source files

Changed paths:
  A engines/glk/comprehend/dictionary.cpp
  A engines/glk/comprehend/dictionary.h
  A engines/glk/comprehend/dump_game_data.cpp
  A engines/glk/comprehend/dump_game_data.h
  A engines/glk/comprehend/file_buf.cpp
  A engines/glk/comprehend/file_buf.h
  A engines/glk/comprehend/game.cpp
  A engines/glk/comprehend/game.h
  A engines/glk/comprehend/game_cc.cpp
  A engines/glk/comprehend/game_data.cpp
  A engines/glk/comprehend/game_data.h
  A engines/glk/comprehend/game_oo.cpp
  A engines/glk/comprehend/game_tm.cpp
  A engines/glk/comprehend/game_tr.cpp
  A engines/glk/comprehend/graphics.cpp
  A engines/glk/comprehend/graphics.h
  A engines/glk/comprehend/image_data.cpp
  A engines/glk/comprehend/image_data.h
  A engines/glk/comprehend/image_view.cpp
  A engines/glk/comprehend/opcode_map.cpp
  A engines/glk/comprehend/opcode_map.h
  A engines/glk/comprehend/recomprehend.cpp
  A engines/glk/comprehend/recomprehend.h
  A engines/glk/comprehend/strings.cpp
  A engines/glk/comprehend/strings.h
  A engines/glk/comprehend/util.cpp
  A engines/glk/comprehend/util.h
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/module.mk


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 36480e02e6..a353c2c5cd 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/dump_game_data.h"
 #include "glk/quetzal.h"
 #include "common/config-manager.h"
 #include "common/translation.h"
@@ -28,8 +29,157 @@
 namespace Glk {
 namespace Comprehend {
 
+Comprehend *g_comprehend;
+
+extern struct comprehend_game game_transylvania;
+extern struct comprehend_game game_crimson_crown_1;
+extern struct comprehend_game game_crimson_crown_2;
+extern struct comprehend_game game_oo_topos;
+extern struct comprehend_game game_talisman;
+
+static struct comprehend_game *comprehend_games[] = {
+    &game_transylvania,
+    &game_crimson_crown_1,
+    &game_crimson_crown_2,
+    &game_oo_topos,
+    &game_talisman,
+};
+
+struct dump_option {
+	const char *const option;
+	unsigned flag;
+};
+
+static const dump_option dump_options[] = {
+    {"strings", DUMP_STRINGS},
+    {"extra-strings", DUMP_EXTRA_STRINGS},
+    {"rooms", DUMP_ROOMS},
+    {"items", DUMP_ITEMS},
+    {"dictionary", DUMP_DICTIONARY},
+    {"word-pairs", DUMP_WORD_PAIRS},
+    {"actions", DUMP_ACTIONS},
+    {"functions", DUMP_FUNCTIONS},
+    {"replace-words", DUMP_REPLACE_WORDS},
+    {"header", DUMP_HEADER},
+    {"all", DUMP_ALL},
+};
+
+#ifdef TODO
+int main(int argc, char **argv) {
+	struct option long_opts[] = {
+	    {"debug", no_argument, 0, 'd'},
+	    {"dump", required_argument, 0, 'D'},
+	    {"no-play", no_argument, 0, 'p'},
+	    {"no-graphics", no_argument, 0, 'g'},
+	    {"no-floodfill", no_argument, 0, 'f'},
+	    {"graphics-width", required_argument, 0, 'w'},
+	    {"graphics-height", required_argument, 0, 'h'},
+	    {"help", no_argument, 0, '?'},
+	    {NULL, 0, 0, 0},
+	};
+	const char *short_opts = "dD:pgfw:h:?";
+	struct comprehend_game *game;
+	const char *game_name, *game_dir;
+	unsigned dump_flags = 0;
+	int i, c, opt_index;
+	unsigned graphics_width = G_RENDER_WIDTH,
+	         graphics_height = G_RENDER_HEIGHT;
+	bool play_game = true, graphics_enabled = true;
+
+	while (1) {
+		c = getopt_long(argc, argv, short_opts, long_opts, &opt_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'd':
+			// FIXME
+			debug_enable(DEBUG_FUNCTIONS);
+			break;
+
+		case 'D':
+			for (i = 0; i < ARRAY_SIZE(dump_options); i++)
+				if (strcmp(optarg, dump_options[i].option) == 0)
+					break;
+			if (i == ARRAY_SIZE(dump_options)) {
+				printf("Invalid dump option '%s'\n", optarg);
+				usage(argv[0]);
+			}
+
+			dump_flags |= dump_options[i].flag;
+			break;
+
+		case 'p':
+			play_game = false;
+			break;
+
+		case 'g':
+			graphics_enabled = false;
+			break;
+
+		case 'f':
+			image_set_draw_flags(IMAGEF_NO_FLOODFILL);
+			break;
+
+		case 'w':
+			graphics_width = strtoul(optarg, NULL, 0);
+			break;
+
+		case 'h':
+			graphics_height = strtoul(optarg, NULL, 0);
+			break;
+
+		case '?':
+			usage(argv[0]);
+			break;
+
+		default:
+			printf("Invalid option\n");
+			usage(argv[0]);
+			break;
+		}
+	}
+
+	if (optind >= argc || argc - optind != 2)
+		usage(argv[0]);
+
+	game_name = argv[optind++];
+	game_dir = argv[optind++];
+
+	/* Lookup game */
+	game = NULL;
+	for (i = 0; i < ARRAY_SIZE(comprehend_games); i++) {
+		if (strcmp(game_name, comprehend_games[i]->short_name) == 0) {
+			game = comprehend_games[i];
+			break;
+		}
+	}
+	if (!game) {
+		printf("Unknown game '%s'\n", game_name);
+		usage(argv[0]);
+	}
+
+	if (graphics_enabled)
+		g_init(graphics_width, graphics_height);
+
+	game->info = xmalloc(sizeof(*game->info));
+	comprehend_load_game(game, game_dir);
+
+	if (dump_flags)
+		dump_game_data(game, dump_flags);
+
+	if (play_game)
+		comprehend_play_game(game);
+}
+#endif
+
 Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
 		_saveSlot(-1) {
+	g_comprehend = this;
+}
+
+Comprehend::~Comprehend() {
+	g_comprehend = nullptr;
 }
 
 void Comprehend::runGame() {
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index c4a7797a66..f890dd5c80 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -29,8 +29,41 @@
 namespace Glk {
 namespace Comprehend {
 
+#undef printf
+#define printf debugN
+#undef getchar
+#define getchar() (0)
+
+#define PATH_MAX 256
+
+struct comprehend_game;
+struct game_info;
+struct game_state;
+
+#define EXTRA_STRING_TABLE(x) (0x8200 | (x))
+
+struct game_strings {
+	uint16 game_restart;
+};
+
+#define ROOM_IS_NORMAL 0
+#define ROOM_IS_DARK 1
+#define ROOM_IS_TOO_BRIGHT 2
+
+struct game_ops {
+	void (*before_game)(struct comprehend_game *game);
+	void (*before_prompt)(struct comprehend_game *game);
+	bool (*before_turn)(struct comprehend_game *game);
+	bool (*after_turn)(struct comprehend_game *game);
+	int (*room_is_special)(struct comprehend_game *game,
+	                       unsigned room_index,
+	                       unsigned *room_desc_string);
+	void (*handle_special_opcode)(struct comprehend_game *game,
+	                              uint8 operand);
+};
+
 /**
- * Scott Adams game interpreter
+ * Comprehend engine
  */
 class Comprehend : public GlkAPI {
 private:
@@ -46,6 +79,8 @@ public:
 	 */
 	Comprehend(OSystem *syst, const GlkGameDescription &gameDesc);
 
+	~Comprehend() override;
+
 	/**
 	 * Returns the running interpreter type
 	 */
@@ -72,6 +107,8 @@ public:
 	}
 };
 
+extern Comprehend *g_comprehend;
+
 } // End of namespace Comprehend
 } // End of namespace Glk
 
diff --git a/engines/glk/comprehend/dictionary.cpp b/engines/glk/comprehend/dictionary.cpp
new file mode 100644
index 0000000000..584d2d4f77
--- /dev/null
+++ b/engines/glk/comprehend/dictionary.cpp
@@ -0,0 +1,97 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/dictionary.h"
+
+namespace Glk {
+namespace Comprehend {
+
+static bool word_match(struct word *word, const char *string)
+{
+	/* Words less than 6 characters must match exactly */
+	if (strlen(word->word) < 6 && strlen(string) != strlen(word->word))
+		return false;
+
+	return strncmp(word->word, string, strlen(word->word)) == 0;
+}
+
+struct word *dict_find_word_by_string(struct comprehend_game *game,
+				      const char *string)
+{
+	uint i;
+
+	if (!string)
+		return NULL;
+
+	for (i = 0; i < game->info->nr_words; i++)
+		if (word_match(&game->info->words[i], string))
+			return &game->info->words[i];
+
+	return NULL;
+}
+
+struct word *dict_find_word_by_index_type(struct comprehend_game *game,
+					  uint8 index, uint8 type)
+{
+	uint i;
+
+	for (i = 0; i < game->info->nr_words; i++) {
+		if (game->info->words[i].index == index &&
+		    game->info->words[i].type == type)
+			return &game->info->words[i];
+	}
+
+	return NULL;
+}
+
+struct word *find_dict_word_by_index(struct comprehend_game *game,
+				     uint8 index, uint8 type_mask)
+{
+	uint i;
+
+	for (i = 0; i < game->info->nr_words; i++) {
+		if (game->info->words[i].index == index &&
+		    (game->info->words[i].type & type_mask) != 0)
+			return &game->info->words[i];
+	}
+
+	return NULL;
+}
+
+bool dict_match_index_type(struct comprehend_game *game, const char *word,
+			   uint8 index, uint8 type_mask)
+{
+	uint i;
+
+	for (i = 0; i < game->info->nr_words; i++)
+		if (game->info->words[i].index == index &&
+		    ((game->info->words[i].type & type_mask) != 0) &&
+		    word_match(&game->info->words[i], word))
+			return true;
+
+	return false;
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/dictionary.h b/engines/glk/comprehend/dictionary.h
new file mode 100644
index 0000000000..8efa401473
--- /dev/null
+++ b/engines/glk/comprehend/dictionary.h
@@ -0,0 +1,44 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_DICTIONARY_H
+#define GLK_COMPREHEND_DICTIONARY_H
+
+namespace Glk {
+namespace Comprehend {
+
+struct comprehend_game;
+struct word;
+
+struct word *find_dict_word_by_index(struct comprehend_game *game,
+				     uint8 index, uint8 type_mask);
+struct word *dict_find_word_by_index_type(struct comprehend_game *game,
+					  uint8 index, uint8 type);
+struct word *dict_find_word_by_string(struct comprehend_game *game,
+				      const char *string);
+bool dict_match_index_type(struct comprehend_game *game, const char *word,
+			   uint8 index, uint8 type_mask);
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
new file mode 100644
index 0000000000..99426a36b5
--- /dev/null
+++ b/engines/glk/comprehend/dump_game_data.cpp
@@ -0,0 +1,453 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/dump_game_data.h"
+#include "glk/comprehend/dictionary.h"
+#include "glk/comprehend/file_buf.h"
+#include "glk/comprehend/strings.h"
+#include "glk/comprehend/game.h"
+#include "glk/comprehend/util.h"
+#include "glk/comprehend/opcode_map.h"
+
+namespace Glk {
+namespace Comprehend {
+
+static const char *opcode_names[] = {
+#ifdef TODO
+	[OPCODE_UNKNOWN]			= "unknown",
+
+	[OPCODE_HAVE_OBJECT]			= "have_object",
+	[OPCODE_NOT_HAVE_OBJECT]		= "not_have_object",
+	[OPCODE_HAVE_CURRENT_OBJECT]		= "have_current_object",
+	[OPCODE_NOT_HAVE_CURRENT_OBJECT]	= "not_have_current_object",
+
+	[OPCODE_OBJECT_IS_NOT_NOWHERE]		= "object_is_not_nowhere",
+
+	[OPCODE_CURRENT_OBJECT_TAKEABLE]	= "current_object_takeable",
+	[OPCODE_CURRENT_OBJECT_NOT_TAKEABLE]	= "current_object_not_takeable",
+
+	[OPCODE_CURRENT_OBJECT_IS_NOWHERE]	= "current_object_is_nowhere",
+
+	[OPCODE_CURRENT_OBJECT_NOT_PRESENT]	= "current_object_not_present",
+
+	[OPCODE_TAKE_OBJECT]			= "take_object",
+	[OPCODE_TAKE_CURRENT_OBJECT]		= "take_current_object",
+	[OPCODE_DROP_OBJECT]			= "drop_object",
+	[OPCODE_DROP_CURRENT_OBJECT]		= "drop_current_object",
+
+	[OPCODE_OR]				= "or",
+	[OPCODE_IN_ROOM]			= "in_room",
+	[OPCODE_VAR_EQ]				= "var_eq",
+	[OPCODE_OBJECT_NOT_VALID]	        = "object_not_valid",
+	[OPCODE_INVENTORY_FULL]			= "inventory_full",
+	[OPCODE_OBJECT_PRESENT]			= "object_present",
+	[OPCODE_ELSE]				= "else",
+	[OPCODE_OBJECT_IN_ROOM]			= "object_in_room",
+	[OPCODE_TEST_FLAG]			= "test_flag",
+	[OPCODE_CURRENT_OBJECT_IN_ROOM]		= "current_object_in_room",
+	[OPCODE_CURRENT_OBJECT_PRESENT]		= "current_object_present",
+	[OPCODE_TEST_ROOM_FLAG]			= "test_room_flag",
+	[OPCODE_NOT_IN_ROOM]			= "not_in_room",
+	[OPCODE_OBJECT_NOT_PRESENT]		= "object_not_present",
+	[OPCODE_OBJECT_NOT_IN_ROOM]		= "object_not_in_room",
+	[OPCODE_TEST_NOT_FLAG]			= "test_not_flag",
+	[OPCODE_OBJECT_IS_NOWHERE]		= "object_is_nowhere",
+	[OPCODE_TEST_NOT_ROOM_FLAG]		= "test_not_room_flag",
+	[OPCODE_INVENTORY]			= "inventory",
+	[OPCODE_MOVE_OBJECT_TO_ROOM]		= "move_object_to_room",
+	[OPCODE_SAVE_ACTION]			= "save_action",
+	[OPCODE_MOVE_TO_ROOM]			= "move_to_room",
+	[OPCODE_VAR_ADD]			= "var_add",
+	[OPCODE_SET_ROOM_DESCRIPTION]		= "set_room_description",
+	[OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM]	= "move_object_to_current_room",
+	[OPCODE_VAR_SUB]			= "var_sub",
+	[OPCODE_SET_OBJECT_DESCRIPTION]		= "set_object_description",
+	[OPCODE_SET_OBJECT_LONG_DESCRIPTION]	= "set_object_long_description",
+	[OPCODE_MOVE]				= "move",
+	[OPCODE_PRINT]				= "print",
+	[OPCODE_REMOVE_OBJECT]			= "remove_object",
+	[OPCODE_SET_FLAG]			= "set_flag",
+	[OPCODE_CALL_FUNC]			= "call_func",
+	[OPCODE_TURN_TICK]			= "turn_tick",
+	[OPCODE_CLEAR_FLAG]			= "clear_flag",
+	[OPCODE_INVENTORY_ROOM]			= "inventory_room",
+	[OPCODE_SPECIAL]			= "special",
+	[OPCODE_SET_ROOM_GRAPHIC]		= "set_room_graphic",
+	[OPCODE_SET_OBJECT_GRAPHIC]		= "set_object_graphic",
+	[OPCODE_REMOVE_CURRENT_OBJECT]		= "remove_current_object",
+	[OPCODE_DO_VERB]			= "do_verb",
+	[OPCODE_VAR_INC]			= "var_inc",
+	[OPCODE_VAR_DEC]			= "var_dec",
+	[OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM]	= "move_current_object_to_room",
+	[OPCODE_DESCRIBE_CURRENT_OBJECT]	= "describe_current_object",
+	[OPCODE_SET_STRING_REPLACEMENT]		= "set_string_replacement",
+	[OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT] = "set_current_noun_string_replacement",
+	[OPCODE_CURRENT_NOT_OBJECT]		= "current_not_object",
+	[OPCODE_CURRENT_IS_OBJECT]		= "current_is_object",
+	[OPCODE_DRAW_ROOM]			= "draw_room",
+	[OPCODE_DRAW_OBJECT]			= "draw_object",
+	[OPCODE_WAIT_KEY]			= "wait_key",
+#else
+	"TODO"
+#endif
+};
+
+void dump_instruction(struct comprehend_game *game,
+		      struct function_state *func_state,
+		      struct instruction *instr)
+{
+	uint i;
+	int str_index, str_table;
+	uint8 *opcode_map, opcode;
+
+	if (func_state)
+		debugN("[or=%d,and=%d,test=%d,else=%d]",
+		       func_state->or_count, func_state->_and,
+		       func_state->test_result, func_state->else_result);
+
+	opcode_map = get_opcode_map(game);
+	opcode = opcode_map[instr->opcode];
+
+	debugN("  [%.2x] ", instr->opcode);
+	if (opcode < ARRAY_SIZE(opcode_names) && opcode_names[opcode])
+		debugN("%s", opcode_names[opcode]);
+	else
+		debugN("unknown");
+
+	if (instr->nr_operands) {
+		debugN("(");
+		for (i = 0; i < instr->nr_operands; i++)
+			debugN("%.2x%s", instr->operand[i],
+			       i == instr->nr_operands - 1 ? ")" : ", ");
+	}
+
+	switch (opcode) {
+	case OPCODE_PRINT:
+	case OPCODE_SET_ROOM_DESCRIPTION:
+	case OPCODE_SET_OBJECT_DESCRIPTION:
+	case OPCODE_SET_OBJECT_LONG_DESCRIPTION:
+
+		if (opcode == OPCODE_PRINT) {
+			str_index = instr->operand[0];
+			str_table = instr->operand[1];
+		} else {
+			str_index = instr->operand[1];
+			str_table = instr->operand[2];
+		}
+
+		debugN(" %s", instr_lookup_string(game, str_index, str_table));
+		break;
+
+	case OPCODE_SET_STRING_REPLACEMENT:
+		debugN(" %s", game->info->replace_words[instr->operand[0] - 1]);
+		break;
+	}
+
+	debugN("\n");
+}
+
+static void dump_functions(struct comprehend_game *game)
+{
+	struct function *func;
+	uint i, j;
+
+	debugN("Functions (%zd entries)\n", game->info->nr_functions);
+	for (i = 0; i < game->info->nr_functions; i++) {
+		func = &game->info->functions[i];
+
+		debugN("[%.4x] (%zd instructions)\n", i, func->nr_instructions);
+		for (j = 0; j < func->nr_instructions; j++)
+			dump_instruction(game, NULL, &func->instructions[j]);
+		debugN("\n");
+	}
+}
+
+static void dump_action_table(struct comprehend_game *game)
+{
+	struct action *action;
+	struct word *word;
+	uint i, j;
+
+	debugN("Action table (%zd entries)\n", game->info->nr_actions);
+	for (i = 0; i < game->info->nr_actions; i++) {
+		action = &game->info->action[i];
+
+		debugN("(");
+		for (j = 0; j < 4; j++) {
+			if (j < action->nr_words) {
+				switch (action->word_type[j]) {
+				case WORD_TYPE_VERB: debugN("v"); break;
+				case WORD_TYPE_JOIN: debugN("j"); break;
+				case WORD_TYPE_NOUN_MASK: debugN("n"); break;
+				default: debugN("?"); break;
+				}
+			} else {
+				debugN(" ");
+			}
+		}
+
+		debugN(") [%.4x] ", i );
+
+		for (j = 0; j < action->nr_words; j++)
+			debugN("%.2x:%.2x ",
+			       action->word[j], action->word_type[j]);
+
+		debugN("| ");
+
+		for (j = 0; j < action->nr_words; j++) {
+			word = find_dict_word_by_index(game, action->word[j],
+						       action->word_type[j]);
+			if (word)
+				debugN("%-6s ", word->word);
+			else
+				debugN("%.2x:%.2x  ", action->word[j],
+				       action->word_type[j]);
+		}
+
+		debugN("-> %.4x\n", action->function);
+	}
+}
+
+static int word_index_compare(const void *a, const void *b)
+{
+	const word *word_a = (const word *)a, *word_b = (const word *)b;
+
+	if (word_a->index > word_b->index)
+		return 1;
+	if (word_a->index < word_b->index)
+		return -1;
+	return 0;
+}
+
+static void dump_dictionary(struct comprehend_game *game)
+{
+	word *dictionary;
+	word *words;
+	uint i;
+
+	/* Sort the dictionary by index */
+	dictionary = (word *)xmalloc(sizeof(*words) * game->info->nr_words);
+	memcpy(dictionary, game->info->words,
+	       sizeof(*words) * game->info->nr_words);
+	qsort(dictionary, game->info->nr_words, sizeof(*words),
+	      word_index_compare);
+
+	debugN("Dictionary (%zd words)\n", game->info->nr_words);
+	for (i = 0; i < game->info->nr_words; i++) {
+		words = &dictionary[i];
+		debugN("  [%.2x] %.2x %s\n", words->index, words->type,
+		       words->word);
+	}
+
+	free(dictionary);
+}
+
+static void dump_word_map(struct comprehend_game *game)
+{
+	struct word *word[3];
+	char str[3][6];
+	struct word_map *map;
+	uint i, j;
+
+	debugN("Word pairs (%zd entries)\n", game->info->nr_word_maps);
+	for (i = 0; i < game->info->nr_word_maps; i++) {
+		map = &game->info->word_map[i];
+
+		for (j = 0; j < 3; j++) {
+			word[j] = dict_find_word_by_index_type(
+				game, map->word[j].index, map->word[j].type);
+			if (word[j])
+				snprintf(str[j], sizeof(str[j]),
+					 "%s", word[j]->word);
+			else
+				snprintf(str[j], sizeof(str[j]), "%.2x:%.2x ",
+					 map->word[j].index, map->word[j].type);
+		}
+
+		debugN("  [%.2x] %-6s %-6s -> %-6s\n",
+		       i, str[0], str[1], str[2]);
+	}
+}
+
+static void dump_rooms(struct comprehend_game *game)
+{
+	struct room *room;
+	uint i;
+
+	/* Room zero acts as the players inventory */
+	debugN("Rooms (%zd entries)\n", game->info->nr_rooms);
+	for (i = 1; i <= game->info->nr_rooms; i++) {
+		room = &game->info->rooms[i];
+
+		debugN("  [%.2x] flags=%.2x, graphic=%.2x\n",
+		       i, room->flags, room->graphic);
+		debugN("    %s\n", string_lookup(game, room->string_desc));
+		debugN("    n: %.2x  s: %.2x  e: %.2x  w: %.2x\n",
+		       room->direction[DIRECTION_NORTH],
+		       room->direction[DIRECTION_SOUTH],
+		       room->direction[DIRECTION_EAST],
+		       room->direction[DIRECTION_WEST]);
+		debugN("    u: %.2x  d: %.2x  i: %.2x  o: %.2x\n",
+		       room->direction[DIRECTION_UP],
+		       room->direction[DIRECTION_DOWN],
+		       room->direction[DIRECTION_IN],
+		       room->direction[DIRECTION_OUT]);
+		debugN("\n");
+	}
+}
+
+static void dump_items(struct comprehend_game *game)
+{
+	struct item *item;
+	uint i, j;
+
+	debugN("Items (%zd entries)\n", game->info->header.nr_items);
+	for (i = 0; i < game->info->header.nr_items; i++) {
+		item = &game->info->item[i];
+
+		debugN("  [%.2x] %s\n", i + 1,
+		       item->string_desc ?
+		       string_lookup(game, item->string_desc) : "");
+		if (game->info->comprehend_version == 2)
+			debugN("    long desc: %s\n",
+			       string_lookup(game, item->long_string));
+
+		debugN("    words: ");
+		for (j = 0; j < game->info->nr_words; j++)
+			if (game->info->words[j].index == item->word &&
+			    (game->info->words[j].type & WORD_TYPE_NOUN_MASK))
+				debugN("%s ", game->info->words[j].word);
+		debugN("\n");
+		debugN("    flags=%.2x (takeable=%d, weight=%d)\n",
+		       item->flags, !!(item->flags & ITEMF_CAN_TAKE),
+		       (item->flags & ITEMF_WEIGHT_MASK));
+		debugN("    room=%.2x, graphic=%.2x\n",
+		       item->room, item->graphic);
+		debugN("\n");
+	}
+}
+
+static void dump_string_table(struct string_table *table)
+{
+	uint i;
+
+	for (i = 0; i < table->nr_strings; i++)
+		debugN("[%.4x] %s\n", i, table->strings[i]);
+}
+
+static void dump_game_data_strings(struct comprehend_game *game)
+{
+	debugN("Main string table (%zd entries)\n",
+	       game->info->strings.nr_strings);
+	dump_string_table(&game->info->strings);
+}
+
+static void dump_extra_strings(struct comprehend_game *game)
+{
+	debugN("Extra strings (%zd entries)\n",
+	       game->info->strings2.nr_strings);
+	dump_string_table(&game->info->strings2);
+}
+
+static void dump_replace_words(struct comprehend_game *game)
+{
+	uint i;
+
+	debugN("Replacement words (%zd entries)\n",
+	       game->info->nr_replace_words);
+	for (i = 0; i < game->info->nr_replace_words; i++)
+		debugN("  [%.2x] %s\n", i + 1, game->info->replace_words[i]);
+}
+
+static void dump_header(struct comprehend_game *game)
+{
+	struct game_header *header = &game->info->header;
+	uint16 *dir_table = header->room_direction_table;
+
+	debugN("Game header:\n");
+	debugN("  magic:                %.4x\n", header->magic);
+	debugN("  action(vvnn):         %.4x\n", header->addr_actions_vvnn);
+	debugN("  actions(?):\n");
+	debugN("  actions(vnjn):        %.4x\n", header->addr_actions_vnjn);
+	debugN("  actions(vjn):         %.4x\n", header->addr_actions_vjn);
+	debugN("  actions(vdn):         %.4x\n", header->addr_actions_vdn);
+	debugN("  actions(vnn):         %.4x\n", header->addr_actions_vnn);
+	debugN("  actions(vn):          %.4x\n", header->addr_actions_vn);
+	debugN("  actions(v):           %.4x\n", header->addr_actions_v);
+	debugN("  functions:            %.4x\n", header->addr_vm);
+	debugN("  dictionary:           %.4x\n", header->addr_dictionary);
+	debugN("  word map pairs:       %.4x\n", header->addr_word_map);
+	debugN("  room desc strings:    %.4x\n", header->room_desc_table);
+	debugN("  room north:           %.4x\n", dir_table[DIRECTION_NORTH]);
+	debugN("  room south:           %.4x\n", dir_table[DIRECTION_SOUTH]);
+	debugN("  room east:            %.4x\n", dir_table[DIRECTION_EAST]);
+	debugN("  room west:            %.4x\n", dir_table[DIRECTION_WEST]);
+	debugN("  room up:              %.4x\n", dir_table[DIRECTION_UP]);
+	debugN("  room down:            %.4x\n", dir_table[DIRECTION_DOWN]);
+	debugN("  room in:              %.4x\n", dir_table[DIRECTION_IN]);
+	debugN("  room out:             %.4x\n", dir_table[DIRECTION_OUT]);
+	debugN("  room flags:           %.4x\n", header->room_flags_table);
+	debugN("  room images:          %.4x\n", header->room_graphics_table);
+	debugN("  item locations:       %.4x\n", header->addr_item_locations);
+	debugN("  item flags:           %.4x\n", header->addr_item_flags);
+	debugN("  item words:           %.4x\n", header->addr_item_word);
+	debugN("  item desc strings:    %.4x\n", header->addr_item_strings);
+	debugN("  item images:          %.4x\n", header->addr_item_graphics);
+	debugN("  string table:         %.4x\n", header->addr_strings);
+	debugN("  string table end:     %.4x\n", header->addr_strings_end);
+}
+
+typedef void (*dump_func_t)(struct comprehend_game *game);
+
+struct dumper {
+	dump_func_t	dump_func;
+	unsigned	flag;
+};
+
+static struct dumper dumpers[] = {
+	{dump_header,			DUMP_HEADER},
+	{dump_game_data_strings,	DUMP_STRINGS},
+	{dump_extra_strings,		DUMP_EXTRA_STRINGS},
+	{dump_rooms,			DUMP_ROOMS},
+	{dump_items,			DUMP_ITEMS},
+	{dump_dictionary,		DUMP_DICTIONARY},
+	{dump_word_map,			DUMP_WORD_PAIRS},
+	{dump_action_table,		DUMP_ACTIONS},
+	{dump_functions,		DUMP_FUNCTIONS},
+	{dump_replace_words,		DUMP_REPLACE_WORDS},
+};
+
+void dump_game_data(struct comprehend_game *game, unsigned flags)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(dumpers); i++)
+		if (flags & dumpers[i].flag) {
+			dumpers[i].dump_func(game);
+			debugN("\n\n");
+		}
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/dump_game_data.h b/engines/glk/comprehend/dump_game_data.h
new file mode 100644
index 0000000000..dbcaf52022
--- /dev/null
+++ b/engines/glk/comprehend/dump_game_data.h
@@ -0,0 +1,53 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_DUMP_GAME_DATA_H
+#define GLK_COMPREHEND_DUMP_GAME_DATA_H
+
+namespace Glk {
+namespace Comprehend {
+
+struct comprehend_game;
+struct function_state;
+struct instruction;
+
+#define DUMP_STRINGS (1 << 0)
+#define DUMP_EXTRA_STRINGS (1 << 1)
+#define DUMP_ROOMS (1 << 2)
+#define DUMP_ITEMS (1 << 3)
+#define DUMP_DICTIONARY (1 << 4)
+#define DUMP_WORD_PAIRS (1 << 5)
+#define DUMP_ACTIONS (1 << 6)
+#define DUMP_FUNCTIONS (1 << 7)
+#define DUMP_REPLACE_WORDS (1 << 8)
+#define DUMP_HEADER (1 << 9)
+#define DUMP_ALL (~0)
+
+void dump_instruction(struct comprehend_game *game,
+                      struct function_state *func_state,
+                      struct instruction *instr);
+void dump_game_data(struct comprehend_game *game, unsigned flags);
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/file_buf.cpp b/engines/glk/comprehend/file_buf.cpp
new file mode 100644
index 0000000000..512d88c705
--- /dev/null
+++ b/engines/glk/comprehend/file_buf.cpp
@@ -0,0 +1,166 @@
+/* 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 "glk/comprehend/file_buf.h"
+#include "glk/comprehend/util.h"
+#include "common/algorithm.h"
+#include "common/file.h"
+
+namespace Glk {
+namespace Comprehend {
+
+int file_buf_map_may_fail(const char *filename, struct file_buf *fb)
+{
+	Common::File f;
+
+	memset(fb, 0, sizeof(*fb));
+
+	if (!f.open(filename))
+		return -1;
+
+	fb->data = (uint8 *)xmalloc(f.size());
+	fb->size = f.size();
+	f.read(fb->data, fb->size);
+	f.close();
+
+	fb->p = fb->data;
+
+	// FIXME - remove
+	fb->marked = (uint8 *)malloc(fb->size);
+	memset(fb->marked, 0, fb->size);
+
+	return 0;
+}
+
+void file_buf_map(const char *filename, struct file_buf *fb)
+{
+	int err;
+
+	err = file_buf_map_may_fail(filename, fb);
+	if (err)
+		fatal_strerror(errno, "Cannot open file '%s'", filename);
+}
+
+void file_buf_unmap(struct file_buf *fb)
+{
+	free(fb->marked);
+	free(fb->data);
+}
+
+void file_buf_set_pos(struct file_buf *fb, unsigned pos)
+{
+	if (pos > fb->size)
+		error("Bad position set in file (%x > %x)",
+			    pos, fb->size);
+
+	fb->p = fb->data + pos;
+}
+
+unsigned file_buf_get_pos(struct file_buf *fb)
+{
+	return fb->p - fb->data;
+}
+
+void *file_buf_data_pointer(struct file_buf *fb)
+{
+	return fb->p;
+}
+
+size_t file_buf_strlen(struct file_buf *fb, bool *eof)
+{
+	uint8 *end;
+
+	if (eof)
+		*eof = false;
+
+	end = (uint8 *)memchr(fb->p, '\0', fb->size - file_buf_get_pos(fb));
+	if (!end) {
+		/* No null terminator - string is remaining length */
+		if (eof)
+			*eof = true;
+		return fb->size - file_buf_get_pos(fb);
+	}
+
+	return end - fb->p;
+}
+
+void file_buf_get_data(struct file_buf *fb, void *data, size_t data_size)
+{
+	if (file_buf_get_pos(fb) + data_size > fb->size)
+		error("Not enough data in file (%x + %x > %x)",
+			    file_buf_get_pos(fb), data_size, fb->size);
+
+	if (data)
+		memcpy(data, fb->p, data_size);
+
+	/* Mark this region of the file as read */
+	memset(fb->marked + file_buf_get_pos(fb), '?', data_size);
+
+	fb->p += data_size;
+}
+
+void file_buf_get_u8(struct file_buf *fb, uint8 *val)
+{
+	file_buf_get_data(fb, val, sizeof(*val));
+}
+
+void file_buf_get_le16(struct file_buf *fb, uint16 *val)
+{
+	file_buf_get_data(fb, val, sizeof(*val));
+	*val = READ_LE_UINT16(val);
+}
+
+/*
+ * Debugging function to show regions of a file that have not been read.
+ */
+void file_buf_show_unmarked(struct file_buf *fb)
+{
+	int i, start = -1;
+
+	for (i = 0; i < (int)fb->size; i++) {
+		if (!fb->marked[i] && start == -1)
+			start = i;
+
+		if ((fb->marked[i] || i == (int)fb->size - 1) && start != -1) {
+			warning("%.4x - %.4x unmarked (%d bytes)\n", 
+			       start, i - 1, i - start);
+			start = -1;
+		}
+	}
+}
+
+void file_buf_put_u8(Common::WriteStream *fd, uint8 val)
+{
+	fd->writeByte(val);
+}
+
+void file_buf_put_le16(Common::WriteStream *fd, uint16 val) {
+	fd->writeUint16LE(val);
+}
+
+void file_buf_put_skip(Common::WriteStream *fd, size_t skip) {
+	for (uint i = 0; i < skip; i++)
+		file_buf_put_u8(fd, 0);
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/file_buf.h b/engines/glk/comprehend/file_buf.h
new file mode 100644
index 0000000000..27d1371034
--- /dev/null
+++ b/engines/glk/comprehend/file_buf.h
@@ -0,0 +1,88 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_FILE_BUF_H
+#define GLK_COMPREHEND_FILE_BUF_H
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+
+namespace Glk {
+namespace Comprehend {
+
+struct file_buf {
+	uint8		*data;
+	size_t		size;
+	uint8		*p;
+
+	uint8		*marked;
+};
+
+void file_buf_map(const char *filename, struct file_buf *fb);
+int file_buf_map_may_fail(const char *filename, struct file_buf *fb);
+void file_buf_unmap(struct file_buf *fb);
+void file_buf_show_unmarked(struct file_buf *fb);
+
+void *file_buf_data_pointer(struct file_buf *fb);
+void file_buf_set_pos(struct file_buf *fb, unsigned pos);
+unsigned file_buf_get_pos(struct file_buf *fb);
+
+size_t file_buf_strlen(struct file_buf *fb, bool *eof);
+
+void file_buf_get_data(struct file_buf *fb, void *data, size_t data_size);
+void file_buf_get_u8(struct file_buf *fb, uint8 *val);
+void file_buf_get_le16(struct file_buf *fb, uint16 *val);
+
+#define file_buf_get_array(fb, type, base, array, member, size)		\
+	do {								\
+		uint __i;						\
+		for (__i = (base); __i < (base) + (size); __i++)	\
+			file_buf_get_##type(fb, &((array)[__i]).member); \
+	} while (0)
+
+#define file_buf_get_array_u8(fb, base, array, member, size) \
+	file_buf_get_array(fb, u8, base, array, member, size)
+
+#define file_buf_get_array_le16(fb, base, array, member, size) \
+	file_buf_get_array(fb, le16, base, array, member, size)
+
+void file_buf_put_skip(Common::WriteStream *fd, size_t skip);
+void file_buf_put_u8(Common::WriteStream *fd, uint8 val);
+void file_buf_put_le16(Common::WriteStream *fd, uint16 val);
+
+#define file_buf_put_array(fd, type, base, array, member, size)		\
+	do {								\
+		int __i;						\
+		for (__i = (base); __i < (base) + (size); __i++)	\
+			file_buf_put_##type(fd, (array)[__i].member);	\
+	} while (0)
+
+#define file_buf_put_array_le16(fd, base, array, member, size) \
+	file_buf_put_array(fd, le16, base, array, member, size)
+
+#define file_buf_put_array_u8(fd, base, array, member, size) \
+	file_buf_put_array(fd, u8, base, array, member, size)
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
new file mode 100644
index 0000000000..8dd1b9d789
--- /dev/null
+++ b/engines/glk/comprehend/game.cpp
@@ -0,0 +1,1231 @@
+/* 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 "glk/comprehend/game.h"
+#include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/dictionary.h"
+#include "glk/comprehend/dump_game_data.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/opcode_map.h"
+#include "glk/comprehend/strings.h"
+#include "glk/comprehend/util.h"
+
+namespace Glk {
+namespace Comprehend {
+
+struct sentence {
+	struct word words[4];
+	size_t nr_words;
+};
+
+struct winsize {
+	uint ws_col;
+};
+static struct winsize console_winsize;
+
+static void console_init(void) {
+	//	ioctl(STDOUT_FILENO, TIOCGWINSZ, &console_winsize);
+}
+
+int console_get_key(void) {
+	int c, dummy;
+
+	dummy = c = getchar();
+
+	/* Clear input buffer */
+	while (dummy != '\n' && dummy != EOF)
+		dummy = getchar();
+
+	return c;
+}
+
+void console_println(comprehend_game *game, const char *text) {
+	const char *replace, *word = nullptr, *p = text;
+	char bad_word[64];
+	size_t line_length = 0;
+	int word_len = 0;
+
+	if (!text) {
+		printf("\n");
+		return;
+	}
+
+	while (*p) {
+		switch (*p) {
+		case '\n':
+			word = NULL;
+			word_len = 0;
+			line_length = 0;
+			printf("\n");
+			p++;
+			break;
+
+		case '@':
+			/* Replace word */
+			if (game->info->current_replace_word >= game->info->nr_replace_words) {
+				snprintf(bad_word, sizeof(bad_word),
+				         "[BAD_REPLACE_WORD(%.2x)]",
+				         game->info->current_replace_word);
+				word = bad_word;
+			} else {
+				word = game->info->replace_words[game->info->current_replace_word];
+			}
+			word_len = strlen(word);
+			p++;
+			break;
+
+		default:
+			/* Find next space */
+			word_len = strcspn(p, " \n");
+			if (word_len == 0)
+				break;
+
+			/*
+			 * If this word contains a replacement symbol, then
+			 * print everything before the symbol.
+			 */
+			replace = strchr(p, '@');
+			if (replace)
+				word_len = replace - p;
+
+			word = p;
+			p += word_len;
+			break;
+		}
+
+		if (!word || !word_len)
+			continue;
+
+		/* Print this word */
+		if (line_length + word_len > console_winsize.ws_col) {
+			/* Too long - insert a line break */
+			printf("\n");
+			line_length = 0;
+		}
+
+		printf("%.*s", word_len, word);
+		line_length += word_len;
+
+		if (*p == ' ') {
+			if (line_length >= console_winsize.ws_col) {
+				/* Newline, don't print the space */
+				printf("\n");
+				line_length = 0;
+			} else {
+				printf(" ");
+				line_length++;
+			}
+			p++;
+
+			/* Skip any double spaces */
+			while (*p == ' ')
+				p++;
+		}
+	}
+
+	printf("\n");
+}
+
+static struct room *get_room(comprehend_game *game, uint16 index) {
+	/* Room zero is reserved for the players inventory */
+	if (index == 0)
+		fatal_error("Room index 0 (player inventory) is invalid");
+
+	if (index - 1 >= (int)game->info->nr_rooms)
+		fatal_error("Room index %d is invalid", index);
+
+	return &game->info->rooms[index];
+}
+
+struct item *get_item(comprehend_game *game, uint16 index) {
+	if (index >= game->info->header.nr_items)
+		fatal_error("Bad item %d\n", index);
+
+	return &game->info->item[index];
+}
+
+void game_save(comprehend_game *game) {
+	char path[PATH_MAX], filename[32];
+	int c;
+
+	console_println(game, game->info->strings.strings[STRING_SAVE_GAME]);
+
+	c = console_get_key();
+	if (c < '1' || c > '3') {
+		/*
+		 * The original Comprehend games just silently ignore any
+		 * invalid selection.
+		 */
+		console_println(game, "Invalid save game number");
+		return;
+	}
+
+	snprintf(filename, sizeof(filename), game->save_game_file_fmt, c - '0');
+	snprintf(path, sizeof(path), "%s%s", game->game_dir, filename);
+	comprehend_save_game(game, path);
+}
+
+void game_restore(comprehend_game *game) {
+	char path[PATH_MAX], filename[32];
+	int c;
+
+	console_println(game, game->info->strings.strings[STRING_RESTORE_GAME]);
+
+	c = console_get_key();
+	if (c < '1' || c > '3') {
+		/*
+		 * The original Comprehend games just silently ignore any
+		 * invalid selection.
+		 */
+		console_println(game, "Invalid save game number");
+		return;
+	}
+
+	snprintf(filename, sizeof(filename), game->save_game_file_fmt, c - '0');
+	snprintf(path, sizeof(path), "%s%s", game->game_dir, filename);
+	comprehend_restore_game(game, path);
+
+	game->info->update_flags = UPDATE_ALL;
+}
+
+void game_restart(comprehend_game *game) {
+	console_println(game, string_lookup(game, game->strings->game_restart));
+	console_get_key();
+
+	comprehend_load_game(game, game->game_dir);
+	game->info->update_flags = UPDATE_ALL;
+}
+
+static struct word_index *is_word_pair(comprehend_game *game,
+                                       struct word *word1, struct word *word2) {
+	struct word_map *map;
+	uint i;
+
+	/* Check if this is a word pair */
+	for (i = 0; i < game->info->nr_word_maps; i++) {
+		map = &game->info->word_map[i];
+
+		if (map->word[0].index == word1->index &&
+		    map->word[0].type == word1->type &&
+		    map->word[1].index == word2->index &&
+		    map->word[1].type == word2->type)
+			return &map->word[2];
+	}
+
+	return NULL;
+}
+
+static struct item *get_item_by_noun(comprehend_game *game,
+                                     struct word *noun) {
+	uint i;
+
+	if (!noun || !(noun->type & WORD_TYPE_NOUN_MASK))
+		return NULL;
+
+	/*
+	 * FIXME - in oo-topos the word 'box' matches more than one object
+	 *         (the box and the snarl-in-a-box). The player is unable
+	 *         to drop the latter because this will match the former.
+	 */
+	for (i = 0; i < game->info->header.nr_items; i++)
+		if (game->info->item[i].word == noun->index)
+			return &game->info->item[i];
+
+	return NULL;
+}
+
+static void update_graphics(comprehend_game *game) {
+	struct item *item;
+	struct room *room;
+	int type;
+	uint i;
+
+	if (!g_enabled())
+		return;
+
+	type = ROOM_IS_NORMAL;
+	if (game->ops->room_is_special)
+		type = game->ops->room_is_special(game, game->info->current_room, NULL);
+
+	switch (type) {
+	case ROOM_IS_DARK:
+		if (game->info->update_flags & UPDATE_GRAPHICS)
+			draw_dark_room();
+		break;
+
+	case ROOM_IS_TOO_BRIGHT:
+		if (game->info->update_flags & UPDATE_GRAPHICS)
+			draw_bright_room();
+		break;
+
+	default:
+		if (game->info->update_flags & UPDATE_GRAPHICS) {
+			room = get_room(game, game->info->current_room);
+			draw_location_image(&game->info->room_images,
+			                    room->graphic - 1);
+		}
+
+		if ((game->info->update_flags & UPDATE_GRAPHICS) ||
+		    (game->info->update_flags & UPDATE_GRAPHICS_ITEMS)) {
+			for (i = 0; i < game->info->header.nr_items; i++) {
+				item = &game->info->item[i];
+
+				if (item->room == game->info->current_room &&
+				    item->graphic != 0)
+					draw_image(&game->info->item_images,
+					           item->graphic - 1);
+			}
+		}
+		break;
+	}
+}
+
+static void describe_objects_in_current_room(comprehend_game *game) {
+	struct item *item;
+	size_t count = 0;
+	uint i;
+
+	for (i = 0; i < game->info->header.nr_items; i++) {
+		item = &game->info->item[i];
+
+		if (item->room == game->info->current_room &&
+		    item->string_desc != 0)
+			count++;
+	}
+
+	if (count > 0) {
+		console_println(game, string_lookup(game, STRING_YOU_SEE));
+
+		for (i = 0; i < game->info->header.nr_items; i++) {
+			item = &game->info->item[i];
+
+			if (item->room == game->info->current_room &&
+			    item->string_desc != 0)
+				console_println(game, string_lookup(game, item->string_desc));
+		}
+	}
+}
+
+static void update(comprehend_game *game) {
+	struct room *room = get_room(game, game->info->current_room);
+	unsigned room_type, room_desc_string;
+
+	update_graphics(game);
+
+	/* Check if the room is special (dark, too bright, etc) */
+	room_type = ROOM_IS_NORMAL;
+	room_desc_string = room->string_desc;
+	if (game->ops->room_is_special)
+		room_type = game->ops->room_is_special(game,
+		                                       game->info->current_room,
+		                                       &room_desc_string);
+
+	if (game->info->update_flags & UPDATE_ROOM_DESC)
+		console_println(game, string_lookup(game, room_desc_string));
+
+	if ((game->info->update_flags & UPDATE_ITEM_LIST) &&
+	    room_type == ROOM_IS_NORMAL)
+		describe_objects_in_current_room(game);
+
+	game->info->update_flags = 0;
+}
+
+static void move_to(comprehend_game *game, uint8 room) {
+	if (room - 1 >= (int)game->info->nr_rooms)
+		fatal_error("Attempted to move to invalid room %.2x\n", room);
+
+	game->info->current_room = room;
+	game->info->update_flags = (UPDATE_GRAPHICS | UPDATE_ROOM_DESC |
+	                            UPDATE_ITEM_LIST);
+}
+
+static void func_set_test_result(struct function_state *func_state, bool value) {
+	if (func_state->or_count == 0) {
+		/* And */
+		if (func_state->_and) {
+			if (!value)
+				func_state->test_result = false;
+		} else {
+			func_state->test_result = value;
+			func_state->_and = true;
+		}
+
+	} else {
+		/* Or */
+		if (value)
+			func_state->test_result = value;
+	}
+}
+
+static size_t num_objects_in_room(comprehend_game *game, int room) {
+	size_t count = 0, i;
+
+	for (i = 0; i < game->info->header.nr_items; i++)
+		if (game->info->item[i].room == room)
+			count++;
+
+	return count;
+}
+
+void move_object(comprehend_game *game, struct item *item, int new_room) {
+	unsigned obj_weight = item->flags & ITEMF_WEIGHT_MASK;
+
+	if (item->room == new_room)
+		return;
+
+	if (item->room == ROOM_INVENTORY) {
+		/* Removed from player's inventory */
+		game->info->variable[VAR_INVENTORY_WEIGHT] -= obj_weight;
+	}
+	if (new_room == ROOM_INVENTORY) {
+		/* Moving to the player's inventory */
+		game->info->variable[VAR_INVENTORY_WEIGHT] += obj_weight;
+	}
+
+	if (item->room == game->info->current_room) {
+		/* Item moved away from the current room */
+		game->info->update_flags |= UPDATE_GRAPHICS;
+
+	} else if (new_room == game->info->current_room) {
+		/*
+		 * Item moved into the current room. Only the item needs a
+		 * redraw, not the whole room.
+		 */
+		game->info->update_flags |= (UPDATE_GRAPHICS_ITEMS |
+		                             UPDATE_ITEM_LIST);
+	}
+
+	item->room = new_room;
+}
+
+static void eval_instruction(comprehend_game *game,
+                             struct function_state *func_state,
+                             struct instruction *instr,
+                             struct word *verb, struct word *noun) {
+	uint8 *opcode_map;
+	struct room *room;
+	struct item *item;
+	uint16 index;
+	bool test;
+	uint i, count;
+
+	room = get_room(game, game->info->current_room);
+
+	if (debugging_enabled()) {
+		if (!instr->is_command) {
+			printf("? ");
+		} else {
+			if (func_state->test_result)
+				printf("+ ");
+			else
+				printf("- ");
+		}
+
+		dump_instruction(game, func_state, instr);
+	}
+
+	if (func_state->or_count)
+		func_state->or_count--;
+
+	if (instr->is_command) {
+		bool do_command;
+
+		func_state->in_command = true;
+		do_command = func_state->test_result;
+
+		if (func_state->or_count != 0)
+			printf("Warning: or_count == %d\n",
+			       func_state->or_count);
+		func_state->or_count = 0;
+
+		if (!do_command)
+			return;
+
+		func_state->else_result = false;
+		func_state->executed = true;
+
+	} else {
+		if (func_state->in_command) {
+			/* Finished command sequence - clear test result */
+			func_state->in_command = false;
+			func_state->test_result = false;
+			func_state->_and = false;
+		}
+	}
+
+	opcode_map = get_opcode_map(game);
+	switch (opcode_map[instr->opcode]) {
+	case OPCODE_VAR_ADD:
+		game->info->variable[instr->operand[0]] +=
+		    game->info->variable[instr->operand[1]];
+		break;
+
+	case OPCODE_VAR_SUB:
+		game->info->variable[instr->operand[0]] -=
+		    game->info->variable[instr->operand[1]];
+		break;
+
+	case OPCODE_VAR_INC:
+		game->info->variable[instr->operand[0]]++;
+		break;
+
+	case OPCODE_VAR_DEC:
+		game->info->variable[instr->operand[0]]--;
+		break;
+
+	case OPCODE_VAR_EQ:
+		func_set_test_result(func_state,
+		                     game->info->variable[instr->operand[0]] ==
+		                         game->info->variable[instr->operand[1]]);
+		break;
+
+	case OPCODE_TURN_TICK:
+		game->info->variable[VAR_TURN_COUNT]++;
+		break;
+
+	case OPCODE_PRINT:
+		console_println(game, instr_lookup_string(game,
+		                                          instr->operand[0],
+		                                          instr->operand[1]));
+		break;
+
+	case OPCODE_TEST_NOT_ROOM_FLAG:
+		func_set_test_result(func_state,
+		                     !(room->flags & instr->operand[0]));
+		break;
+
+	case OPCODE_TEST_ROOM_FLAG:
+		func_set_test_result(func_state,
+		                     room->flags & instr->operand[0]);
+		break;
+
+	case OPCODE_NOT_IN_ROOM:
+		func_set_test_result(func_state,
+		                     game->info->current_room != instr->operand[0]);
+		break;
+
+	case OPCODE_IN_ROOM:
+		func_set_test_result(func_state,
+		                     game->info->current_room == instr->operand[0]);
+		break;
+
+	case OPCODE_MOVE_TO_ROOM:
+		if (instr->operand[0] == 0xff) {
+			/*
+			 * FIXME - Not sure what this is for. Transylvania
+			 * uses it in the 'go north' case when in room
+			 * 0x01 or 0x0c, and Oo-Topos uses it when you shoot
+			 * the alien. Ignore it for now.
+			 */
+			break;
+		}
+
+		move_to(game, instr->operand[0]);
+		break;
+
+	case OPCODE_MOVE:
+		/* Move in the direction dictated by the current verb */
+		if (verb->index - 1 >= NR_DIRECTIONS)
+			fatal_error("Bad verb %d:%d in move",
+			            verb->index, verb->type);
+
+		if (room->direction[verb->index - 1])
+			move_to(game, room->direction[verb->index - 1]);
+		else
+			console_println(game, string_lookup(game, STRING_CANT_GO));
+		break;
+
+	case OPCODE_MOVE_DIRECTION:
+		if (room->direction[instr->operand[0] - 1])
+			move_to(game, room->direction[instr->operand[0] - 1]);
+		else
+			console_println(game, string_lookup(game, STRING_CANT_GO));
+		break;
+
+	case OPCODE_ELSE:
+		func_state->test_result = func_state->else_result;
+		break;
+
+	case OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM:
+		item = get_item(game, instr->operand[0] - 1);
+		move_object(game, item, game->info->current_room);
+		break;
+
+	case OPCODE_OBJECT_IN_ROOM:
+		item = get_item(game, instr->operand[0] - 1);
+		func_set_test_result(func_state,
+		                     item->room == instr->operand[1]);
+		break;
+
+	case OPCODE_OBJECT_NOT_IN_ROOM:
+		item = get_item(game, instr->operand[0] - 1);
+		func_set_test_result(func_state,
+		                     item->room != instr->operand[1]);
+		break;
+
+	case OPCODE_MOVE_OBJECT_TO_ROOM:
+		item = get_item(game, instr->operand[0] - 1);
+		move_object(game, item, instr->operand[1]);
+		break;
+
+	case OPCODE_INVENTORY_FULL:
+		item = get_item_by_noun(game, noun);
+		func_set_test_result(func_state,
+		                     game->info->variable[VAR_INVENTORY_WEIGHT] +
+		                             (item->flags & ITEMF_WEIGHT_MASK) >
+		                         game->info->variable[VAR_INVENTORY_LIMIT]);
+		break;
+
+	case OPCODE_DESCRIBE_CURRENT_OBJECT:
+		/*
+		 * This opcode is only used in version 2
+		 * FIXME - unsure what the single operand is for.
+		 */
+		item = get_item_by_noun(game, noun);
+		printf("%s\n", string_lookup(game, item->long_string));
+		break;
+
+	case OPCODE_CURRENT_OBJECT_IN_ROOM:
+		/* FIXME - use common code for these two ops */
+		test = false;
+
+		if (noun) {
+			for (i = 0; i < game->info->header.nr_items; i++) {
+				struct item *itemP = &game->info->item[i];
+
+				if (itemP->word == noun->index &&
+				    itemP->room == instr->operand[0]) {
+					test = true;
+					break;
+				}
+			}
+		}
+
+		func_set_test_result(func_state, test);
+		break;
+
+	case OPCODE_CURRENT_OBJECT_NOT_PRESENT:
+		/* FIXME - use common code for these two ops */
+		item = get_item_by_noun(game, noun);
+		if (item)
+			func_set_test_result(func_state,
+			                     item->room != game->info->current_room);
+		else
+			func_set_test_result(func_state, true);
+		break;
+
+	case OPCODE_CURRENT_OBJECT_PRESENT:
+		item = get_item_by_noun(game, noun);
+		if (item)
+			func_set_test_result(func_state,
+			                     item->room == game->info->current_room);
+		else
+			func_set_test_result(func_state, false);
+		break;
+
+	case OPCODE_HAVE_OBJECT:
+		item = get_item(game, instr->operand[0] - 1);
+		func_set_test_result(func_state,
+		                     item->room == ROOM_INVENTORY);
+		break;
+
+	case OPCODE_NOT_HAVE_CURRENT_OBJECT:
+		item = get_item_by_noun(game, noun);
+		func_set_test_result(func_state,
+		                     !item || item->room != ROOM_INVENTORY);
+		break;
+
+	case OPCODE_HAVE_CURRENT_OBJECT:
+		item = get_item_by_noun(game, noun);
+		func_set_test_result(func_state,
+		                     item->room == ROOM_INVENTORY);
+		break;
+
+	case OPCODE_NOT_HAVE_OBJECT:
+		item = get_item(game, instr->operand[0] - 1);
+		func_set_test_result(func_state,
+		                     item->room != ROOM_INVENTORY);
+		break;
+
+	case OPCODE_CURRENT_OBJECT_TAKEABLE:
+		item = get_item_by_noun(game, noun);
+		if (!item)
+			func_set_test_result(func_state, false);
+		else
+			func_set_test_result(func_state,
+			                     (item->flags & ITEMF_CAN_TAKE));
+		break;
+
+	case OPCODE_CURRENT_OBJECT_NOT_TAKEABLE:
+		item = get_item_by_noun(game, noun);
+		if (!item)
+			func_set_test_result(func_state, true);
+		else
+			func_set_test_result(func_state,
+			                     !(item->flags & ITEMF_CAN_TAKE));
+		break;
+
+	case OPCODE_CURRENT_OBJECT_IS_NOWHERE:
+		item = get_item_by_noun(game, noun);
+		if (!item)
+			func_set_test_result(func_state, false);
+		else
+			func_set_test_result(func_state,
+			                     item->room == ROOM_NOWHERE);
+		break;
+
+	case OPCODE_OBJECT_IS_NOWHERE:
+		item = get_item(game, instr->operand[0] - 1);
+		func_set_test_result(func_state,
+		                     item->room == ROOM_NOWHERE);
+		break;
+
+	case OPCODE_OBJECT_IS_NOT_NOWHERE:
+		item = get_item(game, instr->operand[0] - 1);
+		func_set_test_result(func_state,
+		                     item->room != ROOM_NOWHERE);
+		break;
+
+	case OPCODE_OBJECT_NOT_PRESENT:
+		item = get_item(game, instr->operand[0] - 1);
+		func_set_test_result(func_state,
+		                     item->room != game->info->current_room);
+		break;
+
+	case OPCODE_OBJECT_PRESENT:
+		item = get_item(game, instr->operand[0] - 1);
+		func_set_test_result(func_state,
+		                     item->room == game->info->current_room);
+		break;
+
+	case OPCODE_OBJECT_NOT_VALID:
+		/* FIXME - should be called OPCODE_CURRENT_OBJECT_NOT_VALID */
+		func_set_test_result(func_state, !noun ||
+		                                     (noun->type & WORD_TYPE_NOUN_MASK) == 0);
+		break;
+
+	case OPCODE_CURRENT_IS_OBJECT:
+		func_set_test_result(func_state,
+		                     get_item_by_noun(game, noun) != NULL);
+		break;
+
+	case OPCODE_CURRENT_NOT_OBJECT:
+		func_set_test_result(func_state,
+		                     get_item_by_noun(game, noun) == NULL);
+		break;
+
+	case OPCODE_REMOVE_OBJECT:
+		item = get_item(game, instr->operand[0] - 1);
+		move_object(game, item, ROOM_NOWHERE);
+		break;
+
+	case OPCODE_REMOVE_CURRENT_OBJECT:
+		item = get_item_by_noun(game, noun);
+		move_object(game, item, ROOM_NOWHERE);
+		break;
+
+	case OPCODE_INVENTORY:
+		count = num_objects_in_room(game, ROOM_INVENTORY);
+		if (count == 0) {
+			console_println(game, string_lookup(game, STRING_INVENTORY_EMPTY));
+			break;
+		}
+
+		console_println(game, string_lookup(game, STRING_INVENTORY));
+		for (i = 0; i < game->info->header.nr_items; i++) {
+			item = &game->info->item[i];
+			if (item->room == ROOM_INVENTORY)
+				printf("%s\n",
+				       string_lookup(game, item->string_desc));
+		}
+		break;
+
+	case OPCODE_INVENTORY_ROOM:
+		count = num_objects_in_room(game, instr->operand[0]);
+		if (count == 0) {
+			console_println(game, string_lookup(game, instr->operand[1] + 1));
+			break;
+		}
+
+		console_println(game, string_lookup(game, instr->operand[1]));
+		for (i = 0; i < game->info->header.nr_items; i++) {
+			item = &game->info->item[i];
+			if (item->room == instr->operand[0])
+				printf("%s\n",
+				       string_lookup(game, item->string_desc));
+		}
+		break;
+
+	case OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM:
+		item = get_item_by_noun(game, noun);
+		if (!item)
+			fatal_error("Bad current object\n");
+
+		move_object(game, item, instr->operand[0]);
+		break;
+
+	case OPCODE_DROP_OBJECT:
+		item = get_item(game, instr->operand[0] - 1);
+		move_object(game, item, game->info->current_room);
+		break;
+
+	case OPCODE_DROP_CURRENT_OBJECT:
+		item = get_item_by_noun(game, noun);
+		if (!item)
+			fatal_error("Attempt to take object failed\n");
+
+		move_object(game, item, game->info->current_room);
+		break;
+
+	case OPCODE_TAKE_CURRENT_OBJECT:
+		item = get_item_by_noun(game, noun);
+		if (!item)
+			fatal_error("Attempt to take object failed\n");
+
+		move_object(game, item, ROOM_INVENTORY);
+		break;
+
+	case OPCODE_TAKE_OBJECT:
+		item = get_item(game, instr->operand[0] - 1);
+		move_object(game, item, ROOM_INVENTORY);
+		break;
+
+	case OPCODE_TEST_FLAG:
+		func_set_test_result(func_state,
+		                     game->info->flags[instr->operand[0]]);
+		break;
+
+	case OPCODE_TEST_NOT_FLAG:
+		func_set_test_result(func_state,
+		                     !game->info->flags[instr->operand[0]]);
+		break;
+
+	case OPCODE_CLEAR_FLAG:
+		game->info->flags[instr->operand[0]] = false;
+		break;
+
+	case OPCODE_SET_FLAG:
+		game->info->flags[instr->operand[0]] = true;
+		break;
+
+	case OPCODE_OR:
+		if (func_state->or_count) {
+			func_state->or_count += 2;
+		} else {
+			func_state->test_result = false;
+			func_state->or_count += 3;
+		}
+		break;
+
+	case OPCODE_SET_OBJECT_DESCRIPTION:
+		item = get_item(game, instr->operand[0] - 1);
+		item->string_desc = (instr->operand[2] << 8) | instr->operand[1];
+		break;
+
+	case OPCODE_SET_OBJECT_LONG_DESCRIPTION:
+		item = get_item(game, instr->operand[0] - 1);
+		item->long_string = (instr->operand[2] << 8) | instr->operand[1];
+		break;
+
+	case OPCODE_SET_ROOM_DESCRIPTION:
+		room = get_room(game, instr->operand[0]);
+		switch (instr->operand[2]) {
+		case 0x80:
+			room->string_desc = instr->operand[1];
+			break;
+		case 0x81:
+			room->string_desc = instr->operand[1] + 0x100;
+			break;
+		case 0x82:
+			room->string_desc = instr->operand[1] + 0x200;
+			break;
+		default:
+			fatal_error("Bad string desc %.2x:%.2x\n",
+			            instr->operand[1], instr->operand[2]);
+			break;
+		}
+		break;
+
+	case OPCODE_SET_OBJECT_GRAPHIC:
+		item = get_item(game, instr->operand[0] - 1);
+		item->graphic = instr->operand[1];
+		if (item->room == game->info->current_room)
+			game->info->update_flags |= UPDATE_GRAPHICS;
+		break;
+
+	case OPCODE_SET_ROOM_GRAPHIC:
+		room = get_room(game, instr->operand[0]);
+		room->graphic = instr->operand[1];
+		if (instr->operand[0] == game->info->current_room)
+			game->info->update_flags |= UPDATE_GRAPHICS;
+		break;
+
+	case OPCODE_CALL_FUNC:
+		index = instr->operand[0];
+		if (instr->operand[1] == 0x81)
+			index += 256;
+		if (index >= game->info->nr_functions)
+			fatal_error("Bad function %.4x >= %.4x\n",
+			            index, game->info->nr_functions);
+
+		debug_printf(DEBUG_FUNCTIONS,
+		             "Calling subfunction %.4x\n", index);
+		eval_function(game, &game->info->functions[index], verb, noun);
+		break;
+
+	case OPCODE_TEST_FALSE:
+		/*
+		 * FIXME - not sure what this is for. In Transylvania
+		 * it is opcode 0x50 and is used when attempting to
+		 * take the bar in the cellar. If it returns true then
+		 * the response is "there's none here".
+		 */
+		func_set_test_result(func_state, false);
+		break;
+
+	case OPCODE_SAVE_ACTION:
+		/*
+		 * FIXME - This saves the current verb and allows the next
+		 * command to use just the noun. This is used to allow
+		 * responses to ask the player what they meant, e.g:
+		 *
+		 *   > drop
+		 *   I don't understand what you want to drop.
+		 *   > gun
+		 *   Okay.
+		 */
+		break;
+
+	case OPCODE_SET_STRING_REPLACEMENT:
+		game->info->current_replace_word = instr->operand[0] - 1;
+		break;
+
+	case OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT:
+		/*
+		 * FIXME - Not sure what the operand is for,
+		 * maybe capitalisation?
+		 */
+		if (noun && (noun->type & WORD_TYPE_NOUN_PLURAL))
+			game->info->current_replace_word = 3;
+		else if (noun && (noun->type & WORD_TYPE_FEMALE))
+			game->info->current_replace_word = 0;
+		else if (noun && (noun->type & WORD_TYPE_MALE))
+			game->info->current_replace_word = 1;
+		else
+			game->info->current_replace_word = 2;
+		break;
+
+	case OPCODE_DRAW_ROOM:
+		draw_location_image(&game->info->room_images,
+		                    instr->operand[0] - 1);
+		break;
+
+	case OPCODE_DRAW_OBJECT:
+		draw_image(&game->info->item_images, instr->operand[0] - 1);
+		break;
+
+	case OPCODE_WAIT_KEY:
+		console_get_key();
+		break;
+
+	case OPCODE_SPECIAL:
+		/* Game specific opcode */
+		if (game->ops->handle_special_opcode)
+			game->ops->handle_special_opcode(game,
+			                                 instr->operand[0]);
+		break;
+
+	default:
+		if (instr->opcode & 0x80) {
+			debug_printf(DEBUG_FUNCTIONS,
+			             "Unhandled command opcode %.2x\n",
+			             instr->opcode);
+		} else {
+			debug_printf(DEBUG_FUNCTIONS,
+			             "Unhandled test opcode %.2x - returning false\n",
+			             instr->opcode);
+			func_set_test_result(func_state, false);
+		}
+		break;
+	}
+}
+
+/*
+ * Comprehend functions consist of test and command instructions (if the MSB
+ * of the opcode is set then it is a command). Functions are parsed by
+ * evaluating each test until a command instruction is encountered. If the
+ * overall result of the tests was true then the command instructions are
+ * executed until either a test instruction is found or the end of the function
+ * is reached. Otherwise the commands instructions are skipped over and the
+ * next test sequence (if there is one) is tried.
+ */
+void eval_function(comprehend_game *game, struct function *func,
+                   struct word *verb, struct word *noun) {
+	struct function_state func_state = {
+	    true, false, 0, false, false, false
+	};
+	uint i;
+
+	func_state.else_result = true;
+	func_state.executed = false;
+
+	for (i = 0; i < func->nr_instructions; i++) {
+		if (func_state.executed && !func->instructions[i].is_command) {
+			/*
+			 * At least one command has been executed and the
+			 * current instruction is a test. Exit the function.
+			 */
+			break;
+		}
+
+		eval_instruction(game, &func_state, &func->instructions[i],
+		                 verb, noun);
+	}
+}
+
+static void skip_whitespace(char **p) {
+	while (**p && Common::isSpace(**p))
+		(*p)++;
+}
+
+static void skip_non_whitespace(char **p) {
+	while (**p && !Common::isSpace(**p) && **p != ',' && **p != '\n')
+		(*p)++;
+}
+
+static void handle_debug_command(comprehend_game *game,
+                                 const char *line) {
+	int i;
+
+	if (strncmp(line, "quit", 4) == 0) {
+		error("Quit");
+
+	} else if (strncmp(line, "debug", 5) == 0) {
+		if (debugging_enabled())
+			debug_disable(DEBUG_ALL);
+		else
+			debug_enable(DEBUG_FUNCTIONS);
+		printf("Debugging %s\n", debugging_enabled() ? "on" : "off");
+
+	} else if (strncmp(line, "dump objects", 12) == 0) {
+		dump_game_data(game, DUMP_ITEMS);
+
+	} else if (strncmp(line, "dump rooms", 10) == 0) {
+		dump_game_data(game, DUMP_ROOMS);
+
+	} else if (strncmp(line, "dump state", 10) == 0) {
+		printf("Current room: %.2x\n", game->info->current_room);
+		printf("Carry weight %d/%d\n\n",
+		       game->info->variable[VAR_INVENTORY_WEIGHT],
+		       game->info->variable[VAR_INVENTORY_LIMIT]);
+
+		printf("Flags:\n");
+		for (i = 0; i < ARRAY_SIZE(game->info->flags); i++)
+			printf("  [%.2x]: %d\n", i, game->info->flags[i]);
+		printf("\n");
+
+		printf("Variables:\n");
+		for (i = 0; i < ARRAY_SIZE(game->info->variable); i++)
+			printf("  [%.2x]: %5d (0x%.4x)\n",
+			       i, game->info->variable[i],
+			       game->info->variable[i]);
+		printf("\n");
+	}
+}
+
+static bool handle_sentence(comprehend_game *game,
+                            struct sentence *sentence) {
+	struct function *func;
+	struct action *action;
+	uint i, j;
+
+	if (sentence->nr_words == 0)
+		return false;
+
+	/* Find a matching action */
+	for (i = 0; i < game->info->nr_actions; i++) {
+		action = &game->info->action[i];
+
+		if (action->type == ACTION_VERB_OPT_NOUN &&
+		    sentence->nr_words > action->nr_words + 1)
+			continue;
+		if (action->type != ACTION_VERB_OPT_NOUN &&
+		    sentence->nr_words != action->nr_words)
+			continue;
+
+		/*
+		 * If all words in a sentence match those for an action then
+		 * run that action's function.
+		 */
+		for (j = 0; j < action->nr_words; j++) {
+			if (sentence->words[j].index == action->word[j] &&
+			    (sentence->words[j].type & action->word_type[j]))
+				continue;
+
+			/* Word didn't match */
+			break;
+		}
+		if (j == action->nr_words) {
+			/* Match */
+			func = &game->info->functions[action->function];
+			eval_function(game, func,
+			              &sentence->words[0], &sentence->words[1]);
+			return true;
+		}
+	}
+
+	/* No matching action */
+	console_println(game, string_lookup(game, STRING_DONT_UNDERSTAND));
+	return false;
+}
+
+static void read_sentence(comprehend_game *game, char **line,
+                          struct sentence *sentence) {
+	bool sentence_end = false;
+	char *word_string, *p = *line;
+	struct word_index *pair;
+	struct word *word;
+	int index;
+
+	memset(sentence, 0, sizeof(*sentence));
+	while (1) {
+		skip_whitespace(&p);
+		word_string = p;
+		skip_non_whitespace(&p);
+
+		if (*p == ',' || *p == '\n') {
+			/* Sentence separator */
+			*p++ = '\0';
+			sentence_end = true;
+		} else {
+			if (*p == '\0')
+				sentence_end = true;
+			else
+				*p++ = '\0';
+		}
+
+		/* Find the dictionary word for this */
+		word = dict_find_word_by_string(game, word_string);
+		if (!word)
+			memset(&sentence->words[sentence->nr_words], 0,
+			       sizeof(sentence->words[sentence->nr_words]));
+		else
+			memcpy(&sentence->words[sentence->nr_words],
+			       word, sizeof(*word));
+
+		sentence->nr_words++;
+
+		if (sentence->nr_words > 1) {
+			index = sentence->nr_words;
+
+			/* See if this word and the previous are a word pair */
+			pair = is_word_pair(game,
+			                    &sentence->words[index - 2],
+			                    &sentence->words[index - 1]);
+			if (pair) {
+				sentence->words[index - 2].index = pair->index;
+				sentence->words[index - 2].type = pair->type;
+				strcpy(sentence->words[index - 2].word,
+				       "[PAIR]");
+				sentence->nr_words--;
+			}
+		}
+
+		if (sentence->nr_words >= ARRAY_SIZE(sentence->words) ||
+		    sentence_end)
+			break;
+	}
+
+	*line = p;
+}
+
+static void before_turn(comprehend_game *game) {
+	/* Run the game specific before turn bits */
+	if (game->ops->before_turn)
+		game->ops->before_turn(game);
+
+	/* Run the each turn functions */
+	eval_function(game, &game->info->functions[0], NULL, NULL);
+
+	update(game);
+}
+
+static void after_turn(comprehend_game *game) {
+	/* Do post turn game specific bits */
+	if (game->ops->after_turn)
+		game->ops->after_turn(game);
+}
+
+static void read_input(comprehend_game *game) {
+#ifdef TODO
+	struct sentence sentence;
+	char *line = NULL, buffer[1024];
+	bool handled;
+
+	if (game->ops->before_prompt)
+		game->ops->before_prompt(game);
+	before_turn(game);
+
+	while (!line) {
+		printf("> ");
+		line = fgets(buffer, sizeof(buffer), stdin);
+	}
+
+	/* Re-comprehend special commands start with '!' */
+	if (*line == '!') {
+		handle_debug_command(game, &line[1]);
+		return;
+	}
+
+	while (1) {
+		read_sentence(game, &line, &sentence);
+		handled = handle_sentence(game, &sentence);
+		if (handled)
+			after_turn(game);
+
+		/* FIXME - handle the 'before you can continue' case */
+		if (*line == '\0')
+			break;
+		line++;
+
+		if (handled)
+			before_turn(game);
+	}
+#else
+	error("TODO: read_input");
+#endif
+}
+
+void comprehend_play_game(comprehend_game *game) {
+	console_init();
+
+	if (game->ops->before_game)
+		game->ops->before_game(game);
+
+	game->info->update_flags = (uint)UPDATE_ALL;
+	while (1)
+		read_input(game);
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
new file mode 100644
index 0000000000..627f7c925b
--- /dev/null
+++ b/engines/glk/comprehend/game.h
@@ -0,0 +1,78 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_GAME_H
+#define GLK_COMPREHEND_GAME_H
+
+#include "common/scummsys.h"
+
+namespace Glk {
+namespace Comprehend {
+
+#define MAX_FILES 10
+
+struct function;
+struct item;
+struct word;
+
+struct string_file {
+	const char *filename;
+	uint32 base_offset;
+	uint32 end_offset;
+};
+
+struct comprehend_game {
+	const char *game_name;
+	const char *short_name;
+
+	const char *game_dir;
+
+	const char *game_data_file;
+	struct string_file string_files[MAX_FILES];
+	const char *location_graphic_files[MAX_FILES];
+	const char *item_graphic_files[MAX_FILES];
+	const char *save_game_file_fmt;
+	unsigned color_table;
+
+	struct game_strings *strings;
+	struct game_ops *ops;
+
+	struct game_info *info;
+};
+
+void console_println(struct comprehend_game *game, const char *text);
+int console_get_key(void);
+
+struct item *get_item(struct comprehend_game *game, uint16 index);
+void move_object(struct comprehend_game *game, struct item *item, int new_room);
+void eval_function(struct comprehend_game *game, struct function *func,
+		   struct word *verb, struct word *noun);
+
+void comprehend_play_game(struct comprehend_game *game);
+void game_save(struct comprehend_game *game);
+void game_restore(struct comprehend_game *game);
+void game_restart(struct comprehend_game *game);
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
new file mode 100644
index 0000000000..070dbf9c88
--- /dev/null
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -0,0 +1,169 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/game.h"
+
+namespace Glk {
+namespace Comprehend {
+
+static void cc_clear_companion_flags(struct comprehend_game *game)
+{
+	/* Clear the Sabrina/Erik action flags */
+	game->info->flags[0xa] = 0;
+	game->info->flags[0xb] = 0;
+}
+
+static bool cc_common_handle_special_opcode(struct comprehend_game *game,
+					    uint8 operand)
+{
+	switch (operand) {
+	case 0x03:
+		/*
+		 * Game over - failure.
+		 *
+		 * FIXME - If playing the second disk this should restart
+		 *         from the beginning of the first disk.
+		 */
+		game_restart(game);
+		break;
+
+	case 0x06:
+		game_save(game);
+		break;
+
+	case 0x07:
+		/*
+		 * FIXME - This will only correctly restore games that were
+		 *         saved for the disk currently being played.
+		 */
+		game_restore(game);
+		return true;
+	}
+
+	return false;
+}
+
+static void cc1_handle_special_opcode(struct comprehend_game *game,
+				      uint8 operand)
+{
+	if (cc_common_handle_special_opcode(game, operand))
+		return;
+
+	switch (operand) {
+	case 0x05:
+		/*
+		 * Completed first part (disk 1) of the game.
+		 *
+		 * FIXME - This should automatically load disk 2.
+		 */
+		error("[Completed disk 1 - to continue run Re-Comprehend with the 'cc2' game]");
+		break;
+	}
+}
+
+static void cc2_handle_special_opcode(struct comprehend_game *game,
+				      uint8 operand)
+{
+	if (cc_common_handle_special_opcode(game, operand))
+		return;
+
+	switch (operand) {
+	case 0x01:
+		/* Enter the Vampire's throne room */
+		eval_function(game, &game->info->functions[0xe], NULL, NULL);
+		break;
+
+	case 0x05:
+		/*
+		 * Won the game.
+		 *
+		 * FIXME - The merchant ship should arrives, etc.
+		 */
+		game_restart(game);
+		break;
+	}
+}
+
+static void cc2_before_prompt(struct comprehend_game *game)
+{
+	cc_clear_companion_flags(game);
+}
+
+static void cc1_before_prompt(struct comprehend_game *game)
+{
+	cc_clear_companion_flags(game);
+}
+
+static struct game_strings cc1_strings = { 0x9 };
+
+static struct game_ops cc1_ops = {
+	nullptr,
+	cc1_before_prompt,
+	nullptr,
+	nullptr,
+	nullptr,
+	cc1_handle_special_opcode
+};
+
+static struct game_ops cc2_ops = {
+	nullptr,
+	cc2_before_prompt,
+	nullptr,
+	nullptr,
+	nullptr,
+	cc2_handle_special_opcode
+};
+
+struct comprehend_game game_crimson_crown_1 = {
+	"Crimson Crown (Part 1/2)",
+	"cc1",
+	nullptr,
+	"CC1.GDA",
+	{ {"MA.MS1", 0x89} },
+	{"RA.MS1", "RB.MS1", "RC.MS1"},
+	{"OA.MS1", "OB.MS1"},
+	"G%d.MS0",
+	0,
+	&cc1_strings,
+	&cc1_ops,
+	nullptr
+};
+
+struct comprehend_game game_crimson_crown_2 = {
+	"Crimson Crown (Part 2/2)",
+	"cc2",
+	nullptr,
+	"CC2.GDA",
+	{ {"MA.MS2", 0x89} },
+	{"RA.MS2", "RB.MS2"},
+	{"OA.MS2", "OB.MS2"},
+	"G%d.MS0",
+	0,
+	nullptr,
+	&cc2_ops,
+	nullptr
+};
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
new file mode 100644
index 0000000000..70125ff369
--- /dev/null
+++ b/engines/glk/comprehend/game_data.cpp
@@ -0,0 +1,1084 @@
+/* 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 "glk/comprehend/game_data.h"
+#include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/dictionary.h"
+#include "glk/comprehend/dump_game_data.h"
+#include "glk/comprehend/file_buf.h"
+#include "glk/comprehend/game.h"
+#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/strings.h"
+#include "glk/comprehend/util.h"
+
+namespace Glk {
+namespace Comprehend {
+
+static char charset[] = "..abcdefghijklmnopqrstuvwxyz .";
+static char special_charset[] = "[]\n!\"#$%&'(),-/0123456789:;?<>";
+
+static uint16 magic_offset;
+
+static void parse_header_le16(struct file_buf *fb, uint16 *val) {
+	file_buf_get_le16(fb, val);
+	*val += (uint16)magic_offset;
+}
+
+static size_t opcode_nr_operands(uint8 opcode) {
+	/* Number of operands is encoded in the low 2 bits */
+	return opcode & 0x3;
+}
+
+static bool opcode_is_command(uint8 opcode) {
+	/* If the MSB is set the instruction is a command */
+	return opcode & 0x80;
+}
+
+static uint8 parse_vm_instruction(struct file_buf *fb,
+                                  struct instruction *instr) {
+	uint i;
+
+	/* Get the opcode */
+	file_buf_get_u8(fb, &instr->opcode);
+	instr->nr_operands = opcode_nr_operands(instr->opcode);
+
+	/* Get the operands */
+	for (i = 0; i < instr->nr_operands; i++)
+		file_buf_get_u8(fb, &instr->operand[i]);
+
+	instr->is_command = opcode_is_command(instr->opcode);
+
+	return instr->opcode;
+}
+
+static void parse_function(struct file_buf *fb, struct function *func) {
+	struct instruction *instruction;
+	uint8 *p, opcode;
+
+	p = (uint8 *)memchr(file_buf_data_pointer(fb), 0x00,
+	                    fb->size - file_buf_get_pos(fb));
+	if (!p)
+		fatal_error("bad function @ %.4x", file_buf_get_pos(fb));
+
+	while (1) {
+		instruction = &func->instructions[func->nr_instructions];
+
+		opcode = parse_vm_instruction(fb, instruction);
+		if (opcode == 0)
+			break;
+
+		func->nr_instructions++;
+		if (func->nr_instructions >= ARRAY_SIZE(func->instructions))
+			fatal_error("Function has too many instructions");
+	}
+}
+
+static void parse_vm(struct comprehend_game *game, struct file_buf *fb) {
+	struct function *func;
+
+	file_buf_set_pos(fb, game->info->header.addr_vm);
+	while (1) {
+		func = &game->info->functions[game->info->nr_functions];
+
+		parse_function(fb, func);
+		if (func->nr_instructions == 0)
+			break;
+
+		game->info->nr_functions++;
+	}
+}
+
+static void parse_action_table_vvnn(struct comprehend_game *game,
+                                    struct file_buf *fb, size_t *index) {
+	struct action *action;
+	uint8 verb, count;
+	int i, j;
+
+	/*
+	 * <verb> <verb> <noun> <noun>
+	 *
+	 * u8: verb1
+	 * u8: count
+	 *     u8:   verb2
+	 *     u8:   noun1
+	 *     u8:   noun2
+	 *     le16: action
+	 */
+	file_buf_set_pos(fb, game->info->header.addr_actions_vvnn);
+	while (1) {
+		file_buf_get_u8(fb, &verb);
+		if (verb == 0)
+			break;
+		file_buf_get_u8(fb, &count);
+
+		for (i = 0; i < count; i++) {
+			action = &game->info->action[*index];
+			action->type = ACTION_VERB_VERB_NOUN_NOUN;
+
+			action->nr_words = 4;
+			action->word_type[0] = WORD_TYPE_VERB;
+			action->word_type[1] = WORD_TYPE_VERB;
+			action->word_type[2] = WORD_TYPE_NOUN_MASK;
+			action->word_type[3] = WORD_TYPE_NOUN_MASK;
+
+			action->word[0] = verb;
+
+			for (j = 0; j < 3; j++)
+				file_buf_get_u8(fb, &action->word[j + 1]);
+			file_buf_get_le16(fb, &action->function);
+
+			(*index)++;
+		}
+	}
+}
+
+static void parse_action_table_vnjn(struct comprehend_game *game,
+                                    struct file_buf *fb, size_t *index) {
+	struct action *action;
+	uint8 join, count;
+	int i;
+
+	/*
+	 * <verb> <noun> <join> <noun>
+	 *
+	 * u8: join
+	 * u8: count
+	 *     u8:   verb
+	 *     u8:   noun1
+	 *     u8:   noun2
+	 *     le16: action
+	 */
+	file_buf_set_pos(fb, game->info->header.addr_actions_vnjn);
+	while (1) {
+		file_buf_get_u8(fb, &join);
+		if (join == 0)
+			break;
+		file_buf_get_u8(fb, &count);
+
+		for (i = 0; i < count; i++) {
+			action = &game->info->action[*index];
+			action->type = ACTION_VERB_NOUN_JOIN_NOUN;
+
+			action->nr_words = 4;
+			action->word_type[0] = WORD_TYPE_VERB;
+			action->word_type[1] = WORD_TYPE_NOUN_MASK;
+			action->word_type[2] = WORD_TYPE_JOIN;
+			action->word_type[3] = WORD_TYPE_NOUN_MASK;
+
+			action->word[2] = join;
+
+			file_buf_get_u8(fb, &action->word[0]);
+			file_buf_get_u8(fb, &action->word[1]);
+			file_buf_get_u8(fb, &action->word[3]);
+			file_buf_get_le16(fb, &action->function);
+
+			(*index)++;
+		}
+	}
+}
+
+static void parse_action_table_vjn(struct comprehend_game *game,
+                                   struct file_buf *fb, size_t *index) {
+	struct action *action;
+	uint8 join, count;
+	int i;
+
+	/*
+	 * <verb> <join> <noun>
+	 *
+	 * u8: join
+	 * u8: count
+	 *     u8:   verb
+	 *     u8:   noun
+	 *     le16: action
+	 */
+	file_buf_set_pos(fb, game->info->header.addr_actions_vjn);
+	while (1) {
+		file_buf_get_u8(fb, &join);
+		if (join == 0)
+			break;
+		file_buf_get_u8(fb, &count);
+
+		for (i = 0; i < count; i++) {
+			action = &game->info->action[*index];
+			action->type = ACTION_VERB_JOIN_NOUN;
+			action->word[1] = join;
+
+			action->nr_words = 3;
+			action->word_type[0] = WORD_TYPE_VERB;
+			action->word_type[1] = WORD_TYPE_JOIN;
+			action->word_type[2] = WORD_TYPE_NOUN_MASK;
+
+			file_buf_get_u8(fb, &action->word[0]);
+			file_buf_get_u8(fb, &action->word[2]);
+			file_buf_get_le16(fb, &action->function);
+
+			(*index)++;
+		}
+	}
+}
+
+static void parse_action_table_vdn(struct comprehend_game *game,
+                                   struct file_buf *fb, size_t *index) {
+	struct action *action;
+	uint8 verb, count;
+	int i;
+
+	/*
+	 * <verb> <dir> <noun>
+	 *
+	 * u8: verb
+	 * u8: count
+	 *     u8:   dir
+	 *     u8:   noun
+	 *     le16: action
+	 */
+	file_buf_set_pos(fb, game->info->header.addr_actions_vdn);
+	while (1) {
+		file_buf_get_u8(fb, &verb);
+		if (verb == 0)
+			break;
+		file_buf_get_u8(fb, &count);
+
+		for (i = 0; i < count; i++) {
+			action = &game->info->action[*index];
+			action->type = ACTION_VERB_JOIN_NOUN;
+			action->word[0] = verb;
+
+			action->nr_words = 3;
+			action->word_type[0] = WORD_TYPE_VERB;
+			action->word_type[1] = WORD_TYPE_VERB;
+			action->word_type[2] = WORD_TYPE_NOUN_MASK;
+
+			file_buf_get_u8(fb, &action->word[1]);
+			file_buf_get_u8(fb, &action->word[2]);
+			file_buf_get_le16(fb, &action->function);
+
+			(*index)++;
+		}
+	}
+}
+
+static void parse_action_table_vnn(struct comprehend_game *game,
+                                   struct file_buf *fb, size_t *index) {
+	struct action *action;
+	uint8 verb, count;
+	int i;
+
+	/*
+	 * <verb> <noun> <noun>
+	 *
+	 * u8: verb
+	 * u8: count
+	 *     u8:   noun1
+	 *     u8:   noun2
+	 *     le16: action
+	 */
+	file_buf_set_pos(fb, game->info->header.addr_actions_vnn);
+	while (1) {
+		/* 2-byte header */
+		file_buf_get_u8(fb, &verb);
+		if (verb == 0)
+			break;
+		file_buf_get_u8(fb, &count);
+
+		for (i = 0; i < count; i++) {
+			action = &game->info->action[*index];
+			action->type = ACTION_VERB_NOUN_NOUN;
+			action->word[0] = verb;
+
+			action->nr_words = 3;
+			action->word_type[0] = WORD_TYPE_VERB;
+			action->word_type[1] = WORD_TYPE_NOUN_MASK;
+			action->word_type[2] = WORD_TYPE_NOUN_MASK;
+
+			file_buf_get_u8(fb, &action->word[1]);
+			file_buf_get_u8(fb, &action->word[2]);
+			file_buf_get_le16(fb, &action->function);
+
+			(*index)++;
+		}
+	}
+}
+
+static void parse_action_table_vn(struct comprehend_game *game,
+                                  struct file_buf *fb, size_t *index) {
+	struct action *action;
+	uint8 verb, count;
+	int i;
+
+	/*
+	 * <verb> <noun>
+	 *
+	 * u8: verb
+	 * u8: count
+	 *     u8:   noun
+	 *     le16: action
+	 */
+	file_buf_set_pos(fb, game->info->header.addr_actions_vn);
+	while (1) {
+		/* 2-byte header */
+		file_buf_get_u8(fb, &verb);
+		if (verb == 0)
+			break;
+		file_buf_get_u8(fb, &count);
+
+		for (i = 0; i < count; i++) {
+			action = &game->info->action[*index];
+			action->type = ACTION_VERB_NOUN;
+			action->word[0] = verb;
+
+			action->nr_words = 2;
+			action->word_type[0] = WORD_TYPE_VERB;
+			action->word_type[1] = WORD_TYPE_NOUN_MASK;
+
+			file_buf_get_u8(fb, &action->word[1]);
+			file_buf_get_le16(fb, &action->function);
+
+			(*index)++;
+		}
+	}
+}
+
+static void parse_action_table_v(struct comprehend_game *game,
+                                 struct file_buf *fb, size_t *index) {
+	struct action *action;
+	uint8 verb, nr_funcs;
+	uint16 func;
+	int i;
+
+	/*
+	 * <verb> [<noun>]
+	 *
+	 * u8: verb
+	 * u8: count (num actions)
+	 *     le16: action
+	 */
+	file_buf_set_pos(fb, game->info->header.addr_actions_v);
+	while (1) {
+		file_buf_get_u8(fb, &verb);
+		if (verb == 0)
+			break;
+
+		action = &game->info->action[*index];
+		action->type = ACTION_VERB_OPT_NOUN;
+		action->word[0] = verb;
+
+		/* Can take an optional noun (nr_words here is maximum) */
+		action->nr_words = 1;
+		action->word_type[0] = WORD_TYPE_VERB;
+
+		/*
+		 * Default actions can have more than one function, but only
+		 * the first one actually seems to be used?
+		 */
+		file_buf_get_u8(fb, &nr_funcs);
+		for (i = 0; i < nr_funcs; i++) {
+			file_buf_get_le16(fb, &func);
+			if (i == 0)
+				action->function = func;
+		}
+
+		(*index)++;
+	}
+}
+
+static void parse_action_table(struct comprehend_game *game,
+                               struct file_buf *fb) {
+	game->info->nr_actions = 0;
+
+	if (game->info->comprehend_version == 1) {
+		parse_action_table_vvnn(game, fb, &game->info->nr_actions);
+		parse_action_table_vdn(game, fb, &game->info->nr_actions);
+	}
+	if (game->info->comprehend_version >= 2) {
+		parse_action_table_vnn(game, fb, &game->info->nr_actions);
+	}
+
+	parse_action_table_vnjn(game, fb, &game->info->nr_actions);
+	parse_action_table_vjn(game, fb, &game->info->nr_actions);
+	parse_action_table_vn(game, fb, &game->info->nr_actions);
+	parse_action_table_v(game, fb, &game->info->nr_actions);
+}
+
+static void parse_dictionary(struct comprehend_game *game, struct file_buf *fb) {
+	word *words;
+	uint i, j;
+
+	// FIXME - fixed size 0xff array?
+	game->info->words = (word *)xmalloc(game->info->nr_words * sizeof(words));
+
+	file_buf_set_pos(fb, game->info->header.addr_dictionary);
+	for (i = 0; i < game->info->nr_words; i++) {
+		words = &game->info->words[i];
+
+		file_buf_get_data(fb, words->word, 6);
+
+		/* Decode */
+		for (j = 0; j < 6; j++)
+			words->word[j] ^= 0x8a;
+		words->word[6] = '\0';
+
+		file_buf_get_u8(fb, &words->index);
+		file_buf_get_u8(fb, &words->type);
+	}
+}
+
+static void parse_word_map(struct comprehend_game *game, struct file_buf *fb) {
+	struct word_map *map;
+	uint8 index, type, dummy;
+	uint i;
+
+	game->info->nr_word_maps = 0;
+	file_buf_set_pos(fb, game->info->header.addr_word_map);
+
+	/*
+	 * Parse the word pair table. Each entry has a pair of dictionary
+	 * index/type values for a first and second word.
+	 */
+	while (1) {
+		map = &game->info->word_map[game->info->nr_word_maps];
+
+		file_buf_get_u8(fb, &index);
+		file_buf_get_u8(fb, &type);
+		if (type == 0 && index == 0) {
+			/* End of pairs */
+			break;
+		}
+
+		map->word[0].index = index;
+		map->word[0].type = type;
+		file_buf_get_u8(fb, &map->flags);
+		file_buf_get_u8(fb, &map->word[1].index);
+		file_buf_get_u8(fb, &map->word[1].type);
+
+		game->info->nr_word_maps++;
+	}
+
+	/* Consume two more null bytes (type and index were also null) */
+	file_buf_get_u8(fb, &dummy);
+	file_buf_get_u8(fb, &dummy);
+
+	/*
+	 * Parse the target word table. Each entry has a dictionary
+	 * index/type. The first and second words from above map to the
+	 * target word here. E.g. 'go north' -> 'north'.
+	 */
+	for (i = 0; i < game->info->nr_word_maps; i++) {
+		map = &game->info->word_map[i];
+
+		file_buf_get_u8(fb, &map->word[2].index);
+		file_buf_get_u8(fb, &map->word[2].type);
+	}
+}
+
+static void parse_items(struct comprehend_game *game, struct file_buf *fb) {
+	size_t nr_items = game->info->header.nr_items;
+
+	/* Item descriptions */
+	file_buf_set_pos(fb, game->info->header.addr_item_strings);
+	file_buf_get_array_le16(fb, 0, game->info->item, string_desc, nr_items);
+
+	if (game->info->comprehend_version == 2) {
+		/* Comprehend version 2 adds long string descriptions */
+		file_buf_set_pos(fb, game->info->header.addr_item_strings +
+		                         (game->info->header.nr_items * sizeof(uint16)));
+		file_buf_get_array_le16(fb, 0, game->info->item, long_string, nr_items);
+	}
+
+	/* Item flags */
+	file_buf_set_pos(fb, game->info->header.addr_item_flags);
+	file_buf_get_array_u8(fb, 0, game->info->item, flags, nr_items);
+
+	/* Item word */
+	file_buf_set_pos(fb, game->info->header.addr_item_word);
+	file_buf_get_array_u8(fb, 0, game->info->item, word, nr_items);
+
+	/* Item locations */
+	file_buf_set_pos(fb, game->info->header.addr_item_locations);
+	file_buf_get_array_u8(fb, 0, game->info->item, room, nr_items);
+
+	/* Item graphic */
+	file_buf_set_pos(fb, game->info->header.addr_item_graphics);
+	file_buf_get_array_u8(fb, 0, game->info->item, graphic, nr_items);
+}
+
+static void parse_rooms(struct comprehend_game *game, struct file_buf *fb) {
+	size_t nr_rooms = game->info->nr_rooms;
+	int i;
+
+	/* Room exit directions */
+	for (i = 0; i < NR_DIRECTIONS; i++) {
+		file_buf_set_pos(fb, game->info->header.room_direction_table[i]);
+		file_buf_get_array_u8(fb, 1, game->info->rooms,
+		                      direction[i], nr_rooms);
+	}
+
+	/* Room string descriptions */
+	file_buf_set_pos(fb, game->info->header.room_desc_table);
+	file_buf_get_array_le16(fb, 1, game->info->rooms, string_desc, nr_rooms);
+
+	/* Room flags */
+	file_buf_set_pos(fb, game->info->header.room_flags_table);
+	file_buf_get_array_u8(fb, 1, game->info->rooms, flags, nr_rooms);
+
+	/* Room graphic */
+	file_buf_set_pos(fb, game->info->header.room_graphics_table);
+	file_buf_get_array_u8(fb, 1, game->info->rooms, graphic, nr_rooms);
+}
+
+static uint64 string_get_chunk(uint8 *string) {
+	uint64 c, val = 0;
+	int i;
+
+	for (i = 0; i < 5; i++) {
+		c = string[i] & 0xff;
+		val |= (c << ((4 - i) * 8));
+	}
+
+	return val;
+}
+
+static char decode_string_elem(uint8 c, bool capital, bool special) {
+	if (special) {
+		if (c < sizeof(special_charset) - 1)
+			return special_charset[c];
+	} else {
+		if (c < sizeof(charset) - 1) {
+			c = charset[c];
+			if (capital) {
+				/*
+				 * A capital space means that the character
+				 * is dynamically replaced by at runtime.
+				 * We use the character '@' since it cannot
+				 * otherwise appear in strings.
+				 */
+				if (c == ' ')
+					return '@';
+				return c - 0x20;
+			} else {
+				return c;
+			}
+		}
+	}
+
+	/* Unknown character */
+	printf("Unknown char %d, caps=%d, special=%d\n", c, capital, special);
+	return '*';
+}
+
+/*
+ * Game strings are stored using 5-bit characters. By default a character
+ * value maps to the lower-case letter table. If a character has the value 0x1e
+ * then the next character is upper-case. An upper-case space is used to
+ * specify that the character should be replaced at runtime (like a '%s'
+ * specifier). If a character has the value 0x1f then the next character is
+ * taken from the symbols table.
+ */
+static char *parse_string(struct file_buf *fb) {
+	bool capital_next = false, special_next = false;
+	unsigned i, j, k = 0;
+	uint64 chunk;
+	uint8 elem, *encoded;
+	char *string, c;
+	size_t encoded_len;
+
+	encoded_len = file_buf_strlen(fb, NULL);
+	string = (char *)xmalloc(encoded_len * 2);
+
+	/* Get the encoded string */
+	encoded = (uint8 *)xmalloc(encoded_len + 5);
+	memset(encoded, 0, encoded_len);
+	file_buf_get_data(fb, encoded, encoded_len);
+
+	/* Skip over the zero byte */
+	if (file_buf_get_pos(fb) < fb->size)
+		file_buf_get_u8(fb, NULL);
+
+	for (i = 0; i < encoded_len; i += 5) {
+		chunk = string_get_chunk(&encoded[i]);
+
+		for (j = 0; j < 8; j++) {
+			elem = (chunk >> (35 - (5 * j))) & 0x1f;
+
+			if (elem == 0)
+				goto done;
+			if (elem == 0x1e) {
+				capital_next = true;
+			} else if (elem == 0x1f) {
+				special_next = true;
+			} else {
+				c = decode_string_elem(elem, capital_next,
+				                       special_next);
+				special_next = false;
+				capital_next = false;
+				string[k++] = c;
+			}
+		}
+	}
+
+done:
+	string[k] = '\0';
+	free(encoded);
+
+	return string;
+}
+
+static void parse_string_table(struct file_buf *fb, unsigned start_addr,
+                               uint32 end_addr, struct string_table *table) {
+	file_buf_set_pos(fb, start_addr);
+	while (1) {
+		table->strings[table->nr_strings++] = parse_string(fb);
+		if (file_buf_get_pos(fb) >= end_addr)
+			break;
+	}
+}
+
+static void parse_variables(struct comprehend_game *game, struct file_buf *fb) {
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(game->info->variable); i++)
+		file_buf_get_le16(fb, &game->info->variable[i]);
+}
+
+static void parse_flags(struct comprehend_game *game, struct file_buf *fb) {
+	int i, bit, flag_index = 0;
+	uint8 bitmask;
+
+	for (i = 0; i < ARRAY_SIZE(game->info->flags) / 8; i++) {
+		file_buf_get_u8(fb, &bitmask);
+		for (bit = 7; bit >= 0; bit--) {
+			game->info->flags[flag_index] = !!(bitmask & (1 << bit));
+			flag_index++;
+		}
+	}
+}
+
+static void parse_replace_words(struct comprehend_game *game,
+                                struct file_buf *fb) {
+	uint16 dummy;
+	size_t len;
+	bool eof;
+	int i;
+
+	/* FIXME - Rename addr_strings_end */
+	file_buf_set_pos(fb, game->info->header.addr_strings_end);
+
+	/* FIXME - what is this for */
+	file_buf_get_le16(fb, &dummy);
+
+	for (i = 0;; i++) {
+		len = file_buf_strlen(fb, &eof);
+		if (len == 0)
+			break;
+
+		game->info->replace_words[i] = xstrndup((char *)fb->p, len);
+		file_buf_get_data(fb, NULL, len + (eof ? 0 : 1));
+		if (eof)
+			break;
+	}
+	game->info->nr_replace_words = i;
+}
+
+/*
+ * The main game data file header has the offsets for where each bit of
+ * game data is. The offsets have a magic constant value added to them.
+ */
+static void parse_header(struct comprehend_game *game, struct file_buf *fb) {
+	struct game_header *header = &game->info->header;
+	uint16 dummy, addr_dictionary_end;
+	uint8 dummy8;
+
+	file_buf_set_pos(fb, 0);
+	file_buf_get_le16(fb, &header->magic);
+	switch (header->magic) {
+	case 0x2000: /* Transylvania, Crimson Crown disk one */
+	case 0x4800: /* Crimson Crown disk two */
+		game->info->comprehend_version = 1;
+		magic_offset = (uint16)(-0x5a00 + 0x4);
+		break;
+
+	case 0x93f0: /* OO-Topos */
+		game->info->comprehend_version = 2;
+		magic_offset = (uint16)-0x5a00;
+		break;
+
+	case 0xa429: /* Talisman */
+		game->info->comprehend_version = 2;
+		magic_offset = (uint16)-0x5a00;
+		break;
+
+	default:
+		fatal_error("Unknown game_data magic %.4x\n", header->magic);
+		break;
+	}
+
+	/* FIXME - Second word in header has unknown usage */
+	parse_header_le16(fb, &dummy);
+
+	/*
+	 * Action tables.
+	 *
+	 * Layout depends on the comprehend version.
+	 */
+	if (game->info->comprehend_version == 1) {
+		parse_header_le16(fb, &header->addr_actions_vvnn);
+		parse_header_le16(fb, &header->addr_actions_unknown);
+		parse_header_le16(fb, &header->addr_actions_vnjn);
+		parse_header_le16(fb, &header->addr_actions_vjn);
+		parse_header_le16(fb, &header->addr_actions_vdn);
+	}
+	if (game->info->comprehend_version >= 2) {
+		parse_header_le16(fb, &header->addr_actions_vnjn);
+		parse_header_le16(fb, &header->addr_actions_vjn);
+		parse_header_le16(fb, &header->addr_actions_vnn);
+	}
+	parse_header_le16(fb, &header->addr_actions_vn);
+	parse_header_le16(fb, &header->addr_actions_v);
+
+	parse_header_le16(fb, &header->addr_vm);
+	parse_header_le16(fb, &header->addr_dictionary);
+
+	parse_header_le16(fb, &header->addr_word_map);
+	/* FIXME - what is this for? */
+	parse_header_le16(fb, &dummy);
+	addr_dictionary_end = header->addr_word_map;
+
+	/* Rooms */
+	parse_header_le16(fb, &header->room_desc_table);
+	parse_header_le16(fb, &header->room_direction_table[DIRECTION_NORTH]);
+	parse_header_le16(fb, &header->room_direction_table[DIRECTION_SOUTH]);
+	parse_header_le16(fb, &header->room_direction_table[DIRECTION_EAST]);
+	parse_header_le16(fb, &header->room_direction_table[DIRECTION_WEST]);
+	parse_header_le16(fb, &header->room_direction_table[DIRECTION_UP]);
+	parse_header_le16(fb, &header->room_direction_table[DIRECTION_DOWN]);
+	parse_header_le16(fb, &header->room_direction_table[DIRECTION_IN]);
+	parse_header_le16(fb, &header->room_direction_table[DIRECTION_OUT]);
+	parse_header_le16(fb, &header->room_flags_table);
+	parse_header_le16(fb, &header->room_graphics_table);
+
+	/*
+	 * Objects.
+	 *
+	 * Layout is dependent on comprehend version.
+	 */
+	if (game->info->comprehend_version == 1) {
+		parse_header_le16(fb, &header->addr_item_locations);
+		parse_header_le16(fb, &header->addr_item_flags);
+		parse_header_le16(fb, &header->addr_item_word);
+		parse_header_le16(fb, &header->addr_item_strings);
+		parse_header_le16(fb, &header->addr_item_graphics);
+
+		header->nr_items = (header->addr_item_word -
+		                    header->addr_item_flags);
+
+	} else {
+		parse_header_le16(fb, &header->addr_item_strings);
+		parse_header_le16(fb, &header->addr_item_word);
+		parse_header_le16(fb, &header->addr_item_locations);
+		parse_header_le16(fb, &header->addr_item_flags);
+		parse_header_le16(fb, &header->addr_item_graphics);
+
+		header->nr_items = (header->addr_item_flags -
+		                    header->addr_item_locations);
+	}
+
+	parse_header_le16(fb, &header->addr_strings);
+	parse_header_le16(fb, &dummy);
+	parse_header_le16(fb, &header->addr_strings_end);
+
+	file_buf_get_u8(fb, &dummy8);
+	file_buf_get_u8(fb, &game->info->start_room);
+	file_buf_get_u8(fb, &dummy8);
+
+	parse_variables(game, fb);
+	parse_flags(game, fb);
+
+	game->info->nr_rooms = header->room_direction_table[DIRECTION_SOUTH] -
+	                       header->room_direction_table[DIRECTION_NORTH];
+
+	game->info->nr_words = (addr_dictionary_end -
+	                        header->addr_dictionary) /
+	                       8;
+}
+
+static void load_extra_string_file(struct comprehend_game *game,
+                                   const char *dirname,
+                                   struct string_file *string_file) {
+	char filename[PATH_MAX];
+	struct file_buf fb;
+	unsigned end;
+
+	snprintf(filename, sizeof(filename), "%s/%s", dirname,
+	         string_file->filename);
+	file_buf_map(filename, &fb);
+
+	if (string_file->end_offset)
+		end = string_file->end_offset;
+	else
+		end = fb.size;
+
+	parse_string_table(&fb, string_file->base_offset,
+	                   end, &game->info->strings2);
+
+	file_buf_unmap(&fb);
+}
+
+static void load_extra_string_files(struct comprehend_game *game,
+                                    const char *dirname) {
+	int i;
+
+	memset(&game->info->strings2, 0, sizeof(game->info->strings2));
+
+	for (i = 0; i < ARRAY_SIZE(game->string_files); i++) {
+		if (!game->string_files[i].filename)
+			break;
+
+		// HACK - get string offsets correct
+		game->info->strings2.nr_strings = 0x40 * i;
+		if (game->info->strings2.nr_strings == 0)
+			game->info->strings2.nr_strings++;
+
+		load_extra_string_file(game, dirname, &game->string_files[i]);
+	}
+}
+
+static void load_game_data(struct comprehend_game *game, const char *dirname) {
+	char data_file[PATH_MAX];
+	struct file_buf fb;
+
+	snprintf(data_file, sizeof(data_file), "%s/%s",
+	         dirname, game->game_data_file);
+
+	memset(game->info, 0, sizeof(*game->info));
+
+	file_buf_map(data_file, &fb);
+
+	parse_header(game, &fb);
+	parse_rooms(game, &fb);
+	parse_items(game, &fb);
+	parse_dictionary(game, &fb);
+	parse_word_map(game, &fb);
+	memset(&game->info->strings, 0, sizeof(game->info->strings));
+	parse_string_table(&fb, game->info->header.addr_strings,
+	                   game->info->header.addr_strings_end,
+	                   &game->info->strings);
+	load_extra_string_files(game, dirname);
+	parse_vm(game, &fb);
+	parse_action_table(game, &fb);
+	parse_replace_words(game, &fb);
+
+	file_buf_unmap(&fb);
+}
+
+void comprehend_load_game(struct comprehend_game *game, const char *dirname) {
+	game->game_dir = dirname;
+
+	/* Load the main game data file */
+	load_game_data(game, dirname);
+
+	if (g_enabled()) {
+		comprehend_load_images(game, dirname);
+		if (game->color_table)
+			g_set_color_table(game->color_table);
+	}
+
+	/* FIXME - This can be merged, don't need to keep start room around */
+	game->info->current_room = game->info->start_room;
+}
+
+#ifdef TODO
+static void patch_string_desc(uint16 *desc) {
+	/*
+	 * String descriptors in the save file sometimes are encoded as a
+	 * table/index value like the instruction opcodes used, and other
+	 * times the are encoded as an absolute index. We fix them up to
+	 * all be the former type.
+	 */
+	if (!(*desc & 0x8000) && *desc >= 0x100) {
+		*desc -= 0x100;
+		*desc |= 0x8100;
+	}
+}
+#endif
+
+void comprehend_save_game(struct comprehend_game *game, const char *filename) {
+#ifdef TODO
+	FILE *fd;
+	uint8 bitmask;
+	int dir, bit, flag_index, i;
+	size_t nr_rooms, nr_items;
+
+	fd = fopen(filename, "w");
+	if (!fd) {
+		printf("Error: Failed to open save file '%s': %s\n",
+		       filename, strerror(errno));
+		return;
+	}
+
+	nr_rooms = game->info->nr_rooms;
+	nr_items = game->info->header.nr_items;
+
+	file_buf_put_u8(fd, 0);
+	file_buf_put_u8(fd, game->info->current_room);
+	file_buf_put_u8(fd, 0);
+
+	/* Variables */
+	for (i = 0; i < ARRAY_SIZE(game->info->variable); i++)
+		file_buf_put_le16(fd, game->info->variable[i]);
+
+	/* Flags */
+	for (flag_index = 0, i = 0; i < ARRAY_SIZE(game->info->flags) / 8; i++) {
+		bitmask = 0;
+		for (bit = 7; bit >= 0; bit--) {
+			bitmask |= (!!game->info->flags[flag_index]) << bit;
+			flag_index++;
+		}
+
+		file_buf_put_u8(fd, bitmask);
+	}
+
+	/*
+	 * Re-Comprehend doesn't need this since the number of items is
+	 * determined by the currently loaded game, but the original games
+	 * won't load the file properly without it.
+	 */
+	file_buf_put_skip(fd, 0x12c - ftell(fd));
+	file_buf_put_u8(fd, nr_items);
+
+	if (game->info->comprehend_version == 1)
+		file_buf_put_skip(fd, 0x230 - ftell(fd));
+	else
+		file_buf_put_skip(fd, 0x130 - ftell(fd));
+
+	/* Rooms */
+	file_buf_put_array_le16(fd, 1, game->info->rooms,
+	                        string_desc, nr_rooms);
+	for (dir = 0; dir < NR_DIRECTIONS; dir++)
+		file_buf_put_array_u8(fd, 1, game->info->rooms,
+		                      direction[dir], nr_rooms);
+	file_buf_put_array_u8(fd, 1, game->info->rooms, flags, nr_rooms);
+	file_buf_put_array_u8(fd, 1, game->info->rooms, graphic, nr_rooms);
+
+	/*
+	 * Objects
+	 *
+	 * Layout differs depending on Comprehend version. Version 2 also
+	 * has long string descriptions for each object.
+	 */
+	file_buf_put_array_le16(fd, 0, game->info->item, string_desc, nr_items);
+	if (game->info->comprehend_version == 1) {
+		file_buf_put_array_u8(fd, 0, game->info->item, room, nr_items);
+		file_buf_put_array_u8(fd, 0, game->info->item, flags, nr_items);
+		file_buf_put_array_u8(fd, 0, game->info->item, word, nr_items);
+		file_buf_put_array_u8(fd, 0, game->info->item, graphic, nr_items);
+	} else {
+		file_buf_put_array_le16(fd, 0, game->info->item, long_string, nr_items);
+		file_buf_put_array_u8(fd, 0, game->info->item, word, nr_items);
+		file_buf_put_array_u8(fd, 0, game->info->item, room, nr_items);
+		file_buf_put_array_u8(fd, 0, game->info->item, flags, nr_items);
+		file_buf_put_array_u8(fd, 0, game->info->item, graphic, nr_items);
+	}
+
+	fclose(fd);
+#else
+	error("Save");
+#endif
+}
+
+void comprehend_restore_game(struct comprehend_game *game, const char *filename) {
+#ifdef TODO
+	struct file_buf fb;
+	size_t nr_rooms, nr_items;
+	uint err, dir, i;
+
+	err = file_buf_map_may_fail(filename, &fb);
+	if (err) {
+		printf("Error: Failed to open save file '%s': %s\n",
+		       filename, strerror(-err));
+		return;
+	}
+
+	nr_rooms = game->info->nr_rooms;
+	nr_items = game->info->header.nr_items;
+
+	/* Restore starting room */
+	file_buf_set_pos(&fb, 1);
+	file_buf_get_u8(&fb, &game->info->current_room);
+
+	/* Restore flags and variables */
+	file_buf_set_pos(&fb, 3);
+	parse_variables(game, &fb);
+	parse_flags(game, &fb);
+
+	/* FIXME - unknown restore data, skip over it */
+	if (game->info->comprehend_version == 1)
+		file_buf_set_pos(&fb, 0x230);
+	else
+		file_buf_set_pos(&fb, 0x130);
+
+	/* Restore rooms */
+	file_buf_get_array_le16(&fb, 1, game->info->rooms,
+	                        string_desc, nr_rooms);
+	for (dir = 0; dir < NR_DIRECTIONS; dir++)
+		file_buf_get_array_u8(&fb, 1, game->info->rooms,
+		                      direction[dir], nr_rooms);
+	file_buf_get_array_u8(&fb, 1, game->info->rooms, flags, nr_rooms);
+	file_buf_get_array_u8(&fb, 1, game->info->rooms, graphic, nr_rooms);
+
+	/*
+	 * Restore objects
+	 *
+	 * Layout differs depending on Comprehend version. Version 2 also
+	 * has long string descriptions for each object.
+	 */
+	file_buf_get_array_le16(&fb, 0, game->info->item, string_desc, nr_items);
+	if (game->info->comprehend_version == 1) {
+		file_buf_get_array_u8(&fb, 0, game->info->item, room, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->info->item, flags, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->info->item, word, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->info->item, graphic, nr_items);
+	} else {
+		file_buf_get_array_le16(&fb, 0, game->info->item, long_string, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->info->item, word, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->info->item, room, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->info->item, flags, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->info->item, graphic, nr_items);
+	}
+
+	/*
+	 * FIXME - The save file has some string descriptors masked with 0x8000.
+	 *         Not sure what this means, so just mask it out for now.
+	 */
+	for (i = 1; i <= nr_rooms; i++)
+		patch_string_desc(&game->info->rooms[i].string_desc);
+	for (i = 0; i < nr_items; i++)
+		patch_string_desc(&game->info->item[i].string_desc);
+
+	file_buf_unmap(&fb);
+#else
+	error("load");
+#endif
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
new file mode 100644
index 0000000000..2892bd29c7
--- /dev/null
+++ b/engines/glk/comprehend/game_data.h
@@ -0,0 +1,318 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_GAME_DATA_H
+#define GLK_COMPREHEND_GAME_DATA_H
+
+#include "glk/comprehend/image_data.h"
+
+namespace Glk {
+namespace Comprehend {
+
+#define MAX_FLAGS	64
+#define MAX_VARIABLES	128
+
+enum {
+	DIRECTION_NORTH,
+	DIRECTION_SOUTH,
+	DIRECTION_EAST,
+	DIRECTION_WEST,
+	DIRECTION_UP,
+	DIRECTION_DOWN,
+	DIRECTION_IN,
+	DIRECTION_OUT,
+	NR_DIRECTIONS,
+};
+
+struct function_state {
+	bool		test_result;
+	bool		else_result;
+	unsigned	or_count;
+	bool		_and;
+	bool		in_command;
+	bool		executed;
+};
+
+struct room {
+	uint8			direction[NR_DIRECTIONS];
+	uint8			flags;
+	uint8			graphic;
+	uint16		string_desc;
+};
+
+struct item {
+	uint16		string_desc;
+	uint16		long_string;	/* Only used by version 2 */
+	uint8			room;
+	uint8			flags;
+	uint8			word;
+	uint8			graphic;
+};
+
+struct word {
+	char			word[7];
+	uint8			index;
+	uint8			type;
+};
+
+struct word_index {
+	uint8			index;
+	uint8			type;
+};
+
+struct word_map {
+	/* <word[0]>, <word[1]> == <word[2]> */
+	struct word_index	word[3];
+	uint8			flags;
+};
+
+struct action {
+	int			type;
+	size_t			nr_words;
+	// FIXME - use struct word_index here.
+	uint8			word[4];
+	uint8			word_type[4];
+	uint16		function;
+};
+
+struct instruction {
+	uint8			opcode;
+	size_t			nr_operands;
+	uint8			operand[3];
+	bool			is_command;
+};
+
+struct function {
+	struct instruction	instructions[0x100];
+	size_t			nr_instructions;
+};
+
+struct string_table {
+	char			*strings[0xffff];
+	size_t			nr_strings;
+};
+
+struct game_header {
+	uint16		magic;
+
+	uint16		room_desc_table;
+	uint16		room_direction_table[NR_DIRECTIONS];
+	uint16		room_flags_table;
+	uint16		room_graphics_table;
+
+	size_t			nr_items;
+	uint16		addr_item_locations;
+	uint16		addr_item_flags;
+	uint16		addr_item_word;
+	uint16		addr_item_strings;
+	uint16		addr_item_graphics;
+
+	uint16		addr_dictionary;
+	uint16		addr_word_map;
+
+	uint16		addr_strings;
+	uint16		addr_strings_end;
+
+	uint16		addr_actions_vvnn;
+	uint16		addr_actions_unknown;
+	uint16		addr_actions_vnjn;
+	uint16		addr_actions_vjn;
+	uint16		addr_actions_vdn;
+	uint16		addr_actions_vnn;
+	uint16		addr_actions_vn;
+	uint16		addr_actions_v;
+
+	uint16		addr_vm; // FIXME - functions
+};
+
+struct game_info {
+	struct game_header	header;
+
+	unsigned		comprehend_version;
+
+	uint8			start_room;
+
+	struct room		rooms[0x100];
+	size_t			nr_rooms;
+	uint8			current_room;
+
+	struct item		item[0xff];
+
+	struct word		*words;
+	size_t			nr_words;
+
+	struct word_map		word_map[0xff];
+	size_t			nr_word_maps;
+
+	struct string_table	strings;
+	struct string_table	strings2;
+
+	struct action		action[0xffff];
+	size_t			nr_actions;
+
+	struct function		functions[0xffff];
+	size_t			nr_functions;
+
+	struct image_data	room_images;
+	struct image_data	item_images;
+
+	bool			flags[MAX_FLAGS];
+	uint16		variable[MAX_VARIABLES];
+
+	char			*replace_words[256];
+	size_t			nr_replace_words;
+
+	uint8			current_replace_word;
+	unsigned		update_flags;
+};
+
+enum {
+	OPCODE_UNKNOWN,
+	OPCODE_TEST_FALSE,
+	OPCODE_HAVE_OBJECT,
+	OPCODE_OR,
+	OPCODE_IN_ROOM,
+	OPCODE_VAR_EQ,
+	OPCODE_CURRENT_OBJECT_TAKEABLE,
+	OPCODE_OBJECT_PRESENT,
+	OPCODE_ELSE,
+	OPCODE_OBJECT_IN_ROOM,
+	OPCODE_OBJECT_NOT_VALID,
+	OPCODE_INVENTORY_FULL,
+	OPCODE_TEST_FLAG,
+	OPCODE_CURRENT_OBJECT_IN_ROOM,
+	OPCODE_HAVE_CURRENT_OBJECT,
+	OPCODE_OBJECT_IS_NOT_NOWHERE,
+	OPCODE_CURRENT_OBJECT_PRESENT,
+	OPCODE_TEST_ROOM_FLAG,
+	OPCODE_NOT_HAVE_OBJECT,
+	OPCODE_NOT_IN_ROOM,
+	OPCODE_CURRENT_OBJECT_IS_NOWHERE,
+	OPCODE_OBJECT_NOT_PRESENT,
+	OPCODE_OBJECT_NOT_IN_ROOM,
+	OPCODE_TEST_NOT_FLAG,
+	OPCODE_NOT_HAVE_CURRENT_OBJECT,
+	OPCODE_OBJECT_IS_NOWHERE,
+	OPCODE_CURRENT_OBJECT_NOT_PRESENT,
+	OPCODE_CURRENT_OBJECT_NOT_TAKEABLE,
+	OPCODE_TEST_NOT_ROOM_FLAG,
+	OPCODE_INVENTORY,
+	OPCODE_TAKE_OBJECT,
+	OPCODE_MOVE_OBJECT_TO_ROOM,
+	OPCODE_SAVE_ACTION,
+	OPCODE_MOVE_TO_ROOM,
+	OPCODE_VAR_ADD,
+	OPCODE_SET_ROOM_DESCRIPTION,
+	OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM,
+	OPCODE_VAR_SUB,
+	OPCODE_SET_OBJECT_DESCRIPTION,
+	OPCODE_SET_OBJECT_LONG_DESCRIPTION,
+	OPCODE_MOVE,
+	OPCODE_MOVE_DIRECTION,
+	OPCODE_PRINT,
+	OPCODE_REMOVE_OBJECT,
+	OPCODE_SET_FLAG,
+	OPCODE_CALL_FUNC,
+	OPCODE_TURN_TICK,
+	OPCODE_CLEAR_FLAG,
+	OPCODE_INVENTORY_ROOM,
+	OPCODE_TAKE_CURRENT_OBJECT,
+	OPCODE_SPECIAL,
+	OPCODE_DROP_OBJECT,
+	OPCODE_DROP_CURRENT_OBJECT,
+	OPCODE_SET_ROOM_GRAPHIC,
+	OPCODE_SET_OBJECT_GRAPHIC,
+	OPCODE_REMOVE_CURRENT_OBJECT,
+	OPCODE_DO_VERB,
+	OPCODE_VAR_INC,
+	OPCODE_VAR_DEC,
+	OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM,
+	OPCODE_DESCRIBE_CURRENT_OBJECT,
+	OPCODE_SET_STRING_REPLACEMENT,
+	OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT,
+	OPCODE_CURRENT_NOT_OBJECT,
+	OPCODE_CURRENT_IS_OBJECT,
+	OPCODE_DRAW_ROOM,
+	OPCODE_DRAW_OBJECT,
+	OPCODE_WAIT_KEY,
+};
+
+/* Game state update flags */
+#define UPDATE_GRAPHICS		(1 << 0) /* Implies UPDATE_GRAPHICS_ITEMS */
+#define UPDATE_GRAPHICS_ITEMS	(1 << 1)
+#define UPDATE_ROOM_DESC	(1 << 2)
+#define UPDATE_ITEM_LIST	(1 << 3)
+#define UPDATE_ALL		(~0U)
+
+/* Action types */
+enum {
+	ACTION_VERB_VERB_NOUN_NOUN,
+	ACTION_VERB_NOUN_JOIN_NOUN,
+	ACTION_VERB_JOIN_NOUN,
+	ACTION_VERB_DIR_NOUN,
+	ACTION_VERB_NOUN_NOUN,
+	ACTION_VERB_NOUN,
+	ACTION_VERB_OPT_NOUN,
+};
+
+/* Standard strings (main string table) */
+#define STRING_CANT_GO		0
+#define STRING_DONT_UNDERSTAND	1
+#define STRING_YOU_SEE		2
+#define STRING_INVENTORY	3
+#define STRING_INVENTORY_EMPTY	4
+#define STRING_BEFORE_CONTINUE	5
+#define STRING_SAVE_GAME	6
+#define STRING_RESTORE_GAME	7
+
+/* Special variables */
+#define VAR_INVENTORY_WEIGHT	0
+#define VAR_INVENTORY_LIMIT	1
+#define VAR_TURN_COUNT		2
+
+/* Special rooms */
+#define ROOM_INVENTORY		0x00
+#define ROOM_NOWHERE		0xff
+
+/* Item flags */
+#define ITEMF_WEIGHT_MASK	(0x3)
+#define ITEMF_CAN_TAKE		(1 << 3)
+
+/* Word types */
+#define WORD_TYPE_VERB		0x01
+#define WORD_TYPE_JOIN		0x02
+#define WORD_TYPE_FEMALE	0x10
+#define WORD_TYPE_MALE		0x20
+#define WORD_TYPE_NOUN		0x40
+#define WORD_TYPE_NOUN_PLURAL	0x80
+#define WORD_TYPE_NOUN_MASK	(WORD_TYPE_FEMALE | WORD_TYPE_MALE |	\
+				 WORD_TYPE_NOUN | WORD_TYPE_NOUN_PLURAL)
+
+void comprehend_load_game(struct comprehend_game *game, const char *dirname);
+void comprehend_restore_game(struct comprehend_game *game,
+			     const char *filename);
+void comprehend_save_game(struct comprehend_game *game, const char *filename);
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
new file mode 100644
index 0000000000..d1d524c116
--- /dev/null
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -0,0 +1,149 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/game.h"
+#include "glk/comprehend/graphics.h"
+
+namespace Glk {
+namespace Comprehend {
+
+#define OO_ROOM_FLAG_DARK	0x02
+
+#define OO_BRIGHT_ROOM		0x19
+
+#define OO_FLAG_WEARING_GOGGLES	0x1b
+#define OO_FLAG_FLASHLIGHT_ON	0x27
+
+static int oo_room_is_special(struct comprehend_game *game, 
+			      unsigned room_index,
+			      unsigned *room_desc_string)
+{
+	struct room *room = &game->info->rooms[room_index];
+
+	/* Is the room dark */
+	if ((room->flags & OO_ROOM_FLAG_DARK) &&
+	    !(game->info->flags[OO_FLAG_FLASHLIGHT_ON])) {
+		if (room_desc_string)
+			*room_desc_string = 0xb3; 
+		return ROOM_IS_DARK;
+	}
+
+	/* Is the room too bright */
+	if (room_index == OO_BRIGHT_ROOM && 
+	    !game->info->flags[OO_FLAG_WEARING_GOGGLES]) {
+		if (room_desc_string)
+			*room_desc_string = 0x1c;
+		return ROOM_IS_TOO_BRIGHT;
+	}
+
+	return ROOM_IS_NORMAL;
+}
+
+static bool oo_before_turn(struct comprehend_game *game)
+{
+	/* FIXME - probably doesn't work correctly with restored games */
+	static bool flashlight_was_on = false, googles_were_worn = false;
+	struct room *room = &game->info->rooms[game->info->current_room];
+
+	/* 
+	 * Check if the room needs to be redrawn because the flashlight
+	 * was switch off or on.
+	 */
+	if (game->info->flags[OO_FLAG_FLASHLIGHT_ON] != flashlight_was_on &&
+	    (room->flags & OO_ROOM_FLAG_DARK)) {
+		flashlight_was_on = game->info->flags[OO_FLAG_FLASHLIGHT_ON];
+		game->info->update_flags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
+	}
+
+	/*
+	 * Check if the room needs to be redrawn because the goggles were
+	 * put on or removed.
+	 */
+	if (game->info->flags[OO_FLAG_WEARING_GOGGLES] != googles_were_worn &&
+	    game->info->current_room == OO_BRIGHT_ROOM) {
+		googles_were_worn = game->info->flags[OO_FLAG_WEARING_GOGGLES];
+		game->info->update_flags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
+	}
+
+	return false;
+}
+
+static void oo_handle_special_opcode(struct comprehend_game *game,
+				     uint8 operand)
+{
+	switch (operand) {
+	case 0x03:
+		/* Game over - failure */
+	case 0x05:
+		/* Won the game */
+	case 0x04:
+		/* Restart game */
+		game_restart(game);
+		break;
+
+	case 0x06:
+		/* Save game */
+		game_save(game);
+		break;
+
+	case 0x07:
+		/* Restore game */
+		game_restore(game);
+		break;
+	}
+}
+
+static struct game_ops oo_ops = {
+	nullptr,
+	nullptr,
+	oo_before_turn,
+	nullptr,
+	oo_room_is_special,
+	oo_handle_special_opcode
+}; 
+
+struct comprehend_game game_oo_topos = {
+	"Oo-Topos",
+	"oo",
+	nullptr,
+	"G0",
+	{
+		// Extra strings are (annoyingly) stored in the game binary
+		{"NOVEL.EXE", 0x16564, 0x17640},
+		{"NOVEL.EXE", 0x17702, 0x18600},
+		{"NOVEL.EXE", 0x186b2, 0x19b80},
+		{"NOVEL.EXE", 0x19c62, 0x1a590},
+		{"NOVEL.EXE", 0x1a634, 0x1b080},
+	},
+	{"RA", "RB", "RC", "RD", "RE"},
+	{"OA", "OB", "OC", "OD"},
+	"G%d",
+	1,
+	nullptr,
+	&oo_ops,
+	nullptr
+};
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/game_tm.cpp b/engines/glk/comprehend/game_tm.cpp
new file mode 100644
index 0000000000..1b8b54690a
--- /dev/null
+++ b/engines/glk/comprehend/game_tm.cpp
@@ -0,0 +1,50 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game.h"
+#include "glk/comprehend/game_data.h"
+
+namespace Glk {
+namespace Comprehend {
+
+static struct game_ops tm_ops = {};
+
+/* FIXME - This is broken */
+struct comprehend_game game_talisman = {
+    "Talisman, Challenging the Sands of Time (broken)",
+    "tm",
+    nullptr,
+    "G0",
+    {},
+	{"RA", "RB", "RC", "RD", "RE", "RF", "RG"},
+    {"OA", "OB", "OE", "OF"},
+    nullptr,
+    0,
+
+    nullptr,
+    &tm_ops,
+    nullptr
+};
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
new file mode 100644
index 0000000000..fc8ad72943
--- /dev/null
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -0,0 +1,223 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/game.h"
+#include "glk/comprehend/util.h"
+
+namespace Glk {
+namespace Comprehend {
+
+struct tr_monster {
+	uint8		object;
+	uint8		dead_flag;
+	unsigned	min_turns_before;
+	unsigned	room_allow_flag;
+	unsigned	randomness;
+};
+
+static struct tr_monster tr_werewolf = {
+	0x21, 7, (1 << 6), 5, 5
+};
+
+static struct tr_monster tr_vampire = {
+	0x26, 5, (1 << 7), 0, 5
+};
+
+static void tr_update_monster(struct comprehend_game *game,
+			      struct tr_monster *monster_info)
+{
+	struct item *monster;
+	struct room *room;
+	uint16 turn_count;
+
+	room = &game->info->rooms[game->info->current_room];
+	turn_count = game->info->variable[VAR_TURN_COUNT];
+
+	monster = get_item(game, monster_info->object);
+	if (monster->room == game->info->current_room) {
+		/* The monster is in the current room - leave it there */
+		return;
+	}
+
+	if ((room->flags & monster_info->room_allow_flag) &&
+	    !game->info->flags[monster_info->dead_flag] &&
+	    turn_count > monster_info->min_turns_before) {
+		/*
+		 * The monster is alive and allowed to move to the current
+		 * room. Randomly decide whether on not to. If not, move
+		 * it back to limbo.
+		 */
+		if ((g_comprehend->getRandomNumber(0x7fffffff) % monster_info->randomness) == 0) {
+			move_object(game, monster, game->info->current_room);
+			game->info->variable[0xf] = turn_count + 1;
+		} else {
+			move_object(game, monster, ROOM_NOWHERE);
+		}
+	}
+}
+
+static int tr_room_is_special(struct comprehend_game *game, unsigned room_index,
+			      unsigned *room_desc_string)
+{
+	struct room *room = &game->info->rooms[room_index];
+
+	if (room_index == 0x28) {
+		if (room_desc_string)
+			*room_desc_string = room->string_desc;
+		return ROOM_IS_DARK;
+	}
+
+	return ROOM_IS_NORMAL;
+}
+
+static bool tr_before_turn(struct comprehend_game *game)
+{
+	tr_update_monster(game, &tr_werewolf);
+	tr_update_monster(game, &tr_vampire);
+	return false;
+}
+
+static void tr_handle_special_opcode(struct comprehend_game *game,
+				     uint8 operand)
+{
+	switch (operand) {
+	case 0x01:
+		/*
+		 * FIXME - Called when the mice are dropped and the cat chases
+		 *         them.
+		 */
+		break;
+
+	case 0x02:
+		/* FIXME - Called when the gun is fired */
+		break;
+
+	case 0x06:
+		game_save(game);
+		break;
+
+	case 0x07:
+		game_restore(game);
+		break;
+
+	case 0x03:
+		/* Game over - failure */
+	case 0x05:
+		/* Won the game */
+	case 0x08:
+		/* Restart game */
+		game_restart(game);
+		break;
+
+	case 0x09:
+		/*
+		 * Show the Zin screen in reponse to doing 'sing some enchanted
+		 * evening' in his cabin.
+		 */
+		draw_location_image(&game->info->room_images, 41);
+		console_get_key();
+		game->info->update_flags |= UPDATE_GRAPHICS;
+		break;
+	}
+}
+
+static void read_string(char *buffer, size_t size)
+{
+#ifdef TODO
+	char *p;
+
+	printf("> ");
+	fgets(buffer, size, stdin);
+
+	/* Remove trailing newline */
+	p = strchr(buffer, '\n');
+	if (p)
+		*p = '\0';
+#else
+	error("TODO");
+#endif
+}
+
+static void tr_before_game(struct comprehend_game *game)
+{
+	char buffer[128];
+
+	/* Welcome to Transylvania - sign your name */
+	console_println(game, game->info->strings.strings[0x20]);
+	read_string(buffer, sizeof(buffer));
+
+	/*
+	 * Transylvania uses replace word 0 as the player's name, the game
+	 * data file stores a bunch of dummy characters, so the length is
+	 * limited (the original game will break if you put a name in that
+	 * is too long).
+	 */
+	if (!game->info->replace_words[0])
+		game->info->replace_words[0] = xstrndup(buffer, strlen(buffer));
+	else
+		snprintf(game->info->replace_words[0],
+			 strlen(game->info->replace_words[0]),
+			 "%s", buffer);
+
+	/* And your next of kin - This isn't store by the game */
+	console_println(game, game->info->strings.strings[0x21]);
+	read_string(buffer, sizeof(buffer));
+}
+
+static struct game_strings tr_strings = {
+	EXTRA_STRING_TABLE(0x8a)
+};
+
+static struct game_ops tr_ops = {
+	tr_before_game,
+	nullptr,
+	tr_before_turn,
+	nullptr,
+	tr_room_is_special,
+	tr_handle_special_opcode,
+};
+
+struct comprehend_game game_transylvania = {
+	"Transylvania",
+	"tr",
+	nullptr,
+	"TR.GDA",
+	{
+		{"MA.MS1", 0x88},
+		{"MB.MS1", 0x88},
+		{"MC.MS1", 0x88},
+		{"MD.MS1", 0x88},
+		{"ME.MS1", 0x88},
+	},
+	{"RA.MS1", "RB.MS1", "RC.MS1"},
+	{"OA.MS1", "OB.MS1", "OC.MS1"},
+	"G%d.MS0",
+	0,
+	&tr_strings,
+	&tr_ops,
+	nullptr
+};
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/graphics.cpp b/engines/glk/comprehend/graphics.cpp
new file mode 100644
index 0000000000..b62df4d2fc
--- /dev/null
+++ b/engines/glk/comprehend/graphics.cpp
@@ -0,0 +1,686 @@
+/* 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 "glk/comprehend/graphics.h"
+#include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/image_data.h"
+#include "glk/comprehend/util.h"
+#include "glk/window_graphics.h"
+
+namespace Glk {
+namespace Comprehend {
+
+#define RENDER_X_MAX 278
+#define RENDER_Y_MAX 162
+
+#define RENDERER_SCREEN 0
+#define RENDERER_PIXEL_DATA 1
+
+static bool graphics_enabled;
+
+static unsigned pen_colors[] = {
+    G_COLOR_BLACK,
+    RGB(0x00, 0x66, 0x00),
+    RGB(0x00, 0xff, 0x00),
+    G_COLOR_WHITE,
+    G_COLOR_BLACK,
+    RGB(0x00, 0xff, 0xff),
+    RGB(0xff, 0x00, 0xff),
+    RGB(0xff, 0x00, 0x00),
+};
+
+struct graphics_context {
+	Window *screen;
+
+	/*
+	 * FIXME - Currently using two renderers. One for drawing the (possibly
+	 *         scaled) image to the screen and the other for getting pixel
+	 *         data for floodfill boundaries. This is almost certainly not
+	 *         the best way to do this.
+	 */
+	//	SDL_Renderer	*renderer[2];
+
+	/* Used for pixel access for flood fills */
+	//	SDL_Surface	*surface;
+};
+
+static struct graphics_context ctx;
+
+unsigned g_set_pen_color(uint8 opcode) {
+	return pen_colors[opcode - IMAGE_OP_PEN_COLOR_A];
+}
+
+/* Used by Transylvania and Crimson Crown */
+static unsigned default_color_table[] = {
+    G_COLOR_WHITE,     // 00
+    G_COLOR_DARK_BLUE, // 01
+    G_COLOR_GRAY1,     // 02
+    G_COLOR_DARK_RED,  // 03
+    G_COLOR_GRAY2,     // 04
+    0, G_COLOR_GRAY3, 0, 0, 0, 0, 0, 0,
+    G_COLOR_BROWN1, G_COLOR_DARK_PURPLE, 0,
+
+    0, 0, G_COLOR_DARK_RED, G_COLOR_BROWN2, 0, 0, 0,
+    G_COLOR_DARK_BLUE, G_COLOR_BLACK, 0, 0, 0, 0, 0, 0, G_COLOR_DARK_PURPLE,
+
+    G_COLOR_DARK_PURPLE, 0, G_COLOR_DARK_RED, 0, 0, 0, 0, 0,
+    0, 0, 0, G_COLOR_DARK_PURPLE, 0, 0, 0, 0,
+
+    0, 0, 0, 0, G_COLOR_WHITE, G_COLOR_GRAY0, RGB(0xb5, 0x6c, 0x47),
+    0, 0, 0, 0, 0, G_COLOR_CYAN, G_COLOR_DARK_RED,
+    G_COLOR_DARK_GREEN1, G_COLOR_DARK_GREEN2,
+
+    G_COLOR_DARK_PURPLE, 0, G_COLOR_DITHERED_PINK, 0, 0,
+    G_COLOR_BROWN2, G_COLOR_DARK_RED, G_COLOR_DARK_BLUE,
+    G_COLOR_DARK_BLUE, G_COLOR_DARK_BLUE, 0, 0, 0,
+    G_COLOR_WHITE, G_COLOR_BROWN2, G_COLOR_BROWN2,
+
+    G_COLOR_BLACK, G_COLOR_DARK_PURPLE, 0, G_COLOR_GRAY2,
+    G_COLOR_BROWN2, 0, 0, G_COLOR_AQUA, 0, 0, G_COLOR_GREEN,
+    G_COLOR_DARK_BLUE, G_COLOR_DARK_PURPLE, G_COLOR_BROWN1,
+    G_COLOR_BROWN2, 0,
+
+    G_COLOR_DARK_PURPLE, G_COLOR_LIGHT_ORANGE, 0, 0,
+    G_COLOR_ORANGE, G_COLOR_RED, G_COLOR_DARK_RED, 0, 0, 0,
+    G_COLOR_DARK_BLUE, G_COLOR_DARK_PURPLE, 0, 0, 0, 0,
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    G_COLOR_BLACK, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+/* Used by OO-topos */
+/* FIXME - incomplete */
+static unsigned color_table_1[] = {
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    RGB(0x80, 0x00, 0x00),
+    0,
+    RGB(0xe6, 0xe6, 0x00),
+    0,
+    0,
+    0,
+    0,
+    RGB(0xc0, 0x00, 0x00),
+    RGB(0x80, 0x00, 0x00),
+    G_COLOR_ORANGE,
+    0,
+
+    0,
+    G_COLOR_BROWN1,
+    RGB(0x00, 0x00, 0x66),
+    RGB(0x33, 0x99, 0xff),
+    0,
+    RGB(0xe8, 0xe8, 0xe8),
+    RGB(0x99, 0xcc, 0xff),
+    0,
+    RGB(0x99, 0x33, 0x33),
+    RGB(0xcc, 0x66, 0x00),
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+
+    G_COLOR_GRAY3,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    RGB(0x99, 0x33, 0x00),
+    G_COLOR_CYAN,
+    0,
+    0,
+    RGB(0x66, 0x00, 0x33),
+    0,
+    0,
+    0,
+    0,
+
+    G_COLOR_AQUA,
+    G_COLOR_GRAY2,
+    0,
+    0,
+    0,
+    G_COLOR_DARK_BLUE,
+    0,
+    0,
+    0,
+    0,
+    G_COLOR_GRAY1,
+    0,
+    0,
+    0,
+    0,
+    0,
+
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+    0,
+};
+
+static unsigned *color_tables[] = {
+    default_color_table,
+    color_table_1,
+};
+
+static unsigned *color_table = default_color_table;
+
+void g_set_color_table(unsigned index) {
+	if (index >= ARRAY_SIZE(color_tables)) {
+		printf("Bad color table %d - using default\n", index);
+		color_table = default_color_table;
+	}
+
+	color_table = color_tables[index];
+}
+
+unsigned g_set_fill_color(uint8 index) {
+	unsigned color;
+
+	color = color_table[index];
+	if (!color) {
+		/* Unknown color - use ugly purple */
+		debug_printf(DEBUG_IMAGE_DRAW, "Unknown color %.2x\n", index);
+		return RGB(0xff, 0x00, 0xff);
+	}
+
+	return color;
+}
+
+#ifdef TODO
+static void set_color(unsigned color) {
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
+		SDL_SetRenderDrawColor(ctx.renderer[i],
+		                       (color >> 24) & 0xff,
+		                       (color >> 16) & 0xff,
+		                       (color >> 8) & 0xff,
+		                       (color >> 0) & 0xff);
+}
+#endif
+
+void g_draw_box(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
+                unsigned color) {
+#ifdef TODO
+	SDL_Rect rect;
+	int i;
+
+	rect.x = x1;
+	rect.y = y1;
+	rect.w = x2 - x1;
+	rect.h = y2 - y1;
+
+	set_color(color);
+	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
+		SDL_RenderDrawRect(ctx.renderer[i], &rect);
+#endif
+}
+
+static void g_draw_filled_box(unsigned x1, unsigned y1,
+                              unsigned x2, unsigned y2, unsigned color) {
+#ifdef TODO
+	SDL_Rect rect;
+	int i;
+
+	rect.x = x1;
+	rect.y = y1;
+	rect.w = x2 - x1;
+	rect.h = y2 - y1;
+
+	set_color(color);
+	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
+		SDL_RenderFillRect(ctx.renderer[i], &rect);
+#endif
+}
+
+unsigned g_get_pixel_color(int x, int y) {
+#ifdef TODO
+	uint32 *pixels, val;
+
+	pixels = ctx.surface->pixels;
+	val = pixels[(y * G_RENDER_WIDTH) + x];
+
+	/* FIXME - correct endianess on all platforms? */
+	return be32toh(val);
+#else
+	return 0;
+#endif
+}
+
+void g_draw_pixel(unsigned x, unsigned y, unsigned color) {
+#ifdef TODO
+	int i;
+
+	set_color(color);
+	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
+		SDL_RenderDrawPoint(ctx.renderer[i], x, y);
+#endif
+}
+
+void g_draw_line(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
+		 unsigned color)
+{
+#ifdef TODO
+	int i;
+
+	set_color(color);
+	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
+		SDL_RenderDrawLine(ctx.renderer[i], x1, y1, x2, y2);
+#endif
+}
+
+void g_draw_shape(int x, int y, int shape_type, unsigned fill_color)
+{
+	int i, j;
+
+	switch (shape_type) {
+	case IMAGE_OP_SHAPE_PIXEL:
+		x += 7; y += 7;
+		g_draw_pixel(x, y, fill_color);
+		break;
+
+	case IMAGE_OP_SHAPE_BOX:
+		x += 6; y += 7;
+		g_draw_filled_box(x, y, x + 2, y + 2, fill_color);
+		break;
+
+	case IMAGE_OP_SHAPE_CIRCLE_TINY:
+		x += 5;
+		y += 5;
+		g_draw_filled_box(x + 1, y, x + 3, y + 4, fill_color);
+		g_draw_filled_box(x, y + 1, x + 4, y + 3, fill_color);
+		break;
+
+	case IMAGE_OP_SHAPE_CIRCLE_SMALL:
+		x += 4; y += 4;
+		g_draw_filled_box(x + 1, y, x + 5, y + 6, fill_color);
+		g_draw_filled_box(x, y + 1, x + 6, y + 5, fill_color);
+		break;
+
+	case IMAGE_OP_SHAPE_CIRCLE_MED:
+		x += 1; y += 1;
+		g_draw_filled_box(x + 1,
+				  y + 1,
+				  x + 1 + (2 + 4 + 2),
+				  y + 1 + (2 + 4 + 2),
+				  fill_color);
+		g_draw_filled_box(x + 3,
+				  y,
+				  x + 3 + 4,
+				  y + (1 + 2 + 4 + 2 + 1),
+				  fill_color);
+		g_draw_filled_box(x,
+				  y + 3,
+				  x + (1 + 2 + 4 + 2 + 1),
+				  y + 3 + 4,
+				  fill_color);
+		break;
+
+	case IMAGE_OP_SHAPE_CIRCLE_LARGE:
+		g_draw_filled_box(x + 2,
+				  y + 1,
+				  x + 2 + (3 + 4 + 3),
+				  y + 1 + (1 + 3 + 4 + 3 + 1),
+				  fill_color);
+		g_draw_filled_box(x + 1,
+				  y + 2,
+				  x + 1 + (1 + 3 + 4 + 3 + 1),
+				  y + 2 + (3 + 4 + 3),
+				  fill_color);
+		g_draw_filled_box(x + 5,
+				  y,
+				  x + 5 + 4,
+				  y + 1 + 1 + 3 + 4 + 3 + 1 + 1,
+				  fill_color);
+		g_draw_filled_box(x,
+				  y + 5,
+				  x + 1 + 1 + 3 + 4 + 3 + 1 + 1,
+				  y + 5 + 4,
+				  fill_color);
+		break;
+
+	case IMAGE_OP_SHAPE_A:
+		/* FIXME - very large circle? */
+		break;
+
+	case IMAGE_OP_SHAPE_SPRAY:
+	{
+		char spray[13][13] = {
+			{0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
+			{0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
+			{0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1},
+			{0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
+			{1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0},
+			{0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0},
+			{1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0},
+			{0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0},
+			{1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0},
+			{0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0},
+			{0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+			{0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0},
+		};
+		for (i = 0; i < 13; i++)
+			for (j = 0; j < 13; j++)
+				if (spray[i][j])
+					g_draw_pixel(x + i, y + j, fill_color);
+		break;
+	}
+
+	default:
+		/* Unknown shape */
+		break;
+	}
+}
+
+void g_floodfill(int x, int y, unsigned fill_color,
+			unsigned old_color)
+{
+	int x1, x2, i;
+
+	if (g_get_pixel_color(x, y) != old_color || fill_color == old_color)
+		return;
+
+	/* Left end of scanline */
+	for (x1 = x; x1 > 0; x1--)
+		if (g_get_pixel_color(x1 - 1, y) != old_color)
+			break;
+
+	/* Right end of scanline */
+	for (x2 = x; x2 < RENDER_X_MAX; x2++)
+		if (g_get_pixel_color(x2 + 1, y) != old_color)
+			break;
+
+	g_draw_line(x1, y, x2, y, fill_color);
+#ifdef TODO
+	SDL_RenderPresent(ctx.renderer[RENDERER_SCREEN]);
+#endif
+	/* Scanline above */
+	for (i = x1; i < x2; i++)
+		if (y > 0 && g_get_pixel_color(i, y - 1) == old_color)
+			g_floodfill(i, y - 1, fill_color, old_color);
+
+	/* Scanline below */
+	for (i = x1; i < x2; i++)
+		if (y < RENDER_Y_MAX && g_get_pixel_color(i, y + 1) == old_color)
+			g_floodfill(i, y + 1, fill_color, old_color);
+
+}
+
+void g_flip_buffers(void)
+{
+#ifdef TODO
+	SDL_RenderPresent(ctx.renderer[RENDERER_SCREEN]);
+#endif
+}
+
+void g_clear_screen(unsigned color) {
+	#ifdef TODO
+	int i;
+
+	set_color(color);
+	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
+		SDL_RenderClear(ctx.renderer[i]);
+
+	SDL_RenderPresent(ctx.renderer[RENDERER_SCREEN]);
+#endif
+}
+
+void g_init(unsigned width, unsigned height)
+{
+	#ifdef TODO
+	int err;
+
+	err = SDL_Init(SDL_INIT_VIDEO);
+	if (err == -1)
+		fatal_error("Failed to initialize graphics\n");
+
+	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2");
+
+	ctx.screen = SDL_CreateWindow("Re-Comprehend",
+				      SDL_WINDOWPOS_CENTERED,
+				      SDL_WINDOWPOS_CENTERED,
+				      width, height, 0);
+
+	ctx.renderer[RENDERER_SCREEN] =
+		SDL_CreateRenderer(ctx.screen, -1, SDL_RENDERER_ACCELERATED);
+	SDL_RenderSetLogicalSize(ctx.renderer[RENDERER_SCREEN],
+				 G_RENDER_WIDTH, G_RENDER_HEIGHT);
+
+	ctx.surface = SDL_CreateRGBSurface(0, G_RENDER_WIDTH, G_RENDER_HEIGHT,
+					   32, 0x000000ff, 0x0000ff00,
+					   0x00ff0000, 0xff000000);
+	ctx.renderer[RENDERER_PIXEL_DATA] =
+		SDL_CreateSoftwareRenderer(ctx.surface);
+#endif
+	graphics_enabled = true;
+}
+
+bool g_enabled(void)
+{
+	return graphics_enabled;
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/graphics.h b/engines/glk/comprehend/graphics.h
new file mode 100644
index 0000000000..414850cbc1
--- /dev/null
+++ b/engines/glk/comprehend/graphics.h
@@ -0,0 +1,88 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_GRAPHICS_H
+#define GLK_COMPREHEND_GRAPHICS_H
+
+#include "common/scummsys.h"
+
+namespace Glk {
+namespace Comprehend {
+
+#define G_RENDER_WIDTH	320
+#define G_RENDER_HEIGHT	240
+
+#define RGB(r, g, b)		(uint32)(((r) << 24) | ((g) << 16) | ((b) << 8) | 0xff)
+
+#define G_COLOR_BLACK		0x000000ff
+#define G_COLOR_WHITE		0xffffffff
+#define G_COLOR_CYAN		0x3366ffff
+#define G_COLOR_YELLOW		0xffff00ff
+#define G_COLOR_RED		0xff0000ff
+
+#define G_COLOR_GRAY0		0x202020ff
+#define G_COLOR_GRAY1		0x404040ff
+#define G_COLOR_GRAY2		0x808080ff
+#define G_COLOR_GRAY3		0xc0c0c0ff
+
+#define G_COLOR_LIGHT_ORANGE	0xff9966ff
+#define G_COLOR_ORANGE		0xff9900ff
+#define G_COLOR_DARK_PURPLE	0x666699ff
+#define G_COLOR_DARK_BLUE	0x000099ff
+
+#define G_COLOR_DARK_RED	0xcc0033ff
+#define G_COLOR_DITHERED_PINK	0xff6699ff
+
+#define G_COLOR_DARK_GREEN1	0x009966ff
+#define G_COLOR_DARK_GREEN2	0x003300ff
+
+#define G_COLOR_AQUA		0x33ccccff
+
+#define G_COLOR_GREEN		0x33cc00ff
+
+#define G_COLOR_BROWN1		0x7a5200ff
+#define G_COLOR_BROWN2		0x663300ff
+
+void g_set_color_table(unsigned index);
+
+unsigned g_set_fill_color(uint8 index);
+unsigned g_set_pen_color(uint8 opcode);
+
+unsigned g_get_pixel_color(int x, int y);
+
+void g_draw_pixel(unsigned x, unsigned y, unsigned color);
+void g_draw_line(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
+		 unsigned color);
+void g_draw_box(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
+		unsigned color);
+void g_draw_shape(int x, int y, int shape_type, unsigned fill_color);
+void g_floodfill(int x, int y, unsigned fill_color, unsigned old_color);
+
+void g_clear_screen(unsigned color);
+void g_flip_buffers(void);
+void g_init(unsigned width, unsigned height);
+bool g_enabled(void);
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
new file mode 100644
index 0000000000..21cfa44db1
--- /dev/null
+++ b/engines/glk/comprehend/image_data.cpp
@@ -0,0 +1,397 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/file_buf.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/image_data.h"
+#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/util.h"
+
+namespace Glk {
+namespace Comprehend {
+
+#define IMAGES_PER_FILE	16
+
+struct image_context {
+	unsigned	x;
+	unsigned	y;
+	unsigned	pen_color;
+	unsigned	fill_color;
+	unsigned	shape;
+
+	unsigned	text_x;
+	unsigned	text_y;
+};
+
+static unsigned draw_flags;
+
+void image_set_draw_flags(unsigned flags)
+{
+	draw_flags |= flags;
+}
+
+static uint16 image_get_operand(struct file_buf *fb)
+{
+	uint8 val;
+
+	file_buf_get_u8(fb, &val);
+	return val;
+}
+
+static bool do_image_op(struct file_buf *fb, struct image_context *ctx)
+{
+	uint8 opcode;
+	uint16 a, b;
+
+	file_buf_get_u8(fb, &opcode);
+	debug_printf(DEBUG_IMAGE_DRAW,
+		     "  %.4x [%.2x]: ", file_buf_get_pos(fb) - 1, opcode);
+
+	switch (opcode) {
+	case IMAGE_OP_SCENE_END:
+	case IMAGE_OP_EOF:
+		debug_printf(DEBUG_IMAGE_DRAW, "end\n");
+		return true;
+
+	case IMAGE_OP_PEN_COLOR_A:
+	case IMAGE_OP_PEN_COLOR_B:
+	case IMAGE_OP_PEN_COLOR_C:
+	case IMAGE_OP_PEN_COLOR_D:
+	case IMAGE_OP_PEN_COLOR_E:
+	case IMAGE_OP_PEN_COLOR_F:
+	case IMAGE_OP_PEN_COLOR_G:
+	case IMAGE_OP_PEN_COLOR_H:
+		debug_printf(DEBUG_IMAGE_DRAW, "set_pen_color(%.2x)\n", opcode);
+		ctx->pen_color = g_set_pen_color(opcode);
+		break;
+
+	case IMAGE_OP_DRAW_LINE:
+	case IMAGE_OP_DRAW_LINE_FAR:
+		a = image_get_operand(fb);
+		b = image_get_operand(fb);
+
+		if (opcode & 0x1)
+			a += 255;
+
+		debug_printf(DEBUG_IMAGE_DRAW,
+			     "draw_line (%d, %d) - (%d, %d)\n", opcode,
+			     ctx->x, ctx->y, a, b);
+		g_draw_line(ctx->x, ctx->y, a, b, ctx->pen_color);
+
+		ctx->x = a;
+		ctx->y = b;
+		break;
+
+	case IMAGE_OP_DRAW_BOX:
+	case IMAGE_OP_DRAW_BOX_FAR:
+		a = image_get_operand(fb);
+		b = image_get_operand(fb);
+
+		if (opcode & 0x1)
+			a += 255;
+
+		debug_printf(DEBUG_IMAGE_DRAW,
+			     "draw_box (%d, %d) - (%d, %d)\n", opcode,
+			     ctx->x, ctx->y, a, b);
+
+		g_draw_box(ctx->x, ctx->y, a, b, ctx->pen_color);
+		break;
+
+	case IMAGE_OP_MOVE_TO:
+	case IMAGE_OP_MOVE_TO_FAR:
+		/* Move to */
+		a = image_get_operand(fb);
+		b = image_get_operand(fb);
+
+		if (opcode & 0x1)
+			a += 255;
+
+		debug_printf(DEBUG_IMAGE_DRAW, "move_to(%d, %d)\n", a, b);
+		ctx->x = a;
+		ctx->y = b;
+		break;
+
+	case IMAGE_OP_SHAPE_PIXEL:
+	case IMAGE_OP_SHAPE_BOX:
+	case IMAGE_OP_SHAPE_CIRCLE_TINY:
+	case IMAGE_OP_SHAPE_CIRCLE_SMALL:
+	case IMAGE_OP_SHAPE_CIRCLE_MED:
+	case IMAGE_OP_SHAPE_CIRCLE_LARGE:
+	case IMAGE_OP_SHAPE_A:
+	case IMAGE_OP_SHAPE_SPRAY:
+		debug_printf(DEBUG_IMAGE_DRAW,
+			     "set_shape_type(%.2x)\n", opcode - 0x40);
+		ctx->shape = opcode;
+		break;
+
+	case 0x48:
+		/*
+		 * FIXME - This appears to be a shape type. Only used by
+		 *         OO-Topos.
+		 */
+		debug_printf(DEBUG_IMAGE_DRAW, "shape_unknown()\n");
+		ctx->shape = IMAGE_OP_SHAPE_PIXEL;
+		break;
+
+	case IMAGE_OP_DRAW_SHAPE:
+	case IMAGE_OP_DRAW_SHAPE_FAR:
+		a = image_get_operand(fb);
+		b = image_get_operand(fb);
+
+		if (opcode & 0x1)
+			a += 255;
+
+		debug_printf(DEBUG_IMAGE_DRAW,
+			     "draw_shape(%d, %d), style=%.2x, fill=%.2x\n",
+			     a, b, ctx->shape, ctx->fill_color);
+
+		g_draw_shape(a, b, ctx->shape, ctx->fill_color);
+		break;
+
+	case IMAGE_OP_PAINT:
+	case IMAGE_OP_PAINT_FAR:
+		/* Paint */
+		a = image_get_operand(fb);
+		b = image_get_operand(fb);
+
+		if (opcode & 0x1)
+			a += 255;
+
+		debug_printf(DEBUG_IMAGE_DRAW, "paint(%d, %d)\n", a, b);
+		if (!(draw_flags & IMAGEF_NO_FLOODFILL))
+			g_floodfill(a, b, ctx->fill_color,
+				    g_get_pixel_color(a, b));
+		break;
+
+	case IMAGE_OP_FILL_COLOR:
+		a = image_get_operand(fb);
+		debug_printf(DEBUG_IMAGE_DRAW, "set_fill_color(%.2x)\n", a);
+		ctx->fill_color = g_set_fill_color(a);
+		break;
+
+	case IMAGE_OP_SET_TEXT_POS:
+		a = image_get_operand(fb);
+		b = image_get_operand(fb);
+		debug_printf(DEBUG_IMAGE_DRAW, "set_text_pos(%d, %d)\n", a, b);
+
+		ctx->text_x = a;
+		ctx->text_y = b;
+		break;
+
+	case IMAGE_OP_DRAW_CHAR:
+		a = image_get_operand(fb);
+		debug_printf(DEBUG_IMAGE_DRAW, "draw_char(%c)\n",
+			     a >= 0x20 && a < 0x7f ? a : '?');
+
+		g_draw_box(ctx->text_x, ctx->text_y,
+			   ctx->text_x + 6, ctx->text_y + 7, ctx->fill_color);
+		ctx->text_x += 8;
+		break;
+
+	case 0xf3:
+		/*
+		 * FIXME - Oo-Topos uses this at the beginning of some room
+		 *         images.
+		 */
+		debug_printf(DEBUG_IMAGE_DRAW, "unknown()\n");
+		break;
+
+	case 0xb5:
+	case 0x82:
+	case 0x50:
+		/* FIXME - unknown, no arguments */
+		debug_printf(DEBUG_IMAGE_DRAW, "unknown\n");
+		break;
+
+	case 0x73:
+	case 0xb0:
+	case 0xd0:
+		/* FIXME - unknown, one argument */
+		a = image_get_operand(fb);
+		debug_printf(DEBUG_IMAGE_DRAW, "unknown %.2x: (%.2x) '%c'\n",
+			     opcode, a,
+			     a >= 0x20 && a < 0x7f ? a : '?');
+		break;
+
+	default:
+		/* FIXME - Unknown, two arguments */
+		a = image_get_operand(fb);
+		b = image_get_operand(fb);
+
+		debug_printf(DEBUG_IMAGE_DRAW,
+			     "unknown(%.2x, %.2x)\n", a, b);
+		g_draw_pixel(a, b, 0x00ff00ff);
+		break;
+	}
+
+	return false;
+}
+
+void draw_image(struct image_data *info, unsigned index)
+{
+	unsigned file_num;
+	struct file_buf *fb;
+	bool done = false;
+	image_context ctx = {
+		0, 0, G_COLOR_BLACK, G_COLOR_BLACK, IMAGE_OP_SHAPE_CIRCLE_LARGE
+	};
+
+	file_num = index / IMAGES_PER_FILE;
+	fb = &info->fb[file_num];
+
+	if (index >= info->nr_images) {
+		printf("WARNING: Bad image index %.8x (max=%.8zx)\n", index,
+		       info->nr_images);
+		return;
+	}
+
+	file_buf_set_pos(fb, info->image_offsets[index]);
+	while (!done) {
+		done = do_image_op(fb, &ctx);
+		if (!done && (draw_flags & IMAGEF_OP_WAIT_KEYPRESS)) {
+			getchar();
+			g_flip_buffers();
+		}
+	}
+
+	g_flip_buffers();
+}
+
+void draw_dark_room(void)
+{
+	g_clear_screen(G_COLOR_BLACK);
+}
+
+void draw_bright_room(void)
+{
+	g_clear_screen(G_COLOR_WHITE);
+}
+
+void draw_location_image(struct image_data *info, unsigned index)
+{
+	g_clear_screen(G_COLOR_WHITE);
+	draw_image(info, index);
+}
+
+static void load_image_file(struct image_data *info, const char *filename,
+			    unsigned file_num)
+{
+	unsigned base = file_num * IMAGES_PER_FILE;
+	struct file_buf *fb;
+	uint16 version;
+	int i;
+
+	fb = &info->fb[file_num];
+	file_buf_map(filename, fb);
+
+	/*
+	 * In earlier versions of Comprehend the first word is 0x1000 and
+	 * the image offsets start four bytes in. In newer versions the
+	 * image offsets start at the beginning of the image file.
+	 */
+	file_buf_get_le16(fb, &version);
+	if (version == 0x1000)
+		file_buf_set_pos(fb, 4);
+	else
+		file_buf_set_pos(fb, 0);
+
+	/* Get the image offsets in the file */
+	for (i = 0; i < IMAGES_PER_FILE; i++) {
+		file_buf_get_le16(fb, &info->image_offsets[base + i]); {
+			if (version == 0x1000)
+				info->image_offsets[base + i] += 4;
+		}
+	}
+}
+
+static void load_image_files(struct image_data *info, const char *game_dir,
+			     const char **filenames, size_t nr_files)
+{
+	char path[256];
+	uint i;
+
+	memset(info, 0, sizeof(*info));
+
+	info->nr_images = nr_files * IMAGES_PER_FILE;
+	info->fb = (file_buf *)xmalloc(info->nr_images * sizeof(*info->fb));
+	info->image_offsets = (uint16 *)xmalloc(info->nr_images * sizeof(uint16));
+
+	for (i = 0; i < nr_files; i++) {
+		snprintf(path, sizeof(path), "%s/%s", game_dir, filenames[i]);
+		load_image_file(info, path, i);
+	}
+}
+
+static size_t graphic_array_count(const char **filenames, size_t max)
+{
+	size_t count;
+
+	for (count = 0; count < max && filenames[count]; count++)
+		;
+	return count;
+}
+
+static void split_path(const char *filename, char **dir, char **base)
+{
+	const char *p;
+
+	p = strrchr(filename, '/');
+	if (!p) {
+		*base = xstrndup(filename, strlen(filename));
+		*dir = xstrndup(".", 1);
+	} else {
+		*base = xstrndup(p, strlen(p));
+		*dir = xstrndup(filename, p - filename);
+	}
+}
+
+void comprehend_load_image_file(const char *filename, struct image_data *info)
+{
+	char *dir, *base;
+
+	split_path(filename, &dir, &base);
+	load_image_files(info, dir, (const char **)&base, 1);
+	free(dir);
+	free(base);
+}
+
+void comprehend_load_images(comprehend_game *game, const char *game_dir)
+{
+	size_t nr_item_files, nr_room_files;
+
+	nr_room_files =
+		graphic_array_count(game->location_graphic_files,
+				    ARRAY_SIZE(game->location_graphic_files));
+	nr_item_files =
+		graphic_array_count(game->item_graphic_files,
+				    ARRAY_SIZE(game->item_graphic_files));
+
+	load_image_files(&game->info->room_images, game_dir,
+			 game->location_graphic_files, nr_room_files);
+
+	load_image_files(&game->info->item_images, game_dir,
+			 game->item_graphic_files, nr_item_files);
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
new file mode 100644
index 0000000000..796e81333e
--- /dev/null
+++ b/engines/glk/comprehend/image_data.h
@@ -0,0 +1,99 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_IMAGE_DATA_H
+#define GLK_COMPREHEND_IMAGE_DATA_H
+
+#include "glk/comprehend/game.h"
+#include "common/scummsys.h"
+
+namespace Glk {
+namespace Comprehend {
+
+struct file_buf;
+
+struct image_data {
+	file_buf	*fb;
+	uint16	*image_offsets;
+	size_t		nr_images;
+};
+
+#define IMAGEF_OP_WAIT_KEYPRESS		(1 << 0)
+#define IMAGEF_NO_FLOODFILL		(1 << 1)
+
+#define IMAGE_OP_SCENE_END		0x00
+
+#define IMAGE_OP_SET_TEXT_POS		0x10
+
+#define IMAGE_OP_PEN_COLOR_A		0x20
+#define IMAGE_OP_PEN_COLOR_B		0x21
+#define IMAGE_OP_PEN_COLOR_C		0x22
+#define IMAGE_OP_PEN_COLOR_D		0x23
+#define IMAGE_OP_PEN_COLOR_E		0x24
+#define IMAGE_OP_PEN_COLOR_F		0x25
+#define IMAGE_OP_PEN_COLOR_G		0x26
+#define IMAGE_OP_PEN_COLOR_H		0x27
+
+#define IMAGE_OP_DRAW_CHAR		0x30
+
+#define IMAGE_OP_SHAPE_PIXEL		0x40
+#define IMAGE_OP_SHAPE_BOX		0x41
+#define IMAGE_OP_SHAPE_CIRCLE_TINY	0x42
+#define IMAGE_OP_SHAPE_CIRCLE_SMALL	0x43
+#define IMAGE_OP_SHAPE_CIRCLE_MED	0x44
+#define IMAGE_OP_SHAPE_CIRCLE_LARGE	0x45
+#define IMAGE_OP_SHAPE_A		0x46
+#define IMAGE_OP_SHAPE_SPRAY		0x47
+
+#define IMAGE_OP_EOF			0x55
+
+#define IMAGE_OP_FILL_COLOR		0x60
+
+#define IMAGE_OP_MOVE_TO		0x80
+#define IMAGE_OP_MOVE_TO_FAR		0x81
+
+#define IMAGE_OP_DRAW_BOX		0x90
+#define IMAGE_OP_DRAW_BOX_FAR		0x91
+
+#define IMAGE_OP_DRAW_LINE		0xa0
+#define IMAGE_OP_DRAW_LINE_FAR		0xa1
+
+#define IMAGE_OP_DRAW_SHAPE		0xc0
+#define IMAGE_OP_DRAW_SHAPE_FAR		0xc1
+
+#define IMAGE_OP_PAINT			0xe0
+#define IMAGE_OP_PAINT_FAR		0xe1
+
+void image_set_draw_flags(unsigned flags);
+
+void draw_dark_room(void);
+void draw_bright_room(void);
+void draw_image(image_data *info, unsigned index);
+void draw_location_image(image_data *info, unsigned index);
+
+void comprehend_load_image_file(const char *filename, image_data *info);
+void comprehend_load_images(comprehend_game *game, const char *game_dir);
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/image_view.cpp b/engines/glk/comprehend/image_view.cpp
new file mode 100644
index 0000000000..c056e4b27d
--- /dev/null
+++ b/engines/glk/comprehend/image_view.cpp
@@ -0,0 +1,147 @@
+/* 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 "glk/comprehend/image_data.h"
+#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/util.h"
+#include "glk/comprehend/comprehend.h"
+
+namespace Glk {
+namespace Comprehend {
+
+#ifdef TODO
+static void usage(const char *progname)
+{
+	printf("%s: [OPTION]... FILENAME INDEX\n", progname);
+	printf("\nOptions:\n");
+	printf("  -w, --width=WIDTH       Graphics width\n");
+	printf("  -h, --height=HEIGHT     Graphics height\n");
+	printf("  -c, --clear=COLOR       Graphics clear color\n");
+	printf("  -t, --color-table=INDEX Color table\n");
+	printf("  -s, --sequence          Disable sequence of images\n");
+	printf("  -p, --pause             Wait for keypress after each draw operation\n");
+	printf("  -f, --floodfill-disable Disable floodfill operation\n");
+	printf("  -d, --debug             Enable debugging\n");
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+	struct option long_opts[] = {
+		{"width",		required_argument,	0, 'w'},
+		{"height",		required_argument,	0, 'h'},
+		{"clear",		required_argument,	0, 'c'},
+		{"color-table",		required_argument,	0, 't'},
+		{"sequence",		no_argument,		0, 's'},
+		{"pause",		no_argument,		0, 'p'},
+		{"floodfill-disable",	no_argument,		0, 'f'},
+		{"debug",		no_argument,		0, 'd'},
+		{"help",		no_argument,		0, '?'},
+		{NULL,			0,			0, 0},
+	};
+	const char *short_opts = "w:h:c:t:spfd?";
+	struct image_data info;
+	const char *filename;
+	unsigned index, clear_color = G_COLOR_WHITE,
+		graphics_width = G_RENDER_WIDTH,
+		graphics_height = G_RENDER_HEIGHT,
+		color_table = 0;
+	bool sequence = false;
+	int c, opt_index;
+
+	while (1) {
+		c = getopt_long(argc, argv, short_opts, long_opts, &opt_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'w':
+			graphics_width = strtoul(optarg, NULL, 0);
+			break;
+
+		case 'h':
+			graphics_height = strtoul(optarg, NULL, 0);
+			break;
+
+		case 'c':
+			clear_color = strtoul(optarg, NULL, 0);
+			break;
+
+		case 't':
+			color_table = strtoul(optarg, NULL, 0);
+			break;
+
+		case 's':
+			sequence = true;
+			break;
+
+		case 'p':
+			image_set_draw_flags(IMAGEF_OP_WAIT_KEYPRESS);
+			break;
+
+		case 'f':
+			image_set_draw_flags(IMAGEF_NO_FLOODFILL);
+			break;
+
+		case 'd':
+			debug_enable(DEBUG_IMAGE_DRAW);
+			break;
+
+		case '?':
+			usage(argv[0]);
+			break;
+
+		default:
+			printf("Invalid option\n");
+			usage(argv[0]);
+			break;
+		}
+	}
+
+	if (optind >= argc || argc - optind != 2)
+		usage(argv[0]);
+
+	filename = argv[optind++];
+	index = strtoul(argv[optind++], NULL, 0);
+
+	g_init(graphics_width, graphics_height);
+	g_set_color_table(color_table);
+	comprehend_load_image_file(filename, &info);
+
+	while (index < 16) {
+		g_clear_screen(clear_color);
+		draw_image(&info, index);
+
+		c = getchar();
+		if (!sequence || c == 'q' || c == 'Q')
+			break;
+
+		index++;
+		printf("Image %d\n", index);
+	}
+
+	exit(EXIT_SUCCESS);
+}
+#endif
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/opcode_map.cpp b/engines/glk/comprehend/opcode_map.cpp
new file mode 100644
index 0000000000..f3a2eccce1
--- /dev/null
+++ b/engines/glk/comprehend/opcode_map.cpp
@@ -0,0 +1,193 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/util.h"
+
+namespace Glk {
+namespace Comprehend {
+
+/*
+ * Version 2 of the Comprehend engine (OO-Topos) changes some of the opcode
+ * numbers and adds new opcodes. Use tables to translate the opcodes used
+ * in the original games into a generic version used by Re-Comprehend.
+ *
+ * FIXME - unimplemented/unknown ocpodes:
+ *
+ * d5(obj): Make object visible. This will print a "you see: object" when the
+ *          object is in the room.
+ */
+static uint8 opcode_map_v1[0x100] = {
+#ifdef TODO
+	[0x01] = OPCODE_HAVE_OBJECT,
+	[0x04] = OPCODE_OR,
+	[0x05] = OPCODE_IN_ROOM,
+	[0x06] = OPCODE_VAR_EQ,
+	[0x08] = OPCODE_CURRENT_OBJECT_TAKEABLE,
+	[0x09] = OPCODE_OBJECT_PRESENT,
+	[0x0c] = OPCODE_ELSE,
+	[0x0e] = OPCODE_OBJECT_IN_ROOM,
+	[0x14] = OPCODE_OBJECT_NOT_VALID,
+	[0x18] = OPCODE_INVENTORY_FULL,
+	[0x19] = OPCODE_TEST_FLAG,
+	[0x1d] = OPCODE_CURRENT_OBJECT_IN_ROOM,
+	[0x20] = OPCODE_HAVE_CURRENT_OBJECT,
+	[0x21] = OPCODE_OBJECT_IS_NOT_NOWHERE,
+	[0x24] = OPCODE_CURRENT_OBJECT_PRESENT,
+	[0x31] = OPCODE_TEST_ROOM_FLAG,
+	[0x41] = OPCODE_NOT_HAVE_OBJECT,
+	[0x45] = OPCODE_NOT_IN_ROOM,
+	[0x48] = OPCODE_CURRENT_OBJECT_IS_NOWHERE,
+	[0x49] = OPCODE_OBJECT_NOT_PRESENT,
+	[0x43] = OPCODE_OBJECT_NOT_IN_ROOM,
+	[0x50] = OPCODE_TEST_FALSE,
+	[0x59] = OPCODE_TEST_NOT_FLAG,
+	[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT,
+	[0x61] = OPCODE_OBJECT_IS_NOWHERE,
+	[0x64] = OPCODE_CURRENT_OBJECT_NOT_PRESENT,
+	[0x68] = OPCODE_CURRENT_OBJECT_NOT_TAKEABLE,
+	[0x71] = OPCODE_TEST_NOT_ROOM_FLAG,
+	[0x80] = OPCODE_INVENTORY,
+	[0x81] = OPCODE_TAKE_OBJECT,
+	[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM,
+	[0x84] = OPCODE_SAVE_ACTION,
+	[0x85] = OPCODE_MOVE_TO_ROOM,
+	[0x86] = OPCODE_VAR_ADD,
+	[0x87] = OPCODE_SET_ROOM_DESCRIPTION,
+	[0x89] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM,
+	[0x8a] = OPCODE_VAR_SUB,
+	[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION,
+	[0x8c] = OPCODE_MOVE,
+	[0x8e] = OPCODE_PRINT,
+	[0x95] = OPCODE_REMOVE_OBJECT,
+	[0x99] = OPCODE_SET_FLAG,
+	[0x92] = OPCODE_CALL_FUNC,
+	[0x98] = OPCODE_TURN_TICK,
+	[0x9d] = OPCODE_CLEAR_FLAG,
+	[0x9e] = OPCODE_INVENTORY_ROOM,
+	[0xa0] = OPCODE_TAKE_CURRENT_OBJECT,
+	[0xa1] = OPCODE_SPECIAL,
+	[0xa4] = OPCODE_DROP_CURRENT_OBJECT,
+	[0xa2] = OPCODE_SET_ROOM_GRAPHIC,
+	[0xb0] = OPCODE_REMOVE_CURRENT_OBJECT,
+	[0xb1] = OPCODE_DO_VERB,
+	[0xb9] = OPCODE_SET_STRING_REPLACEMENT,
+	[0xbd] = OPCODE_VAR_INC,
+	[0xc1] = OPCODE_VAR_DEC,
+	[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM
+#else
+	0
+	#endif
+};
+
+static uint8 opcode_map_v2[0x100] = {
+#ifdef TODO
+	[0x01] = OPCODE_HAVE_OBJECT,
+	[0x04] = OPCODE_OR,
+	[0x05] = OPCODE_IN_ROOM,
+	[0x06] = OPCODE_VAR_EQ,
+	[0x08] = OPCODE_CURRENT_IS_OBJECT,
+	[0x09] = OPCODE_OBJECT_PRESENT,
+	[0x0c] = OPCODE_ELSE,
+	[0x11] = OPCODE_OBJECT_IS_NOWHERE,
+	[0x14] = OPCODE_OBJECT_NOT_VALID,
+	[0x19] = OPCODE_TEST_FLAG,
+	[0x1d] = OPCODE_TEST_ROOM_FLAG,
+	[0x20] = OPCODE_HAVE_CURRENT_OBJECT,
+	[0x21] = OPCODE_OBJECT_PRESENT,
+	[0x22] = OPCODE_OBJECT_IN_ROOM,
+	[0x30] = OPCODE_CURRENT_OBJECT_PRESENT,
+	[0x31] = OPCODE_TEST_ROOM_FLAG,
+	[0x38] = OPCODE_INVENTORY_FULL,
+	[0x41] = OPCODE_NOT_HAVE_OBJECT,
+	[0x45] = OPCODE_NOT_IN_ROOM,
+	[0x48] = OPCODE_CURRENT_OBJECT_IS_NOWHERE,
+	[0x43] = OPCODE_OBJECT_NOT_IN_ROOM,
+	[0x59] = OPCODE_TEST_NOT_FLAG,
+	[0x5d] = OPCODE_TEST_NOT_ROOM_FLAG,
+	[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT,
+	[0x61] = OPCODE_OBJECT_NOT_PRESENT,
+	[0x70] = OPCODE_CURRENT_OBJECT_NOT_PRESENT,
+	[0x74] = OPCODE_CURRENT_NOT_OBJECT,
+	[0x80] = OPCODE_INVENTORY,
+	[0x81] = OPCODE_TAKE_OBJECT,
+	[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM,
+	[0x84] = OPCODE_SAVE_ACTION,
+	[0x85] = OPCODE_MOVE_TO_ROOM,
+	[0x86] = OPCODE_VAR_ADD,
+	[0x87] = OPCODE_SET_ROOM_DESCRIPTION,
+	[0x89] = OPCODE_SPECIAL,
+	[0x8a] = OPCODE_VAR_SUB,
+	[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION,
+	[0x8c] = OPCODE_MOVE,
+	[0x8e] = OPCODE_PRINT,
+	[0x8f] = OPCODE_SET_OBJECT_LONG_DESCRIPTION,
+	[0x90] = OPCODE_WAIT_KEY,
+	[0x92] = OPCODE_CALL_FUNC,
+	[0x95] = OPCODE_REMOVE_OBJECT,
+	[0x98] = OPCODE_TURN_TICK,
+	[0x99] = OPCODE_SET_FLAG,
+	[0x9d] = OPCODE_CLEAR_FLAG,
+	[0x9e] = OPCODE_INVENTORY_ROOM,
+	[0xa0] = OPCODE_TAKE_CURRENT_OBJECT,
+	[0xa2] = OPCODE_SET_OBJECT_GRAPHIC,
+	[0xb1] = OPCODE_DO_VERB,
+	[0xb5] = OPCODE_DESCRIBE_CURRENT_OBJECT,
+	[0xc1] = OPCODE_VAR_DEC,
+	[0xc2] = OPCODE_SET_ROOM_GRAPHIC,
+	[0xc5] = OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT,
+	[0xc6] = OPCODE_SET_OBJECT_GRAPHIC,
+	[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM,
+	[0xcd] = OPCODE_SET_STRING_REPLACEMENT,
+	[0xd1] = OPCODE_MOVE_DIRECTION,
+	[0xd5] = OPCODE_DRAW_ROOM,
+	[0xd9] = OPCODE_DRAW_OBJECT,
+	[0xdd] = OPCODE_VAR_INC,
+	[0xe1] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM,
+	[0xed] = OPCODE_REMOVE_OBJECT,
+	[0xf0] = OPCODE_DROP_CURRENT_OBJECT,
+	[0xfc] = OPCODE_REMOVE_CURRENT_OBJECT
+#else
+	0
+	#endif
+};
+
+uint8 *get_opcode_map(comprehend_game *game)
+{
+	switch (game->info->comprehend_version) {
+	case 1:
+		return opcode_map_v1;
+		break;
+	case 2:
+		return opcode_map_v2;
+	default:
+		fatal_error("Unsupported Comprehend version %d\n",
+			    game->info->comprehend_version);
+
+		/* Not reached */
+		return NULL;
+	}
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/opcode_map.h b/engines/glk/comprehend/opcode_map.h
new file mode 100644
index 0000000000..73eb5eb014
--- /dev/null
+++ b/engines/glk/comprehend/opcode_map.h
@@ -0,0 +1,36 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_OPCODE_MAP_H
+#define GLK_COMPREHEND_OPCODE_MAP_H
+
+#include "glk/comprehend/game.h"
+
+namespace Glk {
+namespace Comprehend {
+
+uint8 *get_opcode_map(comprehend_game *game);
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/recomprehend.cpp b/engines/glk/comprehend/recomprehend.cpp
new file mode 100644
index 0000000000..a6646c0798
--- /dev/null
+++ b/engines/glk/comprehend/recomprehend.cpp
@@ -0,0 +1,201 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/dump_game_data.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/game.h"
+#include "glk/comprehend/util.h"
+
+namespace Glk {
+namespace Comprehend {
+
+extern struct comprehend_game game_transylvania;
+extern struct comprehend_game game_crimson_crown_1;
+extern struct comprehend_game game_crimson_crown_2;
+extern struct comprehend_game game_oo_topos;
+extern struct comprehend_game game_talisman;
+
+static struct comprehend_game *comprehend_games[] = {
+	&game_transylvania,
+	&game_crimson_crown_1,
+	&game_crimson_crown_2,
+	&game_oo_topos,
+	&game_talisman,
+};
+
+struct dump_option {
+	const char	*option;
+	unsigned	flag;
+};
+
+static struct dump_option dump_options[] = {
+	{"strings",		DUMP_STRINGS},
+	{"extra-strings",	DUMP_EXTRA_STRINGS},
+	{"rooms",		DUMP_ROOMS},
+	{"items",		DUMP_ITEMS},
+	{"dictionary",		DUMP_DICTIONARY},
+	{"word-pairs",		DUMP_WORD_PAIRS},
+	{"actions",		DUMP_ACTIONS},
+	{"functions",		DUMP_FUNCTIONS},
+	{"replace-words",	DUMP_REPLACE_WORDS},
+	{"header",		DUMP_HEADER},
+	{"all",			DUMP_ALL},
+};
+
+static void usage(const char *progname)
+{
+	int i;
+
+	printf("Usage %s [OPTION]... GAME_NAME GAME_DIR\n", progname);
+	printf("\nOptions:\n");
+	printf("  -d, --debug                   Enable debugging\n");
+	printf("  -D, --dump=OPTION             Dump game data\n");
+	for (i = 0; i < ARRAY_SIZE(dump_options); i++)
+		printf("        %s\n", dump_options[i].option);
+	printf("  -p, --no-play                 Don't run the interpreter\n");
+	printf("  -g, --no-graphics             Disable graphics\n");
+	printf("  -f, --no-floodfill            Disable floodfill\n");
+	printf("  -w, --graphics-width=WIDTH    Graphics width\n");
+	printf("  -h, --graphics-height=HEIGHT  Graphics height\n");
+
+	printf("\nSupported games:\n");
+	for (i = 0; i < ARRAY_SIZE(comprehend_games); i++)
+		printf("    %-10s %s\n", comprehend_games[i]->short_name,
+		       comprehend_games[i]->game_name);
+
+	exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+	struct option long_opts[] = {
+		{"debug",		no_argument,		0, 'd'},
+		{"dump",		required_argument,	0, 'D'},
+		{"no-play",		no_argument,		0, 'p'},
+		{"no-graphics",		no_argument,		0, 'g'},
+		{"no-floodfill",	no_argument,		0, 'f'},
+		{"graphics-width",	required_argument,	0, 'w'},
+		{"graphics-height",	required_argument,	0, 'h'},
+		{"help",		no_argument,		0, '?'},
+		{NULL,			0,			0, 0},
+	};
+	const char *short_opts = "dD:pgfw:h:?";
+	struct comprehend_game *game;
+	const char *game_name, *game_dir;
+	unsigned dump_flags = 0;
+	int i, c, opt_index;
+	unsigned graphics_width = G_RENDER_WIDTH,
+		graphics_height = G_RENDER_HEIGHT;
+	bool play_game = true, graphics_enabled = true;
+
+	while (1) {
+		c = getopt_long(argc, argv, short_opts, long_opts, &opt_index);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'd':
+			// FIXME
+			debug_enable(DEBUG_FUNCTIONS);
+			break;
+
+		case 'D':
+			for (i = 0; i < ARRAY_SIZE(dump_options); i++)
+				if (strcmp(optarg, dump_options[i].option) == 0)
+					break;
+			if (i == ARRAY_SIZE(dump_options)) {
+				printf("Invalid dump option '%s'\n", optarg);
+				usage(argv[0]);
+			}
+
+			dump_flags |= dump_options[i].flag;
+			break;
+
+		case 'p':
+			play_game = false;
+			break;
+
+		case 'g':
+			graphics_enabled = false;
+			break;
+
+		case 'f':
+			image_set_draw_flags(IMAGEF_NO_FLOODFILL);
+			break;
+
+		case 'w':
+			graphics_width = strtoul(optarg, NULL, 0);
+			break;
+
+		case 'h':
+			graphics_height = strtoul(optarg, NULL, 0);
+			break;
+
+		case '?':
+			usage(argv[0]);
+			break;
+
+		default:
+			printf("Invalid option\n");
+			usage(argv[0]);
+			break;
+		}
+	}
+
+	if (optind >= argc || argc - optind != 2)
+		usage(argv[0]);
+
+	game_name = argv[optind++];
+	game_dir = argv[optind++];
+
+	/* Lookup game */
+	game = NULL;
+	for (i = 0; i < ARRAY_SIZE(comprehend_games); i++) {
+		if (strcmp(game_name, comprehend_games[i]->short_name) == 0) {
+			game = comprehend_games[i];
+			break;
+		}
+	}
+	if (!game) {
+		printf("Unknown game '%s'\n", game_name);
+		usage(argv[0]);
+	}
+
+	if (graphics_enabled)
+		g_init(graphics_width, graphics_height);
+
+	game->info = xmalloc(sizeof(*game->info));
+	comprehend_load_game(game, game_dir);
+
+	if (dump_flags)
+		dump_game_data(game, dump_flags);
+
+	if (play_game)
+		comprehend_play_game(game);
+
+	exit(EXIT_SUCCESS);
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/recomprehend.h b/engines/glk/comprehend/recomprehend.h
new file mode 100644
index 0000000000..fd0fe31f80
--- /dev/null
+++ b/engines/glk/comprehend/recomprehend.h
@@ -0,0 +1,32 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_RECOMPREHEND_H
+#define GLK_COMPREHEND_RECOMPREHEND_H
+
+namespace Glk {
+namespace Comprehend {
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/strings.cpp b/engines/glk/comprehend/strings.cpp
new file mode 100644
index 0000000000..9bae241f97
--- /dev/null
+++ b/engines/glk/comprehend/strings.cpp
@@ -0,0 +1,83 @@
+/* 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 "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game.h"
+#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/strings.h"
+
+namespace Glk {
+namespace Comprehend {
+
+static char bad_string[128];
+
+const char *string_lookup(comprehend_game *game, uint16 index)
+{
+	uint16 string;
+	uint8 table;
+
+	/*
+	 * There are two tables of strings. The first is stored in the main
+	 * game data file, and the second is stored in multiple string files.
+	 *
+	 * In instructions string indexes are split into a table and index
+	 * value. In other places such as the save files strings from the
+	 * main table are occasionally just a straight 16-bit index. We
+	 * convert all string indexes to the former case so that we can handle
+	 * them the same everywhere.
+	 */
+	table = (index >> 8) & 0xff;
+	string = index & 0xff;
+
+	switch (table) {
+	case 0x81:
+	case 0x01:
+		string += 0x100;
+		/* Fall-through */
+	case 0x00:
+	case 0x80:
+		if (string < game->info->strings.nr_strings)
+			return game->info->strings.strings[string];
+		break;
+
+	case 0x83:
+		string += 0x100;
+		/* Fall-through */
+	case 0x02:
+	case 0x82:
+		if (string < game->info->strings2.nr_strings)
+			return game->info->strings2.strings[string];
+		break;
+	}
+
+	snprintf(bad_string, sizeof(bad_string), "BAD_STRING(%.4x)", index);
+	return bad_string;
+}
+
+const char *instr_lookup_string(struct comprehend_game *game, uint8 index,
+				uint8 table)
+{
+	return string_lookup(game, table << 8 | index);
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/strings.h b/engines/glk/comprehend/strings.h
new file mode 100644
index 0000000000..b3994cc257
--- /dev/null
+++ b/engines/glk/comprehend/strings.h
@@ -0,0 +1,38 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_STRINGS_H
+#define GLK_COMPREHEND_STRINGS_H
+
+namespace Glk {
+namespace Comprehend {
+
+struct comprehend_game;
+
+const char *string_lookup(struct comprehend_game *game, uint16 index);
+const char *instr_lookup_string(struct comprehend_game *game, uint8 index,
+				uint8 table);
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/util.cpp b/engines/glk/comprehend/util.cpp
new file mode 100644
index 0000000000..5740b69215
--- /dev/null
+++ b/engines/glk/comprehend/util.cpp
@@ -0,0 +1,88 @@
+/* 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 "glk/comprehend/util.h"
+#include "common/debug.h"
+#include "common/str.h"
+#include "common/textconsole.h"
+
+namespace Glk {
+namespace Comprehend {
+
+static unsigned debug_flags;
+
+void __fatal_error(const char *func, unsigned line, const char *fmt, ...) {
+	error("TODO");
+}
+
+void fatal_strerror(int err, const char *fmt, ...) {
+	error("TODO");
+}
+
+void *xmalloc(size_t size) {
+	void *p;
+
+	p = malloc(size);
+	if (!p)
+		fatal_error("Out of memory");
+
+	memset(p, 0, size);
+	return p;
+}
+
+char *xstrndup(const char *str, size_t len) {
+	char *p;
+
+	Common::String s(str, len);
+	p = scumm_strdup(s.c_str());
+	if (!p)
+		fatal_error("Out of memory");
+	return p;
+}
+
+void debug_printf(unsigned flags, const char *fmt, ...) {
+	va_list args;
+
+	if (debug_flags & flags) {
+		va_start(args, fmt);
+		Common::String msg = Common::String(fmt, args);
+		va_end(args);
+
+		debug(1, "%s", msg.c_str());
+	}
+}
+
+void debug_enable(unsigned flags) {
+	debug_flags |= flags;
+}
+
+void debug_disable(unsigned flags) {
+	debug_flags &= ~flags;
+}
+
+bool debugging_enabled(void) {
+	// FIXME
+	return debug_flags;
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/util.h b/engines/glk/comprehend/util.h
new file mode 100644
index 0000000000..947317aa71
--- /dev/null
+++ b/engines/glk/comprehend/util.h
@@ -0,0 +1,51 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_UTIL_H
+#define GLK_COMPREHEND_UTIL_H
+
+namespace Glk {
+namespace Comprehend {
+
+#define DEBUG_IMAGE_DRAW	(1 << 0)
+#define DEBUG_GAME_STATE	(1 << 1)
+#define DEBUG_FUNCTIONS		(1 << 2)
+#define DEBUG_ALL		(~0U)
+
+#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
+
+#define fatal_error error
+
+void __fatal_error(const char *func, unsigned line, const char *fmt, ...);
+void fatal_strerror(int err, const char *fmt, ...);
+void *xmalloc(size_t size);
+char *xstrndup(const char *str, size_t size);
+
+void debug_printf(unsigned flags, const char *fmt, ...);
+void debug_enable(unsigned flags);
+void debug_disable(unsigned flags);
+bool debugging_enabled(void);
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index edffd13a06..d4fb6f873d 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -168,6 +168,21 @@ MODULE_OBJS := \
 	archetype/token.o \
 	comprehend/comprehend.o \
 	comprehend/detection.o \
+	comprehend/dictionary.o \
+	comprehend/dump_game_data.o \
+	comprehend/file_buf.o \
+	comprehend/game.o \
+	comprehend/game_cc.o \
+	comprehend/game_data.o \
+	comprehend/game_oo.o \
+	comprehend/game_tm.o \
+	comprehend/game_tr.o \
+	comprehend/graphics.o \
+	comprehend/image_data.o \
+	comprehend/image_view.o \
+	comprehend/opcode_map.o \
+	comprehend/strings.o \
+	comprehend/util.o \
 	frotz/bitmap_font.o \
 	frotz/config.o \
 	frotz/detection.o \


Commit: 8a9ef1a5a1eb9b2671bc4799d6c73d300db29c98
    https://github.com/scummvm/scummvm/commit/8a9ef1a5a1eb9b2671bc4799d6c73d300db29c98
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:08-07:00

Commit Message:
GLK: COMPREHEND: Adding startup code, cleanup

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/dump_game_data.h


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index a353c2c5cd..5ba1aa14f1 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -22,6 +22,8 @@
 
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/dump_game_data.h"
+#include "glk/comprehend/game.h"
+#include "glk/comprehend/game_data.h"
 #include "glk/quetzal.h"
 #include "common/config-manager.h"
 #include "common/translation.h"
@@ -31,18 +33,18 @@ namespace Comprehend {
 
 Comprehend *g_comprehend;
 
-extern struct comprehend_game game_transylvania;
-extern struct comprehend_game game_crimson_crown_1;
-extern struct comprehend_game game_crimson_crown_2;
-extern struct comprehend_game game_oo_topos;
-extern struct comprehend_game game_talisman;
+extern comprehend_game game_transylvania;
+extern comprehend_game game_crimson_crown_1;
+extern comprehend_game game_crimson_crown_2;
+extern comprehend_game game_oo_topos;
+extern comprehend_game game_talisman;
 
-static struct comprehend_game *comprehend_games[] = {
+static comprehend_game *comprehend_games[] = {
     &game_transylvania,
     &game_crimson_crown_1,
     &game_crimson_crown_2,
     &game_oo_topos,
-    &game_talisman,
+    &game_talisman
 };
 
 struct dump_option {
@@ -145,31 +147,6 @@ int main(int argc, char **argv) {
 
 	game_name = argv[optind++];
 	game_dir = argv[optind++];
-
-	/* Lookup game */
-	game = NULL;
-	for (i = 0; i < ARRAY_SIZE(comprehend_games); i++) {
-		if (strcmp(game_name, comprehend_games[i]->short_name) == 0) {
-			game = comprehend_games[i];
-			break;
-		}
-	}
-	if (!game) {
-		printf("Unknown game '%s'\n", game_name);
-		usage(argv[0]);
-	}
-
-	if (graphics_enabled)
-		g_init(graphics_width, graphics_height);
-
-	game->info = xmalloc(sizeof(*game->info));
-	comprehend_load_game(game, game_dir);
-
-	if (dump_flags)
-		dump_game_data(game, dump_flags);
-
-	if (play_game)
-		comprehend_play_game(game);
 }
 #endif
 
@@ -184,7 +161,28 @@ Comprehend::~Comprehend() {
 
 void Comprehend::runGame() {
 	initialize();
-	#ifdef TODO
+
+	// Lookup game
+	Common::String filename = getFilename();
+	comprehend_game *game = NULL;
+	for (uint i = 0; i < 5; ++i) {
+		if (filename.equalsIgnoreCase(comprehend_games[i]->short_name) == 0) {
+			game = comprehend_games[i];
+			break;
+		}
+	}
+	assert(game);
+
+	game->info = (game_info *)malloc(sizeof(*game->info));
+	comprehend_load_game(game, nullptr);
+
+	comprehend_play_game(game);
+}
+
+void Comprehend::initialize() {
+
+
+#ifdef TODO
 	_bottomWindow = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
 	if (_bottomWindow == nullptr) {
 		glk_exit();
@@ -194,8 +192,5 @@ void Comprehend::runGame() {
 #endif
 }
 
-void Comprehend::initialize() {
-}
-
 } // End of namespace Comprehend
 } // End of namespace Glk
diff --git a/engines/glk/comprehend/dump_game_data.h b/engines/glk/comprehend/dump_game_data.h
index dbcaf52022..361a47f969 100644
--- a/engines/glk/comprehend/dump_game_data.h
+++ b/engines/glk/comprehend/dump_game_data.h
@@ -40,7 +40,7 @@ struct instruction;
 #define DUMP_FUNCTIONS (1 << 7)
 #define DUMP_REPLACE_WORDS (1 << 8)
 #define DUMP_HEADER (1 << 9)
-#define DUMP_ALL (~0)
+#define DUMP_ALL (~0U)
 
 void dump_instruction(struct comprehend_game *game,
                       struct function_state *func_state,


Commit: 2ecbd720ea93345adcfc64f8866b2e45dce95e77
    https://github.com/scummvm/scummvm/commit/2ecbd720ea93345adcfc64f8866b2e45dce95e77
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:08-07:00

Commit Message:
GLK: COMPREHEND: Work on startup

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_tm.cpp
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_data.h


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 5ba1aa14f1..cdf52a95db 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -21,12 +21,12 @@
  */
 
 #include "glk/comprehend/comprehend.h"
+#include "common/config-manager.h"
+#include "common/translation.h"
 #include "glk/comprehend/dump_game_data.h"
 #include "glk/comprehend/game.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/quetzal.h"
-#include "common/config-manager.h"
-#include "common/translation.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -44,8 +44,7 @@ static comprehend_game *comprehend_games[] = {
     &game_crimson_crown_1,
     &game_crimson_crown_2,
     &game_oo_topos,
-    &game_talisman
-};
+    &game_talisman};
 
 struct dump_option {
 	const char *const option;
@@ -151,7 +150,7 @@ int main(int argc, char **argv) {
 #endif
 
 Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
-		_saveSlot(-1) {
+                                                                            _saveSlot(-1) {
 	g_comprehend = this;
 }
 
@@ -174,22 +173,23 @@ void Comprehend::runGame() {
 	assert(game);
 
 	game->info = (game_info *)malloc(sizeof(*game->info));
-	comprehend_load_game(game, nullptr);
+	comprehend_load_game(game);
 
 	comprehend_play_game(game);
+
+	deinitialize();
 }
 
 void Comprehend::initialize() {
+	_textBufferWindow = (TextBufferWindow *)glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
+	_graphicsWindow = (GraphicsWindow *)glk_window_open(
+	    _textBufferWindow, winmethod_Above | winmethod_Proportional,
+	    160, wintype_Graphics, 0);
+}
 
-
-#ifdef TODO
-	_bottomWindow = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
-	if (_bottomWindow == nullptr) {
-		glk_exit();
-		return;
-	}
-	glk_set_window(_bottomWindow);
-#endif
+void Comprehend::deinitialize() {
+	glk_window_close(_graphicsWindow);
+	glk_window_close(_textBufferWindow);
 }
 
 } // End of namespace Comprehend
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index f890dd5c80..045412137a 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -25,6 +25,8 @@
 
 #include "common/scummsys.h"
 #include "glk/glk_api.h"
+#include "glk/window_graphics.h"
+#include "glk/window_text_buffer.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -68,11 +70,19 @@ struct game_ops {
 class Comprehend : public GlkAPI {
 private:
 	int _saveSlot;		 ///< Save slot when loading savegame from launcher
+public:
+	GraphicsWindow *_graphicsWindow;
+	TextBufferWindow *_textBufferWindow;
 private:
 	/**
 	 * Initialization code
 	 */
 	void initialize();
+
+	/**
+	 * Deinitialization
+	 */
+	void deinitialize();
 public:
 	/**
 	 * Constructor
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 8dd1b9d789..8291e7dd27 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -165,7 +165,7 @@ struct item *get_item(comprehend_game *game, uint16 index) {
 }
 
 void game_save(comprehend_game *game) {
-	char path[PATH_MAX], filename[32];
+	char filename[32];
 	int c;
 
 	console_println(game, game->info->strings.strings[STRING_SAVE_GAME]);
@@ -181,12 +181,11 @@ void game_save(comprehend_game *game) {
 	}
 
 	snprintf(filename, sizeof(filename), game->save_game_file_fmt, c - '0');
-	snprintf(path, sizeof(path), "%s%s", game->game_dir, filename);
-	comprehend_save_game(game, path);
+	comprehend_save_game(game, filename);
 }
 
 void game_restore(comprehend_game *game) {
-	char path[PATH_MAX], filename[32];
+	char filename[32];
 	int c;
 
 	console_println(game, game->info->strings.strings[STRING_RESTORE_GAME]);
@@ -202,8 +201,7 @@ void game_restore(comprehend_game *game) {
 	}
 
 	snprintf(filename, sizeof(filename), game->save_game_file_fmt, c - '0');
-	snprintf(path, sizeof(path), "%s%s", game->game_dir, filename);
-	comprehend_restore_game(game, path);
+	comprehend_restore_game(game, filename);
 
 	game->info->update_flags = UPDATE_ALL;
 }
@@ -212,7 +210,7 @@ void game_restart(comprehend_game *game) {
 	console_println(game, string_lookup(game, game->strings->game_restart));
 	console_get_key();
 
-	comprehend_load_game(game, game->game_dir);
+	comprehend_load_game(game);
 	game->info->update_flags = UPDATE_ALL;
 }
 
@@ -1013,6 +1011,7 @@ static void skip_non_whitespace(char **p) {
 		(*p)++;
 }
 
+#ifdef TODO
 static void handle_debug_command(comprehend_game *game,
                                  const char *line) {
 	int i;
@@ -1052,6 +1051,7 @@ static void handle_debug_command(comprehend_game *game,
 		printf("\n");
 	}
 }
+#endif
 
 static bool handle_sentence(comprehend_game *game,
                             struct sentence *sentence) {
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 627f7c925b..026f4c9ad5 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -44,8 +44,6 @@ struct comprehend_game {
 	const char *game_name;
 	const char *short_name;
 
-	const char *game_dir;
-
 	const char *game_data_file;
 	struct string_file string_files[MAX_FILES];
 	const char *location_graphic_files[MAX_FILES];
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index 070dbf9c88..208d77be19 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -138,7 +138,6 @@ static struct game_ops cc2_ops = {
 struct comprehend_game game_crimson_crown_1 = {
 	"Crimson Crown (Part 1/2)",
 	"cc1",
-	nullptr,
 	"CC1.GDA",
 	{ {"MA.MS1", 0x89} },
 	{"RA.MS1", "RB.MS1", "RC.MS1"},
@@ -153,7 +152,6 @@ struct comprehend_game game_crimson_crown_1 = {
 struct comprehend_game game_crimson_crown_2 = {
 	"Crimson Crown (Part 2/2)",
 	"cc2",
-	nullptr,
 	"CC2.GDA",
 	{ {"MA.MS2", 0x89} },
 	{"RA.MS2", "RB.MS2"},
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 70125ff369..c06b2813c8 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -821,16 +821,12 @@ static void parse_header(struct comprehend_game *game, struct file_buf *fb) {
 	                       8;
 }
 
-static void load_extra_string_file(struct comprehend_game *game,
-                                   const char *dirname,
-                                   struct string_file *string_file) {
-	char filename[PATH_MAX];
+static void load_extra_string_file(comprehend_game *game,
+                                   string_file *string_file) {
 	struct file_buf fb;
 	unsigned end;
 
-	snprintf(filename, sizeof(filename), "%s/%s", dirname,
-	         string_file->filename);
-	file_buf_map(filename, &fb);
+	file_buf_map(string_file->filename, &fb);
 
 	if (string_file->end_offset)
 		end = string_file->end_offset;
@@ -843,8 +839,7 @@ static void load_extra_string_file(struct comprehend_game *game,
 	file_buf_unmap(&fb);
 }
 
-static void load_extra_string_files(struct comprehend_game *game,
-                                    const char *dirname) {
+static void load_extra_string_files(comprehend_game *game) {
 	int i;
 
 	memset(&game->info->strings2, 0, sizeof(game->info->strings2));
@@ -858,20 +853,15 @@ static void load_extra_string_files(struct comprehend_game *game,
 		if (game->info->strings2.nr_strings == 0)
 			game->info->strings2.nr_strings++;
 
-		load_extra_string_file(game, dirname, &game->string_files[i]);
+		load_extra_string_file(game, &game->string_files[i]);
 	}
 }
 
-static void load_game_data(struct comprehend_game *game, const char *dirname) {
-	char data_file[PATH_MAX];
+static void load_game_data(struct comprehend_game *game) {
 	struct file_buf fb;
 
-	snprintf(data_file, sizeof(data_file), "%s/%s",
-	         dirname, game->game_data_file);
-
 	memset(game->info, 0, sizeof(*game->info));
-
-	file_buf_map(data_file, &fb);
+	file_buf_map(game->game_data_file, &fb);
 
 	parse_header(game, &fb);
 	parse_rooms(game, &fb);
@@ -882,7 +872,7 @@ static void load_game_data(struct comprehend_game *game, const char *dirname) {
 	parse_string_table(&fb, game->info->header.addr_strings,
 	                   game->info->header.addr_strings_end,
 	                   &game->info->strings);
-	load_extra_string_files(game, dirname);
+	load_extra_string_files(game);
 	parse_vm(game, &fb);
 	parse_action_table(game, &fb);
 	parse_replace_words(game, &fb);
@@ -890,14 +880,12 @@ static void load_game_data(struct comprehend_game *game, const char *dirname) {
 	file_buf_unmap(&fb);
 }
 
-void comprehend_load_game(struct comprehend_game *game, const char *dirname) {
-	game->game_dir = dirname;
-
+void comprehend_load_game(struct comprehend_game *game) {
 	/* Load the main game data file */
-	load_game_data(game, dirname);
+	load_game_data(game);
 
 	if (g_enabled()) {
-		comprehend_load_images(game, dirname);
+		comprehend_load_images(game);
 		if (game->color_table)
 			g_set_color_table(game->color_table);
 	}
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 2892bd29c7..42aac38dc4 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -307,7 +307,7 @@ enum {
 #define WORD_TYPE_NOUN_MASK	(WORD_TYPE_FEMALE | WORD_TYPE_MALE |	\
 				 WORD_TYPE_NOUN | WORD_TYPE_NOUN_PLURAL)
 
-void comprehend_load_game(struct comprehend_game *game, const char *dirname);
+void comprehend_load_game(struct comprehend_game *game);
 void comprehend_restore_game(struct comprehend_game *game,
 			     const char *filename);
 void comprehend_save_game(struct comprehend_game *game, const char *filename);
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index d1d524c116..d04c9fc2d9 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -126,7 +126,6 @@ static struct game_ops oo_ops = {
 struct comprehend_game game_oo_topos = {
 	"Oo-Topos",
 	"oo",
-	nullptr,
 	"G0",
 	{
 		// Extra strings are (annoyingly) stored in the game binary
diff --git a/engines/glk/comprehend/game_tm.cpp b/engines/glk/comprehend/game_tm.cpp
index 1b8b54690a..dc5ae64a9d 100644
--- a/engines/glk/comprehend/game_tm.cpp
+++ b/engines/glk/comprehend/game_tm.cpp
@@ -33,7 +33,6 @@ static struct game_ops tm_ops = {};
 struct comprehend_game game_talisman = {
     "Talisman, Challenging the Sands of Time (broken)",
     "tm",
-    nullptr,
     "G0",
     {},
 	{"RA", "RB", "RC", "RD", "RE", "RF", "RG"},
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index fc8ad72943..84ea764848 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -201,7 +201,6 @@ static struct game_ops tr_ops = {
 struct comprehend_game game_transylvania = {
 	"Transylvania",
 	"tr",
-	nullptr,
 	"TR.GDA",
 	{
 		{"MA.MS1", 0x88},
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 21cfa44db1..3407a55b6e 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -324,10 +324,9 @@ static void load_image_file(struct image_data *info, const char *filename,
 	}
 }
 
-static void load_image_files(struct image_data *info, const char *game_dir,
+static void load_image_files(struct image_data *info,
 			     const char **filenames, size_t nr_files)
 {
-	char path[256];
 	uint i;
 
 	memset(info, 0, sizeof(*info));
@@ -337,8 +336,7 @@ static void load_image_files(struct image_data *info, const char *game_dir,
 	info->image_offsets = (uint16 *)xmalloc(info->nr_images * sizeof(uint16));
 
 	for (i = 0; i < nr_files; i++) {
-		snprintf(path, sizeof(path), "%s/%s", game_dir, filenames[i]);
-		load_image_file(info, path, i);
+		load_image_file(info, filenames[i], i);
 	}
 }
 
@@ -351,31 +349,12 @@ static size_t graphic_array_count(const char **filenames, size_t max)
 	return count;
 }
 
-static void split_path(const char *filename, char **dir, char **base)
-{
-	const char *p;
-
-	p = strrchr(filename, '/');
-	if (!p) {
-		*base = xstrndup(filename, strlen(filename));
-		*dir = xstrndup(".", 1);
-	} else {
-		*base = xstrndup(p, strlen(p));
-		*dir = xstrndup(filename, p - filename);
-	}
-}
-
 void comprehend_load_image_file(const char *filename, struct image_data *info)
 {
-	char *dir, *base;
-
-	split_path(filename, &dir, &base);
-	load_image_files(info, dir, (const char **)&base, 1);
-	free(dir);
-	free(base);
+	load_image_files(info, (const char **)&filename, 1);
 }
 
-void comprehend_load_images(comprehend_game *game, const char *game_dir)
+void comprehend_load_images(comprehend_game *game)
 {
 	size_t nr_item_files, nr_room_files;
 
@@ -386,10 +365,10 @@ void comprehend_load_images(comprehend_game *game, const char *game_dir)
 		graphic_array_count(game->item_graphic_files,
 				    ARRAY_SIZE(game->item_graphic_files));
 
-	load_image_files(&game->info->room_images, game_dir,
+	load_image_files(&game->info->room_images,
 			 game->location_graphic_files, nr_room_files);
 
-	load_image_files(&game->info->item_images, game_dir,
+	load_image_files(&game->info->item_images,
 			 game->item_graphic_files, nr_item_files);
 }
 
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
index 796e81333e..e85313eaf4 100644
--- a/engines/glk/comprehend/image_data.h
+++ b/engines/glk/comprehend/image_data.h
@@ -91,7 +91,7 @@ void draw_image(image_data *info, unsigned index);
 void draw_location_image(image_data *info, unsigned index);
 
 void comprehend_load_image_file(const char *filename, image_data *info);
-void comprehend_load_images(comprehend_game *game, const char *game_dir);
+void comprehend_load_images(comprehend_game *game);
 
 } // namespace Comprehend
 } // namespace Glk


Commit: 10aa0e48fead7caf43b612537c789d6650c08337
    https://github.com/scummvm/scummvm/commit/10aa0e48fead7caf43b612537c789d6650c08337
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:08-07:00

Commit Message:
GLK: COMPREHEND: Cleaning up some structure dependencies

Changed paths:
    engines/glk/comprehend/dictionary.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_data.h
    engines/glk/comprehend/opcode_map.cpp


diff --git a/engines/glk/comprehend/dictionary.cpp b/engines/glk/comprehend/dictionary.cpp
index 584d2d4f77..a25f91f240 100644
--- a/engines/glk/comprehend/dictionary.cpp
+++ b/engines/glk/comprehend/dictionary.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/dictionary.h"
 
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 026f4c9ad5..b8d78d5371 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -23,6 +23,7 @@
 #ifndef GLK_COMPREHEND_GAME_H
 #define GLK_COMPREHEND_GAME_H
 
+#include "glk/comprehend/game_data.h"
 #include "common/scummsys.h"
 
 namespace Glk {
@@ -30,16 +31,6 @@ namespace Comprehend {
 
 #define MAX_FILES 10
 
-struct function;
-struct item;
-struct word;
-
-struct string_file {
-	const char *filename;
-	uint32 base_offset;
-	uint32 end_offset;
-};
-
 struct comprehend_game {
 	const char *game_name;
 	const char *short_name;
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 42aac38dc4..6890f6fe74 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -185,6 +185,12 @@ struct game_info {
 	unsigned		update_flags;
 };
 
+struct string_file {
+	const char *filename;
+	uint32 base_offset;
+	uint32 end_offset;
+};
+
 enum {
 	OPCODE_UNKNOWN,
 	OPCODE_TEST_FALSE,
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 3407a55b6e..4059b6ea89 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -22,6 +22,7 @@
 
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/file_buf.h"
+#include "glk/comprehend/game.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/image_data.h"
 #include "glk/comprehend/graphics.h"
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
index e85313eaf4..9a2c1882c1 100644
--- a/engines/glk/comprehend/image_data.h
+++ b/engines/glk/comprehend/image_data.h
@@ -23,12 +23,12 @@
 #ifndef GLK_COMPREHEND_IMAGE_DATA_H
 #define GLK_COMPREHEND_IMAGE_DATA_H
 
-#include "glk/comprehend/game.h"
 #include "common/scummsys.h"
 
 namespace Glk {
 namespace Comprehend {
 
+struct comprehend_game;
 struct file_buf;
 
 struct image_data {
diff --git a/engines/glk/comprehend/opcode_map.cpp b/engines/glk/comprehend/opcode_map.cpp
index f3a2eccce1..30d1932a70 100644
--- a/engines/glk/comprehend/opcode_map.cpp
+++ b/engines/glk/comprehend/opcode_map.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/game.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/util.h"
 


Commit: 20533b4a1adc37eb33c6f4dd459a99df2cb73145
    https://github.com/scummvm/scummvm/commit/20533b4a1adc37eb33c6f4dd459a99df2cb73145
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:08-07:00

Commit Message:
GLK: COMPREHEND: Start of sub-classes for each different game

Changed paths:
  A engines/glk/comprehend/game_cc.h
  A engines/glk/comprehend/game_oo.h
  A engines/glk/comprehend/game_tm.h
  A engines/glk/comprehend/game_tr.h
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/detection_tables.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_tm.cpp
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/image_data.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index cdf52a95db..cf1eb2933d 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -25,7 +25,11 @@
 #include "common/translation.h"
 #include "glk/comprehend/dump_game_data.h"
 #include "glk/comprehend/game.h"
+#include "glk/comprehend/game_cc.h"
 #include "glk/comprehend/game_data.h"
+#include "glk/comprehend/game_oo.h"
+#include "glk/comprehend/game_tm.h"
+#include "glk/comprehend/game_tr.h"
 #include "glk/quetzal.h"
 
 namespace Glk {
@@ -33,19 +37,6 @@ namespace Comprehend {
 
 Comprehend *g_comprehend;
 
-extern comprehend_game game_transylvania;
-extern comprehend_game game_crimson_crown_1;
-extern comprehend_game game_crimson_crown_2;
-extern comprehend_game game_oo_topos;
-extern comprehend_game game_talisman;
-
-static comprehend_game *comprehend_games[] = {
-    &game_transylvania,
-    &game_crimson_crown_1,
-    &game_crimson_crown_2,
-    &game_oo_topos,
-    &game_talisman};
-
 struct dump_option {
 	const char *const option;
 	unsigned flag;
@@ -162,19 +153,9 @@ void Comprehend::runGame() {
 	initialize();
 
 	// Lookup game
-	Common::String filename = getFilename();
-	comprehend_game *game = NULL;
-	for (uint i = 0; i < 5; ++i) {
-		if (filename.equalsIgnoreCase(comprehend_games[i]->short_name) == 0) {
-			game = comprehend_games[i];
-			break;
-		}
-	}
-	assert(game);
+	comprehend_game *game = createGame();
 
-	game->info = (game_info *)malloc(sizeof(*game->info));
 	comprehend_load_game(game);
-
 	comprehend_play_game(game);
 
 	deinitialize();
@@ -192,5 +173,18 @@ void Comprehend::deinitialize() {
 	glk_window_close(_textBufferWindow);
 }
 
-} // End of namespace Comprehend
-} // End of namespace Glk
+comprehend_game *Comprehend::createGame() {
+	if (_gameDescription._gameId == "crimsoncrown")
+		return new CrimsonCrownGame();
+	if (_gameDescription._gameId == "ootopis")
+		return new OOToposGame();
+	if (_gameDescription._gameId == "talisman")
+		return new OOToposGame();
+	if (_gameDescription._gameId == "transylvania")
+		return new TransylvaniaGame();
+
+	error("Unknown game");
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 045412137a..351ccef491 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -83,6 +83,9 @@ private:
 	 * Deinitialization
 	 */
 	void deinitialize();
+
+	comprehend_game *createGame();
+
 public:
 	/**
 	 * Constructor
diff --git a/engines/glk/comprehend/detection_tables.h b/engines/glk/comprehend/detection_tables.h
index aa8185eeef..cd884b90b7 100644
--- a/engines/glk/comprehend/detection_tables.h
+++ b/engines/glk/comprehend/detection_tables.h
@@ -29,9 +29,11 @@ namespace Comprehend {
 
 const PlainGameDescriptor COMPREHEND_GAME_LIST[] = {
     {"crimsoncrown", "Crimson Crown"},
+    {"ootopis", "OO-Topos"},
     {"transylvania", "Transylvania"},
-
-    {nullptr, nullptr}};
+    {"talisman", "Talisman"},
+	{nullptr, nullptr}
+};
 
 struct ComprehendDetectionEntry {
 	const char *const _gameId;
@@ -44,8 +46,7 @@ const ComprehendDetectionEntry COMPREHEND_GAMES[] = {
     {"crimsoncrown", "cc1.gda", "f2abf019675ac5c9bcfd81032bc7787b"},
     {"transylvania", "tr.gda", "22e08633eea02ceee49b909dfd982d22"},
 
-    {nullptr, nullptr, nullptr}
-};
+    {nullptr, nullptr, nullptr}};
 
 } // End of namespace Comprehend
 } // End of namespace Glk
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 8291e7dd27..4cd28e9b20 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -43,6 +43,20 @@ struct winsize {
 };
 static struct winsize console_winsize;
 
+comprehend_game::comprehend_game() : game_name(nullptr),
+                                     short_name(nullptr),
+                                     game_data_file(nullptr),
+                                     save_game_file_fmt(nullptr),
+                                     color_table(0),
+                                     strings(nullptr),
+                                     ops(nullptr) {
+	info = (game_info *)malloc(sizeof(*info));
+}
+
+comprehend_game::~comprehend_game() {
+	free(info);
+}
+
 static void console_init(void) {
 	//	ioctl(STDOUT_FILENO, TIOCGWINSZ, &console_winsize);
 }
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index b8d78d5371..cfd5133666 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -24,21 +24,20 @@
 #define GLK_COMPREHEND_GAME_H
 
 #include "glk/comprehend/game_data.h"
-#include "common/scummsys.h"
+#include "common/array.h"
 
 namespace Glk {
 namespace Comprehend {
 
-#define MAX_FILES 10
-
 struct comprehend_game {
+public:
 	const char *game_name;
 	const char *short_name;
 
 	const char *game_data_file;
-	struct string_file string_files[MAX_FILES];
-	const char *location_graphic_files[MAX_FILES];
-	const char *item_graphic_files[MAX_FILES];
+	Common::Array<string_file> string_files;
+	Common::Array <const char *> location_graphic_files;
+	Common::Array <const char *> item_graphic_files;
 	const char *save_game_file_fmt;
 	unsigned color_table;
 
@@ -46,6 +45,10 @@ struct comprehend_game {
 	struct game_ops *ops;
 
 	struct game_info *info;
+
+public:
+	comprehend_game();
+	~comprehend_game();
 };
 
 void console_println(struct comprehend_game *game, const char *text);
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index 208d77be19..bed5603cce 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -20,23 +20,72 @@
  *
  */
 
+#include "glk/comprehend/game_cc.h"
 #include "glk/comprehend/comprehend.h"
-#include "glk/comprehend/game_data.h"
-#include "glk/comprehend/game.h"
 
 namespace Glk {
 namespace Comprehend {
 
-static void cc_clear_companion_flags(struct comprehend_game *game)
-{
+static struct game_strings cc1_strings = {0x9};
+
+static struct game_ops cc1_ops = {
+    nullptr,
+    CrimsonCrownGame::cc1_before_prompt,
+    nullptr,
+    nullptr,
+    nullptr,
+    CrimsonCrownGame::cc1_handle_special_opcode};
+
+#ifdef TODO
+static struct game_ops cc2_ops = {
+    nullptr,
+    cc2_before_prompt,
+    nullptr,
+    nullptr,
+    nullptr,
+    cc2_handle_special_opcode};
+#endif
+
+CrimsonCrownGame::CrimsonCrownGame() : comprehend_game() {
+	game_name = "Crimson Crown";
+	short_name = "cc1";
+	game_data_file = "cc1.gda";
+
+	string_files.push_back(string_file("ma.ms1", 0x89));
+	location_graphic_files.push_back("RA.MS1");
+	location_graphic_files.push_back("RB.MS1");
+	location_graphic_files.push_back("RC.MS1");
+	item_graphic_files.push_back("OA.MS1");
+	item_graphic_files.push_back("OB.MS1");
+
+	save_game_file_fmt = "G%d.MS0";
+	strings = &cc1_strings;
+	ops = &cc1_ops;
+}
+
+#ifdef TODO
+struct comprehend_game game_crimson_crown_2 = {
+    "Crimson Crown (Part 2/2)",
+    "cc2",
+    "CC2.GDA",
+    {{"MA.MS2", 0x89}},
+    {"RA.MS2", "RB.MS2"},
+    {"OA.MS2", "OB.MS2"},
+    "G%d.MS0",
+    0,
+    nullptr,
+    &cc2_ops,
+    nullptr};
+#endif
+
+static void cc_clear_companion_flags(struct comprehend_game *game) {
 	/* Clear the Sabrina/Erik action flags */
 	game->info->flags[0xa] = 0;
 	game->info->flags[0xb] = 0;
 }
 
 static bool cc_common_handle_special_opcode(struct comprehend_game *game,
-					    uint8 operand)
-{
+                                            uint8 operand) {
 	switch (operand) {
 	case 0x03:
 		/*
@@ -64,9 +113,8 @@ static bool cc_common_handle_special_opcode(struct comprehend_game *game,
 	return false;
 }
 
-static void cc1_handle_special_opcode(struct comprehend_game *game,
-				      uint8 operand)
-{
+void CrimsonCrownGame::cc1_handle_special_opcode(comprehend_game *game,
+		uint8 operand) {
 	if (cc_common_handle_special_opcode(game, operand))
 		return;
 
@@ -83,8 +131,7 @@ static void cc1_handle_special_opcode(struct comprehend_game *game,
 }
 
 static void cc2_handle_special_opcode(struct comprehend_game *game,
-				      uint8 operand)
-{
+                                      uint8 operand) {
 	if (cc_common_handle_special_opcode(game, operand))
 		return;
 
@@ -105,63 +152,13 @@ static void cc2_handle_special_opcode(struct comprehend_game *game,
 	}
 }
 
-static void cc2_before_prompt(struct comprehend_game *game)
-{
+static void cc2_before_prompt(struct comprehend_game *game) {
 	cc_clear_companion_flags(game);
 }
 
-static void cc1_before_prompt(struct comprehend_game *game)
-{
+void CrimsonCrownGame::cc1_before_prompt(comprehend_game *game) {
 	cc_clear_companion_flags(game);
 }
 
-static struct game_strings cc1_strings = { 0x9 };
-
-static struct game_ops cc1_ops = {
-	nullptr,
-	cc1_before_prompt,
-	nullptr,
-	nullptr,
-	nullptr,
-	cc1_handle_special_opcode
-};
-
-static struct game_ops cc2_ops = {
-	nullptr,
-	cc2_before_prompt,
-	nullptr,
-	nullptr,
-	nullptr,
-	cc2_handle_special_opcode
-};
-
-struct comprehend_game game_crimson_crown_1 = {
-	"Crimson Crown (Part 1/2)",
-	"cc1",
-	"CC1.GDA",
-	{ {"MA.MS1", 0x89} },
-	{"RA.MS1", "RB.MS1", "RC.MS1"},
-	{"OA.MS1", "OB.MS1"},
-	"G%d.MS0",
-	0,
-	&cc1_strings,
-	&cc1_ops,
-	nullptr
-};
-
-struct comprehend_game game_crimson_crown_2 = {
-	"Crimson Crown (Part 2/2)",
-	"cc2",
-	"CC2.GDA",
-	{ {"MA.MS2", 0x89} },
-	{"RA.MS2", "RB.MS2"},
-	{"OA.MS2", "OB.MS2"},
-	"G%d.MS0",
-	0,
-	nullptr,
-	&cc2_ops,
-	nullptr
-};
-
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game_cc.h b/engines/glk/comprehend/game_cc.h
new file mode 100644
index 0000000000..00ba334b5a
--- /dev/null
+++ b/engines/glk/comprehend/game_cc.h
@@ -0,0 +1,44 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_GAME_CC_H
+#define GLK_COMPREHEND_GAME_CC_H
+
+#include "glk/comprehend/game.h"
+
+namespace Glk {
+namespace Comprehend {
+
+class CrimsonCrownGame : public comprehend_game {
+public:
+	CrimsonCrownGame();
+
+public:
+	static void cc1_before_prompt(comprehend_game *game);
+	static void cc1_handle_special_opcode(comprehend_game *game,
+		uint8 operand);
+};
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 6890f6fe74..d48b6f68fe 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -28,8 +28,8 @@
 namespace Glk {
 namespace Comprehend {
 
-#define MAX_FLAGS	64
-#define MAX_VARIABLES	128
+#define MAX_FLAGS 64
+#define MAX_VARIABLES 128
 
 enum {
 	DIRECTION_NORTH,
@@ -44,151 +44,156 @@ enum {
 };
 
 struct function_state {
-	bool		test_result;
-	bool		else_result;
-	unsigned	or_count;
-	bool		_and;
-	bool		in_command;
-	bool		executed;
+	bool test_result;
+	bool else_result;
+	unsigned or_count;
+	bool _and;
+	bool in_command;
+	bool executed;
 };
 
 struct room {
-	uint8			direction[NR_DIRECTIONS];
-	uint8			flags;
-	uint8			graphic;
-	uint16		string_desc;
+	uint8 direction[NR_DIRECTIONS];
+	uint8 flags;
+	uint8 graphic;
+	uint16 string_desc;
 };
 
 struct item {
-	uint16		string_desc;
-	uint16		long_string;	/* Only used by version 2 */
-	uint8			room;
-	uint8			flags;
-	uint8			word;
-	uint8			graphic;
+	uint16 string_desc;
+	uint16 long_string; /* Only used by version 2 */
+	uint8 room;
+	uint8 flags;
+	uint8 word;
+	uint8 graphic;
 };
 
 struct word {
-	char			word[7];
-	uint8			index;
-	uint8			type;
+	char word[7];
+	uint8 index;
+	uint8 type;
 };
 
 struct word_index {
-	uint8			index;
-	uint8			type;
+	uint8 index;
+	uint8 type;
 };
 
 struct word_map {
 	/* <word[0]>, <word[1]> == <word[2]> */
-	struct word_index	word[3];
-	uint8			flags;
+	struct word_index word[3];
+	uint8 flags;
 };
 
 struct action {
-	int			type;
-	size_t			nr_words;
+	int type;
+	size_t nr_words;
 	// FIXME - use struct word_index here.
-	uint8			word[4];
-	uint8			word_type[4];
-	uint16		function;
+	uint8 word[4];
+	uint8 word_type[4];
+	uint16 function;
 };
 
 struct instruction {
-	uint8			opcode;
-	size_t			nr_operands;
-	uint8			operand[3];
-	bool			is_command;
+	uint8 opcode;
+	size_t nr_operands;
+	uint8 operand[3];
+	bool is_command;
 };
 
 struct function {
-	struct instruction	instructions[0x100];
-	size_t			nr_instructions;
+	struct instruction instructions[0x100];
+	size_t nr_instructions;
 };
 
 struct string_table {
-	char			*strings[0xffff];
-	size_t			nr_strings;
+	char *strings[0xffff];
+	size_t nr_strings;
 };
 
 struct game_header {
-	uint16		magic;
-
-	uint16		room_desc_table;
-	uint16		room_direction_table[NR_DIRECTIONS];
-	uint16		room_flags_table;
-	uint16		room_graphics_table;
-
-	size_t			nr_items;
-	uint16		addr_item_locations;
-	uint16		addr_item_flags;
-	uint16		addr_item_word;
-	uint16		addr_item_strings;
-	uint16		addr_item_graphics;
-
-	uint16		addr_dictionary;
-	uint16		addr_word_map;
-
-	uint16		addr_strings;
-	uint16		addr_strings_end;
-
-	uint16		addr_actions_vvnn;
-	uint16		addr_actions_unknown;
-	uint16		addr_actions_vnjn;
-	uint16		addr_actions_vjn;
-	uint16		addr_actions_vdn;
-	uint16		addr_actions_vnn;
-	uint16		addr_actions_vn;
-	uint16		addr_actions_v;
-
-	uint16		addr_vm; // FIXME - functions
+	uint16 magic;
+
+	uint16 room_desc_table;
+	uint16 room_direction_table[NR_DIRECTIONS];
+	uint16 room_flags_table;
+	uint16 room_graphics_table;
+
+	size_t nr_items;
+	uint16 addr_item_locations;
+	uint16 addr_item_flags;
+	uint16 addr_item_word;
+	uint16 addr_item_strings;
+	uint16 addr_item_graphics;
+
+	uint16 addr_dictionary;
+	uint16 addr_word_map;
+
+	uint16 addr_strings;
+	uint16 addr_strings_end;
+
+	uint16 addr_actions_vvnn;
+	uint16 addr_actions_unknown;
+	uint16 addr_actions_vnjn;
+	uint16 addr_actions_vjn;
+	uint16 addr_actions_vdn;
+	uint16 addr_actions_vnn;
+	uint16 addr_actions_vn;
+	uint16 addr_actions_v;
+
+	uint16 addr_vm; // FIXME - functions
 };
 
 struct game_info {
-	struct game_header	header;
+	struct game_header header;
 
-	unsigned		comprehend_version;
+	unsigned comprehend_version;
 
-	uint8			start_room;
+	uint8 start_room;
 
-	struct room		rooms[0x100];
-	size_t			nr_rooms;
-	uint8			current_room;
+	struct room rooms[0x100];
+	size_t nr_rooms;
+	uint8 current_room;
 
-	struct item		item[0xff];
+	struct item item[0xff];
 
-	struct word		*words;
-	size_t			nr_words;
+	struct word *words;
+	size_t nr_words;
 
-	struct word_map		word_map[0xff];
-	size_t			nr_word_maps;
+	struct word_map word_map[0xff];
+	size_t nr_word_maps;
 
-	struct string_table	strings;
-	struct string_table	strings2;
+	struct string_table strings;
+	struct string_table strings2;
 
-	struct action		action[0xffff];
-	size_t			nr_actions;
+	struct action action[0xffff];
+	size_t nr_actions;
 
-	struct function		functions[0xffff];
-	size_t			nr_functions;
+	struct function functions[0xffff];
+	size_t nr_functions;
 
-	struct image_data	room_images;
-	struct image_data	item_images;
+	struct image_data room_images;
+	struct image_data item_images;
 
-	bool			flags[MAX_FLAGS];
-	uint16		variable[MAX_VARIABLES];
+	bool flags[MAX_FLAGS];
+	uint16 variable[MAX_VARIABLES];
 
-	char			*replace_words[256];
-	size_t			nr_replace_words;
+	char *replace_words[256];
+	size_t nr_replace_words;
 
-	uint8			current_replace_word;
-	unsigned		update_flags;
+	uint8 current_replace_word;
+	unsigned update_flags;
 };
 
 struct string_file {
 	const char *filename;
 	uint32 base_offset;
 	uint32 end_offset;
+
+	string_file() : filename(nullptr), base_offset(0), end_offset(0) {}
+	string_file(const char *fname, uint32 baseOfs, uint32 endO = 0) :
+		filename(fname), base_offset(baseOfs), end_offset(endO) {
+	}
 };
 
 enum {
@@ -263,11 +268,11 @@ enum {
 };
 
 /* Game state update flags */
-#define UPDATE_GRAPHICS		(1 << 0) /* Implies UPDATE_GRAPHICS_ITEMS */
-#define UPDATE_GRAPHICS_ITEMS	(1 << 1)
-#define UPDATE_ROOM_DESC	(1 << 2)
-#define UPDATE_ITEM_LIST	(1 << 3)
-#define UPDATE_ALL		(~0U)
+#define UPDATE_GRAPHICS (1 << 0) /* Implies UPDATE_GRAPHICS_ITEMS */
+#define UPDATE_GRAPHICS_ITEMS (1 << 1)
+#define UPDATE_ROOM_DESC (1 << 2)
+#define UPDATE_ITEM_LIST (1 << 3)
+#define UPDATE_ALL (~0U)
 
 /* Action types */
 enum {
@@ -281,41 +286,41 @@ enum {
 };
 
 /* Standard strings (main string table) */
-#define STRING_CANT_GO		0
-#define STRING_DONT_UNDERSTAND	1
-#define STRING_YOU_SEE		2
-#define STRING_INVENTORY	3
-#define STRING_INVENTORY_EMPTY	4
-#define STRING_BEFORE_CONTINUE	5
-#define STRING_SAVE_GAME	6
-#define STRING_RESTORE_GAME	7
+#define STRING_CANT_GO 0
+#define STRING_DONT_UNDERSTAND 1
+#define STRING_YOU_SEE 2
+#define STRING_INVENTORY 3
+#define STRING_INVENTORY_EMPTY 4
+#define STRING_BEFORE_CONTINUE 5
+#define STRING_SAVE_GAME 6
+#define STRING_RESTORE_GAME 7
 
 /* Special variables */
-#define VAR_INVENTORY_WEIGHT	0
-#define VAR_INVENTORY_LIMIT	1
-#define VAR_TURN_COUNT		2
+#define VAR_INVENTORY_WEIGHT 0
+#define VAR_INVENTORY_LIMIT 1
+#define VAR_TURN_COUNT 2
 
 /* Special rooms */
-#define ROOM_INVENTORY		0x00
-#define ROOM_NOWHERE		0xff
+#define ROOM_INVENTORY 0x00
+#define ROOM_NOWHERE 0xff
 
 /* Item flags */
-#define ITEMF_WEIGHT_MASK	(0x3)
-#define ITEMF_CAN_TAKE		(1 << 3)
+#define ITEMF_WEIGHT_MASK (0x3)
+#define ITEMF_CAN_TAKE (1 << 3)
 
 /* Word types */
-#define WORD_TYPE_VERB		0x01
-#define WORD_TYPE_JOIN		0x02
-#define WORD_TYPE_FEMALE	0x10
-#define WORD_TYPE_MALE		0x20
-#define WORD_TYPE_NOUN		0x40
-#define WORD_TYPE_NOUN_PLURAL	0x80
-#define WORD_TYPE_NOUN_MASK	(WORD_TYPE_FEMALE | WORD_TYPE_MALE |	\
-				 WORD_TYPE_NOUN | WORD_TYPE_NOUN_PLURAL)
+#define WORD_TYPE_VERB 0x01
+#define WORD_TYPE_JOIN 0x02
+#define WORD_TYPE_FEMALE 0x10
+#define WORD_TYPE_MALE 0x20
+#define WORD_TYPE_NOUN 0x40
+#define WORD_TYPE_NOUN_PLURAL 0x80
+#define WORD_TYPE_NOUN_MASK (WORD_TYPE_FEMALE | WORD_TYPE_MALE | \
+	                         WORD_TYPE_NOUN | WORD_TYPE_NOUN_PLURAL)
 
 void comprehend_load_game(struct comprehend_game *game);
 void comprehend_restore_game(struct comprehend_game *game,
-			     const char *filename);
+                             const char *filename);
 void comprehend_save_game(struct comprehend_game *game, const char *filename);
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index d04c9fc2d9..3926b42192 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -20,37 +20,70 @@
  *
  */
 
+#include "glk/comprehend/game_oo.h"
 #include "glk/comprehend/comprehend.h"
-#include "glk/comprehend/game_data.h"
-#include "glk/comprehend/game.h"
 #include "glk/comprehend/graphics.h"
 
 namespace Glk {
 namespace Comprehend {
 
-#define OO_ROOM_FLAG_DARK	0x02
+#define OO_ROOM_FLAG_DARK 0x02
 
-#define OO_BRIGHT_ROOM		0x19
+#define OO_BRIGHT_ROOM 0x19
 
-#define OO_FLAG_WEARING_GOGGLES	0x1b
-#define OO_FLAG_FLASHLIGHT_ON	0x27
+#define OO_FLAG_WEARING_GOGGLES 0x1b
+#define OO_FLAG_FLASHLIGHT_ON 0x27
 
-static int oo_room_is_special(struct comprehend_game *game, 
-			      unsigned room_index,
-			      unsigned *room_desc_string)
-{
+static struct game_ops oo_ops = {
+    nullptr,
+    nullptr,
+    OOToposGame::oo_before_turn,
+    nullptr,
+    OOToposGame::oo_room_is_special,
+    OOToposGame::oo_handle_special_opcode
+};
+
+OOToposGame::OOToposGame() : comprehend_game() {
+	game_name = "Oo-Topos";
+	short_name = "oo";
+	game_data_file = "g0";
+
+	// Extra strings are (annoyingly) stored in the game binary
+	string_files.push_back(string_file("NOVEL.EXE", 0x16564, 0x17640));
+	string_files.push_back(string_file("NOVEL.EXE", 0x17702, 0x18600));
+	string_files.push_back(string_file("NOVEL.EXE", 0x186b2, 0x19b80));
+	string_files.push_back(string_file("NOVEL.EXE", 0x19c62, 0x1a590));
+	string_files.push_back(string_file("NOVEL.EXE", 0x1a634, 0x1b080));
+	location_graphic_files.push_back("RA");
+	location_graphic_files.push_back("RB");
+	location_graphic_files.push_back("RC");
+	location_graphic_files.push_back("RD");
+	location_graphic_files.push_back("RE");
+	item_graphic_files.push_back("OA");
+	item_graphic_files.push_back("OB");
+	item_graphic_files.push_back("OC");
+	item_graphic_files.push_back("OD");
+
+	save_game_file_fmt = "G%d";
+	color_table = 1;
+	ops = &oo_ops;
+}
+
+int OOToposGame::oo_room_is_special(comprehend_game *game,
+                              unsigned room_index,
+                              unsigned *room_desc_string) {
 	struct room *room = &game->info->rooms[room_index];
 
 	/* Is the room dark */
 	if ((room->flags & OO_ROOM_FLAG_DARK) &&
 	    !(game->info->flags[OO_FLAG_FLASHLIGHT_ON])) {
 		if (room_desc_string)
-			*room_desc_string = 0xb3; 
+			*room_desc_string = 0xb3;
 		return ROOM_IS_DARK;
 	}
 
 	/* Is the room too bright */
-	if (room_index == OO_BRIGHT_ROOM && 
+	if (room_index == OO_BRIGHT_ROOM &&
 	    !game->info->flags[OO_FLAG_WEARING_GOGGLES]) {
 		if (room_desc_string)
 			*room_desc_string = 0x1c;
@@ -60,8 +93,7 @@ static int oo_room_is_special(struct comprehend_game *game,
 	return ROOM_IS_NORMAL;
 }
 
-static bool oo_before_turn(struct comprehend_game *game)
-{
+bool OOToposGame::oo_before_turn(comprehend_game *game) {
 	/* FIXME - probably doesn't work correctly with restored games */
 	static bool flashlight_was_on = false, googles_were_worn = false;
 	struct room *room = &game->info->rooms[game->info->current_room];
@@ -89,9 +121,8 @@ static bool oo_before_turn(struct comprehend_game *game)
 	return false;
 }
 
-static void oo_handle_special_opcode(struct comprehend_game *game,
-				     uint8 operand)
-{
+void OOToposGame::oo_handle_special_opcode(comprehend_game *game,
+		uint8 operand) {
 	switch (operand) {
 	case 0x03:
 		/* Game over - failure */
@@ -114,35 +145,5 @@ static void oo_handle_special_opcode(struct comprehend_game *game,
 	}
 }
 
-static struct game_ops oo_ops = {
-	nullptr,
-	nullptr,
-	oo_before_turn,
-	nullptr,
-	oo_room_is_special,
-	oo_handle_special_opcode
-}; 
-
-struct comprehend_game game_oo_topos = {
-	"Oo-Topos",
-	"oo",
-	"G0",
-	{
-		// Extra strings are (annoyingly) stored in the game binary
-		{"NOVEL.EXE", 0x16564, 0x17640},
-		{"NOVEL.EXE", 0x17702, 0x18600},
-		{"NOVEL.EXE", 0x186b2, 0x19b80},
-		{"NOVEL.EXE", 0x19c62, 0x1a590},
-		{"NOVEL.EXE", 0x1a634, 0x1b080},
-	},
-	{"RA", "RB", "RC", "RD", "RE"},
-	{"OA", "OB", "OC", "OD"},
-	"G%d",
-	1,
-	nullptr,
-	&oo_ops,
-	nullptr
-};
-
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game_oo.h b/engines/glk/comprehend/game_oo.h
new file mode 100644
index 0000000000..fe475cb2c2
--- /dev/null
+++ b/engines/glk/comprehend/game_oo.h
@@ -0,0 +1,46 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_GAME_OO_H
+#define GLK_COMPREHEND_GAME_OO_H
+
+#include "glk/comprehend/game.h"
+
+namespace Glk {
+namespace Comprehend {
+
+class OOToposGame : public comprehend_game {
+public:
+	OOToposGame();
+
+public:
+	static bool oo_before_turn(comprehend_game *game);
+	static int oo_room_is_special(comprehend_game *game,
+		unsigned room_index, unsigned *room_desc_string);
+	static void oo_handle_special_opcode(comprehend_game *game,
+		uint8 operand);
+};
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/game_tm.cpp b/engines/glk/comprehend/game_tm.cpp
index dc5ae64a9d..35b1f03a9e 100644
--- a/engines/glk/comprehend/game_tm.cpp
+++ b/engines/glk/comprehend/game_tm.cpp
@@ -21,29 +21,30 @@
  */
 
 #include "glk/comprehend/comprehend.h"
-#include "glk/comprehend/game.h"
-#include "glk/comprehend/game_data.h"
+#include "glk/comprehend/game_tm.h"
 
 namespace Glk {
 namespace Comprehend {
 
-static struct game_ops tm_ops = {};
-
 /* FIXME - This is broken */
-struct comprehend_game game_talisman = {
-    "Talisman, Challenging the Sands of Time (broken)",
-    "tm",
-    "G0",
-    {},
-	{"RA", "RB", "RC", "RD", "RE", "RF", "RG"},
-    {"OA", "OB", "OE", "OF"},
-    nullptr,
-    0,
 
-    nullptr,
-    &tm_ops,
-    nullptr
-};
+TalismanGame::TalismanGame() : comprehend_game() {
+	game_name = "Talisman, Challenging the Sands of Time (broken)";
+	short_name = "tm";
+	game_data_file = "G0";
+
+	location_graphic_files.push_back("RA");
+	location_graphic_files.push_back("RB");
+	location_graphic_files.push_back("RC");
+	location_graphic_files.push_back("RD");
+	location_graphic_files.push_back("RE");
+	location_graphic_files.push_back("RF");
+	location_graphic_files.push_back("RG");
+	item_graphic_files.push_back("OA");
+	item_graphic_files.push_back("OB");
+	item_graphic_files.push_back("OE");
+	item_graphic_files.push_back("OF");
+}
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game_tm.h b/engines/glk/comprehend/game_tm.h
new file mode 100644
index 0000000000..a1cb8f8086
--- /dev/null
+++ b/engines/glk/comprehend/game_tm.h
@@ -0,0 +1,39 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_GAME_TM_H
+#define GLK_COMPREHEND_GAME_TM_H
+
+#include "glk/comprehend/game.h"
+
+namespace Glk {
+namespace Comprehend {
+
+class TalismanGame : public comprehend_game {
+public:
+	TalismanGame();
+};
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 84ea764848..5b7d841089 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -22,7 +22,7 @@
 
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/game_data.h"
-#include "glk/comprehend/game.h"
+#include "glk/comprehend/game_tr.h"
 #include "glk/comprehend/util.h"
 
 namespace Glk {
@@ -44,6 +44,45 @@ static struct tr_monster tr_vampire = {
 	0x26, 5, (1 << 7), 0, 5
 };
 
+static struct game_strings tr_strings = {
+    EXTRA_STRING_TABLE(0x8a)
+};
+
+static struct game_ops tr_ops = {
+    TransylvaniaGame::tr_before_game,
+    nullptr,
+    TransylvaniaGame::tr_before_turn,
+    nullptr,
+    TransylvaniaGame::tr_room_is_special,
+    TransylvaniaGame::tr_handle_special_opcode,
+};
+
+
+TransylvaniaGame::TransylvaniaGame() : comprehend_game() {
+	game_name = "Transylvania";
+	short_name = "tr";
+	game_data_file = "tr.gda";
+
+	string_files.push_back(string_file("MA.MS1", 0x88));
+	string_files.push_back(string_file("MB.MS1", 0x88));
+	string_files.push_back(string_file("MC.MS1", 0x88));
+	string_files.push_back(string_file("MD.MS1", 0x88));
+	string_files.push_back(string_file("ME.MS1", 0x88));
+
+    location_graphic_files.push_back("RA.MS1");
+	location_graphic_files.push_back("RB.MS1");
+	location_graphic_files.push_back("RC.MS1");
+
+	item_graphic_files.push_back("OA.MS1");
+	item_graphic_files.push_back("OB.MS1");
+	item_graphic_files.push_back("OC.MS1");
+
+	save_game_file_fmt = "G%d.MS0";
+	strings = &tr_strings;
+	ops = &tr_ops;
+};
+
+
 static void tr_update_monster(struct comprehend_game *game,
 			      struct tr_monster *monster_info)
 {
@@ -77,7 +116,7 @@ static void tr_update_monster(struct comprehend_game *game,
 	}
 }
 
-static int tr_room_is_special(struct comprehend_game *game, unsigned room_index,
+int TransylvaniaGame::tr_room_is_special(comprehend_game *game, unsigned room_index,
 			      unsigned *room_desc_string)
 {
 	struct room *room = &game->info->rooms[room_index];
@@ -91,14 +130,14 @@ static int tr_room_is_special(struct comprehend_game *game, unsigned room_index,
 	return ROOM_IS_NORMAL;
 }
 
-static bool tr_before_turn(struct comprehend_game *game)
+bool TransylvaniaGame::tr_before_turn(comprehend_game *game)
 {
 	tr_update_monster(game, &tr_werewolf);
 	tr_update_monster(game, &tr_vampire);
 	return false;
 }
 
-static void tr_handle_special_opcode(struct comprehend_game *game,
+void TransylvaniaGame::tr_handle_special_opcode(comprehend_game *game,
 				     uint8 operand)
 {
 	switch (operand) {
@@ -159,8 +198,7 @@ static void read_string(char *buffer, size_t size)
 #endif
 }
 
-static void tr_before_game(struct comprehend_game *game)
-{
+void TransylvaniaGame::tr_before_game(struct comprehend_game *game) {
 	char buffer[128];
 
 	/* Welcome to Transylvania - sign your name */
@@ -185,38 +223,5 @@ static void tr_before_game(struct comprehend_game *game)
 	read_string(buffer, sizeof(buffer));
 }
 
-static struct game_strings tr_strings = {
-	EXTRA_STRING_TABLE(0x8a)
-};
-
-static struct game_ops tr_ops = {
-	tr_before_game,
-	nullptr,
-	tr_before_turn,
-	nullptr,
-	tr_room_is_special,
-	tr_handle_special_opcode,
-};
-
-struct comprehend_game game_transylvania = {
-	"Transylvania",
-	"tr",
-	"TR.GDA",
-	{
-		{"MA.MS1", 0x88},
-		{"MB.MS1", 0x88},
-		{"MC.MS1", 0x88},
-		{"MD.MS1", 0x88},
-		{"ME.MS1", 0x88},
-	},
-	{"RA.MS1", "RB.MS1", "RC.MS1"},
-	{"OA.MS1", "OB.MS1", "OC.MS1"},
-	"G%d.MS0",
-	0,
-	&tr_strings,
-	&tr_ops,
-	nullptr
-};
-
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game_tr.h b/engines/glk/comprehend/game_tr.h
new file mode 100644
index 0000000000..a4d5f3db46
--- /dev/null
+++ b/engines/glk/comprehend/game_tr.h
@@ -0,0 +1,47 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_GAME_TR_H
+#define GLK_COMPREHEND_GAME_TR_H
+
+#include "glk/comprehend/game.h"
+
+namespace Glk {
+namespace Comprehend {
+
+class TransylvaniaGame : public comprehend_game {
+public:
+	TransylvaniaGame();
+
+public:
+	static void tr_before_game(comprehend_game *game);
+	static bool tr_before_turn(comprehend_game *game);
+	static int tr_room_is_special(comprehend_game *game,
+		unsigned room_index, unsigned *room_desc_string);
+	static void tr_handle_special_opcode(comprehend_game *game,
+		uint8 operand);
+};
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 4059b6ea89..d5751d3038 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -326,51 +326,34 @@ static void load_image_file(struct image_data *info, const char *filename,
 }
 
 static void load_image_files(struct image_data *info,
-			     const char **filenames, size_t nr_files)
-{
+	const Common::Array<const char *> filenames) {
 	uint i;
 
 	memset(info, 0, sizeof(*info));
 
-	info->nr_images = nr_files * IMAGES_PER_FILE;
+	info->nr_images = filenames.size() * IMAGES_PER_FILE;
 	info->fb = (file_buf *)xmalloc(info->nr_images * sizeof(*info->fb));
 	info->image_offsets = (uint16 *)xmalloc(info->nr_images * sizeof(uint16));
 
-	for (i = 0; i < nr_files; i++) {
+	for (i = 0; i < filenames.size(); i++) {
 		load_image_file(info, filenames[i], i);
 	}
 }
 
-static size_t graphic_array_count(const char **filenames, size_t max)
-{
-	size_t count;
-
-	for (count = 0; count < max && filenames[count]; count++)
-		;
-	return count;
-}
-
 void comprehend_load_image_file(const char *filename, struct image_data *info)
 {
-	load_image_files(info, (const char **)&filename, 1);
-}
-
-void comprehend_load_images(comprehend_game *game)
-{
-	size_t nr_item_files, nr_room_files;
+	Common::Array<const char *> filenames;
+	filenames.push_back(filename);
 
-	nr_room_files =
-		graphic_array_count(game->location_graphic_files,
-				    ARRAY_SIZE(game->location_graphic_files));
-	nr_item_files =
-		graphic_array_count(game->item_graphic_files,
-				    ARRAY_SIZE(game->item_graphic_files));
+	load_image_files(info, filenames);
+}
 
+void comprehend_load_images(comprehend_game *game) {
 	load_image_files(&game->info->room_images,
-			 game->location_graphic_files, nr_room_files);
+			 game->location_graphic_files);
 
 	load_image_files(&game->info->item_images,
-			 game->item_graphic_files, nr_item_files);
+			 game->item_graphic_files);
 }
 
 } // namespace Comprehend


Commit: 7e7e6a5fab134d36a7d0fcdfab40fc162af98560
    https://github.com/scummvm/scummvm/commit/7e7e6a5fab134d36a7d0fcdfab40fc162af98560
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:08-07:00

Commit Message:
GLK: COMPREHEND: Changing operation methods to virtual methods

Changed paths:
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_cc.h
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_oo.h
    engines/glk/comprehend/game_tm.h
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/game_tr.h


diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 351ccef491..49b80efdb6 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -48,22 +48,6 @@ struct game_strings {
 	uint16 game_restart;
 };
 
-#define ROOM_IS_NORMAL 0
-#define ROOM_IS_DARK 1
-#define ROOM_IS_TOO_BRIGHT 2
-
-struct game_ops {
-	void (*before_game)(struct comprehend_game *game);
-	void (*before_prompt)(struct comprehend_game *game);
-	bool (*before_turn)(struct comprehend_game *game);
-	bool (*after_turn)(struct comprehend_game *game);
-	int (*room_is_special)(struct comprehend_game *game,
-	                       unsigned room_index,
-	                       unsigned *room_desc_string);
-	void (*handle_special_opcode)(struct comprehend_game *game,
-	                              uint8 operand);
-};
-
 /**
  * Comprehend engine
  */
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 4cd28e9b20..6eff98ffc2 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -48,8 +48,7 @@ comprehend_game::comprehend_game() : game_name(nullptr),
                                      game_data_file(nullptr),
                                      save_game_file_fmt(nullptr),
                                      color_table(0),
-                                     strings(nullptr),
-                                     ops(nullptr) {
+                                     strings(nullptr) {
 	info = (game_info *)malloc(sizeof(*info));
 }
 
@@ -275,9 +274,7 @@ static void update_graphics(comprehend_game *game) {
 	if (!g_enabled())
 		return;
 
-	type = ROOM_IS_NORMAL;
-	if (game->ops->room_is_special)
-		type = game->ops->room_is_special(game, game->info->current_room, NULL);
+	type = game->room_is_special(game->info->current_room, NULL);
 
 	switch (type) {
 	case ROOM_IS_DARK:
@@ -345,12 +342,9 @@ static void update(comprehend_game *game) {
 	update_graphics(game);
 
 	/* Check if the room is special (dark, too bright, etc) */
-	room_type = ROOM_IS_NORMAL;
 	room_desc_string = room->string_desc;
-	if (game->ops->room_is_special)
-		room_type = game->ops->room_is_special(game,
-		                                       game->info->current_room,
-		                                       &room_desc_string);
+	room_type = game->room_is_special(game->info->current_room,
+		&room_desc_string);
 
 	if (game->info->update_flags & UPDATE_ROOM_DESC)
 		console_println(game, string_lookup(game, room_desc_string));
@@ -962,9 +956,7 @@ static void eval_instruction(comprehend_game *game,
 
 	case OPCODE_SPECIAL:
 		/* Game specific opcode */
-		if (game->ops->handle_special_opcode)
-			game->ops->handle_special_opcode(game,
-			                                 instr->operand[0]);
+		game->handle_special_opcode(instr->operand[0]);
 		break;
 
 	default:
@@ -1174,20 +1166,18 @@ static void read_sentence(comprehend_game *game, char **line,
 }
 
 static void before_turn(comprehend_game *game) {
-	/* Run the game specific before turn bits */
-	if (game->ops->before_turn)
-		game->ops->before_turn(game);
+	// Run the game specific before turn bits
+	game->before_turn();
 
-	/* Run the each turn functions */
+	// Run the each turn functions
 	eval_function(game, &game->info->functions[0], NULL, NULL);
 
 	update(game);
 }
 
 static void after_turn(comprehend_game *game) {
-	/* Do post turn game specific bits */
-	if (game->ops->after_turn)
-		game->ops->after_turn(game);
+	// Do post turn game specific bits
+	game->after_turn();
 }
 
 static void read_input(comprehend_game *game) {
@@ -1205,7 +1195,7 @@ static void read_input(comprehend_game *game) {
 		line = fgets(buffer, sizeof(buffer), stdin);
 	}
 
-	/* Re-comprehend special commands start with '!' */
+	// Re-comprehend special commands start with '!'
 	if (*line == '!') {
 		handle_debug_command(game, &line[1]);
 		return;
@@ -1233,11 +1223,10 @@ static void read_input(comprehend_game *game) {
 void comprehend_play_game(comprehend_game *game) {
 	console_init();
 
-	if (game->ops->before_game)
-		game->ops->before_game(game);
+	game->before_game();
 
 	game->info->update_flags = (uint)UPDATE_ALL;
-	while (1)
+	while (!g_comprehend->shouldQuit())
 		read_input(game);
 }
 
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index cfd5133666..6a3d80b607 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -23,12 +23,16 @@
 #ifndef GLK_COMPREHEND_GAME_H
 #define GLK_COMPREHEND_GAME_H
 
-#include "glk/comprehend/game_data.h"
 #include "common/array.h"
+#include "glk/comprehend/game_data.h"
 
 namespace Glk {
 namespace Comprehend {
 
+#define ROOM_IS_NORMAL 0
+#define ROOM_IS_DARK 1
+#define ROOM_IS_TOO_BRIGHT 2
+
 struct comprehend_game {
 public:
 	const char *game_name;
@@ -36,33 +40,45 @@ public:
 
 	const char *game_data_file;
 	Common::Array<string_file> string_files;
-	Common::Array <const char *> location_graphic_files;
-	Common::Array <const char *> item_graphic_files;
+	Common::Array<const char *> location_graphic_files;
+	Common::Array<const char *> item_graphic_files;
 	const char *save_game_file_fmt;
 	unsigned color_table;
 
 	struct game_strings *strings;
-	struct game_ops *ops;
-
 	struct game_info *info;
 
 public:
 	comprehend_game();
-	~comprehend_game();
+	virtual ~comprehend_game();
+
+	virtual void before_game() {}
+	virtual void before_prompt() {}
+	virtual bool before_turn() {
+		return false;
+	}
+	virtual bool after_turn() {
+		return false;
+	}
+	virtual int room_is_special(unsigned room_index,
+		unsigned *room_desc_string) {
+		return ROOM_IS_NORMAL;
+	}
+	virtual void handle_special_opcode(uint8 operand) {}
 };
 
-void console_println(struct comprehend_game *game, const char *text);
+void console_println(comprehend_game *game, const char *text);
 int console_get_key(void);
 
-struct item *get_item(struct comprehend_game *game, uint16 index);
-void move_object(struct comprehend_game *game, struct item *item, int new_room);
-void eval_function(struct comprehend_game *game, struct function *func,
-		   struct word *verb, struct word *noun);
+struct item *get_item(comprehend_game *game, uint16 index);
+void move_object(comprehend_game *game, struct item *item, int new_room);
+void eval_function(comprehend_game *game, struct function *func,
+                   struct word *verb, struct word *noun);
 
-void comprehend_play_game(struct comprehend_game *game);
-void game_save(struct comprehend_game *game);
-void game_restore(struct comprehend_game *game);
-void game_restart(struct comprehend_game *game);
+void comprehend_play_game(comprehend_game *game);
+void game_save(comprehend_game *game);
+void game_restore(comprehend_game *game);
+void game_restart(comprehend_game *game);
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index bed5603cce..9bc6a3daa3 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -28,14 +28,6 @@ namespace Comprehend {
 
 static struct game_strings cc1_strings = {0x9};
 
-static struct game_ops cc1_ops = {
-    nullptr,
-    CrimsonCrownGame::cc1_before_prompt,
-    nullptr,
-    nullptr,
-    nullptr,
-    CrimsonCrownGame::cc1_handle_special_opcode};
-
 #ifdef TODO
 static struct game_ops cc2_ops = {
     nullptr,
@@ -60,7 +52,6 @@ CrimsonCrownGame::CrimsonCrownGame() : comprehend_game() {
 
 	save_game_file_fmt = "G%d.MS0";
 	strings = &cc1_strings;
-	ops = &cc1_ops;
 }
 
 #ifdef TODO
@@ -113,9 +104,8 @@ static bool cc_common_handle_special_opcode(struct comprehend_game *game,
 	return false;
 }
 
-void CrimsonCrownGame::cc1_handle_special_opcode(comprehend_game *game,
-		uint8 operand) {
-	if (cc_common_handle_special_opcode(game, operand))
+void CrimsonCrownGame::handle_special_opcode(uint8 operand) {
+	if (cc_common_handle_special_opcode(this, operand))
 		return;
 
 	switch (operand) {
@@ -156,8 +146,8 @@ static void cc2_before_prompt(struct comprehend_game *game) {
 	cc_clear_companion_flags(game);
 }
 
-void CrimsonCrownGame::cc1_before_prompt(comprehend_game *game) {
-	cc_clear_companion_flags(game);
+void CrimsonCrownGame::before_prompt() {
+	cc_clear_companion_flags(this);
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game_cc.h b/engines/glk/comprehend/game_cc.h
index 00ba334b5a..ccbbc147a9 100644
--- a/engines/glk/comprehend/game_cc.h
+++ b/engines/glk/comprehend/game_cc.h
@@ -31,11 +31,10 @@ namespace Comprehend {
 class CrimsonCrownGame : public comprehend_game {
 public:
 	CrimsonCrownGame();
+	~CrimsonCrownGame() override {}
 
-public:
-	static void cc1_before_prompt(comprehend_game *game);
-	static void cc1_handle_special_opcode(comprehend_game *game,
-		uint8 operand);
+	void before_prompt() override;
+	void handle_special_opcode(uint8 operand) override;
 };
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index 3926b42192..ab6a67c4bb 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -34,15 +34,6 @@ namespace Comprehend {
 #define OO_FLAG_WEARING_GOGGLES 0x1b
 #define OO_FLAG_FLASHLIGHT_ON 0x27
 
-static struct game_ops oo_ops = {
-    nullptr,
-    nullptr,
-    OOToposGame::oo_before_turn,
-    nullptr,
-    OOToposGame::oo_room_is_special,
-    OOToposGame::oo_handle_special_opcode
-};
-
 OOToposGame::OOToposGame() : comprehend_game() {
 	game_name = "Oo-Topos";
 	short_name = "oo";
@@ -66,17 +57,15 @@ OOToposGame::OOToposGame() : comprehend_game() {
 
 	save_game_file_fmt = "G%d";
 	color_table = 1;
-	ops = &oo_ops;
 }
 
-int OOToposGame::oo_room_is_special(comprehend_game *game,
-                              unsigned room_index,
+int OOToposGame::room_is_special(unsigned room_index,
                               unsigned *room_desc_string) {
-	struct room *room = &game->info->rooms[room_index];
+	room *room = &info->rooms[room_index];
 
 	/* Is the room dark */
 	if ((room->flags & OO_ROOM_FLAG_DARK) &&
-	    !(game->info->flags[OO_FLAG_FLASHLIGHT_ON])) {
+	    !(info->flags[OO_FLAG_FLASHLIGHT_ON])) {
 		if (room_desc_string)
 			*room_desc_string = 0xb3;
 		return ROOM_IS_DARK;
@@ -84,7 +73,7 @@ int OOToposGame::oo_room_is_special(comprehend_game *game,
 
 	/* Is the room too bright */
 	if (room_index == OO_BRIGHT_ROOM &&
-	    !game->info->flags[OO_FLAG_WEARING_GOGGLES]) {
+	    !info->flags[OO_FLAG_WEARING_GOGGLES]) {
 		if (room_desc_string)
 			*room_desc_string = 0x1c;
 		return ROOM_IS_TOO_BRIGHT;
@@ -93,36 +82,35 @@ int OOToposGame::oo_room_is_special(comprehend_game *game,
 	return ROOM_IS_NORMAL;
 }
 
-bool OOToposGame::oo_before_turn(comprehend_game *game) {
+bool OOToposGame::before_turn() {
 	/* FIXME - probably doesn't work correctly with restored games */
 	static bool flashlight_was_on = false, googles_were_worn = false;
-	struct room *room = &game->info->rooms[game->info->current_room];
+	struct room *room = &info->rooms[info->current_room];
 
 	/* 
 	 * Check if the room needs to be redrawn because the flashlight
 	 * was switch off or on.
 	 */
-	if (game->info->flags[OO_FLAG_FLASHLIGHT_ON] != flashlight_was_on &&
+	if (info->flags[OO_FLAG_FLASHLIGHT_ON] != flashlight_was_on &&
 	    (room->flags & OO_ROOM_FLAG_DARK)) {
-		flashlight_was_on = game->info->flags[OO_FLAG_FLASHLIGHT_ON];
-		game->info->update_flags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
+		flashlight_was_on = info->flags[OO_FLAG_FLASHLIGHT_ON];
+		info->update_flags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
 	}
 
 	/*
 	 * Check if the room needs to be redrawn because the goggles were
 	 * put on or removed.
 	 */
-	if (game->info->flags[OO_FLAG_WEARING_GOGGLES] != googles_were_worn &&
-	    game->info->current_room == OO_BRIGHT_ROOM) {
-		googles_were_worn = game->info->flags[OO_FLAG_WEARING_GOGGLES];
-		game->info->update_flags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
+	if (info->flags[OO_FLAG_WEARING_GOGGLES] != googles_were_worn &&
+	    info->current_room == OO_BRIGHT_ROOM) {
+		googles_were_worn = info->flags[OO_FLAG_WEARING_GOGGLES];
+		info->update_flags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
 	}
 
 	return false;
 }
 
-void OOToposGame::oo_handle_special_opcode(comprehend_game *game,
-		uint8 operand) {
+void OOToposGame::handle_special_opcode(uint8 operand) {
 	switch (operand) {
 	case 0x03:
 		/* Game over - failure */
@@ -130,17 +118,17 @@ void OOToposGame::oo_handle_special_opcode(comprehend_game *game,
 		/* Won the game */
 	case 0x04:
 		/* Restart game */
-		game_restart(game);
+		game_restart(this);
 		break;
 
 	case 0x06:
 		/* Save game */
-		game_save(game);
+		game_save(this);
 		break;
 
 	case 0x07:
 		/* Restore game */
-		game_restore(game);
+		game_restore(this);
 		break;
 	}
 }
diff --git a/engines/glk/comprehend/game_oo.h b/engines/glk/comprehend/game_oo.h
index fe475cb2c2..c1b1f767e4 100644
--- a/engines/glk/comprehend/game_oo.h
+++ b/engines/glk/comprehend/game_oo.h
@@ -31,13 +31,11 @@ namespace Comprehend {
 class OOToposGame : public comprehend_game {
 public:
 	OOToposGame();
+	~OOToposGame() override {}
 
-public:
-	static bool oo_before_turn(comprehend_game *game);
-	static int oo_room_is_special(comprehend_game *game,
-		unsigned room_index, unsigned *room_desc_string);
-	static void oo_handle_special_opcode(comprehend_game *game,
-		uint8 operand);
+	bool before_turn() override;
+	int room_is_special(unsigned room_index, unsigned *room_desc_string) override;
+	void handle_special_opcode(uint8 operand) override;
 };
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game_tm.h b/engines/glk/comprehend/game_tm.h
index a1cb8f8086..70f8537102 100644
--- a/engines/glk/comprehend/game_tm.h
+++ b/engines/glk/comprehend/game_tm.h
@@ -31,6 +31,7 @@ namespace Comprehend {
 class TalismanGame : public comprehend_game {
 public:
 	TalismanGame();
+	~TalismanGame() override {}
 };
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 5b7d841089..9596e48b42 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -28,19 +28,11 @@
 namespace Glk {
 namespace Comprehend {
 
-struct tr_monster {
-	uint8		object;
-	uint8		dead_flag;
-	unsigned	min_turns_before;
-	unsigned	room_allow_flag;
-	unsigned	randomness;
-};
-
-static struct tr_monster tr_werewolf = {
+const tr_monster TransylvaniaGame::WEREWOLF = {
 	0x21, 7, (1 << 6), 5, 5
 };
 
-static struct tr_monster tr_vampire = {
+const tr_monster TransylvaniaGame::VAMPIRE = {
 	0x26, 5, (1 << 7), 0, 5
 };
 
@@ -48,15 +40,6 @@ static struct game_strings tr_strings = {
     EXTRA_STRING_TABLE(0x8a)
 };
 
-static struct game_ops tr_ops = {
-    TransylvaniaGame::tr_before_game,
-    nullptr,
-    TransylvaniaGame::tr_before_turn,
-    nullptr,
-    TransylvaniaGame::tr_room_is_special,
-    TransylvaniaGame::tr_handle_special_opcode,
-};
-
 
 TransylvaniaGame::TransylvaniaGame() : comprehend_game() {
 	game_name = "Transylvania";
@@ -79,28 +62,24 @@ TransylvaniaGame::TransylvaniaGame() : comprehend_game() {
 
 	save_game_file_fmt = "G%d.MS0";
 	strings = &tr_strings;
-	ops = &tr_ops;
 };
 
-
-static void tr_update_monster(struct comprehend_game *game,
-			      struct tr_monster *monster_info)
-{
+void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
 	struct item *monster;
 	struct room *room;
 	uint16 turn_count;
 
-	room = &game->info->rooms[game->info->current_room];
-	turn_count = game->info->variable[VAR_TURN_COUNT];
+	room = &info->rooms[info->current_room];
+	turn_count = info->variable[VAR_TURN_COUNT];
 
-	monster = get_item(game, monster_info->object);
-	if (monster->room == game->info->current_room) {
+	monster = get_item(this, monster_info->object);
+	if (monster->room == info->current_room) {
 		/* The monster is in the current room - leave it there */
 		return;
 	}
 
 	if ((room->flags & monster_info->room_allow_flag) &&
-	    !game->info->flags[monster_info->dead_flag] &&
+	    !info->flags[monster_info->dead_flag] &&
 	    turn_count > monster_info->min_turns_before) {
 		/*
 		 * The monster is alive and allowed to move to the current
@@ -108,18 +87,18 @@ static void tr_update_monster(struct comprehend_game *game,
 		 * it back to limbo.
 		 */
 		if ((g_comprehend->getRandomNumber(0x7fffffff) % monster_info->randomness) == 0) {
-			move_object(game, monster, game->info->current_room);
-			game->info->variable[0xf] = turn_count + 1;
+			move_object(this, monster, info->current_room);
+			info->variable[0xf] = turn_count + 1;
 		} else {
-			move_object(game, monster, ROOM_NOWHERE);
+			move_object(this, monster, ROOM_NOWHERE);
 		}
 	}
 }
 
-int TransylvaniaGame::tr_room_is_special(comprehend_game *game, unsigned room_index,
+int TransylvaniaGame::room_is_special(unsigned room_index,
 			      unsigned *room_desc_string)
 {
-	struct room *room = &game->info->rooms[room_index];
+	struct room *room = &info->rooms[room_index];
 
 	if (room_index == 0x28) {
 		if (room_desc_string)
@@ -130,15 +109,13 @@ int TransylvaniaGame::tr_room_is_special(comprehend_game *game, unsigned room_in
 	return ROOM_IS_NORMAL;
 }
 
-bool TransylvaniaGame::tr_before_turn(comprehend_game *game)
-{
-	tr_update_monster(game, &tr_werewolf);
-	tr_update_monster(game, &tr_vampire);
+bool TransylvaniaGame::before_turn() {
+	update_monster(&WEREWOLF);
+	update_monster(&VAMPIRE);
 	return false;
 }
 
-void TransylvaniaGame::tr_handle_special_opcode(comprehend_game *game,
-				     uint8 operand)
+void TransylvaniaGame::handle_special_opcode(uint8 operand)
 {
 	switch (operand) {
 	case 0x01:
@@ -153,11 +130,11 @@ void TransylvaniaGame::tr_handle_special_opcode(comprehend_game *game,
 		break;
 
 	case 0x06:
-		game_save(game);
+		game_save(this);
 		break;
 
 	case 0x07:
-		game_restore(game);
+		game_restore(this);
 		break;
 
 	case 0x03:
@@ -166,7 +143,7 @@ void TransylvaniaGame::tr_handle_special_opcode(comprehend_game *game,
 		/* Won the game */
 	case 0x08:
 		/* Restart game */
-		game_restart(game);
+		game_restart(this);
 		break;
 
 	case 0x09:
@@ -174,9 +151,9 @@ void TransylvaniaGame::tr_handle_special_opcode(comprehend_game *game,
 		 * Show the Zin screen in reponse to doing 'sing some enchanted
 		 * evening' in his cabin.
 		 */
-		draw_location_image(&game->info->room_images, 41);
+		draw_location_image(&info->room_images, 41);
 		console_get_key();
-		game->info->update_flags |= UPDATE_GRAPHICS;
+		info->update_flags |= UPDATE_GRAPHICS;
 		break;
 	}
 }
@@ -198,11 +175,11 @@ static void read_string(char *buffer, size_t size)
 #endif
 }
 
-void TransylvaniaGame::tr_before_game(struct comprehend_game *game) {
+void TransylvaniaGame::before_game() {
 	char buffer[128];
 
 	/* Welcome to Transylvania - sign your name */
-	console_println(game, game->info->strings.strings[0x20]);
+	console_println(this, info->strings.strings[0x20]);
 	read_string(buffer, sizeof(buffer));
 
 	/*
@@ -211,15 +188,15 @@ void TransylvaniaGame::tr_before_game(struct comprehend_game *game) {
 	 * limited (the original game will break if you put a name in that
 	 * is too long).
 	 */
-	if (!game->info->replace_words[0])
-		game->info->replace_words[0] = xstrndup(buffer, strlen(buffer));
+	if (!info->replace_words[0])
+		info->replace_words[0] = xstrndup(buffer, strlen(buffer));
 	else
-		snprintf(game->info->replace_words[0],
-			 strlen(game->info->replace_words[0]),
+		snprintf(info->replace_words[0],
+			 strlen(info->replace_words[0]),
 			 "%s", buffer);
 
 	/* And your next of kin - This isn't store by the game */
-	console_println(game, game->info->strings.strings[0x21]);
+	console_println(this, info->strings.strings[0x21]);
 	read_string(buffer, sizeof(buffer));
 }
 
diff --git a/engines/glk/comprehend/game_tr.h b/engines/glk/comprehend/game_tr.h
index a4d5f3db46..74dc09ba55 100644
--- a/engines/glk/comprehend/game_tr.h
+++ b/engines/glk/comprehend/game_tr.h
@@ -28,17 +28,29 @@
 namespace Glk {
 namespace Comprehend {
 
+struct tr_monster {
+	uint8 object;
+	uint8 dead_flag;
+	unsigned min_turns_before;
+	unsigned room_allow_flag;
+	unsigned randomness;
+};
+
 class TransylvaniaGame : public comprehend_game {
+private:
+	static const tr_monster WEREWOLF;
+	static const tr_monster VAMPIRE;
+
+	void update_monster(const tr_monster *monster_info);
+
 public:
 	TransylvaniaGame();
+	~TransylvaniaGame() override {}
 
-public:
-	static void tr_before_game(comprehend_game *game);
-	static bool tr_before_turn(comprehend_game *game);
-	static int tr_room_is_special(comprehend_game *game,
-		unsigned room_index, unsigned *room_desc_string);
-	static void tr_handle_special_opcode(comprehend_game *game,
-		uint8 operand);
+	void before_game() override;
+	bool before_turn() override;
+	int room_is_special(unsigned room_index, unsigned *room_desc_string) override;
+	void handle_special_opcode(uint8 operand) override;
 };
 
 } // namespace Comprehend


Commit: 2dd367aa6f4dc9750b4cbfdaba43a3b07189d590
    https://github.com/scummvm/scummvm/commit/2dd367aa6f4dc9750b4cbfdaba43a3b07189d590
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Adding initialization defaults for game info

Changed paths:
    engines/glk/comprehend/dictionary.cpp
    engines/glk/comprehend/dump_game_data.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h


diff --git a/engines/glk/comprehend/dictionary.cpp b/engines/glk/comprehend/dictionary.cpp
index a25f91f240..cbab1ff0c4 100644
--- a/engines/glk/comprehend/dictionary.cpp
+++ b/engines/glk/comprehend/dictionary.cpp
@@ -31,13 +31,13 @@ namespace Comprehend {
 static bool word_match(struct word *word, const char *string)
 {
 	/* Words less than 6 characters must match exactly */
-	if (strlen(word->word) < 6 && strlen(string) != strlen(word->word))
+	if (strlen(word->_word) < 6 && strlen(string) != strlen(word->_word))
 		return false;
 
-	return strncmp(word->word, string, strlen(word->word)) == 0;
+	return strncmp(word->_word, string, strlen(word->_word)) == 0;
 }
 
-struct word *dict_find_word_by_string(struct comprehend_game *game,
+word *dict_find_word_by_string(struct comprehend_game *game,
 				      const char *string)
 {
 	uint i;
@@ -58,8 +58,8 @@ struct word *dict_find_word_by_index_type(struct comprehend_game *game,
 	uint i;
 
 	for (i = 0; i < game->info->nr_words; i++) {
-		if (game->info->words[i].index == index &&
-		    game->info->words[i].type == type)
+		if (game->info->words[i]._index == index &&
+		    game->info->words[i]._type == type)
 			return &game->info->words[i];
 	}
 
@@ -72,8 +72,8 @@ struct word *find_dict_word_by_index(struct comprehend_game *game,
 	uint i;
 
 	for (i = 0; i < game->info->nr_words; i++) {
-		if (game->info->words[i].index == index &&
-		    (game->info->words[i].type & type_mask) != 0)
+		if (game->info->words[i]._index == index &&
+		    (game->info->words[i]._type & type_mask) != 0)
 			return &game->info->words[i];
 	}
 
@@ -86,8 +86,8 @@ bool dict_match_index_type(struct comprehend_game *game, const char *word,
 	uint i;
 
 	for (i = 0; i < game->info->nr_words; i++)
-		if (game->info->words[i].index == index &&
-		    ((game->info->words[i].type & type_mask) != 0) &&
+		if (game->info->words[i]._index == index &&
+		    ((game->info->words[i]._type & type_mask) != 0) &&
 		    word_match(&game->info->words[i], word))
 			return true;
 
diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
index 99426a36b5..6ef5a66478 100644
--- a/engines/glk/comprehend/dump_game_data.cpp
+++ b/engines/glk/comprehend/dump_game_data.cpp
@@ -219,7 +219,7 @@ static void dump_action_table(struct comprehend_game *game)
 			word = find_dict_word_by_index(game, action->word[j],
 						       action->word_type[j]);
 			if (word)
-				debugN("%-6s ", word->word);
+				debugN("%-6s ", word->_word);
 			else
 				debugN("%.2x:%.2x  ", action->word[j],
 				       action->word_type[j]);
@@ -233,9 +233,9 @@ static int word_index_compare(const void *a, const void *b)
 {
 	const word *word_a = (const word *)a, *word_b = (const word *)b;
 
-	if (word_a->index > word_b->index)
+	if (word_a->_index > word_b->_index)
 		return 1;
-	if (word_a->index < word_b->index)
+	if (word_a->_index < word_b->_index)
 		return -1;
 	return 0;
 }
@@ -256,8 +256,8 @@ static void dump_dictionary(struct comprehend_game *game)
 	debugN("Dictionary (%zd words)\n", game->info->nr_words);
 	for (i = 0; i < game->info->nr_words; i++) {
 		words = &dictionary[i];
-		debugN("  [%.2x] %.2x %s\n", words->index, words->type,
-		       words->word);
+		debugN("  [%.2x] %.2x %s\n", words->_index, words->_type,
+		       words->_word);
 	}
 
 	free(dictionary);
@@ -279,7 +279,7 @@ static void dump_word_map(struct comprehend_game *game)
 				game, map->word[j].index, map->word[j].type);
 			if (word[j])
 				snprintf(str[j], sizeof(str[j]),
-					 "%s", word[j]->word);
+				         "%s", word[j]->_word);
 			else
 				snprintf(str[j], sizeof(str[j]), "%.2x:%.2x ",
 					 map->word[j].index, map->word[j].type);
@@ -335,9 +335,9 @@ static void dump_items(struct comprehend_game *game)
 
 		debugN("    words: ");
 		for (j = 0; j < game->info->nr_words; j++)
-			if (game->info->words[j].index == item->word &&
-			    (game->info->words[j].type & WORD_TYPE_NOUN_MASK))
-				debugN("%s ", game->info->words[j].word);
+			if (game->info->words[j]._index == item->word &&
+			    (game->info->words[j]._type & WORD_TYPE_NOUN_MASK))
+				debugN("%s ", game->info->words[j]._word);
 		debugN("\n");
 		debugN("    flags=%.2x (takeable=%d, weight=%d)\n",
 		       item->flags, !!(item->flags & ITEMF_CAN_TAKE),
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 6eff98ffc2..c55145f7a2 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -236,10 +236,10 @@ static struct word_index *is_word_pair(comprehend_game *game,
 	for (i = 0; i < game->info->nr_word_maps; i++) {
 		map = &game->info->word_map[i];
 
-		if (map->word[0].index == word1->index &&
-		    map->word[0].type == word1->type &&
-		    map->word[1].index == word2->index &&
-		    map->word[1].type == word2->type)
+		if (map->word[0].index == word1->_index &&
+		    map->word[0].type == word1->_type &&
+		    map->word[1].index == word2->_index &&
+		    map->word[1].type == word2->_type)
 			return &map->word[2];
 	}
 
@@ -250,7 +250,7 @@ static struct item *get_item_by_noun(comprehend_game *game,
                                      struct word *noun) {
 	uint i;
 
-	if (!noun || !(noun->type & WORD_TYPE_NOUN_MASK))
+	if (!noun || !(noun->_type & WORD_TYPE_NOUN_MASK))
 		return NULL;
 
 	/*
@@ -259,7 +259,7 @@ static struct item *get_item_by_noun(comprehend_game *game,
 	 *         to drop the latter because this will match the former.
 	 */
 	for (i = 0; i < game->info->header.nr_items; i++)
-		if (game->info->item[i].word == noun->index)
+		if (game->info->item[i].word == noun->_index)
 			return &game->info->item[i];
 
 	return NULL;
@@ -551,12 +551,12 @@ static void eval_instruction(comprehend_game *game,
 
 	case OPCODE_MOVE:
 		/* Move in the direction dictated by the current verb */
-		if (verb->index - 1 >= NR_DIRECTIONS)
+		if (verb->_index - 1 >= NR_DIRECTIONS)
 			fatal_error("Bad verb %d:%d in move",
-			            verb->index, verb->type);
+			            verb->_index, verb->_type);
 
-		if (room->direction[verb->index - 1])
-			move_to(game, room->direction[verb->index - 1]);
+		if (room->direction[verb->_index - 1])
+			move_to(game, room->direction[verb->_index - 1]);
 		else
 			console_println(game, string_lookup(game, STRING_CANT_GO));
 		break;
@@ -619,7 +619,7 @@ static void eval_instruction(comprehend_game *game,
 			for (i = 0; i < game->info->header.nr_items; i++) {
 				struct item *itemP = &game->info->item[i];
 
-				if (itemP->word == noun->index &&
+				if (itemP->word == noun->_index &&
 				    itemP->room == instr->operand[0]) {
 					test = true;
 					break;
@@ -727,7 +727,7 @@ static void eval_instruction(comprehend_game *game,
 	case OPCODE_OBJECT_NOT_VALID:
 		/* FIXME - should be called OPCODE_CURRENT_OBJECT_NOT_VALID */
 		func_set_test_result(func_state, !noun ||
-		                                     (noun->type & WORD_TYPE_NOUN_MASK) == 0);
+		                                     (noun->_type & WORD_TYPE_NOUN_MASK) == 0);
 		break;
 
 	case OPCODE_CURRENT_IS_OBJECT:
@@ -931,11 +931,11 @@ static void eval_instruction(comprehend_game *game,
 		 * FIXME - Not sure what the operand is for,
 		 * maybe capitalisation?
 		 */
-		if (noun && (noun->type & WORD_TYPE_NOUN_PLURAL))
+		if (noun && (noun->_type & WORD_TYPE_NOUN_PLURAL))
 			game->info->current_replace_word = 3;
-		else if (noun && (noun->type & WORD_TYPE_FEMALE))
+		else if (noun && (noun->_type & WORD_TYPE_FEMALE))
 			game->info->current_replace_word = 0;
-		else if (noun && (noun->type & WORD_TYPE_MALE))
+		else if (noun && (noun->_type & WORD_TYPE_MALE))
 			game->info->current_replace_word = 1;
 		else
 			game->info->current_replace_word = 2;
@@ -985,9 +985,7 @@ static void eval_instruction(comprehend_game *game,
  */
 void eval_function(comprehend_game *game, struct function *func,
                    struct word *verb, struct word *noun) {
-	struct function_state func_state = {
-	    true, false, 0, false, false, false
-	};
+	struct function_state func_state;
 	uint i;
 
 	func_state.else_result = true;
@@ -1084,8 +1082,8 @@ static bool handle_sentence(comprehend_game *game,
 		 * run that action's function.
 		 */
 		for (j = 0; j < action->nr_words; j++) {
-			if (sentence->words[j].index == action->word[j] &&
-			    (sentence->words[j].type & action->word_type[j]))
+			if (sentence->words[j]._index == action->word[j] &&
+			    (sentence->words[j]._type & action->word_type[j]))
 				continue;
 
 			/* Word didn't match */
@@ -1149,9 +1147,9 @@ static void read_sentence(comprehend_game *game, char **line,
 			                    &sentence->words[index - 2],
 			                    &sentence->words[index - 1]);
 			if (pair) {
-				sentence->words[index - 2].index = pair->index;
-				sentence->words[index - 2].type = pair->type;
-				strcpy(sentence->words[index - 2].word,
+				sentence->words[index - 2]._index = pair->index;
+				sentence->words[index - 2]._type = pair->type;
+				strcpy(sentence->words[index - 2]._word,
 				       "[PAIR]");
 				sentence->nr_words--;
 			}
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index c06b2813c8..5c92182e2d 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -38,7 +38,102 @@ static char special_charset[] = "[]\n!\"#$%&'(),-/0123456789:;?<>";
 
 static uint16 magic_offset;
 
-static void parse_header_le16(struct file_buf *fb, uint16 *val) {
+function_state::function_state() : test_result(true),
+                                   else_result(false),
+                                   or_count(0),
+                                   _and(false),
+                                   in_command(false),
+                                   executed(false) {
+}
+
+/*-------------------------------------------------------*/
+
+room::room() : flags(0),
+               graphic(0),
+               string_desc(0) {
+	Common::fill(&direction[0], &direction[NR_DIRECTIONS], 0);
+}
+
+/*-------------------------------------------------------*/
+
+item::item() : string_desc(0),
+               long_string(0),
+               room(0),
+               flags(0),
+               word(0),
+               graphic(0) {
+}
+
+/*-------------------------------------------------------*/
+
+word::word() : _index(0), _type(0) {
+	Common::fill(&_word[0], &_word[7], '\0');
+}
+
+/*-------------------------------------------------------*/
+
+action::action() : type(0), nr_words(0), function(0) {
+	Common::fill(&word[0], &word[4], 0);
+	Common::fill(&word_type[0], &word_type[4], 0);
+}
+
+instruction::instruction() : opcode(0), nr_operands(0),
+		is_command(false) {
+	Common::fill(&operand[0], &operand[3], 0);
+}
+
+/*-------------------------------------------------------*/
+
+string_table::string_table() : nr_strings(0) {
+	Common::fill(&strings[0], &strings[0xffff], nullptr);
+}
+
+/*-------------------------------------------------------*/
+
+game_header::game_header() : magic(0),
+	                             room_desc_table(0),
+	                             room_flags_table(0),
+	                             room_graphics_table(0),
+	                             nr_items(0),
+	                             addr_item_locations(0),
+	                             addr_item_flags(0),
+	                             addr_item_word(0),
+	                             addr_item_strings(0),
+	                             addr_item_graphics(0),
+	                             addr_dictionary(0),
+	                             addr_word_map(0),
+	                             addr_strings(0),
+	                             addr_strings_end(0),
+	                             addr_actions_vvnn(0),
+	                             addr_actions_unknown(0),
+	                             addr_actions_vnjn(0),
+	                             addr_actions_vjn(0),
+	                             addr_actions_vdn(0),
+	                             addr_actions_vnn(0),
+	                             addr_actions_vn(0),
+	                             addr_actions_v(0),
+	                             addr_vm(0) // FIXME - functions
+{
+	Common::fill(&room_direction_table[0], &room_direction_table[NR_DIRECTIONS], 0);
+}
+
+/*-------------------------------------------------------*/
+
+game_info::game_info() : comprehend_version(0),
+	                        start_room(0),
+	                        nr_rooms(0),
+	                        current_room(0),
+	                        words(nullptr),
+	                        nr_words(0),
+	                        nr_word_maps(0),
+	                        nr_actions(0),
+	                        nr_functions(0),
+	                        nr_replace_words(0),
+	                        current_replace_word(0),
+	                        update_flags(0) {
+}
+
+static void parse_header_le16(struct file_buf * fb, uint16 * val) {
 	file_buf_get_le16(fb, val);
 	*val += (uint16)magic_offset;
 }
@@ -53,8 +148,8 @@ static bool opcode_is_command(uint8 opcode) {
 	return opcode & 0x80;
 }
 
-static uint8 parse_vm_instruction(struct file_buf *fb,
-                                  struct instruction *instr) {
+static uint8 parse_vm_instruction(struct file_buf * fb,
+	                                struct instruction * instr) {
 	uint i;
 
 	/* Get the opcode */
@@ -70,12 +165,12 @@ static uint8 parse_vm_instruction(struct file_buf *fb,
 	return instr->opcode;
 }
 
-static void parse_function(struct file_buf *fb, struct function *func) {
+static void parse_function(struct file_buf * fb, struct function * func) {
 	struct instruction *instruction;
 	uint8 *p, opcode;
 
 	p = (uint8 *)memchr(file_buf_data_pointer(fb), 0x00,
-	                    fb->size - file_buf_get_pos(fb));
+		                fb->size - file_buf_get_pos(fb));
 	if (!p)
 		fatal_error("bad function @ %.4x", file_buf_get_pos(fb));
 
@@ -92,7 +187,7 @@ static void parse_function(struct file_buf *fb, struct function *func) {
 	}
 }
 
-static void parse_vm(struct comprehend_game *game, struct file_buf *fb) {
+static void parse_vm(struct comprehend_game * game, struct file_buf * fb) {
 	struct function *func;
 
 	file_buf_set_pos(fb, game->info->header.addr_vm);
@@ -107,22 +202,22 @@ static void parse_vm(struct comprehend_game *game, struct file_buf *fb) {
 	}
 }
 
-static void parse_action_table_vvnn(struct comprehend_game *game,
-                                    struct file_buf *fb, size_t *index) {
+static void parse_action_table_vvnn(struct comprehend_game * game,
+	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
 	int i, j;
 
 	/*
-	 * <verb> <verb> <noun> <noun>
-	 *
-	 * u8: verb1
-	 * u8: count
-	 *     u8:   verb2
-	 *     u8:   noun1
-	 *     u8:   noun2
-	 *     le16: action
-	 */
+	* <verb> <verb> <noun> <noun>
+	*
+	* u8: verb1
+	* u8: count
+	*     u8:   verb2
+	*     u8:   noun1
+	*     u8:   noun2
+	*     le16: action
+	*/
 	file_buf_set_pos(fb, game->info->header.addr_actions_vvnn);
 	while (1) {
 		file_buf_get_u8(fb, &verb);
@@ -151,22 +246,22 @@ static void parse_action_table_vvnn(struct comprehend_game *game,
 	}
 }
 
-static void parse_action_table_vnjn(struct comprehend_game *game,
-                                    struct file_buf *fb, size_t *index) {
+static void parse_action_table_vnjn(struct comprehend_game * game,
+	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 join, count;
 	int i;
 
 	/*
-	 * <verb> <noun> <join> <noun>
-	 *
-	 * u8: join
-	 * u8: count
-	 *     u8:   verb
-	 *     u8:   noun1
-	 *     u8:   noun2
-	 *     le16: action
-	 */
+	* <verb> <noun> <join> <noun>
+	*
+	* u8: join
+	* u8: count
+	*     u8:   verb
+	*     u8:   noun1
+	*     u8:   noun2
+	*     le16: action
+	*/
 	file_buf_set_pos(fb, game->info->header.addr_actions_vnjn);
 	while (1) {
 		file_buf_get_u8(fb, &join);
@@ -196,21 +291,21 @@ static void parse_action_table_vnjn(struct comprehend_game *game,
 	}
 }
 
-static void parse_action_table_vjn(struct comprehend_game *game,
-                                   struct file_buf *fb, size_t *index) {
+static void parse_action_table_vjn(struct comprehend_game * game,
+	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 join, count;
 	int i;
 
 	/*
-	 * <verb> <join> <noun>
-	 *
-	 * u8: join
-	 * u8: count
-	 *     u8:   verb
-	 *     u8:   noun
-	 *     le16: action
-	 */
+	* <verb> <join> <noun>
+	*
+	* u8: join
+	* u8: count
+	*     u8:   verb
+	*     u8:   noun
+	*     le16: action
+	*/
 	file_buf_set_pos(fb, game->info->header.addr_actions_vjn);
 	while (1) {
 		file_buf_get_u8(fb, &join);
@@ -237,21 +332,21 @@ static void parse_action_table_vjn(struct comprehend_game *game,
 	}
 }
 
-static void parse_action_table_vdn(struct comprehend_game *game,
-                                   struct file_buf *fb, size_t *index) {
+static void parse_action_table_vdn(struct comprehend_game * game,
+	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
 	int i;
 
 	/*
-	 * <verb> <dir> <noun>
-	 *
-	 * u8: verb
-	 * u8: count
-	 *     u8:   dir
-	 *     u8:   noun
-	 *     le16: action
-	 */
+	* <verb> <dir> <noun>
+	*
+	* u8: verb
+	* u8: count
+	*     u8:   dir
+	*     u8:   noun
+	*     le16: action
+	*/
 	file_buf_set_pos(fb, game->info->header.addr_actions_vdn);
 	while (1) {
 		file_buf_get_u8(fb, &verb);
@@ -278,21 +373,21 @@ static void parse_action_table_vdn(struct comprehend_game *game,
 	}
 }
 
-static void parse_action_table_vnn(struct comprehend_game *game,
-                                   struct file_buf *fb, size_t *index) {
+static void parse_action_table_vnn(struct comprehend_game * game,
+	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
 	int i;
 
 	/*
-	 * <verb> <noun> <noun>
-	 *
-	 * u8: verb
-	 * u8: count
-	 *     u8:   noun1
-	 *     u8:   noun2
-	 *     le16: action
-	 */
+	* <verb> <noun> <noun>
+	*
+	* u8: verb
+	* u8: count
+	*     u8:   noun1
+	*     u8:   noun2
+	*     le16: action
+	*/
 	file_buf_set_pos(fb, game->info->header.addr_actions_vnn);
 	while (1) {
 		/* 2-byte header */
@@ -320,20 +415,20 @@ static void parse_action_table_vnn(struct comprehend_game *game,
 	}
 }
 
-static void parse_action_table_vn(struct comprehend_game *game,
-                                  struct file_buf *fb, size_t *index) {
+static void parse_action_table_vn(struct comprehend_game * game,
+	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
 	int i;
 
 	/*
-	 * <verb> <noun>
-	 *
-	 * u8: verb
-	 * u8: count
-	 *     u8:   noun
-	 *     le16: action
-	 */
+	* <verb> <noun>
+	*
+	* u8: verb
+	* u8: count
+	*     u8:   noun
+	*     le16: action
+	*/
 	file_buf_set_pos(fb, game->info->header.addr_actions_vn);
 	while (1) {
 		/* 2-byte header */
@@ -359,20 +454,20 @@ static void parse_action_table_vn(struct comprehend_game *game,
 	}
 }
 
-static void parse_action_table_v(struct comprehend_game *game,
-                                 struct file_buf *fb, size_t *index) {
+static void parse_action_table_v(struct comprehend_game * game,
+	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, nr_funcs;
 	uint16 func;
 	int i;
 
 	/*
-	 * <verb> [<noun>]
-	 *
-	 * u8: verb
-	 * u8: count (num actions)
-	 *     le16: action
-	 */
+	* <verb> [<noun>]
+	*
+	* u8: verb
+	* u8: count (num actions)
+	*     le16: action
+	*/
 	file_buf_set_pos(fb, game->info->header.addr_actions_v);
 	while (1) {
 		file_buf_get_u8(fb, &verb);
@@ -388,9 +483,9 @@ static void parse_action_table_v(struct comprehend_game *game,
 		action->word_type[0] = WORD_TYPE_VERB;
 
 		/*
-		 * Default actions can have more than one function, but only
-		 * the first one actually seems to be used?
-		 */
+		* Default actions can have more than one function, but only
+		* the first one actually seems to be used?
+		*/
 		file_buf_get_u8(fb, &nr_funcs);
 		for (i = 0; i < nr_funcs; i++) {
 			file_buf_get_le16(fb, &func);
@@ -402,8 +497,8 @@ static void parse_action_table_v(struct comprehend_game *game,
 	}
 }
 
-static void parse_action_table(struct comprehend_game *game,
-                               struct file_buf *fb) {
+static void parse_action_table(struct comprehend_game * game,
+	                            struct file_buf * fb) {
 	game->info->nr_actions = 0;
 
 	if (game->info->comprehend_version == 1) {
@@ -420,7 +515,7 @@ static void parse_action_table(struct comprehend_game *game,
 	parse_action_table_v(game, fb, &game->info->nr_actions);
 }
 
-static void parse_dictionary(struct comprehend_game *game, struct file_buf *fb) {
+static void parse_dictionary(struct comprehend_game * game, struct file_buf * fb) {
 	word *words;
 	uint i, j;
 
@@ -431,19 +526,19 @@ static void parse_dictionary(struct comprehend_game *game, struct file_buf *fb)
 	for (i = 0; i < game->info->nr_words; i++) {
 		words = &game->info->words[i];
 
-		file_buf_get_data(fb, words->word, 6);
+		file_buf_get_data(fb, words->_word, 6);
 
 		/* Decode */
 		for (j = 0; j < 6; j++)
-			words->word[j] ^= 0x8a;
-		words->word[6] = '\0';
+			words->_word[j] ^= 0x8a;
+		words->_word[6] = '\0';
 
-		file_buf_get_u8(fb, &words->index);
-		file_buf_get_u8(fb, &words->type);
+		file_buf_get_u8(fb, &words->_index);
+		file_buf_get_u8(fb, &words->_type);
 	}
 }
 
-static void parse_word_map(struct comprehend_game *game, struct file_buf *fb) {
+static void parse_word_map(struct comprehend_game * game, struct file_buf * fb) {
 	struct word_map *map;
 	uint8 index, type, dummy;
 	uint i;
@@ -452,9 +547,9 @@ static void parse_word_map(struct comprehend_game *game, struct file_buf *fb) {
 	file_buf_set_pos(fb, game->info->header.addr_word_map);
 
 	/*
-	 * Parse the word pair table. Each entry has a pair of dictionary
-	 * index/type values for a first and second word.
-	 */
+	* Parse the word pair table. Each entry has a pair of dictionary
+	* index/type values for a first and second word.
+	*/
 	while (1) {
 		map = &game->info->word_map[game->info->nr_word_maps];
 
@@ -479,10 +574,10 @@ static void parse_word_map(struct comprehend_game *game, struct file_buf *fb) {
 	file_buf_get_u8(fb, &dummy);
 
 	/*
-	 * Parse the target word table. Each entry has a dictionary
-	 * index/type. The first and second words from above map to the
-	 * target word here. E.g. 'go north' -> 'north'.
-	 */
+	* Parse the target word table. Each entry has a dictionary
+	* index/type. The first and second words from above map to the
+	* target word here. E.g. 'go north' -> 'north'.
+	*/
 	for (i = 0; i < game->info->nr_word_maps; i++) {
 		map = &game->info->word_map[i];
 
@@ -491,7 +586,7 @@ static void parse_word_map(struct comprehend_game *game, struct file_buf *fb) {
 	}
 }
 
-static void parse_items(struct comprehend_game *game, struct file_buf *fb) {
+static void parse_items(struct comprehend_game * game, struct file_buf * fb) {
 	size_t nr_items = game->info->header.nr_items;
 
 	/* Item descriptions */
@@ -501,7 +596,7 @@ static void parse_items(struct comprehend_game *game, struct file_buf *fb) {
 	if (game->info->comprehend_version == 2) {
 		/* Comprehend version 2 adds long string descriptions */
 		file_buf_set_pos(fb, game->info->header.addr_item_strings +
-		                         (game->info->header.nr_items * sizeof(uint16)));
+			                        (game->info->header.nr_items * sizeof(uint16)));
 		file_buf_get_array_le16(fb, 0, game->info->item, long_string, nr_items);
 	}
 
@@ -522,7 +617,7 @@ static void parse_items(struct comprehend_game *game, struct file_buf *fb) {
 	file_buf_get_array_u8(fb, 0, game->info->item, graphic, nr_items);
 }
 
-static void parse_rooms(struct comprehend_game *game, struct file_buf *fb) {
+static void parse_rooms(struct comprehend_game * game, struct file_buf * fb) {
 	size_t nr_rooms = game->info->nr_rooms;
 	int i;
 
@@ -530,7 +625,7 @@ static void parse_rooms(struct comprehend_game *game, struct file_buf *fb) {
 	for (i = 0; i < NR_DIRECTIONS; i++) {
 		file_buf_set_pos(fb, game->info->header.room_direction_table[i]);
 		file_buf_get_array_u8(fb, 1, game->info->rooms,
-		                      direction[i], nr_rooms);
+			                    direction[i], nr_rooms);
 	}
 
 	/* Room string descriptions */
@@ -546,7 +641,7 @@ static void parse_rooms(struct comprehend_game *game, struct file_buf *fb) {
 	file_buf_get_array_u8(fb, 1, game->info->rooms, graphic, nr_rooms);
 }
 
-static uint64 string_get_chunk(uint8 *string) {
+static uint64 string_get_chunk(uint8 * string) {
 	uint64 c, val = 0;
 	int i;
 
@@ -567,11 +662,11 @@ static char decode_string_elem(uint8 c, bool capital, bool special) {
 			c = charset[c];
 			if (capital) {
 				/*
-				 * A capital space means that the character
-				 * is dynamically replaced by at runtime.
-				 * We use the character '@' since it cannot
-				 * otherwise appear in strings.
-				 */
+				* A capital space means that the character
+				* is dynamically replaced by at runtime.
+				* We use the character '@' since it cannot
+				* otherwise appear in strings.
+				*/
 				if (c == ' ')
 					return '@';
 				return c - 0x20;
@@ -587,14 +682,14 @@ static char decode_string_elem(uint8 c, bool capital, bool special) {
 }
 
 /*
- * Game strings are stored using 5-bit characters. By default a character
- * value maps to the lower-case letter table. If a character has the value 0x1e
- * then the next character is upper-case. An upper-case space is used to
- * specify that the character should be replaced at runtime (like a '%s'
- * specifier). If a character has the value 0x1f then the next character is
- * taken from the symbols table.
- */
-static char *parse_string(struct file_buf *fb) {
+* Game strings are stored using 5-bit characters. By default a character
+* value maps to the lower-case letter table. If a character has the value 0x1e
+* then the next character is upper-case. An upper-case space is used to
+* specify that the character should be replaced at runtime (like a '%s'
+* specifier). If a character has the value 0x1f then the next character is
+* taken from the symbols table.
+*/
+static char *parse_string(struct file_buf * fb) {
 	bool capital_next = false, special_next = false;
 	unsigned i, j, k = 0;
 	uint64 chunk;
@@ -628,7 +723,7 @@ static char *parse_string(struct file_buf *fb) {
 				special_next = true;
 			} else {
 				c = decode_string_elem(elem, capital_next,
-				                       special_next);
+					                    special_next);
 				special_next = false;
 				capital_next = false;
 				string[k++] = c;
@@ -643,8 +738,8 @@ done:
 	return string;
 }
 
-static void parse_string_table(struct file_buf *fb, unsigned start_addr,
-                               uint32 end_addr, struct string_table *table) {
+static void parse_string_table(struct file_buf * fb, unsigned start_addr,
+	                            uint32 end_addr, struct string_table *table) {
 	file_buf_set_pos(fb, start_addr);
 	while (1) {
 		table->strings[table->nr_strings++] = parse_string(fb);
@@ -653,14 +748,14 @@ static void parse_string_table(struct file_buf *fb, unsigned start_addr,
 	}
 }
 
-static void parse_variables(struct comprehend_game *game, struct file_buf *fb) {
+static void parse_variables(struct comprehend_game * game, struct file_buf * fb) {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(game->info->variable); i++)
 		file_buf_get_le16(fb, &game->info->variable[i]);
 }
 
-static void parse_flags(struct comprehend_game *game, struct file_buf *fb) {
+static void parse_flags(struct comprehend_game * game, struct file_buf * fb) {
 	int i, bit, flag_index = 0;
 	uint8 bitmask;
 
@@ -673,8 +768,8 @@ static void parse_flags(struct comprehend_game *game, struct file_buf *fb) {
 	}
 }
 
-static void parse_replace_words(struct comprehend_game *game,
-                                struct file_buf *fb) {
+static void parse_replace_words(struct comprehend_game * game,
+	                            struct file_buf * fb) {
 	uint16 dummy;
 	size_t len;
 	bool eof;
@@ -700,10 +795,10 @@ static void parse_replace_words(struct comprehend_game *game,
 }
 
 /*
- * The main game data file header has the offsets for where each bit of
- * game data is. The offsets have a magic constant value added to them.
- */
-static void parse_header(struct comprehend_game *game, struct file_buf *fb) {
+* The main game data file header has the offsets for where each bit of
+* game data is. The offsets have a magic constant value added to them.
+*/
+static void parse_header(struct comprehend_game * game, struct file_buf * fb) {
 	struct game_header *header = &game->info->header;
 	uint16 dummy, addr_dictionary_end;
 	uint8 dummy8;
@@ -736,10 +831,10 @@ static void parse_header(struct comprehend_game *game, struct file_buf *fb) {
 	parse_header_le16(fb, &dummy);
 
 	/*
-	 * Action tables.
-	 *
-	 * Layout depends on the comprehend version.
-	 */
+	* Action tables.
+	*
+	* Layout depends on the comprehend version.
+	*/
 	if (game->info->comprehend_version == 1) {
 		parse_header_le16(fb, &header->addr_actions_vvnn);
 		parse_header_le16(fb, &header->addr_actions_unknown);
@@ -777,10 +872,10 @@ static void parse_header(struct comprehend_game *game, struct file_buf *fb) {
 	parse_header_le16(fb, &header->room_graphics_table);
 
 	/*
-	 * Objects.
-	 *
-	 * Layout is dependent on comprehend version.
-	 */
+	* Objects.
+	*
+	* Layout is dependent on comprehend version.
+	*/
 	if (game->info->comprehend_version == 1) {
 		parse_header_le16(fb, &header->addr_item_locations);
 		parse_header_le16(fb, &header->addr_item_flags);
@@ -789,7 +884,7 @@ static void parse_header(struct comprehend_game *game, struct file_buf *fb) {
 		parse_header_le16(fb, &header->addr_item_graphics);
 
 		header->nr_items = (header->addr_item_word -
-		                    header->addr_item_flags);
+			                header->addr_item_flags);
 
 	} else {
 		parse_header_le16(fb, &header->addr_item_strings);
@@ -799,7 +894,7 @@ static void parse_header(struct comprehend_game *game, struct file_buf *fb) {
 		parse_header_le16(fb, &header->addr_item_graphics);
 
 		header->nr_items = (header->addr_item_flags -
-		                    header->addr_item_locations);
+			                header->addr_item_locations);
 	}
 
 	parse_header_le16(fb, &header->addr_strings);
@@ -814,15 +909,15 @@ static void parse_header(struct comprehend_game *game, struct file_buf *fb) {
 	parse_flags(game, fb);
 
 	game->info->nr_rooms = header->room_direction_table[DIRECTION_SOUTH] -
-	                       header->room_direction_table[DIRECTION_NORTH];
+		                    header->room_direction_table[DIRECTION_NORTH];
 
 	game->info->nr_words = (addr_dictionary_end -
-	                        header->addr_dictionary) /
-	                       8;
+		                    header->addr_dictionary) /
+		                    8;
 }
 
-static void load_extra_string_file(comprehend_game *game,
-                                   string_file *string_file) {
+static void load_extra_string_file(comprehend_game * game,
+	                                string_file * string_file) {
 	struct file_buf fb;
 	unsigned end;
 
@@ -834,12 +929,12 @@ static void load_extra_string_file(comprehend_game *game,
 		end = fb.size;
 
 	parse_string_table(&fb, string_file->base_offset,
-	                   end, &game->info->strings2);
+		                end, &game->info->strings2);
 
 	file_buf_unmap(&fb);
 }
 
-static void load_extra_string_files(comprehend_game *game) {
+static void load_extra_string_files(comprehend_game * game) {
 	int i;
 
 	memset(&game->info->strings2, 0, sizeof(game->info->strings2));
@@ -857,7 +952,7 @@ static void load_extra_string_files(comprehend_game *game) {
 	}
 }
 
-static void load_game_data(struct comprehend_game *game) {
+static void load_game_data(struct comprehend_game * game) {
 	struct file_buf fb;
 
 	memset(game->info, 0, sizeof(*game->info));
@@ -870,8 +965,8 @@ static void load_game_data(struct comprehend_game *game) {
 	parse_word_map(game, &fb);
 	memset(&game->info->strings, 0, sizeof(game->info->strings));
 	parse_string_table(&fb, game->info->header.addr_strings,
-	                   game->info->header.addr_strings_end,
-	                   &game->info->strings);
+		                game->info->header.addr_strings_end,
+		                &game->info->strings);
 	load_extra_string_files(game);
 	parse_vm(game, &fb);
 	parse_action_table(game, &fb);
@@ -880,7 +975,7 @@ static void load_game_data(struct comprehend_game *game) {
 	file_buf_unmap(&fb);
 }
 
-void comprehend_load_game(struct comprehend_game *game) {
+void comprehend_load_game(struct comprehend_game * game) {
 	/* Load the main game data file */
 	load_game_data(game);
 
@@ -895,13 +990,13 @@ void comprehend_load_game(struct comprehend_game *game) {
 }
 
 #ifdef TODO
-static void patch_string_desc(uint16 *desc) {
+static void patch_string_desc(uint16 * desc) {
 	/*
-	 * String descriptors in the save file sometimes are encoded as a
-	 * table/index value like the instruction opcodes used, and other
-	 * times the are encoded as an absolute index. We fix them up to
-	 * all be the former type.
-	 */
+	* String descriptors in the save file sometimes are encoded as a
+	* table/index value like the instruction opcodes used, and other
+	* times the are encoded as an absolute index. We fix them up to
+	* all be the former type.
+	*/
 	if (!(*desc & 0x8000) && *desc >= 0x100) {
 		*desc -= 0x100;
 		*desc |= 0x8100;
@@ -909,7 +1004,7 @@ static void patch_string_desc(uint16 *desc) {
 }
 #endif
 
-void comprehend_save_game(struct comprehend_game *game, const char *filename) {
+void comprehend_save_game(struct comprehend_game * game, const char *filename) {
 #ifdef TODO
 	FILE *fd;
 	uint8 bitmask;
@@ -919,7 +1014,7 @@ void comprehend_save_game(struct comprehend_game *game, const char *filename) {
 	fd = fopen(filename, "w");
 	if (!fd) {
 		printf("Error: Failed to open save file '%s': %s\n",
-		       filename, strerror(errno));
+			    filename, strerror(errno));
 		return;
 	}
 
@@ -946,10 +1041,10 @@ void comprehend_save_game(struct comprehend_game *game, const char *filename) {
 	}
 
 	/*
-	 * Re-Comprehend doesn't need this since the number of items is
-	 * determined by the currently loaded game, but the original games
-	 * won't load the file properly without it.
-	 */
+	* Re-Comprehend doesn't need this since the number of items is
+	* determined by the currently loaded game, but the original games
+	* won't load the file properly without it.
+	*/
 	file_buf_put_skip(fd, 0x12c - ftell(fd));
 	file_buf_put_u8(fd, nr_items);
 
@@ -960,19 +1055,19 @@ void comprehend_save_game(struct comprehend_game *game, const char *filename) {
 
 	/* Rooms */
 	file_buf_put_array_le16(fd, 1, game->info->rooms,
-	                        string_desc, nr_rooms);
+		                    string_desc, nr_rooms);
 	for (dir = 0; dir < NR_DIRECTIONS; dir++)
 		file_buf_put_array_u8(fd, 1, game->info->rooms,
-		                      direction[dir], nr_rooms);
+			                    direction[dir], nr_rooms);
 	file_buf_put_array_u8(fd, 1, game->info->rooms, flags, nr_rooms);
 	file_buf_put_array_u8(fd, 1, game->info->rooms, graphic, nr_rooms);
 
 	/*
-	 * Objects
-	 *
-	 * Layout differs depending on Comprehend version. Version 2 also
-	 * has long string descriptions for each object.
-	 */
+	* Objects
+	*
+	* Layout differs depending on Comprehend version. Version 2 also
+	* has long string descriptions for each object.
+	*/
 	file_buf_put_array_le16(fd, 0, game->info->item, string_desc, nr_items);
 	if (game->info->comprehend_version == 1) {
 		file_buf_put_array_u8(fd, 0, game->info->item, room, nr_items);
@@ -993,7 +1088,7 @@ void comprehend_save_game(struct comprehend_game *game, const char *filename) {
 #endif
 }
 
-void comprehend_restore_game(struct comprehend_game *game, const char *filename) {
+void comprehend_restore_game(struct comprehend_game * game, const char *filename) {
 #ifdef TODO
 	struct file_buf fb;
 	size_t nr_rooms, nr_items;
@@ -1002,7 +1097,7 @@ void comprehend_restore_game(struct comprehend_game *game, const char *filename)
 	err = file_buf_map_may_fail(filename, &fb);
 	if (err) {
 		printf("Error: Failed to open save file '%s': %s\n",
-		       filename, strerror(-err));
+			    filename, strerror(-err));
 		return;
 	}
 
@@ -1026,19 +1121,19 @@ void comprehend_restore_game(struct comprehend_game *game, const char *filename)
 
 	/* Restore rooms */
 	file_buf_get_array_le16(&fb, 1, game->info->rooms,
-	                        string_desc, nr_rooms);
+		                    string_desc, nr_rooms);
 	for (dir = 0; dir < NR_DIRECTIONS; dir++)
 		file_buf_get_array_u8(&fb, 1, game->info->rooms,
-		                      direction[dir], nr_rooms);
+			                    direction[dir], nr_rooms);
 	file_buf_get_array_u8(&fb, 1, game->info->rooms, flags, nr_rooms);
 	file_buf_get_array_u8(&fb, 1, game->info->rooms, graphic, nr_rooms);
 
 	/*
-	 * Restore objects
-	 *
-	 * Layout differs depending on Comprehend version. Version 2 also
-	 * has long string descriptions for each object.
-	 */
+	* Restore objects
+	*
+	* Layout differs depending on Comprehend version. Version 2 also
+	* has long string descriptions for each object.
+	*/
 	file_buf_get_array_le16(&fb, 0, game->info->item, string_desc, nr_items);
 	if (game->info->comprehend_version == 1) {
 		file_buf_get_array_u8(&fb, 0, game->info->item, room, nr_items);
@@ -1054,9 +1149,9 @@ void comprehend_restore_game(struct comprehend_game *game, const char *filename)
 	}
 
 	/*
-	 * FIXME - The save file has some string descriptors masked with 0x8000.
-	 *         Not sure what this means, so just mask it out for now.
-	 */
+	* FIXME - The save file has some string descriptors masked with 0x8000.
+	*         Not sure what this means, so just mask it out for now.
+	*/
 	for (i = 1; i <= nr_rooms; i++)
 		patch_string_desc(&game->info->rooms[i].string_desc);
 	for (i = 0; i < nr_items; i++)
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index d48b6f68fe..74636f5319 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -50,6 +50,8 @@ struct function_state {
 	bool _and;
 	bool in_command;
 	bool executed;
+
+	function_state();
 };
 
 struct room {
@@ -57,6 +59,8 @@ struct room {
 	uint8 flags;
 	uint8 graphic;
 	uint16 string_desc;
+
+	room();
 };
 
 struct item {
@@ -66,23 +70,31 @@ struct item {
 	uint8 flags;
 	uint8 word;
 	uint8 graphic;
+
+	item();
 };
 
 struct word {
-	char word[7];
-	uint8 index;
-	uint8 type;
+	char _word[7];
+	uint8 _index;
+	uint8 _type;
+
+	word();
 };
 
 struct word_index {
 	uint8 index;
 	uint8 type;
+
+	word_index() : index(0), type(0) {}
 };
 
 struct word_map {
 	/* <word[0]>, <word[1]> == <word[2]> */
-	struct word_index word[3];
+	word_index word[3];
 	uint8 flags;
+
+	word_map() : flags(0) {}
 };
 
 struct action {
@@ -92,6 +104,8 @@ struct action {
 	uint8 word[4];
 	uint8 word_type[4];
 	uint16 function;
+
+	action();
 };
 
 struct instruction {
@@ -99,16 +113,22 @@ struct instruction {
 	size_t nr_operands;
 	uint8 operand[3];
 	bool is_command;
+
+	instruction();
 };
 
 struct function {
-	struct instruction instructions[0x100];
+	instruction instructions[0x100];
 	size_t nr_instructions;
+
+	function() : nr_instructions(0) {}
 };
 
 struct string_table {
 	char *strings[0xffff];
 	size_t nr_strings;
+
+	string_table();
 };
 
 struct game_header {
@@ -142,16 +162,18 @@ struct game_header {
 	uint16 addr_actions_v;
 
 	uint16 addr_vm; // FIXME - functions
+
+	game_header();
 };
 
 struct game_info {
-	struct game_header header;
+	game_header header;
 
 	unsigned comprehend_version;
 
 	uint8 start_room;
 
-	struct room rooms[0x100];
+	room rooms[0x100];
 	size_t nr_rooms;
 	uint8 current_room;
 
@@ -183,6 +205,8 @@ struct game_info {
 
 	uint8 current_replace_word;
 	unsigned update_flags;
+
+	game_info();
 };
 
 struct string_file {
@@ -191,8 +215,7 @@ struct string_file {
 	uint32 end_offset;
 
 	string_file() : filename(nullptr), base_offset(0), end_offset(0) {}
-	string_file(const char *fname, uint32 baseOfs, uint32 endO = 0) :
-		filename(fname), base_offset(baseOfs), end_offset(endO) {
+	string_file(const char *fname, uint32 baseOfs, uint32 endO = 0) : filename(fname), base_offset(baseOfs), end_offset(endO) {
 	}
 };
 


Commit: 16b1713afd6e39d75103de93e747c39e2006c0fa
    https://github.com/scummvm/scummvm/commit/16b1713afd6e39d75103de93e747c39e2006c0fa
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Change comprehend_game to ComprehendGame

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/detection.cpp
    engines/glk/comprehend/detection_tables.h
    engines/glk/comprehend/dictionary.cpp
    engines/glk/comprehend/dictionary.h
    engines/glk/comprehend/dump_game_data.cpp
    engines/glk/comprehend/dump_game_data.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_cc.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_oo.h
    engines/glk/comprehend/game_tm.cpp
    engines/glk/comprehend/game_tm.h
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/game_tr.h
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_data.h
    engines/glk/comprehend/opcode_map.cpp
    engines/glk/comprehend/opcode_map.h
    engines/glk/comprehend/recomprehend.cpp
    engines/glk/comprehend/strings.cpp
    engines/glk/comprehend/strings.h


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index cf1eb2933d..e2a0a09bbb 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -70,7 +70,7 @@ int main(int argc, char **argv) {
 	    {NULL, 0, 0, 0},
 	};
 	const char *short_opts = "dD:pgfw:h:?";
-	struct comprehend_game *game;
+	ComprehendGame *game;
 	const char *game_name, *game_dir;
 	unsigned dump_flags = 0;
 	int i, c, opt_index;
@@ -153,7 +153,7 @@ void Comprehend::runGame() {
 	initialize();
 
 	// Lookup game
-	comprehend_game *game = createGame();
+	ComprehendGame *game = createGame();
 
 	comprehend_load_game(game);
 	comprehend_play_game(game);
@@ -173,7 +173,7 @@ void Comprehend::deinitialize() {
 	glk_window_close(_textBufferWindow);
 }
 
-comprehend_game *Comprehend::createGame() {
+ComprehendGame *Comprehend::createGame() {
 	if (_gameDescription._gameId == "crimsoncrown")
 		return new CrimsonCrownGame();
 	if (_gameDescription._gameId == "ootopis")
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 49b80efdb6..6b83e8896c 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -27,6 +27,7 @@
 #include "glk/glk_api.h"
 #include "glk/window_graphics.h"
 #include "glk/window_text_buffer.h"
+#include "glk/comprehend/game.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -38,7 +39,6 @@ namespace Comprehend {
 
 #define PATH_MAX 256
 
-struct comprehend_game;
 struct game_info;
 struct game_state;
 
@@ -68,7 +68,7 @@ private:
 	 */
 	void deinitialize();
 
-	comprehend_game *createGame();
+	ComprehendGame *createGame();
 
 public:
 	/**
diff --git a/engines/glk/comprehend/detection.cpp b/engines/glk/comprehend/detection.cpp
index ca5074a17c..8624a3b7b9 100644
--- a/engines/glk/comprehend/detection.cpp
+++ b/engines/glk/comprehend/detection.cpp
@@ -31,12 +31,12 @@ namespace Glk {
 namespace Comprehend {
 
 void ComprehendMetaEngine::getSupportedGames(PlainGameList &games) {
-	for (const PlainGameDescriptor *pd = COMPREHEND_GAME_LIST; pd->gameId; ++pd)
+	for (const PlainGameDescriptor *pd = ComprehendGame_LIST; pd->gameId; ++pd)
 		games.push_back(*pd);
 }
 
 GameDescriptor ComprehendMetaEngine::findGame(const char *gameId) {
-	for (const PlainGameDescriptor *pd = COMPREHEND_GAME_LIST; pd->gameId; ++pd) {
+	for (const PlainGameDescriptor *pd = ComprehendGame_LIST; pd->gameId; ++pd) {
 		if (!strcmp(gameId, pd->gameId))
 			return *pd;
 	}
@@ -64,7 +64,7 @@ bool ComprehendMetaEngine::detectGames(const Common::FSList &fslist, DetectedGam
 		gameFile.close();
 
 		// Iterate through the known games
-		const ComprehendDetectionEntry *p = COMPREHEND_GAMES;
+		const ComprehendDetectionEntry *p = ComprehendGameS;
 		for (; p->_gameId; ++p) {
 			if (filename.equalsIgnoreCase(p->_filename)) {
 				// Check for an md5 match
@@ -81,7 +81,7 @@ bool ComprehendMetaEngine::detectGames(const Common::FSList &fslist, DetectedGam
 }
 
 void ComprehendMetaEngine::detectClashes(Common::StringMap &map) {
-	for (const PlainGameDescriptor *pd = COMPREHEND_GAME_LIST; pd->gameId; ++pd) {
+	for (const PlainGameDescriptor *pd = ComprehendGame_LIST; pd->gameId; ++pd) {
 		if (map.contains(pd->gameId))
 			error("Duplicate game Id found - %s", pd->gameId);
 		map[pd->gameId] = "";
diff --git a/engines/glk/comprehend/detection_tables.h b/engines/glk/comprehend/detection_tables.h
index cd884b90b7..5b744f86b2 100644
--- a/engines/glk/comprehend/detection_tables.h
+++ b/engines/glk/comprehend/detection_tables.h
@@ -27,7 +27,7 @@
 namespace Glk {
 namespace Comprehend {
 
-const PlainGameDescriptor COMPREHEND_GAME_LIST[] = {
+const PlainGameDescriptor ComprehendGame_LIST[] = {
     {"crimsoncrown", "Crimson Crown"},
     {"ootopis", "OO-Topos"},
     {"transylvania", "Transylvania"},
@@ -41,7 +41,7 @@ struct ComprehendDetectionEntry {
 	const char *const _md5;
 };
 
-const ComprehendDetectionEntry COMPREHEND_GAMES[] = {
+const ComprehendDetectionEntry ComprehendGameS[] = {
     // DOS games
     {"crimsoncrown", "cc1.gda", "f2abf019675ac5c9bcfd81032bc7787b"},
     {"transylvania", "tr.gda", "22e08633eea02ceee49b909dfd982d22"},
diff --git a/engines/glk/comprehend/dictionary.cpp b/engines/glk/comprehend/dictionary.cpp
index cbab1ff0c4..4899476f89 100644
--- a/engines/glk/comprehend/dictionary.cpp
+++ b/engines/glk/comprehend/dictionary.cpp
@@ -37,7 +37,7 @@ static bool word_match(struct word *word, const char *string)
 	return strncmp(word->_word, string, strlen(word->_word)) == 0;
 }
 
-word *dict_find_word_by_string(struct comprehend_game *game,
+word *dict_find_word_by_string(ComprehendGame *game,
 				      const char *string)
 {
 	uint i;
@@ -52,7 +52,7 @@ word *dict_find_word_by_string(struct comprehend_game *game,
 	return NULL;
 }
 
-struct word *dict_find_word_by_index_type(struct comprehend_game *game,
+struct word *dict_find_word_by_index_type(ComprehendGame *game,
 					  uint8 index, uint8 type)
 {
 	uint i;
@@ -66,7 +66,7 @@ struct word *dict_find_word_by_index_type(struct comprehend_game *game,
 	return NULL;
 }
 
-struct word *find_dict_word_by_index(struct comprehend_game *game,
+struct word *find_dict_word_by_index(ComprehendGame *game,
 				     uint8 index, uint8 type_mask)
 {
 	uint i;
@@ -80,7 +80,7 @@ struct word *find_dict_word_by_index(struct comprehend_game *game,
 	return NULL;
 }
 
-bool dict_match_index_type(struct comprehend_game *game, const char *word,
+bool dict_match_index_type(ComprehendGame *game, const char *word,
 			   uint8 index, uint8 type_mask)
 {
 	uint i;
diff --git a/engines/glk/comprehend/dictionary.h b/engines/glk/comprehend/dictionary.h
index 8efa401473..cdf4add8a8 100644
--- a/engines/glk/comprehend/dictionary.h
+++ b/engines/glk/comprehend/dictionary.h
@@ -26,16 +26,16 @@
 namespace Glk {
 namespace Comprehend {
 
-struct comprehend_game;
+class ComprehendGame;
 struct word;
 
-struct word *find_dict_word_by_index(struct comprehend_game *game,
+struct word *find_dict_word_by_index(ComprehendGame *game,
 				     uint8 index, uint8 type_mask);
-struct word *dict_find_word_by_index_type(struct comprehend_game *game,
+struct word *dict_find_word_by_index_type(ComprehendGame *game,
 					  uint8 index, uint8 type);
-struct word *dict_find_word_by_string(struct comprehend_game *game,
+struct word *dict_find_word_by_string(ComprehendGame *game,
 				      const char *string);
-bool dict_match_index_type(struct comprehend_game *game, const char *word,
+bool dict_match_index_type(ComprehendGame *game, const char *word,
 			   uint8 index, uint8 type_mask);
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
index 6ef5a66478..52dde56f89 100644
--- a/engines/glk/comprehend/dump_game_data.cpp
+++ b/engines/glk/comprehend/dump_game_data.cpp
@@ -113,7 +113,7 @@ static const char *opcode_names[] = {
 #endif
 };
 
-void dump_instruction(struct comprehend_game *game,
+void dump_instruction(ComprehendGame *game,
 		      struct function_state *func_state,
 		      struct instruction *instr)
 {
@@ -167,7 +167,7 @@ void dump_instruction(struct comprehend_game *game,
 	debugN("\n");
 }
 
-static void dump_functions(struct comprehend_game *game)
+static void dump_functions(ComprehendGame *game)
 {
 	struct function *func;
 	uint i, j;
@@ -183,7 +183,7 @@ static void dump_functions(struct comprehend_game *game)
 	}
 }
 
-static void dump_action_table(struct comprehend_game *game)
+static void dump_action_table(ComprehendGame *game)
 {
 	struct action *action;
 	struct word *word;
@@ -240,7 +240,7 @@ static int word_index_compare(const void *a, const void *b)
 	return 0;
 }
 
-static void dump_dictionary(struct comprehend_game *game)
+static void dump_dictionary(ComprehendGame *game)
 {
 	word *dictionary;
 	word *words;
@@ -263,7 +263,7 @@ static void dump_dictionary(struct comprehend_game *game)
 	free(dictionary);
 }
 
-static void dump_word_map(struct comprehend_game *game)
+static void dump_word_map(ComprehendGame *game)
 {
 	struct word *word[3];
 	char str[3][6];
@@ -290,7 +290,7 @@ static void dump_word_map(struct comprehend_game *game)
 	}
 }
 
-static void dump_rooms(struct comprehend_game *game)
+static void dump_rooms(ComprehendGame *game)
 {
 	struct room *room;
 	uint i;
@@ -317,7 +317,7 @@ static void dump_rooms(struct comprehend_game *game)
 	}
 }
 
-static void dump_items(struct comprehend_game *game)
+static void dump_items(ComprehendGame *game)
 {
 	struct item *item;
 	uint i, j;
@@ -356,21 +356,21 @@ static void dump_string_table(struct string_table *table)
 		debugN("[%.4x] %s\n", i, table->strings[i]);
 }
 
-static void dump_game_data_strings(struct comprehend_game *game)
+static void dump_game_data_strings(ComprehendGame *game)
 {
 	debugN("Main string table (%zd entries)\n",
 	       game->info->strings.nr_strings);
 	dump_string_table(&game->info->strings);
 }
 
-static void dump_extra_strings(struct comprehend_game *game)
+static void dump_extra_strings(ComprehendGame *game)
 {
 	debugN("Extra strings (%zd entries)\n",
 	       game->info->strings2.nr_strings);
 	dump_string_table(&game->info->strings2);
 }
 
-static void dump_replace_words(struct comprehend_game *game)
+static void dump_replace_words(ComprehendGame *game)
 {
 	uint i;
 
@@ -380,7 +380,7 @@ static void dump_replace_words(struct comprehend_game *game)
 		debugN("  [%.2x] %s\n", i + 1, game->info->replace_words[i]);
 }
 
-static void dump_header(struct comprehend_game *game)
+static void dump_header(ComprehendGame *game)
 {
 	struct game_header *header = &game->info->header;
 	uint16 *dir_table = header->room_direction_table;
@@ -418,7 +418,7 @@ static void dump_header(struct comprehend_game *game)
 	debugN("  string table end:     %.4x\n", header->addr_strings_end);
 }
 
-typedef void (*dump_func_t)(struct comprehend_game *game);
+typedef void (*dump_func_t)(ComprehendGame *game);
 
 struct dumper {
 	dump_func_t	dump_func;
@@ -438,7 +438,7 @@ static struct dumper dumpers[] = {
 	{dump_replace_words,		DUMP_REPLACE_WORDS},
 };
 
-void dump_game_data(struct comprehend_game *game, unsigned flags)
+void dump_game_data(ComprehendGame *game, unsigned flags)
 {
 	int i;
 
diff --git a/engines/glk/comprehend/dump_game_data.h b/engines/glk/comprehend/dump_game_data.h
index 361a47f969..bb91757d15 100644
--- a/engines/glk/comprehend/dump_game_data.h
+++ b/engines/glk/comprehend/dump_game_data.h
@@ -26,7 +26,7 @@
 namespace Glk {
 namespace Comprehend {
 
-struct comprehend_game;
+class ComprehendGame;
 struct function_state;
 struct instruction;
 
@@ -42,10 +42,10 @@ struct instruction;
 #define DUMP_HEADER (1 << 9)
 #define DUMP_ALL (~0U)
 
-void dump_instruction(struct comprehend_game *game,
+void dump_instruction(ComprehendGame *game,
                       struct function_state *func_state,
                       struct instruction *instr);
-void dump_game_data(struct comprehend_game *game, unsigned flags);
+void dump_game_data(ComprehendGame *game, unsigned flags);
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index c55145f7a2..862ebeaa03 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -43,7 +43,7 @@ struct winsize {
 };
 static struct winsize console_winsize;
 
-comprehend_game::comprehend_game() : game_name(nullptr),
+ComprehendGame::ComprehendGame() : game_name(nullptr),
                                      short_name(nullptr),
                                      game_data_file(nullptr),
                                      save_game_file_fmt(nullptr),
@@ -52,7 +52,7 @@ comprehend_game::comprehend_game() : game_name(nullptr),
 	info = (game_info *)malloc(sizeof(*info));
 }
 
-comprehend_game::~comprehend_game() {
+ComprehendGame::~ComprehendGame() {
 	free(info);
 }
 
@@ -72,7 +72,7 @@ int console_get_key(void) {
 	return c;
 }
 
-void console_println(comprehend_game *game, const char *text) {
+void console_println(ComprehendGame *game, const char *text) {
 	const char *replace, *word = nullptr, *p = text;
 	char bad_word[64];
 	size_t line_length = 0;
@@ -159,7 +159,7 @@ void console_println(comprehend_game *game, const char *text) {
 	printf("\n");
 }
 
-static struct room *get_room(comprehend_game *game, uint16 index) {
+static struct room *get_room(ComprehendGame *game, uint16 index) {
 	/* Room zero is reserved for the players inventory */
 	if (index == 0)
 		fatal_error("Room index 0 (player inventory) is invalid");
@@ -170,14 +170,14 @@ static struct room *get_room(comprehend_game *game, uint16 index) {
 	return &game->info->rooms[index];
 }
 
-struct item *get_item(comprehend_game *game, uint16 index) {
+struct item *get_item(ComprehendGame *game, uint16 index) {
 	if (index >= game->info->header.nr_items)
 		fatal_error("Bad item %d\n", index);
 
 	return &game->info->item[index];
 }
 
-void game_save(comprehend_game *game) {
+void game_save(ComprehendGame *game) {
 	char filename[32];
 	int c;
 
@@ -197,7 +197,7 @@ void game_save(comprehend_game *game) {
 	comprehend_save_game(game, filename);
 }
 
-void game_restore(comprehend_game *game) {
+void game_restore(ComprehendGame *game) {
 	char filename[32];
 	int c;
 
@@ -219,7 +219,7 @@ void game_restore(comprehend_game *game) {
 	game->info->update_flags = UPDATE_ALL;
 }
 
-void game_restart(comprehend_game *game) {
+void game_restart(ComprehendGame *game) {
 	console_println(game, string_lookup(game, game->strings->game_restart));
 	console_get_key();
 
@@ -227,7 +227,7 @@ void game_restart(comprehend_game *game) {
 	game->info->update_flags = UPDATE_ALL;
 }
 
-static struct word_index *is_word_pair(comprehend_game *game,
+static struct word_index *is_word_pair(ComprehendGame *game,
                                        struct word *word1, struct word *word2) {
 	struct word_map *map;
 	uint i;
@@ -246,7 +246,7 @@ static struct word_index *is_word_pair(comprehend_game *game,
 	return NULL;
 }
 
-static struct item *get_item_by_noun(comprehend_game *game,
+static struct item *get_item_by_noun(ComprehendGame *game,
                                      struct word *noun) {
 	uint i;
 
@@ -265,7 +265,7 @@ static struct item *get_item_by_noun(comprehend_game *game,
 	return NULL;
 }
 
-static void update_graphics(comprehend_game *game) {
+static void update_graphics(ComprehendGame *game) {
 	struct item *item;
 	struct room *room;
 	int type;
@@ -309,7 +309,7 @@ static void update_graphics(comprehend_game *game) {
 	}
 }
 
-static void describe_objects_in_current_room(comprehend_game *game) {
+static void describe_objects_in_current_room(ComprehendGame *game) {
 	struct item *item;
 	size_t count = 0;
 	uint i;
@@ -335,7 +335,7 @@ static void describe_objects_in_current_room(comprehend_game *game) {
 	}
 }
 
-static void update(comprehend_game *game) {
+static void update(ComprehendGame *game) {
 	struct room *room = get_room(game, game->info->current_room);
 	unsigned room_type, room_desc_string;
 
@@ -356,7 +356,7 @@ static void update(comprehend_game *game) {
 	game->info->update_flags = 0;
 }
 
-static void move_to(comprehend_game *game, uint8 room) {
+static void move_to(ComprehendGame *game, uint8 room) {
 	if (room - 1 >= (int)game->info->nr_rooms)
 		fatal_error("Attempted to move to invalid room %.2x\n", room);
 
@@ -383,7 +383,7 @@ static void func_set_test_result(struct function_state *func_state, bool value)
 	}
 }
 
-static size_t num_objects_in_room(comprehend_game *game, int room) {
+static size_t num_objects_in_room(ComprehendGame *game, int room) {
 	size_t count = 0, i;
 
 	for (i = 0; i < game->info->header.nr_items; i++)
@@ -393,7 +393,7 @@ static size_t num_objects_in_room(comprehend_game *game, int room) {
 	return count;
 }
 
-void move_object(comprehend_game *game, struct item *item, int new_room) {
+void move_object(ComprehendGame *game, struct item *item, int new_room) {
 	unsigned obj_weight = item->flags & ITEMF_WEIGHT_MASK;
 
 	if (item->room == new_room)
@@ -424,7 +424,7 @@ void move_object(comprehend_game *game, struct item *item, int new_room) {
 	item->room = new_room;
 }
 
-static void eval_instruction(comprehend_game *game,
+static void eval_instruction(ComprehendGame *game,
                              struct function_state *func_state,
                              struct instruction *instr,
                              struct word *verb, struct word *noun) {
@@ -983,7 +983,7 @@ static void eval_instruction(comprehend_game *game,
  * is reached. Otherwise the commands instructions are skipped over and the
  * next test sequence (if there is one) is tried.
  */
-void eval_function(comprehend_game *game, struct function *func,
+void eval_function(ComprehendGame *game, struct function *func,
                    struct word *verb, struct word *noun) {
 	struct function_state func_state;
 	uint i;
@@ -1016,7 +1016,7 @@ static void skip_non_whitespace(char **p) {
 }
 
 #ifdef TODO
-static void handle_debug_command(comprehend_game *game,
+static void handle_debug_command(ComprehendGame *game,
                                  const char *line) {
 	int i;
 
@@ -1057,7 +1057,7 @@ static void handle_debug_command(comprehend_game *game,
 }
 #endif
 
-static bool handle_sentence(comprehend_game *game,
+static bool handle_sentence(ComprehendGame *game,
                             struct sentence *sentence) {
 	struct function *func;
 	struct action *action;
@@ -1103,7 +1103,7 @@ static bool handle_sentence(comprehend_game *game,
 	return false;
 }
 
-static void read_sentence(comprehend_game *game, char **line,
+static void read_sentence(ComprehendGame *game, char **line,
                           struct sentence *sentence) {
 	bool sentence_end = false;
 	char *word_string, *p = *line;
@@ -1163,7 +1163,7 @@ static void read_sentence(comprehend_game *game, char **line,
 	*line = p;
 }
 
-static void before_turn(comprehend_game *game) {
+static void before_turn(ComprehendGame *game) {
 	// Run the game specific before turn bits
 	game->before_turn();
 
@@ -1173,12 +1173,12 @@ static void before_turn(comprehend_game *game) {
 	update(game);
 }
 
-static void after_turn(comprehend_game *game) {
+static void after_turn(ComprehendGame *game) {
 	// Do post turn game specific bits
 	game->after_turn();
 }
 
-static void read_input(comprehend_game *game) {
+static void read_input(ComprehendGame *game) {
 #ifdef TODO
 	struct sentence sentence;
 	char *line = NULL, buffer[1024];
@@ -1218,7 +1218,7 @@ static void read_input(comprehend_game *game) {
 #endif
 }
 
-void comprehend_play_game(comprehend_game *game) {
+void comprehend_play_game(ComprehendGame *game) {
 	console_init();
 
 	game->before_game();
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 6a3d80b607..1d0b8c02e3 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef GLK_COMPREHEND_GAME_H
-#define GLK_COMPREHEND_GAME_H
+#ifndef GLK_ComprehendGame_H
+#define GLK_ComprehendGame_H
 
 #include "common/array.h"
 #include "glk/comprehend/game_data.h"
@@ -33,7 +33,7 @@ namespace Comprehend {
 #define ROOM_IS_DARK 1
 #define ROOM_IS_TOO_BRIGHT 2
 
-struct comprehend_game {
+class ComprehendGame {
 public:
 	const char *game_name;
 	const char *short_name;
@@ -49,8 +49,8 @@ public:
 	struct game_info *info;
 
 public:
-	comprehend_game();
-	virtual ~comprehend_game();
+	ComprehendGame();
+	virtual ~ComprehendGame();
 
 	virtual void before_game() {}
 	virtual void before_prompt() {}
@@ -67,18 +67,18 @@ public:
 	virtual void handle_special_opcode(uint8 operand) {}
 };
 
-void console_println(comprehend_game *game, const char *text);
+void console_println(ComprehendGame *game, const char *text);
 int console_get_key(void);
 
-struct item *get_item(comprehend_game *game, uint16 index);
-void move_object(comprehend_game *game, struct item *item, int new_room);
-void eval_function(comprehend_game *game, struct function *func,
+struct item *get_item(ComprehendGame *game, uint16 index);
+void move_object(ComprehendGame *game, struct item *item, int new_room);
+void eval_function(ComprehendGame *game, struct function *func,
                    struct word *verb, struct word *noun);
 
-void comprehend_play_game(comprehend_game *game);
-void game_save(comprehend_game *game);
-void game_restore(comprehend_game *game);
-void game_restart(comprehend_game *game);
+void comprehend_play_game(ComprehendGame *game);
+void game_save(ComprehendGame *game);
+void game_restore(ComprehendGame *game);
+void game_restart(ComprehendGame *game);
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index 9bc6a3daa3..74e5cdfe1e 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -38,7 +38,7 @@ static struct game_ops cc2_ops = {
     cc2_handle_special_opcode};
 #endif
 
-CrimsonCrownGame::CrimsonCrownGame() : comprehend_game() {
+CrimsonCrownGame::CrimsonCrownGame() : ComprehendGame() {
 	game_name = "Crimson Crown";
 	short_name = "cc1";
 	game_data_file = "cc1.gda";
@@ -55,7 +55,7 @@ CrimsonCrownGame::CrimsonCrownGame() : comprehend_game() {
 }
 
 #ifdef TODO
-struct comprehend_game game_crimson_crown_2 = {
+ComprehendGame game_crimson_crown_2 = {
     "Crimson Crown (Part 2/2)",
     "cc2",
     "CC2.GDA",
@@ -69,13 +69,13 @@ struct comprehend_game game_crimson_crown_2 = {
     nullptr};
 #endif
 
-static void cc_clear_companion_flags(struct comprehend_game *game) {
+static void cc_clear_companion_flags(ComprehendGame *game) {
 	/* Clear the Sabrina/Erik action flags */
 	game->info->flags[0xa] = 0;
 	game->info->flags[0xb] = 0;
 }
 
-static bool cc_common_handle_special_opcode(struct comprehend_game *game,
+static bool cc_common_handle_special_opcode(ComprehendGame *game,
                                             uint8 operand) {
 	switch (operand) {
 	case 0x03:
@@ -120,7 +120,7 @@ void CrimsonCrownGame::handle_special_opcode(uint8 operand) {
 	}
 }
 
-static void cc2_handle_special_opcode(struct comprehend_game *game,
+static void cc2_handle_special_opcode(ComprehendGame *game,
                                       uint8 operand) {
 	if (cc_common_handle_special_opcode(game, operand))
 		return;
@@ -142,7 +142,7 @@ static void cc2_handle_special_opcode(struct comprehend_game *game,
 	}
 }
 
-static void cc2_before_prompt(struct comprehend_game *game) {
+static void cc2_before_prompt(ComprehendGame *game) {
 	cc_clear_companion_flags(game);
 }
 
diff --git a/engines/glk/comprehend/game_cc.h b/engines/glk/comprehend/game_cc.h
index ccbbc147a9..a60d9f2317 100644
--- a/engines/glk/comprehend/game_cc.h
+++ b/engines/glk/comprehend/game_cc.h
@@ -20,15 +20,15 @@
  *
  */
 
-#ifndef GLK_COMPREHEND_GAME_CC_H
-#define GLK_COMPREHEND_GAME_CC_H
+#ifndef GLK_ComprehendGame_CC_H
+#define GLK_ComprehendGame_CC_H
 
 #include "glk/comprehend/game.h"
 
 namespace Glk {
 namespace Comprehend {
 
-class CrimsonCrownGame : public comprehend_game {
+class CrimsonCrownGame : public ComprehendGame {
 public:
 	CrimsonCrownGame();
 	~CrimsonCrownGame() override {}
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 5c92182e2d..ea3d2eae07 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -187,7 +187,7 @@ static void parse_function(struct file_buf * fb, struct function * func) {
 	}
 }
 
-static void parse_vm(struct comprehend_game * game, struct file_buf * fb) {
+static void parse_vm(ComprehendGame * game, struct file_buf * fb) {
 	struct function *func;
 
 	file_buf_set_pos(fb, game->info->header.addr_vm);
@@ -202,7 +202,7 @@ static void parse_vm(struct comprehend_game * game, struct file_buf * fb) {
 	}
 }
 
-static void parse_action_table_vvnn(struct comprehend_game * game,
+static void parse_action_table_vvnn(ComprehendGame * game,
 	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
@@ -246,7 +246,7 @@ static void parse_action_table_vvnn(struct comprehend_game * game,
 	}
 }
 
-static void parse_action_table_vnjn(struct comprehend_game * game,
+static void parse_action_table_vnjn(ComprehendGame * game,
 	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 join, count;
@@ -291,7 +291,7 @@ static void parse_action_table_vnjn(struct comprehend_game * game,
 	}
 }
 
-static void parse_action_table_vjn(struct comprehend_game * game,
+static void parse_action_table_vjn(ComprehendGame * game,
 	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 join, count;
@@ -332,7 +332,7 @@ static void parse_action_table_vjn(struct comprehend_game * game,
 	}
 }
 
-static void parse_action_table_vdn(struct comprehend_game * game,
+static void parse_action_table_vdn(ComprehendGame * game,
 	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
@@ -373,7 +373,7 @@ static void parse_action_table_vdn(struct comprehend_game * game,
 	}
 }
 
-static void parse_action_table_vnn(struct comprehend_game * game,
+static void parse_action_table_vnn(ComprehendGame * game,
 	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
@@ -415,7 +415,7 @@ static void parse_action_table_vnn(struct comprehend_game * game,
 	}
 }
 
-static void parse_action_table_vn(struct comprehend_game * game,
+static void parse_action_table_vn(ComprehendGame * game,
 	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
@@ -454,7 +454,7 @@ static void parse_action_table_vn(struct comprehend_game * game,
 	}
 }
 
-static void parse_action_table_v(struct comprehend_game * game,
+static void parse_action_table_v(ComprehendGame * game,
 	                                struct file_buf * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, nr_funcs;
@@ -497,7 +497,7 @@ static void parse_action_table_v(struct comprehend_game * game,
 	}
 }
 
-static void parse_action_table(struct comprehend_game * game,
+static void parse_action_table(ComprehendGame * game,
 	                            struct file_buf * fb) {
 	game->info->nr_actions = 0;
 
@@ -515,7 +515,7 @@ static void parse_action_table(struct comprehend_game * game,
 	parse_action_table_v(game, fb, &game->info->nr_actions);
 }
 
-static void parse_dictionary(struct comprehend_game * game, struct file_buf * fb) {
+static void parse_dictionary(ComprehendGame * game, struct file_buf * fb) {
 	word *words;
 	uint i, j;
 
@@ -538,7 +538,7 @@ static void parse_dictionary(struct comprehend_game * game, struct file_buf * fb
 	}
 }
 
-static void parse_word_map(struct comprehend_game * game, struct file_buf * fb) {
+static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 	struct word_map *map;
 	uint8 index, type, dummy;
 	uint i;
@@ -586,7 +586,7 @@ static void parse_word_map(struct comprehend_game * game, struct file_buf * fb)
 	}
 }
 
-static void parse_items(struct comprehend_game * game, struct file_buf * fb) {
+static void parse_items(ComprehendGame * game, struct file_buf * fb) {
 	size_t nr_items = game->info->header.nr_items;
 
 	/* Item descriptions */
@@ -617,7 +617,7 @@ static void parse_items(struct comprehend_game * game, struct file_buf * fb) {
 	file_buf_get_array_u8(fb, 0, game->info->item, graphic, nr_items);
 }
 
-static void parse_rooms(struct comprehend_game * game, struct file_buf * fb) {
+static void parse_rooms(ComprehendGame * game, struct file_buf * fb) {
 	size_t nr_rooms = game->info->nr_rooms;
 	int i;
 
@@ -748,14 +748,14 @@ static void parse_string_table(struct file_buf * fb, unsigned start_addr,
 	}
 }
 
-static void parse_variables(struct comprehend_game * game, struct file_buf * fb) {
+static void parse_variables(ComprehendGame * game, struct file_buf * fb) {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(game->info->variable); i++)
 		file_buf_get_le16(fb, &game->info->variable[i]);
 }
 
-static void parse_flags(struct comprehend_game * game, struct file_buf * fb) {
+static void parse_flags(ComprehendGame * game, struct file_buf * fb) {
 	int i, bit, flag_index = 0;
 	uint8 bitmask;
 
@@ -768,7 +768,7 @@ static void parse_flags(struct comprehend_game * game, struct file_buf * fb) {
 	}
 }
 
-static void parse_replace_words(struct comprehend_game * game,
+static void parse_replace_words(ComprehendGame * game,
 	                            struct file_buf * fb) {
 	uint16 dummy;
 	size_t len;
@@ -798,7 +798,7 @@ static void parse_replace_words(struct comprehend_game * game,
 * The main game data file header has the offsets for where each bit of
 * game data is. The offsets have a magic constant value added to them.
 */
-static void parse_header(struct comprehend_game * game, struct file_buf * fb) {
+static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	struct game_header *header = &game->info->header;
 	uint16 dummy, addr_dictionary_end;
 	uint8 dummy8;
@@ -916,7 +916,7 @@ static void parse_header(struct comprehend_game * game, struct file_buf * fb) {
 		                    8;
 }
 
-static void load_extra_string_file(comprehend_game * game,
+static void load_extra_string_file(ComprehendGame * game,
 	                                string_file * string_file) {
 	struct file_buf fb;
 	unsigned end;
@@ -934,7 +934,7 @@ static void load_extra_string_file(comprehend_game * game,
 	file_buf_unmap(&fb);
 }
 
-static void load_extra_string_files(comprehend_game * game) {
+static void load_extra_string_files(ComprehendGame * game) {
 	int i;
 
 	memset(&game->info->strings2, 0, sizeof(game->info->strings2));
@@ -952,7 +952,7 @@ static void load_extra_string_files(comprehend_game * game) {
 	}
 }
 
-static void load_game_data(struct comprehend_game * game) {
+static void load_game_data(ComprehendGame * game) {
 	struct file_buf fb;
 
 	memset(game->info, 0, sizeof(*game->info));
@@ -975,7 +975,7 @@ static void load_game_data(struct comprehend_game * game) {
 	file_buf_unmap(&fb);
 }
 
-void comprehend_load_game(struct comprehend_game * game) {
+void comprehend_load_game(ComprehendGame * game) {
 	/* Load the main game data file */
 	load_game_data(game);
 
@@ -1004,7 +1004,7 @@ static void patch_string_desc(uint16 * desc) {
 }
 #endif
 
-void comprehend_save_game(struct comprehend_game * game, const char *filename) {
+void comprehend_save_game(ComprehendGame * game, const char *filename) {
 #ifdef TODO
 	FILE *fd;
 	uint8 bitmask;
@@ -1088,7 +1088,7 @@ void comprehend_save_game(struct comprehend_game * game, const char *filename) {
 #endif
 }
 
-void comprehend_restore_game(struct comprehend_game * game, const char *filename) {
+void comprehend_restore_game(ComprehendGame * game, const char *filename) {
 #ifdef TODO
 	struct file_buf fb;
 	size_t nr_rooms, nr_items;
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 74636f5319..4146bf8ba5 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef GLK_COMPREHEND_GAME_DATA_H
-#define GLK_COMPREHEND_GAME_DATA_H
+#ifndef GLK_ComprehendGame_DATA_H
+#define GLK_ComprehendGame_DATA_H
 
 #include "glk/comprehend/image_data.h"
 
@@ -341,10 +341,10 @@ enum {
 #define WORD_TYPE_NOUN_MASK (WORD_TYPE_FEMALE | WORD_TYPE_MALE | \
 	                         WORD_TYPE_NOUN | WORD_TYPE_NOUN_PLURAL)
 
-void comprehend_load_game(struct comprehend_game *game);
-void comprehend_restore_game(struct comprehend_game *game,
+void comprehend_load_game(ComprehendGame *game);
+void comprehend_restore_game(ComprehendGame *game,
                              const char *filename);
-void comprehend_save_game(struct comprehend_game *game, const char *filename);
+void comprehend_save_game(ComprehendGame *game, const char *filename);
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index ab6a67c4bb..c53c6bf824 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -34,7 +34,7 @@ namespace Comprehend {
 #define OO_FLAG_WEARING_GOGGLES 0x1b
 #define OO_FLAG_FLASHLIGHT_ON 0x27
 
-OOToposGame::OOToposGame() : comprehend_game() {
+OOToposGame::OOToposGame() : ComprehendGame() {
 	game_name = "Oo-Topos";
 	short_name = "oo";
 	game_data_file = "g0";
diff --git a/engines/glk/comprehend/game_oo.h b/engines/glk/comprehend/game_oo.h
index c1b1f767e4..469a85e384 100644
--- a/engines/glk/comprehend/game_oo.h
+++ b/engines/glk/comprehend/game_oo.h
@@ -20,15 +20,15 @@
  *
  */
 
-#ifndef GLK_COMPREHEND_GAME_OO_H
-#define GLK_COMPREHEND_GAME_OO_H
+#ifndef GLK_ComprehendGame_OO_H
+#define GLK_ComprehendGame_OO_H
 
 #include "glk/comprehend/game.h"
 
 namespace Glk {
 namespace Comprehend {
 
-class OOToposGame : public comprehend_game {
+class OOToposGame : public ComprehendGame {
 public:
 	OOToposGame();
 	~OOToposGame() override {}
diff --git a/engines/glk/comprehend/game_tm.cpp b/engines/glk/comprehend/game_tm.cpp
index 35b1f03a9e..ad714fb398 100644
--- a/engines/glk/comprehend/game_tm.cpp
+++ b/engines/glk/comprehend/game_tm.cpp
@@ -28,7 +28,7 @@ namespace Comprehend {
 
 /* FIXME - This is broken */
 
-TalismanGame::TalismanGame() : comprehend_game() {
+TalismanGame::TalismanGame() : ComprehendGame() {
 	game_name = "Talisman, Challenging the Sands of Time (broken)";
 	short_name = "tm";
 	game_data_file = "G0";
diff --git a/engines/glk/comprehend/game_tm.h b/engines/glk/comprehend/game_tm.h
index 70f8537102..86c9cf20bb 100644
--- a/engines/glk/comprehend/game_tm.h
+++ b/engines/glk/comprehend/game_tm.h
@@ -20,15 +20,15 @@
  *
  */
 
-#ifndef GLK_COMPREHEND_GAME_TM_H
-#define GLK_COMPREHEND_GAME_TM_H
+#ifndef GLK_ComprehendGame_TM_H
+#define GLK_ComprehendGame_TM_H
 
 #include "glk/comprehend/game.h"
 
 namespace Glk {
 namespace Comprehend {
 
-class TalismanGame : public comprehend_game {
+class TalismanGame : public ComprehendGame {
 public:
 	TalismanGame();
 	~TalismanGame() override {}
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 9596e48b42..f03fc29321 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -41,7 +41,7 @@ static struct game_strings tr_strings = {
 };
 
 
-TransylvaniaGame::TransylvaniaGame() : comprehend_game() {
+TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
 	game_name = "Transylvania";
 	short_name = "tr";
 	game_data_file = "tr.gda";
diff --git a/engines/glk/comprehend/game_tr.h b/engines/glk/comprehend/game_tr.h
index 74dc09ba55..634588c58f 100644
--- a/engines/glk/comprehend/game_tr.h
+++ b/engines/glk/comprehend/game_tr.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef GLK_COMPREHEND_GAME_TR_H
-#define GLK_COMPREHEND_GAME_TR_H
+#ifndef GLK_ComprehendGame_TR_H
+#define GLK_ComprehendGame_TR_H
 
 #include "glk/comprehend/game.h"
 
@@ -36,7 +36,7 @@ struct tr_monster {
 	unsigned randomness;
 };
 
-class TransylvaniaGame : public comprehend_game {
+class TransylvaniaGame : public ComprehendGame {
 private:
 	static const tr_monster WEREWOLF;
 	static const tr_monster VAMPIRE;
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index d5751d3038..7f783abe7c 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -348,7 +348,7 @@ void comprehend_load_image_file(const char *filename, struct image_data *info)
 	load_image_files(info, filenames);
 }
 
-void comprehend_load_images(comprehend_game *game) {
+void comprehend_load_images(ComprehendGame *game) {
 	load_image_files(&game->info->room_images,
 			 game->location_graphic_files);
 
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
index 9a2c1882c1..ece82e98a4 100644
--- a/engines/glk/comprehend/image_data.h
+++ b/engines/glk/comprehend/image_data.h
@@ -28,7 +28,7 @@
 namespace Glk {
 namespace Comprehend {
 
-struct comprehend_game;
+class ComprehendGame;
 struct file_buf;
 
 struct image_data {
@@ -91,7 +91,7 @@ void draw_image(image_data *info, unsigned index);
 void draw_location_image(image_data *info, unsigned index);
 
 void comprehend_load_image_file(const char *filename, image_data *info);
-void comprehend_load_images(comprehend_game *game);
+void comprehend_load_images(ComprehendGame *game);
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/opcode_map.cpp b/engines/glk/comprehend/opcode_map.cpp
index 30d1932a70..61b0526b48 100644
--- a/engines/glk/comprehend/opcode_map.cpp
+++ b/engines/glk/comprehend/opcode_map.cpp
@@ -173,7 +173,7 @@ static uint8 opcode_map_v2[0x100] = {
 	#endif
 };
 
-uint8 *get_opcode_map(comprehend_game *game)
+uint8 *get_opcode_map(ComprehendGame *game)
 {
 	switch (game->info->comprehend_version) {
 	case 1:
diff --git a/engines/glk/comprehend/opcode_map.h b/engines/glk/comprehend/opcode_map.h
index 73eb5eb014..102a88dee6 100644
--- a/engines/glk/comprehend/opcode_map.h
+++ b/engines/glk/comprehend/opcode_map.h
@@ -28,7 +28,7 @@
 namespace Glk {
 namespace Comprehend {
 
-uint8 *get_opcode_map(comprehend_game *game);
+uint8 *get_opcode_map(ComprehendGame *game);
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/recomprehend.cpp b/engines/glk/comprehend/recomprehend.cpp
index a6646c0798..193bdad487 100644
--- a/engines/glk/comprehend/recomprehend.cpp
+++ b/engines/glk/comprehend/recomprehend.cpp
@@ -30,13 +30,13 @@
 namespace Glk {
 namespace Comprehend {
 
-extern struct comprehend_game game_transylvania;
-extern struct comprehend_game game_crimson_crown_1;
-extern struct comprehend_game game_crimson_crown_2;
-extern struct comprehend_game game_oo_topos;
-extern struct comprehend_game game_talisman;
+extern ComprehendGame game_transylvania;
+extern ComprehendGame game_crimson_crown_1;
+extern ComprehendGame game_crimson_crown_2;
+extern ComprehendGame game_oo_topos;
+extern ComprehendGame game_talisman;
 
-static struct comprehend_game *comprehend_games[] = {
+static ComprehendGame *ComprehendGames[] = {
 	&game_transylvania,
 	&game_crimson_crown_1,
 	&game_crimson_crown_2,
@@ -80,9 +80,9 @@ static void usage(const char *progname)
 	printf("  -h, --graphics-height=HEIGHT  Graphics height\n");
 
 	printf("\nSupported games:\n");
-	for (i = 0; i < ARRAY_SIZE(comprehend_games); i++)
-		printf("    %-10s %s\n", comprehend_games[i]->short_name,
-		       comprehend_games[i]->game_name);
+	for (i = 0; i < ARRAY_SIZE(ComprehendGames); i++)
+		printf("    %-10s %s\n", ComprehendGames[i]->short_name,
+		       ComprehendGames[i]->game_name);
 
 	exit(EXIT_FAILURE);
 }
@@ -101,7 +101,7 @@ int main(int argc, char **argv)
 		{NULL,			0,			0, 0},
 	};
 	const char *short_opts = "dD:pgfw:h:?";
-	struct comprehend_game *game;
+	ComprehendGame *game;
 	const char *game_name, *game_dir;
 	unsigned dump_flags = 0;
 	int i, c, opt_index;
@@ -171,9 +171,9 @@ int main(int argc, char **argv)
 
 	/* Lookup game */
 	game = NULL;
-	for (i = 0; i < ARRAY_SIZE(comprehend_games); i++) {
-		if (strcmp(game_name, comprehend_games[i]->short_name) == 0) {
-			game = comprehend_games[i];
+	for (i = 0; i < ARRAY_SIZE(ComprehendGames); i++) {
+		if (strcmp(game_name, ComprehendGames[i]->short_name) == 0) {
+			game = ComprehendGames[i];
 			break;
 		}
 	}
diff --git a/engines/glk/comprehend/strings.cpp b/engines/glk/comprehend/strings.cpp
index 9bae241f97..784dfec506 100644
--- a/engines/glk/comprehend/strings.cpp
+++ b/engines/glk/comprehend/strings.cpp
@@ -30,7 +30,7 @@ namespace Comprehend {
 
 static char bad_string[128];
 
-const char *string_lookup(comprehend_game *game, uint16 index)
+const char *string_lookup(ComprehendGame *game, uint16 index)
 {
 	uint16 string;
 	uint8 table;
@@ -73,7 +73,7 @@ const char *string_lookup(comprehend_game *game, uint16 index)
 	return bad_string;
 }
 
-const char *instr_lookup_string(struct comprehend_game *game, uint8 index,
+const char *instr_lookup_string(ComprehendGame *game, uint8 index,
 				uint8 table)
 {
 	return string_lookup(game, table << 8 | index);
diff --git a/engines/glk/comprehend/strings.h b/engines/glk/comprehend/strings.h
index b3994cc257..4d5a40db11 100644
--- a/engines/glk/comprehend/strings.h
+++ b/engines/glk/comprehend/strings.h
@@ -26,10 +26,10 @@
 namespace Glk {
 namespace Comprehend {
 
-struct comprehend_game;
+class ComprehendGame;
 
-const char *string_lookup(struct comprehend_game *game, uint16 index);
-const char *instr_lookup_string(struct comprehend_game *game, uint8 index,
+const char *string_lookup(ComprehendGame *game, uint16 index);
+const char *instr_lookup_string(ComprehendGame *game, uint8 index,
 				uint8 table);
 
 } // namespace Comprehend


Commit: 14cf02cc1b3d5aebcbb2370b36720fe222cf9ba0
    https://github.com/scummvm/scummvm/commit/14cf02cc1b3d5aebcbb2370b36720fe222cf9ba0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Field renamings

Changed paths:
    engines/glk/comprehend/dictionary.cpp
    engines/glk/comprehend/dump_game_data.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_tm.cpp
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/opcode_map.cpp
    engines/glk/comprehend/strings.cpp


diff --git a/engines/glk/comprehend/dictionary.cpp b/engines/glk/comprehend/dictionary.cpp
index 4899476f89..4ca9d545ac 100644
--- a/engines/glk/comprehend/dictionary.cpp
+++ b/engines/glk/comprehend/dictionary.cpp
@@ -45,9 +45,9 @@ word *dict_find_word_by_string(ComprehendGame *game,
 	if (!string)
 		return NULL;
 
-	for (i = 0; i < game->info->nr_words; i++)
-		if (word_match(&game->info->words[i], string))
-			return &game->info->words[i];
+	for (i = 0; i < game->info->_nr_words; i++)
+		if (word_match(&game->info->_words[i], string))
+			return &game->info->_words[i];
 
 	return NULL;
 }
@@ -57,10 +57,10 @@ struct word *dict_find_word_by_index_type(ComprehendGame *game,
 {
 	uint i;
 
-	for (i = 0; i < game->info->nr_words; i++) {
-		if (game->info->words[i]._index == index &&
-		    game->info->words[i]._type == type)
-			return &game->info->words[i];
+	for (i = 0; i < game->info->_nr_words; i++) {
+		if (game->info->_words[i]._index == index &&
+		    game->info->_words[i]._type == type)
+			return &game->info->_words[i];
 	}
 
 	return NULL;
@@ -71,10 +71,10 @@ struct word *find_dict_word_by_index(ComprehendGame *game,
 {
 	uint i;
 
-	for (i = 0; i < game->info->nr_words; i++) {
-		if (game->info->words[i]._index == index &&
-		    (game->info->words[i]._type & type_mask) != 0)
-			return &game->info->words[i];
+	for (i = 0; i < game->info->_nr_words; i++) {
+		if (game->info->_words[i]._index == index &&
+		    (game->info->_words[i]._type & type_mask) != 0)
+			return &game->info->_words[i];
 	}
 
 	return NULL;
@@ -85,10 +85,10 @@ bool dict_match_index_type(ComprehendGame *game, const char *word,
 {
 	uint i;
 
-	for (i = 0; i < game->info->nr_words; i++)
-		if (game->info->words[i]._index == index &&
-		    ((game->info->words[i]._type & type_mask) != 0) &&
-		    word_match(&game->info->words[i], word))
+	for (i = 0; i < game->info->_nr_words; i++)
+		if (game->info->_words[i]._index == index &&
+		    ((game->info->_words[i]._type & type_mask) != 0) &&
+		    word_match(&game->info->_words[i], word))
 			return true;
 
 	return false;
diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
index 52dde56f89..16ac91262b 100644
--- a/engines/glk/comprehend/dump_game_data.cpp
+++ b/engines/glk/comprehend/dump_game_data.cpp
@@ -160,7 +160,7 @@ void dump_instruction(ComprehendGame *game,
 		break;
 
 	case OPCODE_SET_STRING_REPLACEMENT:
-		debugN(" %s", game->info->replace_words[instr->operand[0] - 1]);
+		debugN(" %s", game->info->_replaceWords[instr->operand[0] - 1]);
 		break;
 	}
 
@@ -172,9 +172,9 @@ static void dump_functions(ComprehendGame *game)
 	struct function *func;
 	uint i, j;
 
-	debugN("Functions (%zd entries)\n", game->info->nr_functions);
-	for (i = 0; i < game->info->nr_functions; i++) {
-		func = &game->info->functions[i];
+	debugN("Functions (%zd entries)\n", game->info->_nr_functions);
+	for (i = 0; i < game->info->_nr_functions; i++) {
+		func = &game->info->_functions[i];
 
 		debugN("[%.4x] (%zd instructions)\n", i, func->nr_instructions);
 		for (j = 0; j < func->nr_instructions; j++)
@@ -189,9 +189,9 @@ static void dump_action_table(ComprehendGame *game)
 	struct word *word;
 	uint i, j;
 
-	debugN("Action table (%zd entries)\n", game->info->nr_actions);
-	for (i = 0; i < game->info->nr_actions; i++) {
-		action = &game->info->action[i];
+	debugN("Action table (%zd entries)\n", game->info->_nr_actions);
+	for (i = 0; i < game->info->_nr_actions; i++) {
+		action = &game->info->_actions[i];
 
 		debugN("(");
 		for (j = 0; j < 4; j++) {
@@ -247,14 +247,14 @@ static void dump_dictionary(ComprehendGame *game)
 	uint i;
 
 	/* Sort the dictionary by index */
-	dictionary = (word *)xmalloc(sizeof(*words) * game->info->nr_words);
-	memcpy(dictionary, game->info->words,
-	       sizeof(*words) * game->info->nr_words);
-	qsort(dictionary, game->info->nr_words, sizeof(*words),
+	dictionary = (word *)xmalloc(sizeof(*words) * game->info->_nr_words);
+	memcpy(dictionary, game->info->_words,
+	       sizeof(*words) * game->info->_nr_words);
+	qsort(dictionary, game->info->_nr_words, sizeof(*words),
 	      word_index_compare);
 
-	debugN("Dictionary (%zd words)\n", game->info->nr_words);
-	for (i = 0; i < game->info->nr_words; i++) {
+	debugN("Dictionary (%zd words)\n", game->info->_nr_words);
+	for (i = 0; i < game->info->_nr_words; i++) {
 		words = &dictionary[i];
 		debugN("  [%.2x] %.2x %s\n", words->_index, words->_type,
 		       words->_word);
@@ -270,9 +270,9 @@ static void dump_word_map(ComprehendGame *game)
 	struct word_map *map;
 	uint i, j;
 
-	debugN("Word pairs (%zd entries)\n", game->info->nr_word_maps);
-	for (i = 0; i < game->info->nr_word_maps; i++) {
-		map = &game->info->word_map[i];
+	debugN("Word pairs (%zd entries)\n", game->info->_nr_word_maps);
+	for (i = 0; i < game->info->_nr_word_maps; i++) {
+		map = &game->info->_wordMaps[i];
 
 		for (j = 0; j < 3; j++) {
 			word[j] = dict_find_word_by_index_type(
@@ -296,9 +296,9 @@ static void dump_rooms(ComprehendGame *game)
 	uint i;
 
 	/* Room zero acts as the players inventory */
-	debugN("Rooms (%zd entries)\n", game->info->nr_rooms);
-	for (i = 1; i <= game->info->nr_rooms; i++) {
-		room = &game->info->rooms[i];
+	debugN("Rooms (%zd entries)\n", game->info->_nr_rooms);
+	for (i = 1; i <= game->info->_nr_rooms; i++) {
+		room = &game->info->_rooms[i];
 
 		debugN("  [%.2x] flags=%.2x, graphic=%.2x\n",
 		       i, room->flags, room->graphic);
@@ -322,22 +322,22 @@ static void dump_items(ComprehendGame *game)
 	struct item *item;
 	uint i, j;
 
-	debugN("Items (%zd entries)\n", game->info->header.nr_items);
-	for (i = 0; i < game->info->header.nr_items; i++) {
-		item = &game->info->item[i];
+	debugN("Items (%zd entries)\n", game->info->_header.nr_items);
+	for (i = 0; i < game->info->_header.nr_items; i++) {
+		item = &game->info->_item[i];
 
 		debugN("  [%.2x] %s\n", i + 1,
 		       item->string_desc ?
 		       string_lookup(game, item->string_desc) : "");
-		if (game->info->comprehend_version == 2)
+		if (game->info->_comprehendVersion == 2)
 			debugN("    long desc: %s\n",
 			       string_lookup(game, item->long_string));
 
 		debugN("    words: ");
-		for (j = 0; j < game->info->nr_words; j++)
-			if (game->info->words[j]._index == item->word &&
-			    (game->info->words[j]._type & WORD_TYPE_NOUN_MASK))
-				debugN("%s ", game->info->words[j]._word);
+		for (j = 0; j < game->info->_nr_words; j++)
+			if (game->info->_words[j]._index == item->word &&
+			    (game->info->_words[j]._type & WORD_TYPE_NOUN_MASK))
+				debugN("%s ", game->info->_words[j]._word);
 		debugN("\n");
 		debugN("    flags=%.2x (takeable=%d, weight=%d)\n",
 		       item->flags, !!(item->flags & ITEMF_CAN_TAKE),
@@ -359,15 +359,15 @@ static void dump_string_table(struct string_table *table)
 static void dump_game_data_strings(ComprehendGame *game)
 {
 	debugN("Main string table (%zd entries)\n",
-	       game->info->strings.nr_strings);
-	dump_string_table(&game->info->strings);
+	       game->info->_strings.nr_strings);
+	dump_string_table(&game->info->_strings);
 }
 
 static void dump_extra_strings(ComprehendGame *game)
 {
 	debugN("Extra strings (%zd entries)\n",
-	       game->info->strings2.nr_strings);
-	dump_string_table(&game->info->strings2);
+	       game->info->_strings2.nr_strings);
+	dump_string_table(&game->info->_strings2);
 }
 
 static void dump_replace_words(ComprehendGame *game)
@@ -375,14 +375,14 @@ static void dump_replace_words(ComprehendGame *game)
 	uint i;
 
 	debugN("Replacement words (%zd entries)\n",
-	       game->info->nr_replace_words);
-	for (i = 0; i < game->info->nr_replace_words; i++)
-		debugN("  [%.2x] %s\n", i + 1, game->info->replace_words[i]);
+	       game->info->_nr_replace_words);
+	for (i = 0; i < game->info->_nr_replace_words; i++)
+		debugN("  [%.2x] %s\n", i + 1, game->info->_replaceWords[i]);
 }
 
 static void dump_header(ComprehendGame *game)
 {
-	struct game_header *header = &game->info->header;
+	struct game_header *header = &game->info->_header;
 	uint16 *dir_table = header->room_direction_table;
 
 	debugN("Game header:\n");
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 862ebeaa03..ff95370978 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -43,12 +43,12 @@ struct winsize {
 };
 static struct winsize console_winsize;
 
-ComprehendGame::ComprehendGame() : game_name(nullptr),
-                                     short_name(nullptr),
-                                     game_data_file(nullptr),
-                                     save_game_file_fmt(nullptr),
-                                     color_table(0),
-                                     strings(nullptr) {
+ComprehendGame::ComprehendGame() : _gameName(nullptr),
+                                     _shortName(nullptr),
+                                     _gameDataFile(nullptr),
+                                     _savegameFileFormat(nullptr),
+                                     _colorTable(0),
+                                     _gameStrings(nullptr) {
 	info = (game_info *)malloc(sizeof(*info));
 }
 
@@ -95,13 +95,13 @@ void console_println(ComprehendGame *game, const char *text) {
 
 		case '@':
 			/* Replace word */
-			if (game->info->current_replace_word >= game->info->nr_replace_words) {
+			if (game->info->_currentReplaceWord >= game->info->_nr_replace_words) {
 				snprintf(bad_word, sizeof(bad_word),
 				         "[BAD_REPLACE_WORD(%.2x)]",
-				         game->info->current_replace_word);
+				         game->info->_currentReplaceWord);
 				word = bad_word;
 			} else {
-				word = game->info->replace_words[game->info->current_replace_word];
+				word = game->info->_replaceWords[game->info->_currentReplaceWord];
 			}
 			word_len = strlen(word);
 			p++;
@@ -164,24 +164,24 @@ static struct room *get_room(ComprehendGame *game, uint16 index) {
 	if (index == 0)
 		fatal_error("Room index 0 (player inventory) is invalid");
 
-	if (index - 1 >= (int)game->info->nr_rooms)
+	if (index - 1 >= (int)game->info->_nr_rooms)
 		fatal_error("Room index %d is invalid", index);
 
-	return &game->info->rooms[index];
+	return &game->info->_rooms[index];
 }
 
 struct item *get_item(ComprehendGame *game, uint16 index) {
-	if (index >= game->info->header.nr_items)
+	if (index >= game->info->_header.nr_items)
 		fatal_error("Bad item %d\n", index);
 
-	return &game->info->item[index];
+	return &game->info->_item[index];
 }
 
 void game_save(ComprehendGame *game) {
 	char filename[32];
 	int c;
 
-	console_println(game, game->info->strings.strings[STRING_SAVE_GAME]);
+	console_println(game, game->info->_strings.strings[STRING_SAVE_GAME]);
 
 	c = console_get_key();
 	if (c < '1' || c > '3') {
@@ -193,7 +193,7 @@ void game_save(ComprehendGame *game) {
 		return;
 	}
 
-	snprintf(filename, sizeof(filename), game->save_game_file_fmt, c - '0');
+	snprintf(filename, sizeof(filename), game->_savegameFileFormat, c - '0');
 	comprehend_save_game(game, filename);
 }
 
@@ -201,7 +201,7 @@ void game_restore(ComprehendGame *game) {
 	char filename[32];
 	int c;
 
-	console_println(game, game->info->strings.strings[STRING_RESTORE_GAME]);
+	console_println(game, game->info->_strings.strings[STRING_RESTORE_GAME]);
 
 	c = console_get_key();
 	if (c < '1' || c > '3') {
@@ -213,18 +213,18 @@ void game_restore(ComprehendGame *game) {
 		return;
 	}
 
-	snprintf(filename, sizeof(filename), game->save_game_file_fmt, c - '0');
+	snprintf(filename, sizeof(filename), game->_savegameFileFormat, c - '0');
 	comprehend_restore_game(game, filename);
 
-	game->info->update_flags = UPDATE_ALL;
+	game->info->_updateFlags = UPDATE_ALL;
 }
 
 void game_restart(ComprehendGame *game) {
-	console_println(game, string_lookup(game, game->strings->game_restart));
+	console_println(game, string_lookup(game, game->_gameStrings->game_restart));
 	console_get_key();
 
 	comprehend_load_game(game);
-	game->info->update_flags = UPDATE_ALL;
+	game->info->_updateFlags = UPDATE_ALL;
 }
 
 static struct word_index *is_word_pair(ComprehendGame *game,
@@ -233,8 +233,8 @@ static struct word_index *is_word_pair(ComprehendGame *game,
 	uint i;
 
 	/* Check if this is a word pair */
-	for (i = 0; i < game->info->nr_word_maps; i++) {
-		map = &game->info->word_map[i];
+	for (i = 0; i < game->info->_nr_word_maps; i++) {
+		map = &game->info->_wordMaps[i];
 
 		if (map->word[0].index == word1->_index &&
 		    map->word[0].type == word1->_type &&
@@ -258,9 +258,9 @@ static struct item *get_item_by_noun(ComprehendGame *game,
 	 *         (the box and the snarl-in-a-box). The player is unable
 	 *         to drop the latter because this will match the former.
 	 */
-	for (i = 0; i < game->info->header.nr_items; i++)
-		if (game->info->item[i].word == noun->_index)
-			return &game->info->item[i];
+	for (i = 0; i < game->info->_header.nr_items; i++)
+		if (game->info->_item[i].word == noun->_index)
+			return &game->info->_item[i];
 
 	return NULL;
 }
@@ -274,34 +274,34 @@ static void update_graphics(ComprehendGame *game) {
 	if (!g_enabled())
 		return;
 
-	type = game->room_is_special(game->info->current_room, NULL);
+	type = game->room_is_special(game->info->_currentRoom, NULL);
 
 	switch (type) {
 	case ROOM_IS_DARK:
-		if (game->info->update_flags & UPDATE_GRAPHICS)
+		if (game->info->_updateFlags & UPDATE_GRAPHICS)
 			draw_dark_room();
 		break;
 
 	case ROOM_IS_TOO_BRIGHT:
-		if (game->info->update_flags & UPDATE_GRAPHICS)
+		if (game->info->_updateFlags & UPDATE_GRAPHICS)
 			draw_bright_room();
 		break;
 
 	default:
-		if (game->info->update_flags & UPDATE_GRAPHICS) {
-			room = get_room(game, game->info->current_room);
-			draw_location_image(&game->info->room_images,
+		if (game->info->_updateFlags & UPDATE_GRAPHICS) {
+			room = get_room(game, game->info->_currentRoom);
+			draw_location_image(&game->info->_roomImages,
 			                    room->graphic - 1);
 		}
 
-		if ((game->info->update_flags & UPDATE_GRAPHICS) ||
-		    (game->info->update_flags & UPDATE_GRAPHICS_ITEMS)) {
-			for (i = 0; i < game->info->header.nr_items; i++) {
-				item = &game->info->item[i];
+		if ((game->info->_updateFlags & UPDATE_GRAPHICS) ||
+		    (game->info->_updateFlags & UPDATE_GRAPHICS_ITEMS)) {
+			for (i = 0; i < game->info->_header.nr_items; i++) {
+				item = &game->info->_item[i];
 
-				if (item->room == game->info->current_room &&
+				if (item->room == game->info->_currentRoom &&
 				    item->graphic != 0)
-					draw_image(&game->info->item_images,
+					draw_image(&game->info->_itemImages,
 					           item->graphic - 1);
 			}
 		}
@@ -314,10 +314,10 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 	size_t count = 0;
 	uint i;
 
-	for (i = 0; i < game->info->header.nr_items; i++) {
-		item = &game->info->item[i];
+	for (i = 0; i < game->info->_header.nr_items; i++) {
+		item = &game->info->_item[i];
 
-		if (item->room == game->info->current_room &&
+		if (item->room == game->info->_currentRoom &&
 		    item->string_desc != 0)
 			count++;
 	}
@@ -325,10 +325,10 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 	if (count > 0) {
 		console_println(game, string_lookup(game, STRING_YOU_SEE));
 
-		for (i = 0; i < game->info->header.nr_items; i++) {
-			item = &game->info->item[i];
+		for (i = 0; i < game->info->_header.nr_items; i++) {
+			item = &game->info->_item[i];
 
-			if (item->room == game->info->current_room &&
+			if (item->room == game->info->_currentRoom &&
 			    item->string_desc != 0)
 				console_println(game, string_lookup(game, item->string_desc));
 		}
@@ -336,32 +336,32 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 }
 
 static void update(ComprehendGame *game) {
-	struct room *room = get_room(game, game->info->current_room);
+	struct room *room = get_room(game, game->info->_currentRoom);
 	unsigned room_type, room_desc_string;
 
 	update_graphics(game);
 
 	/* Check if the room is special (dark, too bright, etc) */
 	room_desc_string = room->string_desc;
-	room_type = game->room_is_special(game->info->current_room,
+	room_type = game->room_is_special(game->info->_currentRoom,
 		&room_desc_string);
 
-	if (game->info->update_flags & UPDATE_ROOM_DESC)
+	if (game->info->_updateFlags & UPDATE_ROOM_DESC)
 		console_println(game, string_lookup(game, room_desc_string));
 
-	if ((game->info->update_flags & UPDATE_ITEM_LIST) &&
+	if ((game->info->_updateFlags & UPDATE_ITEM_LIST) &&
 	    room_type == ROOM_IS_NORMAL)
 		describe_objects_in_current_room(game);
 
-	game->info->update_flags = 0;
+	game->info->_updateFlags = 0;
 }
 
 static void move_to(ComprehendGame *game, uint8 room) {
-	if (room - 1 >= (int)game->info->nr_rooms)
+	if (room - 1 >= (int)game->info->_nr_rooms)
 		fatal_error("Attempted to move to invalid room %.2x\n", room);
 
-	game->info->current_room = room;
-	game->info->update_flags = (UPDATE_GRAPHICS | UPDATE_ROOM_DESC |
+	game->info->_currentRoom = room;
+	game->info->_updateFlags = (UPDATE_GRAPHICS | UPDATE_ROOM_DESC |
 	                            UPDATE_ITEM_LIST);
 }
 
@@ -386,8 +386,8 @@ static void func_set_test_result(struct function_state *func_state, bool value)
 static size_t num_objects_in_room(ComprehendGame *game, int room) {
 	size_t count = 0, i;
 
-	for (i = 0; i < game->info->header.nr_items; i++)
-		if (game->info->item[i].room == room)
+	for (i = 0; i < game->info->_header.nr_items; i++)
+		if (game->info->_item[i].room == room)
 			count++;
 
 	return count;
@@ -401,23 +401,23 @@ void move_object(ComprehendGame *game, struct item *item, int new_room) {
 
 	if (item->room == ROOM_INVENTORY) {
 		/* Removed from player's inventory */
-		game->info->variable[VAR_INVENTORY_WEIGHT] -= obj_weight;
+		game->info->_variables[VAR_INVENTORY_WEIGHT] -= obj_weight;
 	}
 	if (new_room == ROOM_INVENTORY) {
 		/* Moving to the player's inventory */
-		game->info->variable[VAR_INVENTORY_WEIGHT] += obj_weight;
+		game->info->_variables[VAR_INVENTORY_WEIGHT] += obj_weight;
 	}
 
-	if (item->room == game->info->current_room) {
+	if (item->room == game->info->_currentRoom) {
 		/* Item moved away from the current room */
-		game->info->update_flags |= UPDATE_GRAPHICS;
+		game->info->_updateFlags |= UPDATE_GRAPHICS;
 
-	} else if (new_room == game->info->current_room) {
+	} else if (new_room == game->info->_currentRoom) {
 		/*
 		 * Item moved into the current room. Only the item needs a
 		 * redraw, not the whole room.
 		 */
-		game->info->update_flags |= (UPDATE_GRAPHICS_ITEMS |
+		game->info->_updateFlags |= (UPDATE_GRAPHICS_ITEMS |
 		                             UPDATE_ITEM_LIST);
 	}
 
@@ -435,7 +435,7 @@ static void eval_instruction(ComprehendGame *game,
 	bool test;
 	uint i, count;
 
-	room = get_room(game, game->info->current_room);
+	room = get_room(game, game->info->_currentRoom);
 
 	if (debugging_enabled()) {
 		if (!instr->is_command) {
@@ -482,31 +482,31 @@ static void eval_instruction(ComprehendGame *game,
 	opcode_map = get_opcode_map(game);
 	switch (opcode_map[instr->opcode]) {
 	case OPCODE_VAR_ADD:
-		game->info->variable[instr->operand[0]] +=
-		    game->info->variable[instr->operand[1]];
+		game->info->_variables[instr->operand[0]] +=
+		    game->info->_variables[instr->operand[1]];
 		break;
 
 	case OPCODE_VAR_SUB:
-		game->info->variable[instr->operand[0]] -=
-		    game->info->variable[instr->operand[1]];
+		game->info->_variables[instr->operand[0]] -=
+		    game->info->_variables[instr->operand[1]];
 		break;
 
 	case OPCODE_VAR_INC:
-		game->info->variable[instr->operand[0]]++;
+		game->info->_variables[instr->operand[0]]++;
 		break;
 
 	case OPCODE_VAR_DEC:
-		game->info->variable[instr->operand[0]]--;
+		game->info->_variables[instr->operand[0]]--;
 		break;
 
 	case OPCODE_VAR_EQ:
 		func_set_test_result(func_state,
-		                     game->info->variable[instr->operand[0]] ==
-		                         game->info->variable[instr->operand[1]]);
+		                     game->info->_variables[instr->operand[0]] ==
+		                         game->info->_variables[instr->operand[1]]);
 		break;
 
 	case OPCODE_TURN_TICK:
-		game->info->variable[VAR_TURN_COUNT]++;
+		game->info->_variables[VAR_TURN_COUNT]++;
 		break;
 
 	case OPCODE_PRINT:
@@ -527,12 +527,12 @@ static void eval_instruction(ComprehendGame *game,
 
 	case OPCODE_NOT_IN_ROOM:
 		func_set_test_result(func_state,
-		                     game->info->current_room != instr->operand[0]);
+		                     game->info->_currentRoom != instr->operand[0]);
 		break;
 
 	case OPCODE_IN_ROOM:
 		func_set_test_result(func_state,
-		                     game->info->current_room == instr->operand[0]);
+		                     game->info->_currentRoom == instr->operand[0]);
 		break;
 
 	case OPCODE_MOVE_TO_ROOM:
@@ -574,7 +574,7 @@ static void eval_instruction(ComprehendGame *game,
 
 	case OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM:
 		item = get_item(game, instr->operand[0] - 1);
-		move_object(game, item, game->info->current_room);
+		move_object(game, item, game->info->_currentRoom);
 		break;
 
 	case OPCODE_OBJECT_IN_ROOM:
@@ -597,9 +597,9 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_INVENTORY_FULL:
 		item = get_item_by_noun(game, noun);
 		func_set_test_result(func_state,
-		                     game->info->variable[VAR_INVENTORY_WEIGHT] +
+		                     game->info->_variables[VAR_INVENTORY_WEIGHT] +
 		                             (item->flags & ITEMF_WEIGHT_MASK) >
-		                         game->info->variable[VAR_INVENTORY_LIMIT]);
+		                         game->info->_variables[VAR_INVENTORY_LIMIT]);
 		break;
 
 	case OPCODE_DESCRIBE_CURRENT_OBJECT:
@@ -616,8 +616,8 @@ static void eval_instruction(ComprehendGame *game,
 		test = false;
 
 		if (noun) {
-			for (i = 0; i < game->info->header.nr_items; i++) {
-				struct item *itemP = &game->info->item[i];
+			for (i = 0; i < game->info->_header.nr_items; i++) {
+				struct item *itemP = &game->info->_item[i];
 
 				if (itemP->word == noun->_index &&
 				    itemP->room == instr->operand[0]) {
@@ -635,7 +635,7 @@ static void eval_instruction(ComprehendGame *game,
 		item = get_item_by_noun(game, noun);
 		if (item)
 			func_set_test_result(func_state,
-			                     item->room != game->info->current_room);
+			                     item->room != game->info->_currentRoom);
 		else
 			func_set_test_result(func_state, true);
 		break;
@@ -644,7 +644,7 @@ static void eval_instruction(ComprehendGame *game,
 		item = get_item_by_noun(game, noun);
 		if (item)
 			func_set_test_result(func_state,
-			                     item->room == game->info->current_room);
+			                     item->room == game->info->_currentRoom);
 		else
 			func_set_test_result(func_state, false);
 		break;
@@ -715,13 +715,13 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_OBJECT_NOT_PRESENT:
 		item = get_item(game, instr->operand[0] - 1);
 		func_set_test_result(func_state,
-		                     item->room != game->info->current_room);
+		                     item->room != game->info->_currentRoom);
 		break;
 
 	case OPCODE_OBJECT_PRESENT:
 		item = get_item(game, instr->operand[0] - 1);
 		func_set_test_result(func_state,
-		                     item->room == game->info->current_room);
+		                     item->room == game->info->_currentRoom);
 		break;
 
 	case OPCODE_OBJECT_NOT_VALID:
@@ -758,8 +758,8 @@ static void eval_instruction(ComprehendGame *game,
 		}
 
 		console_println(game, string_lookup(game, STRING_INVENTORY));
-		for (i = 0; i < game->info->header.nr_items; i++) {
-			item = &game->info->item[i];
+		for (i = 0; i < game->info->_header.nr_items; i++) {
+			item = &game->info->_item[i];
 			if (item->room == ROOM_INVENTORY)
 				printf("%s\n",
 				       string_lookup(game, item->string_desc));
@@ -774,8 +774,8 @@ static void eval_instruction(ComprehendGame *game,
 		}
 
 		console_println(game, string_lookup(game, instr->operand[1]));
-		for (i = 0; i < game->info->header.nr_items; i++) {
-			item = &game->info->item[i];
+		for (i = 0; i < game->info->_header.nr_items; i++) {
+			item = &game->info->_item[i];
 			if (item->room == instr->operand[0])
 				printf("%s\n",
 				       string_lookup(game, item->string_desc));
@@ -792,7 +792,7 @@ static void eval_instruction(ComprehendGame *game,
 
 	case OPCODE_DROP_OBJECT:
 		item = get_item(game, instr->operand[0] - 1);
-		move_object(game, item, game->info->current_room);
+		move_object(game, item, game->info->_currentRoom);
 		break;
 
 	case OPCODE_DROP_CURRENT_OBJECT:
@@ -800,7 +800,7 @@ static void eval_instruction(ComprehendGame *game,
 		if (!item)
 			fatal_error("Attempt to take object failed\n");
 
-		move_object(game, item, game->info->current_room);
+		move_object(game, item, game->info->_currentRoom);
 		break;
 
 	case OPCODE_TAKE_CURRENT_OBJECT:
@@ -818,20 +818,20 @@ static void eval_instruction(ComprehendGame *game,
 
 	case OPCODE_TEST_FLAG:
 		func_set_test_result(func_state,
-		                     game->info->flags[instr->operand[0]]);
+		                     game->info->_flags[instr->operand[0]]);
 		break;
 
 	case OPCODE_TEST_NOT_FLAG:
 		func_set_test_result(func_state,
-		                     !game->info->flags[instr->operand[0]]);
+		                     !game->info->_flags[instr->operand[0]]);
 		break;
 
 	case OPCODE_CLEAR_FLAG:
-		game->info->flags[instr->operand[0]] = false;
+		game->info->_flags[instr->operand[0]] = false;
 		break;
 
 	case OPCODE_SET_FLAG:
-		game->info->flags[instr->operand[0]] = true;
+		game->info->_flags[instr->operand[0]] = true;
 		break;
 
 	case OPCODE_OR:
@@ -875,28 +875,28 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_SET_OBJECT_GRAPHIC:
 		item = get_item(game, instr->operand[0] - 1);
 		item->graphic = instr->operand[1];
-		if (item->room == game->info->current_room)
-			game->info->update_flags |= UPDATE_GRAPHICS;
+		if (item->room == game->info->_currentRoom)
+			game->info->_updateFlags |= UPDATE_GRAPHICS;
 		break;
 
 	case OPCODE_SET_ROOM_GRAPHIC:
 		room = get_room(game, instr->operand[0]);
 		room->graphic = instr->operand[1];
-		if (instr->operand[0] == game->info->current_room)
-			game->info->update_flags |= UPDATE_GRAPHICS;
+		if (instr->operand[0] == game->info->_currentRoom)
+			game->info->_updateFlags |= UPDATE_GRAPHICS;
 		break;
 
 	case OPCODE_CALL_FUNC:
 		index = instr->operand[0];
 		if (instr->operand[1] == 0x81)
 			index += 256;
-		if (index >= game->info->nr_functions)
+		if (index >= game->info->_nr_functions)
 			fatal_error("Bad function %.4x >= %.4x\n",
-			            index, game->info->nr_functions);
+			            index, game->info->_nr_functions);
 
 		debug_printf(DEBUG_FUNCTIONS,
 		             "Calling subfunction %.4x\n", index);
-		eval_function(game, &game->info->functions[index], verb, noun);
+		eval_function(game, &game->info->_functions[index], verb, noun);
 		break;
 
 	case OPCODE_TEST_FALSE:
@@ -923,7 +923,7 @@ static void eval_instruction(ComprehendGame *game,
 		break;
 
 	case OPCODE_SET_STRING_REPLACEMENT:
-		game->info->current_replace_word = instr->operand[0] - 1;
+		game->info->_currentReplaceWord = instr->operand[0] - 1;
 		break;
 
 	case OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT:
@@ -932,22 +932,22 @@ static void eval_instruction(ComprehendGame *game,
 		 * maybe capitalisation?
 		 */
 		if (noun && (noun->_type & WORD_TYPE_NOUN_PLURAL))
-			game->info->current_replace_word = 3;
+			game->info->_currentReplaceWord = 3;
 		else if (noun && (noun->_type & WORD_TYPE_FEMALE))
-			game->info->current_replace_word = 0;
+			game->info->_currentReplaceWord = 0;
 		else if (noun && (noun->_type & WORD_TYPE_MALE))
-			game->info->current_replace_word = 1;
+			game->info->_currentReplaceWord = 1;
 		else
-			game->info->current_replace_word = 2;
+			game->info->_currentReplaceWord = 2;
 		break;
 
 	case OPCODE_DRAW_ROOM:
-		draw_location_image(&game->info->room_images,
+		draw_location_image(&game->info->_roomImages,
 		                    instr->operand[0] - 1);
 		break;
 
 	case OPCODE_DRAW_OBJECT:
-		draw_image(&game->info->item_images, instr->operand[0] - 1);
+		draw_image(&game->info->_itemImages, instr->operand[0] - 1);
 		break;
 
 	case OPCODE_WAIT_KEY:
@@ -1067,8 +1067,8 @@ static bool handle_sentence(ComprehendGame *game,
 		return false;
 
 	/* Find a matching action */
-	for (i = 0; i < game->info->nr_actions; i++) {
-		action = &game->info->action[i];
+	for (i = 0; i < game->info->_nr_actions; i++) {
+		action = &game->info->_actions[i];
 
 		if (action->type == ACTION_VERB_OPT_NOUN &&
 		    sentence->nr_words > action->nr_words + 1)
@@ -1091,7 +1091,7 @@ static bool handle_sentence(ComprehendGame *game,
 		}
 		if (j == action->nr_words) {
 			/* Match */
-			func = &game->info->functions[action->function];
+			func = &game->info->_functions[action->function];
 			eval_function(game, func,
 			              &sentence->words[0], &sentence->words[1]);
 			return true;
@@ -1168,7 +1168,7 @@ static void before_turn(ComprehendGame *game) {
 	game->before_turn();
 
 	// Run the each turn functions
-	eval_function(game, &game->info->functions[0], NULL, NULL);
+	eval_function(game, &game->info->_functions[0], NULL, NULL);
 
 	update(game);
 }
@@ -1223,7 +1223,7 @@ void comprehend_play_game(ComprehendGame *game) {
 
 	game->before_game();
 
-	game->info->update_flags = (uint)UPDATE_ALL;
+	game->info->_updateFlags = (uint)UPDATE_ALL;
 	while (!g_comprehend->shouldQuit())
 		read_input(game);
 }
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 1d0b8c02e3..8f0bcf710e 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -35,17 +35,17 @@ namespace Comprehend {
 
 class ComprehendGame {
 public:
-	const char *game_name;
-	const char *short_name;
+	const char *_gameName;
+	const char *_shortName;
 
-	const char *game_data_file;
-	Common::Array<string_file> string_files;
-	Common::Array<const char *> location_graphic_files;
-	Common::Array<const char *> item_graphic_files;
-	const char *save_game_file_fmt;
-	unsigned color_table;
+	const char *_gameDataFile;
+	Common::Array<string_file> _stringFiles;
+	Common::Array<const char *> _locationGraphicFiles;
+	Common::Array<const char *> _itemGraphicFiles;
+	const char *_savegameFileFormat;
+	unsigned _colorTable;
 
-	struct game_strings *strings;
+	struct game_strings *_gameStrings;
 	struct game_info *info;
 
 public:
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index 74e5cdfe1e..e0a4dca5b6 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -39,19 +39,19 @@ static struct game_ops cc2_ops = {
 #endif
 
 CrimsonCrownGame::CrimsonCrownGame() : ComprehendGame() {
-	game_name = "Crimson Crown";
-	short_name = "cc1";
-	game_data_file = "cc1.gda";
-
-	string_files.push_back(string_file("ma.ms1", 0x89));
-	location_graphic_files.push_back("RA.MS1");
-	location_graphic_files.push_back("RB.MS1");
-	location_graphic_files.push_back("RC.MS1");
-	item_graphic_files.push_back("OA.MS1");
-	item_graphic_files.push_back("OB.MS1");
-
-	save_game_file_fmt = "G%d.MS0";
-	strings = &cc1_strings;
+	_gameName = "Crimson Crown";
+	_shortName = "cc1";
+	_gameDataFile = "cc1.gda";
+
+	_stringFiles.push_back(string_file("ma.ms1", 0x89));
+	_locationGraphicFiles.push_back("RA.MS1");
+	_locationGraphicFiles.push_back("RB.MS1");
+	_locationGraphicFiles.push_back("RC.MS1");
+	_itemGraphicFiles.push_back("OA.MS1");
+	_itemGraphicFiles.push_back("OB.MS1");
+
+	_savegameFileFormat = "G%d.MS0";
+	_gameStrings = &cc1_strings;
 }
 
 #ifdef TODO
@@ -71,8 +71,8 @@ ComprehendGame game_crimson_crown_2 = {
 
 static void cc_clear_companion_flags(ComprehendGame *game) {
 	/* Clear the Sabrina/Erik action flags */
-	game->info->flags[0xa] = 0;
-	game->info->flags[0xb] = 0;
+	game->info->_flags[0xa] = 0;
+	game->info->_flags[0xb] = 0;
 }
 
 static bool cc_common_handle_special_opcode(ComprehendGame *game,
@@ -128,7 +128,7 @@ static void cc2_handle_special_opcode(ComprehendGame *game,
 	switch (operand) {
 	case 0x01:
 		/* Enter the Vampire's throne room */
-		eval_function(game, &game->info->functions[0xe], NULL, NULL);
+		eval_function(game, &game->info->_functions[0xe], NULL, NULL);
 		break;
 
 	case 0x05:
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index ea3d2eae07..7b7cf3efd7 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -119,18 +119,18 @@ game_header::game_header() : magic(0),
 
 /*-------------------------------------------------------*/
 
-game_info::game_info() : comprehend_version(0),
-	                        start_room(0),
-	                        nr_rooms(0),
-	                        current_room(0),
-	                        words(nullptr),
-	                        nr_words(0),
-	                        nr_word_maps(0),
-	                        nr_actions(0),
-	                        nr_functions(0),
-	                        nr_replace_words(0),
-	                        current_replace_word(0),
-	                        update_flags(0) {
+game_info::game_info() : _comprehendVersion(0),
+	                        _startRoom(0),
+	                        _nr_rooms(0),
+	                        _currentRoom(0),
+	                        _words(nullptr),
+	                        _nr_words(0),
+	                        _nr_word_maps(0),
+	                        _nr_actions(0),
+	                        _nr_functions(0),
+	                        _nr_replace_words(0),
+	                        _currentReplaceWord(0),
+	                        _updateFlags(0) {
 }
 
 static void parse_header_le16(struct file_buf * fb, uint16 * val) {
@@ -190,15 +190,15 @@ static void parse_function(struct file_buf * fb, struct function * func) {
 static void parse_vm(ComprehendGame * game, struct file_buf * fb) {
 	struct function *func;
 
-	file_buf_set_pos(fb, game->info->header.addr_vm);
+	file_buf_set_pos(fb, game->info->_header.addr_vm);
 	while (1) {
-		func = &game->info->functions[game->info->nr_functions];
+		func = &game->info->_functions[game->info->_nr_functions];
 
 		parse_function(fb, func);
 		if (func->nr_instructions == 0)
 			break;
 
-		game->info->nr_functions++;
+		game->info->_nr_functions++;
 	}
 }
 
@@ -218,7 +218,7 @@ static void parse_action_table_vvnn(ComprehendGame * game,
 	*     u8:   noun2
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->header.addr_actions_vvnn);
+	file_buf_set_pos(fb, game->info->_header.addr_actions_vvnn);
 	while (1) {
 		file_buf_get_u8(fb, &verb);
 		if (verb == 0)
@@ -226,7 +226,7 @@ static void parse_action_table_vvnn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->action[*index];
+			action = &game->info->_actions[*index];
 			action->type = ACTION_VERB_VERB_NOUN_NOUN;
 
 			action->nr_words = 4;
@@ -262,7 +262,7 @@ static void parse_action_table_vnjn(ComprehendGame * game,
 	*     u8:   noun2
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->header.addr_actions_vnjn);
+	file_buf_set_pos(fb, game->info->_header.addr_actions_vnjn);
 	while (1) {
 		file_buf_get_u8(fb, &join);
 		if (join == 0)
@@ -270,7 +270,7 @@ static void parse_action_table_vnjn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->action[*index];
+			action = &game->info->_actions[*index];
 			action->type = ACTION_VERB_NOUN_JOIN_NOUN;
 
 			action->nr_words = 4;
@@ -306,7 +306,7 @@ static void parse_action_table_vjn(ComprehendGame * game,
 	*     u8:   noun
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->header.addr_actions_vjn);
+	file_buf_set_pos(fb, game->info->_header.addr_actions_vjn);
 	while (1) {
 		file_buf_get_u8(fb, &join);
 		if (join == 0)
@@ -314,7 +314,7 @@ static void parse_action_table_vjn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->action[*index];
+			action = &game->info->_actions[*index];
 			action->type = ACTION_VERB_JOIN_NOUN;
 			action->word[1] = join;
 
@@ -347,7 +347,7 @@ static void parse_action_table_vdn(ComprehendGame * game,
 	*     u8:   noun
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->header.addr_actions_vdn);
+	file_buf_set_pos(fb, game->info->_header.addr_actions_vdn);
 	while (1) {
 		file_buf_get_u8(fb, &verb);
 		if (verb == 0)
@@ -355,7 +355,7 @@ static void parse_action_table_vdn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->action[*index];
+			action = &game->info->_actions[*index];
 			action->type = ACTION_VERB_JOIN_NOUN;
 			action->word[0] = verb;
 
@@ -388,7 +388,7 @@ static void parse_action_table_vnn(ComprehendGame * game,
 	*     u8:   noun2
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->header.addr_actions_vnn);
+	file_buf_set_pos(fb, game->info->_header.addr_actions_vnn);
 	while (1) {
 		/* 2-byte header */
 		file_buf_get_u8(fb, &verb);
@@ -397,7 +397,7 @@ static void parse_action_table_vnn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->action[*index];
+			action = &game->info->_actions[*index];
 			action->type = ACTION_VERB_NOUN_NOUN;
 			action->word[0] = verb;
 
@@ -429,7 +429,7 @@ static void parse_action_table_vn(ComprehendGame * game,
 	*     u8:   noun
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->header.addr_actions_vn);
+	file_buf_set_pos(fb, game->info->_header.addr_actions_vn);
 	while (1) {
 		/* 2-byte header */
 		file_buf_get_u8(fb, &verb);
@@ -438,7 +438,7 @@ static void parse_action_table_vn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->action[*index];
+			action = &game->info->_actions[*index];
 			action->type = ACTION_VERB_NOUN;
 			action->word[0] = verb;
 
@@ -468,13 +468,13 @@ static void parse_action_table_v(ComprehendGame * game,
 	* u8: count (num actions)
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->header.addr_actions_v);
+	file_buf_set_pos(fb, game->info->_header.addr_actions_v);
 	while (1) {
 		file_buf_get_u8(fb, &verb);
 		if (verb == 0)
 			break;
 
-		action = &game->info->action[*index];
+		action = &game->info->_actions[*index];
 		action->type = ACTION_VERB_OPT_NOUN;
 		action->word[0] = verb;
 
@@ -499,20 +499,20 @@ static void parse_action_table_v(ComprehendGame * game,
 
 static void parse_action_table(ComprehendGame * game,
 	                            struct file_buf * fb) {
-	game->info->nr_actions = 0;
+	game->info->_nr_actions = 0;
 
-	if (game->info->comprehend_version == 1) {
-		parse_action_table_vvnn(game, fb, &game->info->nr_actions);
-		parse_action_table_vdn(game, fb, &game->info->nr_actions);
+	if (game->info->_comprehendVersion == 1) {
+		parse_action_table_vvnn(game, fb, &game->info->_nr_actions);
+		parse_action_table_vdn(game, fb, &game->info->_nr_actions);
 	}
-	if (game->info->comprehend_version >= 2) {
-		parse_action_table_vnn(game, fb, &game->info->nr_actions);
+	if (game->info->_comprehendVersion >= 2) {
+		parse_action_table_vnn(game, fb, &game->info->_nr_actions);
 	}
 
-	parse_action_table_vnjn(game, fb, &game->info->nr_actions);
-	parse_action_table_vjn(game, fb, &game->info->nr_actions);
-	parse_action_table_vn(game, fb, &game->info->nr_actions);
-	parse_action_table_v(game, fb, &game->info->nr_actions);
+	parse_action_table_vnjn(game, fb, &game->info->_nr_actions);
+	parse_action_table_vjn(game, fb, &game->info->_nr_actions);
+	parse_action_table_vn(game, fb, &game->info->_nr_actions);
+	parse_action_table_v(game, fb, &game->info->_nr_actions);
 }
 
 static void parse_dictionary(ComprehendGame * game, struct file_buf * fb) {
@@ -520,11 +520,11 @@ static void parse_dictionary(ComprehendGame * game, struct file_buf * fb) {
 	uint i, j;
 
 	// FIXME - fixed size 0xff array?
-	game->info->words = (word *)xmalloc(game->info->nr_words * sizeof(words));
+	game->info->_words = (word *)xmalloc(game->info->_nr_words * sizeof(words));
 
-	file_buf_set_pos(fb, game->info->header.addr_dictionary);
-	for (i = 0; i < game->info->nr_words; i++) {
-		words = &game->info->words[i];
+	file_buf_set_pos(fb, game->info->_header.addr_dictionary);
+	for (i = 0; i < game->info->_nr_words; i++) {
+		words = &game->info->_words[i];
 
 		file_buf_get_data(fb, words->_word, 6);
 
@@ -543,15 +543,15 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 	uint8 index, type, dummy;
 	uint i;
 
-	game->info->nr_word_maps = 0;
-	file_buf_set_pos(fb, game->info->header.addr_word_map);
+	game->info->_nr_word_maps = 0;
+	file_buf_set_pos(fb, game->info->_header.addr_word_map);
 
 	/*
 	* Parse the word pair table. Each entry has a pair of dictionary
 	* index/type values for a first and second word.
 	*/
 	while (1) {
-		map = &game->info->word_map[game->info->nr_word_maps];
+		map = &game->info->_wordMaps[game->info->_nr_word_maps];
 
 		file_buf_get_u8(fb, &index);
 		file_buf_get_u8(fb, &type);
@@ -566,7 +566,7 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 		file_buf_get_u8(fb, &map->word[1].index);
 		file_buf_get_u8(fb, &map->word[1].type);
 
-		game->info->nr_word_maps++;
+		game->info->_nr_word_maps++;
 	}
 
 	/* Consume two more null bytes (type and index were also null) */
@@ -578,8 +578,8 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 	* index/type. The first and second words from above map to the
 	* target word here. E.g. 'go north' -> 'north'.
 	*/
-	for (i = 0; i < game->info->nr_word_maps; i++) {
-		map = &game->info->word_map[i];
+	for (i = 0; i < game->info->_nr_word_maps; i++) {
+		map = &game->info->_wordMaps[i];
 
 		file_buf_get_u8(fb, &map->word[2].index);
 		file_buf_get_u8(fb, &map->word[2].type);
@@ -587,58 +587,58 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 }
 
 static void parse_items(ComprehendGame * game, struct file_buf * fb) {
-	size_t nr_items = game->info->header.nr_items;
+	size_t nr_items = game->info->_header.nr_items;
 
 	/* Item descriptions */
-	file_buf_set_pos(fb, game->info->header.addr_item_strings);
-	file_buf_get_array_le16(fb, 0, game->info->item, string_desc, nr_items);
+	file_buf_set_pos(fb, game->info->_header.addr_item_strings);
+	file_buf_get_array_le16(fb, 0, game->info->_item, string_desc, nr_items);
 
-	if (game->info->comprehend_version == 2) {
+	if (game->info->_comprehendVersion == 2) {
 		/* Comprehend version 2 adds long string descriptions */
-		file_buf_set_pos(fb, game->info->header.addr_item_strings +
-			                        (game->info->header.nr_items * sizeof(uint16)));
-		file_buf_get_array_le16(fb, 0, game->info->item, long_string, nr_items);
+		file_buf_set_pos(fb, game->info->_header.addr_item_strings +
+			                        (game->info->_header.nr_items * sizeof(uint16)));
+		file_buf_get_array_le16(fb, 0, game->info->_item, long_string, nr_items);
 	}
 
 	/* Item flags */
-	file_buf_set_pos(fb, game->info->header.addr_item_flags);
-	file_buf_get_array_u8(fb, 0, game->info->item, flags, nr_items);
+	file_buf_set_pos(fb, game->info->_header.addr_item_flags);
+	file_buf_get_array_u8(fb, 0, game->info->_item, flags, nr_items);
 
 	/* Item word */
-	file_buf_set_pos(fb, game->info->header.addr_item_word);
-	file_buf_get_array_u8(fb, 0, game->info->item, word, nr_items);
+	file_buf_set_pos(fb, game->info->_header.addr_item_word);
+	file_buf_get_array_u8(fb, 0, game->info->_item, word, nr_items);
 
 	/* Item locations */
-	file_buf_set_pos(fb, game->info->header.addr_item_locations);
-	file_buf_get_array_u8(fb, 0, game->info->item, room, nr_items);
+	file_buf_set_pos(fb, game->info->_header.addr_item_locations);
+	file_buf_get_array_u8(fb, 0, game->info->_item, room, nr_items);
 
 	/* Item graphic */
-	file_buf_set_pos(fb, game->info->header.addr_item_graphics);
-	file_buf_get_array_u8(fb, 0, game->info->item, graphic, nr_items);
+	file_buf_set_pos(fb, game->info->_header.addr_item_graphics);
+	file_buf_get_array_u8(fb, 0, game->info->_item, graphic, nr_items);
 }
 
 static void parse_rooms(ComprehendGame * game, struct file_buf * fb) {
-	size_t nr_rooms = game->info->nr_rooms;
+	size_t nr_rooms = game->info->_nr_rooms;
 	int i;
 
 	/* Room exit directions */
 	for (i = 0; i < NR_DIRECTIONS; i++) {
-		file_buf_set_pos(fb, game->info->header.room_direction_table[i]);
-		file_buf_get_array_u8(fb, 1, game->info->rooms,
+		file_buf_set_pos(fb, game->info->_header.room_direction_table[i]);
+		file_buf_get_array_u8(fb, 1, game->info->_rooms,
 			                    direction[i], nr_rooms);
 	}
 
 	/* Room string descriptions */
-	file_buf_set_pos(fb, game->info->header.room_desc_table);
-	file_buf_get_array_le16(fb, 1, game->info->rooms, string_desc, nr_rooms);
+	file_buf_set_pos(fb, game->info->_header.room_desc_table);
+	file_buf_get_array_le16(fb, 1, game->info->_rooms, string_desc, nr_rooms);
 
 	/* Room flags */
-	file_buf_set_pos(fb, game->info->header.room_flags_table);
-	file_buf_get_array_u8(fb, 1, game->info->rooms, flags, nr_rooms);
+	file_buf_set_pos(fb, game->info->_header.room_flags_table);
+	file_buf_get_array_u8(fb, 1, game->info->_rooms, flags, nr_rooms);
 
 	/* Room graphic */
-	file_buf_set_pos(fb, game->info->header.room_graphics_table);
-	file_buf_get_array_u8(fb, 1, game->info->rooms, graphic, nr_rooms);
+	file_buf_set_pos(fb, game->info->_header.room_graphics_table);
+	file_buf_get_array_u8(fb, 1, game->info->_rooms, graphic, nr_rooms);
 }
 
 static uint64 string_get_chunk(uint8 * string) {
@@ -751,18 +751,18 @@ static void parse_string_table(struct file_buf * fb, unsigned start_addr,
 static void parse_variables(ComprehendGame * game, struct file_buf * fb) {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(game->info->variable); i++)
-		file_buf_get_le16(fb, &game->info->variable[i]);
+	for (i = 0; i < ARRAY_SIZE(game->info->_variables); i++)
+		file_buf_get_le16(fb, &game->info->_variables[i]);
 }
 
 static void parse_flags(ComprehendGame * game, struct file_buf * fb) {
 	int i, bit, flag_index = 0;
 	uint8 bitmask;
 
-	for (i = 0; i < ARRAY_SIZE(game->info->flags) / 8; i++) {
+	for (i = 0; i < ARRAY_SIZE(game->info->_flags) / 8; i++) {
 		file_buf_get_u8(fb, &bitmask);
 		for (bit = 7; bit >= 0; bit--) {
-			game->info->flags[flag_index] = !!(bitmask & (1 << bit));
+			game->info->_flags[flag_index] = !!(bitmask & (1 << bit));
 			flag_index++;
 		}
 	}
@@ -776,7 +776,7 @@ static void parse_replace_words(ComprehendGame * game,
 	int i;
 
 	/* FIXME - Rename addr_strings_end */
-	file_buf_set_pos(fb, game->info->header.addr_strings_end);
+	file_buf_set_pos(fb, game->info->_header.addr_strings_end);
 
 	/* FIXME - what is this for */
 	file_buf_get_le16(fb, &dummy);
@@ -786,12 +786,12 @@ static void parse_replace_words(ComprehendGame * game,
 		if (len == 0)
 			break;
 
-		game->info->replace_words[i] = xstrndup((char *)fb->p, len);
+		game->info->_replaceWords[i] = xstrndup((char *)fb->p, len);
 		file_buf_get_data(fb, NULL, len + (eof ? 0 : 1));
 		if (eof)
 			break;
 	}
-	game->info->nr_replace_words = i;
+	game->info->_nr_replace_words = i;
 }
 
 /*
@@ -799,7 +799,7 @@ static void parse_replace_words(ComprehendGame * game,
 * game data is. The offsets have a magic constant value added to them.
 */
 static void parse_header(ComprehendGame * game, struct file_buf * fb) {
-	struct game_header *header = &game->info->header;
+	struct game_header *header = &game->info->_header;
 	uint16 dummy, addr_dictionary_end;
 	uint8 dummy8;
 
@@ -808,17 +808,17 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	switch (header->magic) {
 	case 0x2000: /* Transylvania, Crimson Crown disk one */
 	case 0x4800: /* Crimson Crown disk two */
-		game->info->comprehend_version = 1;
+		game->info->_comprehendVersion = 1;
 		magic_offset = (uint16)(-0x5a00 + 0x4);
 		break;
 
 	case 0x93f0: /* OO-Topos */
-		game->info->comprehend_version = 2;
+		game->info->_comprehendVersion = 2;
 		magic_offset = (uint16)-0x5a00;
 		break;
 
 	case 0xa429: /* Talisman */
-		game->info->comprehend_version = 2;
+		game->info->_comprehendVersion = 2;
 		magic_offset = (uint16)-0x5a00;
 		break;
 
@@ -835,14 +835,14 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	*
 	* Layout depends on the comprehend version.
 	*/
-	if (game->info->comprehend_version == 1) {
+	if (game->info->_comprehendVersion == 1) {
 		parse_header_le16(fb, &header->addr_actions_vvnn);
 		parse_header_le16(fb, &header->addr_actions_unknown);
 		parse_header_le16(fb, &header->addr_actions_vnjn);
 		parse_header_le16(fb, &header->addr_actions_vjn);
 		parse_header_le16(fb, &header->addr_actions_vdn);
 	}
-	if (game->info->comprehend_version >= 2) {
+	if (game->info->_comprehendVersion >= 2) {
 		parse_header_le16(fb, &header->addr_actions_vnjn);
 		parse_header_le16(fb, &header->addr_actions_vjn);
 		parse_header_le16(fb, &header->addr_actions_vnn);
@@ -876,7 +876,7 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	*
 	* Layout is dependent on comprehend version.
 	*/
-	if (game->info->comprehend_version == 1) {
+	if (game->info->_comprehendVersion == 1) {
 		parse_header_le16(fb, &header->addr_item_locations);
 		parse_header_le16(fb, &header->addr_item_flags);
 		parse_header_le16(fb, &header->addr_item_word);
@@ -902,16 +902,16 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	parse_header_le16(fb, &header->addr_strings_end);
 
 	file_buf_get_u8(fb, &dummy8);
-	file_buf_get_u8(fb, &game->info->start_room);
+	file_buf_get_u8(fb, &game->info->_startRoom);
 	file_buf_get_u8(fb, &dummy8);
 
 	parse_variables(game, fb);
 	parse_flags(game, fb);
 
-	game->info->nr_rooms = header->room_direction_table[DIRECTION_SOUTH] -
+	game->info->_nr_rooms = header->room_direction_table[DIRECTION_SOUTH] -
 		                    header->room_direction_table[DIRECTION_NORTH];
 
-	game->info->nr_words = (addr_dictionary_end -
+	game->info->_nr_words = (addr_dictionary_end -
 		                    header->addr_dictionary) /
 		                    8;
 }
@@ -929,7 +929,7 @@ static void load_extra_string_file(ComprehendGame * game,
 		end = fb.size;
 
 	parse_string_table(&fb, string_file->base_offset,
-		                end, &game->info->strings2);
+		                end, &game->info->_strings2);
 
 	file_buf_unmap(&fb);
 }
@@ -937,18 +937,18 @@ static void load_extra_string_file(ComprehendGame * game,
 static void load_extra_string_files(ComprehendGame * game) {
 	int i;
 
-	memset(&game->info->strings2, 0, sizeof(game->info->strings2));
+	memset(&game->info->_strings2, 0, sizeof(game->info->_strings2));
 
-	for (i = 0; i < ARRAY_SIZE(game->string_files); i++) {
-		if (!game->string_files[i].filename)
+	for (i = 0; i < ARRAY_SIZE(game->_stringFiles); i++) {
+		if (!game->_stringFiles[i].filename)
 			break;
 
 		// HACK - get string offsets correct
-		game->info->strings2.nr_strings = 0x40 * i;
-		if (game->info->strings2.nr_strings == 0)
-			game->info->strings2.nr_strings++;
+		game->info->_strings2.nr_strings = 0x40 * i;
+		if (game->info->_strings2.nr_strings == 0)
+			game->info->_strings2.nr_strings++;
 
-		load_extra_string_file(game, &game->string_files[i]);
+		load_extra_string_file(game, &game->_stringFiles[i]);
 	}
 }
 
@@ -956,17 +956,17 @@ static void load_game_data(ComprehendGame * game) {
 	struct file_buf fb;
 
 	memset(game->info, 0, sizeof(*game->info));
-	file_buf_map(game->game_data_file, &fb);
+	file_buf_map(game->_gameDataFile, &fb);
 
 	parse_header(game, &fb);
 	parse_rooms(game, &fb);
 	parse_items(game, &fb);
 	parse_dictionary(game, &fb);
 	parse_word_map(game, &fb);
-	memset(&game->info->strings, 0, sizeof(game->info->strings));
-	parse_string_table(&fb, game->info->header.addr_strings,
-		                game->info->header.addr_strings_end,
-		                &game->info->strings);
+	memset(&game->info->_strings, 0, sizeof(game->info->_strings));
+	parse_string_table(&fb, game->info->_header.addr_strings,
+		                game->info->_header.addr_strings_end,
+		                &game->info->_strings);
 	load_extra_string_files(game);
 	parse_vm(game, &fb);
 	parse_action_table(game, &fb);
@@ -981,12 +981,12 @@ void comprehend_load_game(ComprehendGame * game) {
 
 	if (g_enabled()) {
 		comprehend_load_images(game);
-		if (game->color_table)
-			g_set_color_table(game->color_table);
+		if (game->_colorTable)
+			g_set_color_table(game->_colorTable);
 	}
 
 	/* FIXME - This can be merged, don't need to keep start room around */
-	game->info->current_room = game->info->start_room;
+	game->info->_currentRoom = game->info->_startRoom;
 }
 
 #ifdef TODO
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 4146bf8ba5..6bc13f211a 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -167,44 +167,44 @@ struct game_header {
 };
 
 struct game_info {
-	game_header header;
+	game_header _header;
 
-	unsigned comprehend_version;
+	unsigned _comprehendVersion;
 
-	uint8 start_room;
+	uint8 _startRoom;
 
-	room rooms[0x100];
-	size_t nr_rooms;
-	uint8 current_room;
+	room _rooms[0x100];
+	size_t _nr_rooms;
+	uint8 _currentRoom;
 
-	struct item item[0xff];
+	struct item _item[0xff];
 
-	struct word *words;
-	size_t nr_words;
+	struct word *_words;
+	size_t _nr_words;
 
-	struct word_map word_map[0xff];
-	size_t nr_word_maps;
+	struct word_map _wordMaps[0xff];
+	size_t _nr_word_maps;
 
-	struct string_table strings;
-	struct string_table strings2;
+	struct string_table _strings;
+	struct string_table _strings2;
 
-	struct action action[0xffff];
-	size_t nr_actions;
+	struct action _actions[0xffff];
+	size_t _nr_actions;
 
-	struct function functions[0xffff];
-	size_t nr_functions;
+	struct function _functions[0xffff];
+	size_t _nr_functions;
 
-	struct image_data room_images;
-	struct image_data item_images;
+	struct image_data _roomImages;
+	struct image_data _itemImages;
 
-	bool flags[MAX_FLAGS];
-	uint16 variable[MAX_VARIABLES];
+	bool _flags[MAX_FLAGS];
+	uint16 _variables[MAX_VARIABLES];
 
-	char *replace_words[256];
-	size_t nr_replace_words;
+	char *_replaceWords[256];
+	size_t _nr_replace_words;
 
-	uint8 current_replace_word;
-	unsigned update_flags;
+	uint8 _currentReplaceWord;
+	unsigned _updateFlags;
 
 	game_info();
 };
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index c53c6bf824..42fb1a0aa3 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -35,37 +35,37 @@ namespace Comprehend {
 #define OO_FLAG_FLASHLIGHT_ON 0x27
 
 OOToposGame::OOToposGame() : ComprehendGame() {
-	game_name = "Oo-Topos";
-	short_name = "oo";
-	game_data_file = "g0";
+	_gameName = "Oo-Topos";
+	_shortName = "oo";
+	_gameDataFile = "g0";
 
 	// Extra strings are (annoyingly) stored in the game binary
-	string_files.push_back(string_file("NOVEL.EXE", 0x16564, 0x17640));
-	string_files.push_back(string_file("NOVEL.EXE", 0x17702, 0x18600));
-	string_files.push_back(string_file("NOVEL.EXE", 0x186b2, 0x19b80));
-	string_files.push_back(string_file("NOVEL.EXE", 0x19c62, 0x1a590));
-	string_files.push_back(string_file("NOVEL.EXE", 0x1a634, 0x1b080));
-	location_graphic_files.push_back("RA");
-	location_graphic_files.push_back("RB");
-	location_graphic_files.push_back("RC");
-	location_graphic_files.push_back("RD");
-	location_graphic_files.push_back("RE");
-	item_graphic_files.push_back("OA");
-	item_graphic_files.push_back("OB");
-	item_graphic_files.push_back("OC");
-	item_graphic_files.push_back("OD");
-
-	save_game_file_fmt = "G%d";
-	color_table = 1;
+	_stringFiles.push_back(string_file("NOVEL.EXE", 0x16564, 0x17640));
+	_stringFiles.push_back(string_file("NOVEL.EXE", 0x17702, 0x18600));
+	_stringFiles.push_back(string_file("NOVEL.EXE", 0x186b2, 0x19b80));
+	_stringFiles.push_back(string_file("NOVEL.EXE", 0x19c62, 0x1a590));
+	_stringFiles.push_back(string_file("NOVEL.EXE", 0x1a634, 0x1b080));
+	_locationGraphicFiles.push_back("RA");
+	_locationGraphicFiles.push_back("RB");
+	_locationGraphicFiles.push_back("RC");
+	_locationGraphicFiles.push_back("RD");
+	_locationGraphicFiles.push_back("RE");
+	_itemGraphicFiles.push_back("OA");
+	_itemGraphicFiles.push_back("OB");
+	_itemGraphicFiles.push_back("OC");
+	_itemGraphicFiles.push_back("OD");
+
+	_savegameFileFormat = "G%d";
+	_colorTable = 1;
 }
 
 int OOToposGame::room_is_special(unsigned room_index,
                               unsigned *room_desc_string) {
-	room *room = &info->rooms[room_index];
+	room *room = &info->_rooms[room_index];
 
 	/* Is the room dark */
 	if ((room->flags & OO_ROOM_FLAG_DARK) &&
-	    !(info->flags[OO_FLAG_FLASHLIGHT_ON])) {
+	    !(info->_flags[OO_FLAG_FLASHLIGHT_ON])) {
 		if (room_desc_string)
 			*room_desc_string = 0xb3;
 		return ROOM_IS_DARK;
@@ -73,7 +73,7 @@ int OOToposGame::room_is_special(unsigned room_index,
 
 	/* Is the room too bright */
 	if (room_index == OO_BRIGHT_ROOM &&
-	    !info->flags[OO_FLAG_WEARING_GOGGLES]) {
+	    !info->_flags[OO_FLAG_WEARING_GOGGLES]) {
 		if (room_desc_string)
 			*room_desc_string = 0x1c;
 		return ROOM_IS_TOO_BRIGHT;
@@ -85,26 +85,26 @@ int OOToposGame::room_is_special(unsigned room_index,
 bool OOToposGame::before_turn() {
 	/* FIXME - probably doesn't work correctly with restored games */
 	static bool flashlight_was_on = false, googles_were_worn = false;
-	struct room *room = &info->rooms[info->current_room];
+	struct room *room = &info->_rooms[info->_currentRoom];
 
 	/* 
 	 * Check if the room needs to be redrawn because the flashlight
 	 * was switch off or on.
 	 */
-	if (info->flags[OO_FLAG_FLASHLIGHT_ON] != flashlight_was_on &&
+	if (info->_flags[OO_FLAG_FLASHLIGHT_ON] != flashlight_was_on &&
 	    (room->flags & OO_ROOM_FLAG_DARK)) {
-		flashlight_was_on = info->flags[OO_FLAG_FLASHLIGHT_ON];
-		info->update_flags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
+		flashlight_was_on = info->_flags[OO_FLAG_FLASHLIGHT_ON];
+		info->_updateFlags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
 	}
 
 	/*
 	 * Check if the room needs to be redrawn because the goggles were
 	 * put on or removed.
 	 */
-	if (info->flags[OO_FLAG_WEARING_GOGGLES] != googles_were_worn &&
-	    info->current_room == OO_BRIGHT_ROOM) {
-		googles_were_worn = info->flags[OO_FLAG_WEARING_GOGGLES];
-		info->update_flags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
+	if (info->_flags[OO_FLAG_WEARING_GOGGLES] != googles_were_worn &&
+	    info->_currentRoom == OO_BRIGHT_ROOM) {
+		googles_were_worn = info->_flags[OO_FLAG_WEARING_GOGGLES];
+		info->_updateFlags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
 	}
 
 	return false;
diff --git a/engines/glk/comprehend/game_tm.cpp b/engines/glk/comprehend/game_tm.cpp
index ad714fb398..6ba9ff960a 100644
--- a/engines/glk/comprehend/game_tm.cpp
+++ b/engines/glk/comprehend/game_tm.cpp
@@ -29,21 +29,21 @@ namespace Comprehend {
 /* FIXME - This is broken */
 
 TalismanGame::TalismanGame() : ComprehendGame() {
-	game_name = "Talisman, Challenging the Sands of Time (broken)";
-	short_name = "tm";
-	game_data_file = "G0";
+	_gameName = "Talisman, Challenging the Sands of Time (broken)";
+	_shortName = "tm";
+	_gameDataFile = "G0";
 
-	location_graphic_files.push_back("RA");
-	location_graphic_files.push_back("RB");
-	location_graphic_files.push_back("RC");
-	location_graphic_files.push_back("RD");
-	location_graphic_files.push_back("RE");
-	location_graphic_files.push_back("RF");
-	location_graphic_files.push_back("RG");
-	item_graphic_files.push_back("OA");
-	item_graphic_files.push_back("OB");
-	item_graphic_files.push_back("OE");
-	item_graphic_files.push_back("OF");
+	_locationGraphicFiles.push_back("RA");
+	_locationGraphicFiles.push_back("RB");
+	_locationGraphicFiles.push_back("RC");
+	_locationGraphicFiles.push_back("RD");
+	_locationGraphicFiles.push_back("RE");
+	_locationGraphicFiles.push_back("RF");
+	_locationGraphicFiles.push_back("RG");
+	_itemGraphicFiles.push_back("OA");
+	_itemGraphicFiles.push_back("OB");
+	_itemGraphicFiles.push_back("OE");
+	_itemGraphicFiles.push_back("OF");
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index f03fc29321..e94814aa86 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -42,26 +42,26 @@ static struct game_strings tr_strings = {
 
 
 TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
-	game_name = "Transylvania";
-	short_name = "tr";
-	game_data_file = "tr.gda";
-
-	string_files.push_back(string_file("MA.MS1", 0x88));
-	string_files.push_back(string_file("MB.MS1", 0x88));
-	string_files.push_back(string_file("MC.MS1", 0x88));
-	string_files.push_back(string_file("MD.MS1", 0x88));
-	string_files.push_back(string_file("ME.MS1", 0x88));
-
-    location_graphic_files.push_back("RA.MS1");
-	location_graphic_files.push_back("RB.MS1");
-	location_graphic_files.push_back("RC.MS1");
-
-	item_graphic_files.push_back("OA.MS1");
-	item_graphic_files.push_back("OB.MS1");
-	item_graphic_files.push_back("OC.MS1");
-
-	save_game_file_fmt = "G%d.MS0";
-	strings = &tr_strings;
+	_gameName = "Transylvania";
+	_shortName = "tr";
+	_gameDataFile = "tr.gda";
+
+	_stringFiles.push_back(string_file("MA.MS1", 0x88));
+	_stringFiles.push_back(string_file("MB.MS1", 0x88));
+	_stringFiles.push_back(string_file("MC.MS1", 0x88));
+	_stringFiles.push_back(string_file("MD.MS1", 0x88));
+	_stringFiles.push_back(string_file("ME.MS1", 0x88));
+
+    _locationGraphicFiles.push_back("RA.MS1");
+	_locationGraphicFiles.push_back("RB.MS1");
+	_locationGraphicFiles.push_back("RC.MS1");
+
+	_itemGraphicFiles.push_back("OA.MS1");
+	_itemGraphicFiles.push_back("OB.MS1");
+	_itemGraphicFiles.push_back("OC.MS1");
+
+	_savegameFileFormat = "G%d.MS0";
+	_gameStrings = &tr_strings;
 };
 
 void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
@@ -69,17 +69,17 @@ void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
 	struct room *room;
 	uint16 turn_count;
 
-	room = &info->rooms[info->current_room];
-	turn_count = info->variable[VAR_TURN_COUNT];
+	room = &info->_rooms[info->_currentRoom];
+	turn_count = info->_variables[VAR_TURN_COUNT];
 
 	monster = get_item(this, monster_info->object);
-	if (monster->room == info->current_room) {
+	if (monster->room == info->_currentRoom) {
 		/* The monster is in the current room - leave it there */
 		return;
 	}
 
 	if ((room->flags & monster_info->room_allow_flag) &&
-	    !info->flags[monster_info->dead_flag] &&
+	    !info->_flags[monster_info->dead_flag] &&
 	    turn_count > monster_info->min_turns_before) {
 		/*
 		 * The monster is alive and allowed to move to the current
@@ -87,8 +87,8 @@ void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
 		 * it back to limbo.
 		 */
 		if ((g_comprehend->getRandomNumber(0x7fffffff) % monster_info->randomness) == 0) {
-			move_object(this, monster, info->current_room);
-			info->variable[0xf] = turn_count + 1;
+			move_object(this, monster, info->_currentRoom);
+			info->_variables[0xf] = turn_count + 1;
 		} else {
 			move_object(this, monster, ROOM_NOWHERE);
 		}
@@ -98,7 +98,7 @@ void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
 int TransylvaniaGame::room_is_special(unsigned room_index,
 			      unsigned *room_desc_string)
 {
-	struct room *room = &info->rooms[room_index];
+	struct room *room = &info->_rooms[room_index];
 
 	if (room_index == 0x28) {
 		if (room_desc_string)
@@ -151,9 +151,9 @@ void TransylvaniaGame::handle_special_opcode(uint8 operand)
 		 * Show the Zin screen in reponse to doing 'sing some enchanted
 		 * evening' in his cabin.
 		 */
-		draw_location_image(&info->room_images, 41);
+		draw_location_image(&info->_roomImages, 41);
 		console_get_key();
-		info->update_flags |= UPDATE_GRAPHICS;
+		info->_updateFlags |= UPDATE_GRAPHICS;
 		break;
 	}
 }
@@ -179,7 +179,7 @@ void TransylvaniaGame::before_game() {
 	char buffer[128];
 
 	/* Welcome to Transylvania - sign your name */
-	console_println(this, info->strings.strings[0x20]);
+	console_println(this, info->_strings.strings[0x20]);
 	read_string(buffer, sizeof(buffer));
 
 	/*
@@ -188,15 +188,15 @@ void TransylvaniaGame::before_game() {
 	 * limited (the original game will break if you put a name in that
 	 * is too long).
 	 */
-	if (!info->replace_words[0])
-		info->replace_words[0] = xstrndup(buffer, strlen(buffer));
+	if (!info->_replaceWords[0])
+		info->_replaceWords[0] = xstrndup(buffer, strlen(buffer));
 	else
-		snprintf(info->replace_words[0],
-			 strlen(info->replace_words[0]),
+		snprintf(info->_replaceWords[0],
+			 strlen(info->_replaceWords[0]),
 			 "%s", buffer);
 
 	/* And your next of kin - This isn't store by the game */
-	console_println(this, info->strings.strings[0x21]);
+	console_println(this, info->_strings.strings[0x21]);
 	read_string(buffer, sizeof(buffer));
 }
 
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 7f783abe7c..77b85167ee 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -349,11 +349,11 @@ void comprehend_load_image_file(const char *filename, struct image_data *info)
 }
 
 void comprehend_load_images(ComprehendGame *game) {
-	load_image_files(&game->info->room_images,
-			 game->location_graphic_files);
+	load_image_files(&game->info->_roomImages,
+			 game->_locationGraphicFiles);
 
-	load_image_files(&game->info->item_images,
-			 game->item_graphic_files);
+	load_image_files(&game->info->_itemImages,
+			 game->_itemGraphicFiles);
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/opcode_map.cpp b/engines/glk/comprehend/opcode_map.cpp
index 61b0526b48..431ba0c065 100644
--- a/engines/glk/comprehend/opcode_map.cpp
+++ b/engines/glk/comprehend/opcode_map.cpp
@@ -175,7 +175,7 @@ static uint8 opcode_map_v2[0x100] = {
 
 uint8 *get_opcode_map(ComprehendGame *game)
 {
-	switch (game->info->comprehend_version) {
+	switch (game->info->_comprehendVersion) {
 	case 1:
 		return opcode_map_v1;
 		break;
@@ -183,7 +183,7 @@ uint8 *get_opcode_map(ComprehendGame *game)
 		return opcode_map_v2;
 	default:
 		fatal_error("Unsupported Comprehend version %d\n",
-			    game->info->comprehend_version);
+			    game->info->_comprehendVersion);
 
 		/* Not reached */
 		return NULL;
diff --git a/engines/glk/comprehend/strings.cpp b/engines/glk/comprehend/strings.cpp
index 784dfec506..7ddf1a5059 100644
--- a/engines/glk/comprehend/strings.cpp
+++ b/engines/glk/comprehend/strings.cpp
@@ -55,8 +55,8 @@ const char *string_lookup(ComprehendGame *game, uint16 index)
 		/* Fall-through */
 	case 0x00:
 	case 0x80:
-		if (string < game->info->strings.nr_strings)
-			return game->info->strings.strings[string];
+		if (string < game->info->_strings.nr_strings)
+			return game->info->_strings.strings[string];
 		break;
 
 	case 0x83:
@@ -64,8 +64,8 @@ const char *string_lookup(ComprehendGame *game, uint16 index)
 		/* Fall-through */
 	case 0x02:
 	case 0x82:
-		if (string < game->info->strings2.nr_strings)
-			return game->info->strings2.strings[string];
+		if (string < game->info->_strings2.nr_strings)
+			return game->info->_strings2.strings[string];
 		break;
 	}
 


Commit: b0fe096225cfc9630bd741f1260d303bafd42c4e
    https://github.com/scummvm/scummvm/commit/b0fe096225cfc9630bd741f1260d303bafd42c4e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Making comprehend game derive from game info

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/dictionary.cpp
    engines/glk/comprehend/dump_game_data.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_data.h
    engines/glk/comprehend/opcode_map.cpp
    engines/glk/comprehend/strings.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index e2a0a09bbb..2f0d317eef 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -158,6 +158,7 @@ void Comprehend::runGame() {
 	comprehend_load_game(game);
 	comprehend_play_game(game);
 
+	delete game;
 	deinitialize();
 }
 
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 6b83e8896c..d77f549182 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -39,7 +39,7 @@ namespace Comprehend {
 
 #define PATH_MAX 256
 
-struct game_info;
+struct GameInfo;
 struct game_state;
 
 #define EXTRA_STRING_TABLE(x) (0x8200 | (x))
diff --git a/engines/glk/comprehend/dictionary.cpp b/engines/glk/comprehend/dictionary.cpp
index 4ca9d545ac..1421763198 100644
--- a/engines/glk/comprehend/dictionary.cpp
+++ b/engines/glk/comprehend/dictionary.cpp
@@ -45,9 +45,9 @@ word *dict_find_word_by_string(ComprehendGame *game,
 	if (!string)
 		return NULL;
 
-	for (i = 0; i < game->info->_nr_words; i++)
-		if (word_match(&game->info->_words[i], string))
-			return &game->info->_words[i];
+	for (i = 0; i < game->_nr_words; i++)
+		if (word_match(&game->_words[i], string))
+			return &game->_words[i];
 
 	return NULL;
 }
@@ -57,10 +57,10 @@ struct word *dict_find_word_by_index_type(ComprehendGame *game,
 {
 	uint i;
 
-	for (i = 0; i < game->info->_nr_words; i++) {
-		if (game->info->_words[i]._index == index &&
-		    game->info->_words[i]._type == type)
-			return &game->info->_words[i];
+	for (i = 0; i < game->_nr_words; i++) {
+		if (game->_words[i]._index == index &&
+		    game->_words[i]._type == type)
+			return &game->_words[i];
 	}
 
 	return NULL;
@@ -71,10 +71,10 @@ struct word *find_dict_word_by_index(ComprehendGame *game,
 {
 	uint i;
 
-	for (i = 0; i < game->info->_nr_words; i++) {
-		if (game->info->_words[i]._index == index &&
-		    (game->info->_words[i]._type & type_mask) != 0)
-			return &game->info->_words[i];
+	for (i = 0; i < game->_nr_words; i++) {
+		if (game->_words[i]._index == index &&
+		    (game->_words[i]._type & type_mask) != 0)
+			return &game->_words[i];
 	}
 
 	return NULL;
@@ -85,10 +85,10 @@ bool dict_match_index_type(ComprehendGame *game, const char *word,
 {
 	uint i;
 
-	for (i = 0; i < game->info->_nr_words; i++)
-		if (game->info->_words[i]._index == index &&
-		    ((game->info->_words[i]._type & type_mask) != 0) &&
-		    word_match(&game->info->_words[i], word))
+	for (i = 0; i < game->_nr_words; i++)
+		if (game->_words[i]._index == index &&
+		    ((game->_words[i]._type & type_mask) != 0) &&
+		    word_match(&game->_words[i], word))
 			return true;
 
 	return false;
diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
index 16ac91262b..d33f8cb62e 100644
--- a/engines/glk/comprehend/dump_game_data.cpp
+++ b/engines/glk/comprehend/dump_game_data.cpp
@@ -160,7 +160,7 @@ void dump_instruction(ComprehendGame *game,
 		break;
 
 	case OPCODE_SET_STRING_REPLACEMENT:
-		debugN(" %s", game->info->_replaceWords[instr->operand[0] - 1]);
+		debugN(" %s", game->_replaceWords[instr->operand[0] - 1]);
 		break;
 	}
 
@@ -172,9 +172,9 @@ static void dump_functions(ComprehendGame *game)
 	struct function *func;
 	uint i, j;
 
-	debugN("Functions (%zd entries)\n", game->info->_nr_functions);
-	for (i = 0; i < game->info->_nr_functions; i++) {
-		func = &game->info->_functions[i];
+	debugN("Functions (%zd entries)\n", game->_nr_functions);
+	for (i = 0; i < game->_nr_functions; i++) {
+		func = &game->_functions[i];
 
 		debugN("[%.4x] (%zd instructions)\n", i, func->nr_instructions);
 		for (j = 0; j < func->nr_instructions; j++)
@@ -189,9 +189,9 @@ static void dump_action_table(ComprehendGame *game)
 	struct word *word;
 	uint i, j;
 
-	debugN("Action table (%zd entries)\n", game->info->_nr_actions);
-	for (i = 0; i < game->info->_nr_actions; i++) {
-		action = &game->info->_actions[i];
+	debugN("Action table (%zd entries)\n", game->_nr_actions);
+	for (i = 0; i < game->_nr_actions; i++) {
+		action = &game->_actions[i];
 
 		debugN("(");
 		for (j = 0; j < 4; j++) {
@@ -247,14 +247,14 @@ static void dump_dictionary(ComprehendGame *game)
 	uint i;
 
 	/* Sort the dictionary by index */
-	dictionary = (word *)xmalloc(sizeof(*words) * game->info->_nr_words);
-	memcpy(dictionary, game->info->_words,
-	       sizeof(*words) * game->info->_nr_words);
-	qsort(dictionary, game->info->_nr_words, sizeof(*words),
+	dictionary = (word *)xmalloc(sizeof(*words) * game->_nr_words);
+	memcpy(dictionary, game->_words,
+	       sizeof(*words) * game->_nr_words);
+	qsort(dictionary, game->_nr_words, sizeof(*words),
 	      word_index_compare);
 
-	debugN("Dictionary (%zd words)\n", game->info->_nr_words);
-	for (i = 0; i < game->info->_nr_words; i++) {
+	debugN("Dictionary (%zd words)\n", game->_nr_words);
+	for (i = 0; i < game->_nr_words; i++) {
 		words = &dictionary[i];
 		debugN("  [%.2x] %.2x %s\n", words->_index, words->_type,
 		       words->_word);
@@ -270,9 +270,9 @@ static void dump_word_map(ComprehendGame *game)
 	struct word_map *map;
 	uint i, j;
 
-	debugN("Word pairs (%zd entries)\n", game->info->_nr_word_maps);
-	for (i = 0; i < game->info->_nr_word_maps; i++) {
-		map = &game->info->_wordMaps[i];
+	debugN("Word pairs (%zd entries)\n", game->_nr_word_maps);
+	for (i = 0; i < game->_nr_word_maps; i++) {
+		map = &game->_wordMaps[i];
 
 		for (j = 0; j < 3; j++) {
 			word[j] = dict_find_word_by_index_type(
@@ -296,9 +296,9 @@ static void dump_rooms(ComprehendGame *game)
 	uint i;
 
 	/* Room zero acts as the players inventory */
-	debugN("Rooms (%zd entries)\n", game->info->_nr_rooms);
-	for (i = 1; i <= game->info->_nr_rooms; i++) {
-		room = &game->info->_rooms[i];
+	debugN("Rooms (%zd entries)\n", game->_nr_rooms);
+	for (i = 1; i <= game->_nr_rooms; i++) {
+		room = &game->_rooms[i];
 
 		debugN("  [%.2x] flags=%.2x, graphic=%.2x\n",
 		       i, room->flags, room->graphic);
@@ -322,22 +322,22 @@ static void dump_items(ComprehendGame *game)
 	struct item *item;
 	uint i, j;
 
-	debugN("Items (%zd entries)\n", game->info->_header.nr_items);
-	for (i = 0; i < game->info->_header.nr_items; i++) {
-		item = &game->info->_item[i];
+	debugN("Items (%zd entries)\n", game->_header.nr_items);
+	for (i = 0; i < game->_header.nr_items; i++) {
+		item = &game->_items[i];
 
 		debugN("  [%.2x] %s\n", i + 1,
 		       item->string_desc ?
 		       string_lookup(game, item->string_desc) : "");
-		if (game->info->_comprehendVersion == 2)
+		if (game->_comprehendVersion == 2)
 			debugN("    long desc: %s\n",
 			       string_lookup(game, item->long_string));
 
 		debugN("    words: ");
-		for (j = 0; j < game->info->_nr_words; j++)
-			if (game->info->_words[j]._index == item->word &&
-			    (game->info->_words[j]._type & WORD_TYPE_NOUN_MASK))
-				debugN("%s ", game->info->_words[j]._word);
+		for (j = 0; j < game->_nr_words; j++)
+			if (game->_words[j]._index == item->word &&
+			    (game->_words[j]._type & WORD_TYPE_NOUN_MASK))
+				debugN("%s ", game->_words[j]._word);
 		debugN("\n");
 		debugN("    flags=%.2x (takeable=%d, weight=%d)\n",
 		       item->flags, !!(item->flags & ITEMF_CAN_TAKE),
@@ -359,15 +359,15 @@ static void dump_string_table(struct string_table *table)
 static void dump_game_data_strings(ComprehendGame *game)
 {
 	debugN("Main string table (%zd entries)\n",
-	       game->info->_strings.nr_strings);
-	dump_string_table(&game->info->_strings);
+	       game->_strings.nr_strings);
+	dump_string_table(&game->_strings);
 }
 
 static void dump_extra_strings(ComprehendGame *game)
 {
 	debugN("Extra strings (%zd entries)\n",
-	       game->info->_strings2.nr_strings);
-	dump_string_table(&game->info->_strings2);
+	       game->_strings2.nr_strings);
+	dump_string_table(&game->_strings2);
 }
 
 static void dump_replace_words(ComprehendGame *game)
@@ -375,14 +375,14 @@ static void dump_replace_words(ComprehendGame *game)
 	uint i;
 
 	debugN("Replacement words (%zd entries)\n",
-	       game->info->_nr_replace_words);
-	for (i = 0; i < game->info->_nr_replace_words; i++)
-		debugN("  [%.2x] %s\n", i + 1, game->info->_replaceWords[i]);
+	       game->_nr_replace_words);
+	for (i = 0; i < game->_nr_replace_words; i++)
+		debugN("  [%.2x] %s\n", i + 1, game->_replaceWords[i]);
 }
 
 static void dump_header(ComprehendGame *game)
 {
-	struct game_header *header = &game->info->_header;
+	struct game_header *header = &game->_header;
 	uint16 *dir_table = header->room_direction_table;
 
 	debugN("Game header:\n");
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index ff95370978..b1440c979c 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -49,11 +49,9 @@ ComprehendGame::ComprehendGame() : _gameName(nullptr),
                                      _savegameFileFormat(nullptr),
                                      _colorTable(0),
                                      _gameStrings(nullptr) {
-	info = (game_info *)malloc(sizeof(*info));
 }
 
 ComprehendGame::~ComprehendGame() {
-	free(info);
 }
 
 static void console_init(void) {
@@ -95,13 +93,13 @@ void console_println(ComprehendGame *game, const char *text) {
 
 		case '@':
 			/* Replace word */
-			if (game->info->_currentReplaceWord >= game->info->_nr_replace_words) {
+			if (game->_currentReplaceWord >= game->_nr_replace_words) {
 				snprintf(bad_word, sizeof(bad_word),
 				         "[BAD_REPLACE_WORD(%.2x)]",
-				         game->info->_currentReplaceWord);
+				         game->_currentReplaceWord);
 				word = bad_word;
 			} else {
-				word = game->info->_replaceWords[game->info->_currentReplaceWord];
+				word = game->_replaceWords[game->_currentReplaceWord];
 			}
 			word_len = strlen(word);
 			p++;
@@ -164,24 +162,24 @@ static struct room *get_room(ComprehendGame *game, uint16 index) {
 	if (index == 0)
 		fatal_error("Room index 0 (player inventory) is invalid");
 
-	if (index - 1 >= (int)game->info->_nr_rooms)
+	if (index - 1 >= (int)game->_nr_rooms)
 		fatal_error("Room index %d is invalid", index);
 
-	return &game->info->_rooms[index];
+	return &game->_rooms[index];
 }
 
 struct item *get_item(ComprehendGame *game, uint16 index) {
-	if (index >= game->info->_header.nr_items)
+	if (index >= game->_header.nr_items)
 		fatal_error("Bad item %d\n", index);
 
-	return &game->info->_item[index];
+	return &game->_items[index];
 }
 
 void game_save(ComprehendGame *game) {
 	char filename[32];
 	int c;
 
-	console_println(game, game->info->_strings.strings[STRING_SAVE_GAME]);
+	console_println(game, game->_strings.strings[STRING_SAVE_GAME]);
 
 	c = console_get_key();
 	if (c < '1' || c > '3') {
@@ -201,7 +199,7 @@ void game_restore(ComprehendGame *game) {
 	char filename[32];
 	int c;
 
-	console_println(game, game->info->_strings.strings[STRING_RESTORE_GAME]);
+	console_println(game, game->_strings.strings[STRING_RESTORE_GAME]);
 
 	c = console_get_key();
 	if (c < '1' || c > '3') {
@@ -216,7 +214,7 @@ void game_restore(ComprehendGame *game) {
 	snprintf(filename, sizeof(filename), game->_savegameFileFormat, c - '0');
 	comprehend_restore_game(game, filename);
 
-	game->info->_updateFlags = UPDATE_ALL;
+	game->_updateFlags = UPDATE_ALL;
 }
 
 void game_restart(ComprehendGame *game) {
@@ -224,7 +222,7 @@ void game_restart(ComprehendGame *game) {
 	console_get_key();
 
 	comprehend_load_game(game);
-	game->info->_updateFlags = UPDATE_ALL;
+	game->_updateFlags = UPDATE_ALL;
 }
 
 static struct word_index *is_word_pair(ComprehendGame *game,
@@ -233,8 +231,8 @@ static struct word_index *is_word_pair(ComprehendGame *game,
 	uint i;
 
 	/* Check if this is a word pair */
-	for (i = 0; i < game->info->_nr_word_maps; i++) {
-		map = &game->info->_wordMaps[i];
+	for (i = 0; i < game->_nr_word_maps; i++) {
+		map = &game->_wordMaps[i];
 
 		if (map->word[0].index == word1->_index &&
 		    map->word[0].type == word1->_type &&
@@ -258,9 +256,9 @@ static struct item *get_item_by_noun(ComprehendGame *game,
 	 *         (the box and the snarl-in-a-box). The player is unable
 	 *         to drop the latter because this will match the former.
 	 */
-	for (i = 0; i < game->info->_header.nr_items; i++)
-		if (game->info->_item[i].word == noun->_index)
-			return &game->info->_item[i];
+	for (i = 0; i < game->_header.nr_items; i++)
+		if (game->_items[i].word == noun->_index)
+			return &game->_items[i];
 
 	return NULL;
 }
@@ -274,34 +272,34 @@ static void update_graphics(ComprehendGame *game) {
 	if (!g_enabled())
 		return;
 
-	type = game->room_is_special(game->info->_currentRoom, NULL);
+	type = game->room_is_special(game->_currentRoom, NULL);
 
 	switch (type) {
 	case ROOM_IS_DARK:
-		if (game->info->_updateFlags & UPDATE_GRAPHICS)
+		if (game->_updateFlags & UPDATE_GRAPHICS)
 			draw_dark_room();
 		break;
 
 	case ROOM_IS_TOO_BRIGHT:
-		if (game->info->_updateFlags & UPDATE_GRAPHICS)
+		if (game->_updateFlags & UPDATE_GRAPHICS)
 			draw_bright_room();
 		break;
 
 	default:
-		if (game->info->_updateFlags & UPDATE_GRAPHICS) {
-			room = get_room(game, game->info->_currentRoom);
-			draw_location_image(&game->info->_roomImages,
+		if (game->_updateFlags & UPDATE_GRAPHICS) {
+			room = get_room(game, game->_currentRoom);
+			draw_location_image(&game->_roomImages,
 			                    room->graphic - 1);
 		}
 
-		if ((game->info->_updateFlags & UPDATE_GRAPHICS) ||
-		    (game->info->_updateFlags & UPDATE_GRAPHICS_ITEMS)) {
-			for (i = 0; i < game->info->_header.nr_items; i++) {
-				item = &game->info->_item[i];
+		if ((game->_updateFlags & UPDATE_GRAPHICS) ||
+		    (game->_updateFlags & UPDATE_GRAPHICS_ITEMS)) {
+			for (i = 0; i < game->_header.nr_items; i++) {
+				item = &game->_items[i];
 
-				if (item->room == game->info->_currentRoom &&
+				if (item->room == game->_currentRoom &&
 				    item->graphic != 0)
-					draw_image(&game->info->_itemImages,
+					draw_image(&game->_itemImages,
 					           item->graphic - 1);
 			}
 		}
@@ -314,10 +312,10 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 	size_t count = 0;
 	uint i;
 
-	for (i = 0; i < game->info->_header.nr_items; i++) {
-		item = &game->info->_item[i];
+	for (i = 0; i < game->_header.nr_items; i++) {
+		item = &game->_items[i];
 
-		if (item->room == game->info->_currentRoom &&
+		if (item->room == game->_currentRoom &&
 		    item->string_desc != 0)
 			count++;
 	}
@@ -325,10 +323,10 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 	if (count > 0) {
 		console_println(game, string_lookup(game, STRING_YOU_SEE));
 
-		for (i = 0; i < game->info->_header.nr_items; i++) {
-			item = &game->info->_item[i];
+		for (i = 0; i < game->_header.nr_items; i++) {
+			item = &game->_items[i];
 
-			if (item->room == game->info->_currentRoom &&
+			if (item->room == game->_currentRoom &&
 			    item->string_desc != 0)
 				console_println(game, string_lookup(game, item->string_desc));
 		}
@@ -336,32 +334,32 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 }
 
 static void update(ComprehendGame *game) {
-	struct room *room = get_room(game, game->info->_currentRoom);
+	struct room *room = get_room(game, game->_currentRoom);
 	unsigned room_type, room_desc_string;
 
 	update_graphics(game);
 
 	/* Check if the room is special (dark, too bright, etc) */
 	room_desc_string = room->string_desc;
-	room_type = game->room_is_special(game->info->_currentRoom,
+	room_type = game->room_is_special(game->_currentRoom,
 		&room_desc_string);
 
-	if (game->info->_updateFlags & UPDATE_ROOM_DESC)
+	if (game->_updateFlags & UPDATE_ROOM_DESC)
 		console_println(game, string_lookup(game, room_desc_string));
 
-	if ((game->info->_updateFlags & UPDATE_ITEM_LIST) &&
+	if ((game->_updateFlags & UPDATE_ITEM_LIST) &&
 	    room_type == ROOM_IS_NORMAL)
 		describe_objects_in_current_room(game);
 
-	game->info->_updateFlags = 0;
+	game->_updateFlags = 0;
 }
 
 static void move_to(ComprehendGame *game, uint8 room) {
-	if (room - 1 >= (int)game->info->_nr_rooms)
+	if (room - 1 >= (int)game->_nr_rooms)
 		fatal_error("Attempted to move to invalid room %.2x\n", room);
 
-	game->info->_currentRoom = room;
-	game->info->_updateFlags = (UPDATE_GRAPHICS | UPDATE_ROOM_DESC |
+	game->_currentRoom = room;
+	game->_updateFlags = (UPDATE_GRAPHICS | UPDATE_ROOM_DESC |
 	                            UPDATE_ITEM_LIST);
 }
 
@@ -386,8 +384,8 @@ static void func_set_test_result(struct function_state *func_state, bool value)
 static size_t num_objects_in_room(ComprehendGame *game, int room) {
 	size_t count = 0, i;
 
-	for (i = 0; i < game->info->_header.nr_items; i++)
-		if (game->info->_item[i].room == room)
+	for (i = 0; i < game->_header.nr_items; i++)
+		if (game->_items[i].room == room)
 			count++;
 
 	return count;
@@ -401,23 +399,23 @@ void move_object(ComprehendGame *game, struct item *item, int new_room) {
 
 	if (item->room == ROOM_INVENTORY) {
 		/* Removed from player's inventory */
-		game->info->_variables[VAR_INVENTORY_WEIGHT] -= obj_weight;
+		game->_variables[VAR_INVENTORY_WEIGHT] -= obj_weight;
 	}
 	if (new_room == ROOM_INVENTORY) {
 		/* Moving to the player's inventory */
-		game->info->_variables[VAR_INVENTORY_WEIGHT] += obj_weight;
+		game->_variables[VAR_INVENTORY_WEIGHT] += obj_weight;
 	}
 
-	if (item->room == game->info->_currentRoom) {
+	if (item->room == game->_currentRoom) {
 		/* Item moved away from the current room */
-		game->info->_updateFlags |= UPDATE_GRAPHICS;
+		game->_updateFlags |= UPDATE_GRAPHICS;
 
-	} else if (new_room == game->info->_currentRoom) {
+	} else if (new_room == game->_currentRoom) {
 		/*
 		 * Item moved into the current room. Only the item needs a
 		 * redraw, not the whole room.
 		 */
-		game->info->_updateFlags |= (UPDATE_GRAPHICS_ITEMS |
+		game->_updateFlags |= (UPDATE_GRAPHICS_ITEMS |
 		                             UPDATE_ITEM_LIST);
 	}
 
@@ -435,7 +433,7 @@ static void eval_instruction(ComprehendGame *game,
 	bool test;
 	uint i, count;
 
-	room = get_room(game, game->info->_currentRoom);
+	room = get_room(game, game->_currentRoom);
 
 	if (debugging_enabled()) {
 		if (!instr->is_command) {
@@ -482,31 +480,31 @@ static void eval_instruction(ComprehendGame *game,
 	opcode_map = get_opcode_map(game);
 	switch (opcode_map[instr->opcode]) {
 	case OPCODE_VAR_ADD:
-		game->info->_variables[instr->operand[0]] +=
-		    game->info->_variables[instr->operand[1]];
+		game->_variables[instr->operand[0]] +=
+		    game->_variables[instr->operand[1]];
 		break;
 
 	case OPCODE_VAR_SUB:
-		game->info->_variables[instr->operand[0]] -=
-		    game->info->_variables[instr->operand[1]];
+		game->_variables[instr->operand[0]] -=
+		    game->_variables[instr->operand[1]];
 		break;
 
 	case OPCODE_VAR_INC:
-		game->info->_variables[instr->operand[0]]++;
+		game->_variables[instr->operand[0]]++;
 		break;
 
 	case OPCODE_VAR_DEC:
-		game->info->_variables[instr->operand[0]]--;
+		game->_variables[instr->operand[0]]--;
 		break;
 
 	case OPCODE_VAR_EQ:
 		func_set_test_result(func_state,
-		                     game->info->_variables[instr->operand[0]] ==
-		                         game->info->_variables[instr->operand[1]]);
+		                     game->_variables[instr->operand[0]] ==
+		                         game->_variables[instr->operand[1]]);
 		break;
 
 	case OPCODE_TURN_TICK:
-		game->info->_variables[VAR_TURN_COUNT]++;
+		game->_variables[VAR_TURN_COUNT]++;
 		break;
 
 	case OPCODE_PRINT:
@@ -527,12 +525,12 @@ static void eval_instruction(ComprehendGame *game,
 
 	case OPCODE_NOT_IN_ROOM:
 		func_set_test_result(func_state,
-		                     game->info->_currentRoom != instr->operand[0]);
+		                     game->_currentRoom != instr->operand[0]);
 		break;
 
 	case OPCODE_IN_ROOM:
 		func_set_test_result(func_state,
-		                     game->info->_currentRoom == instr->operand[0]);
+		                     game->_currentRoom == instr->operand[0]);
 		break;
 
 	case OPCODE_MOVE_TO_ROOM:
@@ -574,7 +572,7 @@ static void eval_instruction(ComprehendGame *game,
 
 	case OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM:
 		item = get_item(game, instr->operand[0] - 1);
-		move_object(game, item, game->info->_currentRoom);
+		move_object(game, item, game->_currentRoom);
 		break;
 
 	case OPCODE_OBJECT_IN_ROOM:
@@ -597,9 +595,9 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_INVENTORY_FULL:
 		item = get_item_by_noun(game, noun);
 		func_set_test_result(func_state,
-		                     game->info->_variables[VAR_INVENTORY_WEIGHT] +
+		                     game->_variables[VAR_INVENTORY_WEIGHT] +
 		                             (item->flags & ITEMF_WEIGHT_MASK) >
-		                         game->info->_variables[VAR_INVENTORY_LIMIT]);
+		                         game->_variables[VAR_INVENTORY_LIMIT]);
 		break;
 
 	case OPCODE_DESCRIBE_CURRENT_OBJECT:
@@ -616,8 +614,8 @@ static void eval_instruction(ComprehendGame *game,
 		test = false;
 
 		if (noun) {
-			for (i = 0; i < game->info->_header.nr_items; i++) {
-				struct item *itemP = &game->info->_item[i];
+			for (i = 0; i < game->_header.nr_items; i++) {
+				struct item *itemP = &game->_items[i];
 
 				if (itemP->word == noun->_index &&
 				    itemP->room == instr->operand[0]) {
@@ -635,7 +633,7 @@ static void eval_instruction(ComprehendGame *game,
 		item = get_item_by_noun(game, noun);
 		if (item)
 			func_set_test_result(func_state,
-			                     item->room != game->info->_currentRoom);
+			                     item->room != game->_currentRoom);
 		else
 			func_set_test_result(func_state, true);
 		break;
@@ -644,7 +642,7 @@ static void eval_instruction(ComprehendGame *game,
 		item = get_item_by_noun(game, noun);
 		if (item)
 			func_set_test_result(func_state,
-			                     item->room == game->info->_currentRoom);
+			                     item->room == game->_currentRoom);
 		else
 			func_set_test_result(func_state, false);
 		break;
@@ -715,13 +713,13 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_OBJECT_NOT_PRESENT:
 		item = get_item(game, instr->operand[0] - 1);
 		func_set_test_result(func_state,
-		                     item->room != game->info->_currentRoom);
+		                     item->room != game->_currentRoom);
 		break;
 
 	case OPCODE_OBJECT_PRESENT:
 		item = get_item(game, instr->operand[0] - 1);
 		func_set_test_result(func_state,
-		                     item->room == game->info->_currentRoom);
+		                     item->room == game->_currentRoom);
 		break;
 
 	case OPCODE_OBJECT_NOT_VALID:
@@ -758,8 +756,8 @@ static void eval_instruction(ComprehendGame *game,
 		}
 
 		console_println(game, string_lookup(game, STRING_INVENTORY));
-		for (i = 0; i < game->info->_header.nr_items; i++) {
-			item = &game->info->_item[i];
+		for (i = 0; i < game->_header.nr_items; i++) {
+			item = &game->_items[i];
 			if (item->room == ROOM_INVENTORY)
 				printf("%s\n",
 				       string_lookup(game, item->string_desc));
@@ -774,8 +772,8 @@ static void eval_instruction(ComprehendGame *game,
 		}
 
 		console_println(game, string_lookup(game, instr->operand[1]));
-		for (i = 0; i < game->info->_header.nr_items; i++) {
-			item = &game->info->_item[i];
+		for (i = 0; i < game->_header.nr_items; i++) {
+			item = &game->_items[i];
 			if (item->room == instr->operand[0])
 				printf("%s\n",
 				       string_lookup(game, item->string_desc));
@@ -792,7 +790,7 @@ static void eval_instruction(ComprehendGame *game,
 
 	case OPCODE_DROP_OBJECT:
 		item = get_item(game, instr->operand[0] - 1);
-		move_object(game, item, game->info->_currentRoom);
+		move_object(game, item, game->_currentRoom);
 		break;
 
 	case OPCODE_DROP_CURRENT_OBJECT:
@@ -800,7 +798,7 @@ static void eval_instruction(ComprehendGame *game,
 		if (!item)
 			fatal_error("Attempt to take object failed\n");
 
-		move_object(game, item, game->info->_currentRoom);
+		move_object(game, item, game->_currentRoom);
 		break;
 
 	case OPCODE_TAKE_CURRENT_OBJECT:
@@ -818,20 +816,20 @@ static void eval_instruction(ComprehendGame *game,
 
 	case OPCODE_TEST_FLAG:
 		func_set_test_result(func_state,
-		                     game->info->_flags[instr->operand[0]]);
+		                     game->_flags[instr->operand[0]]);
 		break;
 
 	case OPCODE_TEST_NOT_FLAG:
 		func_set_test_result(func_state,
-		                     !game->info->_flags[instr->operand[0]]);
+		                     !game->_flags[instr->operand[0]]);
 		break;
 
 	case OPCODE_CLEAR_FLAG:
-		game->info->_flags[instr->operand[0]] = false;
+		game->_flags[instr->operand[0]] = false;
 		break;
 
 	case OPCODE_SET_FLAG:
-		game->info->_flags[instr->operand[0]] = true;
+		game->_flags[instr->operand[0]] = true;
 		break;
 
 	case OPCODE_OR:
@@ -875,28 +873,28 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_SET_OBJECT_GRAPHIC:
 		item = get_item(game, instr->operand[0] - 1);
 		item->graphic = instr->operand[1];
-		if (item->room == game->info->_currentRoom)
-			game->info->_updateFlags |= UPDATE_GRAPHICS;
+		if (item->room == game->_currentRoom)
+			game->_updateFlags |= UPDATE_GRAPHICS;
 		break;
 
 	case OPCODE_SET_ROOM_GRAPHIC:
 		room = get_room(game, instr->operand[0]);
 		room->graphic = instr->operand[1];
-		if (instr->operand[0] == game->info->_currentRoom)
-			game->info->_updateFlags |= UPDATE_GRAPHICS;
+		if (instr->operand[0] == game->_currentRoom)
+			game->_updateFlags |= UPDATE_GRAPHICS;
 		break;
 
 	case OPCODE_CALL_FUNC:
 		index = instr->operand[0];
 		if (instr->operand[1] == 0x81)
 			index += 256;
-		if (index >= game->info->_nr_functions)
+		if (index >= game->_nr_functions)
 			fatal_error("Bad function %.4x >= %.4x\n",
-			            index, game->info->_nr_functions);
+			            index, game->_nr_functions);
 
 		debug_printf(DEBUG_FUNCTIONS,
 		             "Calling subfunction %.4x\n", index);
-		eval_function(game, &game->info->_functions[index], verb, noun);
+		eval_function(game, &game->_functions[index], verb, noun);
 		break;
 
 	case OPCODE_TEST_FALSE:
@@ -923,7 +921,7 @@ static void eval_instruction(ComprehendGame *game,
 		break;
 
 	case OPCODE_SET_STRING_REPLACEMENT:
-		game->info->_currentReplaceWord = instr->operand[0] - 1;
+		game->_currentReplaceWord = instr->operand[0] - 1;
 		break;
 
 	case OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT:
@@ -932,22 +930,22 @@ static void eval_instruction(ComprehendGame *game,
 		 * maybe capitalisation?
 		 */
 		if (noun && (noun->_type & WORD_TYPE_NOUN_PLURAL))
-			game->info->_currentReplaceWord = 3;
+			game->_currentReplaceWord = 3;
 		else if (noun && (noun->_type & WORD_TYPE_FEMALE))
-			game->info->_currentReplaceWord = 0;
+			game->_currentReplaceWord = 0;
 		else if (noun && (noun->_type & WORD_TYPE_MALE))
-			game->info->_currentReplaceWord = 1;
+			game->_currentReplaceWord = 1;
 		else
-			game->info->_currentReplaceWord = 2;
+			game->_currentReplaceWord = 2;
 		break;
 
 	case OPCODE_DRAW_ROOM:
-		draw_location_image(&game->info->_roomImages,
+		draw_location_image(&game->_roomImages,
 		                    instr->operand[0] - 1);
 		break;
 
 	case OPCODE_DRAW_OBJECT:
-		draw_image(&game->info->_itemImages, instr->operand[0] - 1);
+		draw_image(&game->_itemImages, instr->operand[0] - 1);
 		break;
 
 	case OPCODE_WAIT_KEY:
@@ -1037,21 +1035,21 @@ static void handle_debug_command(ComprehendGame *game,
 		dump_game_data(game, DUMP_ROOMS);
 
 	} else if (strncmp(line, "dump state", 10) == 0) {
-		printf("Current room: %.2x\n", game->info->current_room);
+		printf("Current room: %.2x\n", game->current_room);
 		printf("Carry weight %d/%d\n\n",
-		       game->info->variable[VAR_INVENTORY_WEIGHT],
-		       game->info->variable[VAR_INVENTORY_LIMIT]);
+		       game->variable[VAR_INVENTORY_WEIGHT],
+		       game->variable[VAR_INVENTORY_LIMIT]);
 
 		printf("Flags:\n");
-		for (i = 0; i < ARRAY_SIZE(game->info->flags); i++)
-			printf("  [%.2x]: %d\n", i, game->info->flags[i]);
+		for (i = 0; i < ARRAY_SIZE(game->flags); i++)
+			printf("  [%.2x]: %d\n", i, game->flags[i]);
 		printf("\n");
 
 		printf("Variables:\n");
-		for (i = 0; i < ARRAY_SIZE(game->info->variable); i++)
+		for (i = 0; i < ARRAY_SIZE(game->variable); i++)
 			printf("  [%.2x]: %5d (0x%.4x)\n",
-			       i, game->info->variable[i],
-			       game->info->variable[i]);
+			       i, game->variable[i],
+			       game->variable[i]);
 		printf("\n");
 	}
 }
@@ -1067,8 +1065,8 @@ static bool handle_sentence(ComprehendGame *game,
 		return false;
 
 	/* Find a matching action */
-	for (i = 0; i < game->info->_nr_actions; i++) {
-		action = &game->info->_actions[i];
+	for (i = 0; i < game->_nr_actions; i++) {
+		action = &game->_actions[i];
 
 		if (action->type == ACTION_VERB_OPT_NOUN &&
 		    sentence->nr_words > action->nr_words + 1)
@@ -1091,7 +1089,7 @@ static bool handle_sentence(ComprehendGame *game,
 		}
 		if (j == action->nr_words) {
 			/* Match */
-			func = &game->info->_functions[action->function];
+			func = &game->_functions[action->function];
 			eval_function(game, func,
 			              &sentence->words[0], &sentence->words[1]);
 			return true;
@@ -1168,7 +1166,7 @@ static void before_turn(ComprehendGame *game) {
 	game->before_turn();
 
 	// Run the each turn functions
-	eval_function(game, &game->info->_functions[0], NULL, NULL);
+	eval_function(game, &game->_functions[0], NULL, NULL);
 
 	update(game);
 }
@@ -1223,7 +1221,7 @@ void comprehend_play_game(ComprehendGame *game) {
 
 	game->before_game();
 
-	game->info->_updateFlags = (uint)UPDATE_ALL;
+	game->_updateFlags = (uint)UPDATE_ALL;
 	while (!g_comprehend->shouldQuit())
 		read_input(game);
 }
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 8f0bcf710e..86fde90347 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -33,7 +33,7 @@ namespace Comprehend {
 #define ROOM_IS_DARK 1
 #define ROOM_IS_TOO_BRIGHT 2
 
-class ComprehendGame {
+class ComprehendGame : public GameInfo {
 public:
 	const char *_gameName;
 	const char *_shortName;
@@ -46,7 +46,6 @@ public:
 	unsigned _colorTable;
 
 	struct game_strings *_gameStrings;
-	struct game_info *info;
 
 public:
 	ComprehendGame();
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index e0a4dca5b6..8eb79938a3 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -71,8 +71,8 @@ ComprehendGame game_crimson_crown_2 = {
 
 static void cc_clear_companion_flags(ComprehendGame *game) {
 	/* Clear the Sabrina/Erik action flags */
-	game->info->_flags[0xa] = 0;
-	game->info->_flags[0xb] = 0;
+	game->_flags[0xa] = 0;
+	game->_flags[0xb] = 0;
 }
 
 static bool cc_common_handle_special_opcode(ComprehendGame *game,
@@ -128,7 +128,7 @@ static void cc2_handle_special_opcode(ComprehendGame *game,
 	switch (operand) {
 	case 0x01:
 		/* Enter the Vampire's throne room */
-		eval_function(game, &game->info->_functions[0xe], NULL, NULL);
+		eval_function(game, &game->_functions[0xe], NULL, NULL);
 		break;
 
 	case 0x05:
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 7b7cf3efd7..482023cd5d 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -38,99 +38,149 @@ static char special_charset[] = "[]\n!\"#$%&'(),-/0123456789:;?<>";
 
 static uint16 magic_offset;
 
-function_state::function_state() : test_result(true),
-                                   else_result(false),
-                                   or_count(0),
-                                   _and(false),
-                                   in_command(false),
-                                   executed(false) {
+void function_state::clear() {
+	test_result = true;
+	else_result = false;
+	or_count = 0;
+	_and = false;
+	in_command = false;
+	executed = false;
 }
 
 /*-------------------------------------------------------*/
 
-room::room() : flags(0),
-               graphic(0),
-               string_desc(0) {
+void room::clear() {
+	flags = 0;
+    graphic = 0;
+	string_desc = 0;
 	Common::fill(&direction[0], &direction[NR_DIRECTIONS], 0);
 }
 
 /*-------------------------------------------------------*/
 
-item::item() : string_desc(0),
-               long_string(0),
-               room(0),
-               flags(0),
-               word(0),
-               graphic(0) {
+void item::clear() {
+	string_desc = 0;
+    long_string = 0;
+    room = 0;
+    flags = 0;
+    word = 0;
+    graphic = 0;
 }
 
 /*-------------------------------------------------------*/
 
-word::word() : _index(0), _type(0) {
+void word::clear() {
+	_index = 0;
+	_type = 0;
 	Common::fill(&_word[0], &_word[7], '\0');
 }
 
 /*-------------------------------------------------------*/
 
-action::action() : type(0), nr_words(0), function(0) {
+void word_map::clear() {
+	flags = 0;
+	for (int idx = 0; idx < 3; ++idx)
+		word[idx].clear();
+}
+
+/*-------------------------------------------------------*/
+
+void action::clear() {
+	type = 0;
+	nr_words = 0;
+	function = 0;
 	Common::fill(&word[0], &word[4], 0);
 	Common::fill(&word_type[0], &word_type[4], 0);
 }
 
-instruction::instruction() : opcode(0), nr_operands(0),
-		is_command(false) {
+/*-------------------------------------------------------*/
+
+void instruction::clear() {
+	opcode = 0;
+	nr_operands = 0;
+	is_command= false;
 	Common::fill(&operand[0], &operand[3], 0);
 }
 
 /*-------------------------------------------------------*/
 
-string_table::string_table() : nr_strings(0) {
+void function::clear() {
+	nr_instructions = 0;
+	for (int idx = 0; idx < 0x100; ++idx)
+		instructions[idx].clear();
+}
+
+/*-------------------------------------------------------*/
+
+void string_table::clear() {
+	nr_strings = 0;	
 	Common::fill(&strings[0], &strings[0xffff], nullptr);
 }
 
 /*-------------------------------------------------------*/
 
-game_header::game_header() : magic(0),
-	                             room_desc_table(0),
-	                             room_flags_table(0),
-	                             room_graphics_table(0),
-	                             nr_items(0),
-	                             addr_item_locations(0),
-	                             addr_item_flags(0),
-	                             addr_item_word(0),
-	                             addr_item_strings(0),
-	                             addr_item_graphics(0),
-	                             addr_dictionary(0),
-	                             addr_word_map(0),
-	                             addr_strings(0),
-	                             addr_strings_end(0),
-	                             addr_actions_vvnn(0),
-	                             addr_actions_unknown(0),
-	                             addr_actions_vnjn(0),
-	                             addr_actions_vjn(0),
-	                             addr_actions_vdn(0),
-	                             addr_actions_vnn(0),
-	                             addr_actions_vn(0),
-	                             addr_actions_v(0),
-	                             addr_vm(0) // FIXME - functions
-{
+void game_header::clear() {
+	magic = 0;
+	room_desc_table = 0;
+	room_flags_table = 0;
+	room_graphics_table = 0;
+	nr_items = 0;
+	addr_item_locations = 0;
+	addr_item_flags = 0;
+	addr_item_word = 0;
+	addr_item_strings = 0;
+	addr_item_graphics = 0;
+	addr_dictionary = 0;
+	addr_word_map = 0;
+	addr_strings = 0;
+	addr_strings_end = 0;
+	addr_actions_vvnn = 0;
+	addr_actions_unknown = 0;
+	addr_actions_vnjn = 0;
+	addr_actions_vjn = 0;
+	addr_actions_vdn = 0;
+	addr_actions_vnn = 0;
+	addr_actions_vn = 0;
+	addr_actions_v = 0;
+	addr_vm = 0; // FIXME - functions
 	Common::fill(&room_direction_table[0], &room_direction_table[NR_DIRECTIONS], 0);
 }
 
 /*-------------------------------------------------------*/
 
-game_info::game_info() : _comprehendVersion(0),
-	                        _startRoom(0),
-	                        _nr_rooms(0),
-	                        _currentRoom(0),
-	                        _words(nullptr),
-	                        _nr_words(0),
-	                        _nr_word_maps(0),
-	                        _nr_actions(0),
-	                        _nr_functions(0),
-	                        _nr_replace_words(0),
-	                        _currentReplaceWord(0),
-	                        _updateFlags(0) {
+void GameInfo::clearInfo() {
+	_header.clear();
+	_comprehendVersion = 0;
+	_startRoom = 0;
+	_nr_rooms = 0;
+	_currentRoom = 0;
+	_words = nullptr;
+	_nr_words = 0;
+	_nr_word_maps = 0;
+	_nr_actions = 0;
+	_nr_functions = 0;
+	_nr_replace_words = 0;
+	_currentReplaceWord = 0;
+	_updateFlags = 0;
+	_strings.clear();
+	_strings2.clear();
+	_roomImages.clear();
+	_itemImages.clear();
+
+	for (uint idx = 0; idx < 0x100; ++idx)
+		_rooms[idx].clear();
+	for (uint idx = 0; idx < 0xff; ++idx)
+		_items[idx].clear();
+	for (uint idx = 0; idx < 0xff; ++idx)
+		_wordMaps[idx].clear();
+	for (uint idx = 0; idx < 0xffff; ++idx)
+		_actions[idx].clear();
+	for (uint idx = 0; idx < 0xffff; ++idx)
+		_functions[idx].clear();
+
+	Common::fill(&_flags[0], &_flags[MAX_FLAGS], false);
+	Common::fill(&_variables[0], &_variables[MAX_VARIABLES], 0);
+	Common::fill(&_replaceWords[0], &_replaceWords[256], (char *)nullptr);
 }
 
 static void parse_header_le16(struct file_buf * fb, uint16 * val) {
@@ -190,15 +240,15 @@ static void parse_function(struct file_buf * fb, struct function * func) {
 static void parse_vm(ComprehendGame * game, struct file_buf * fb) {
 	struct function *func;
 
-	file_buf_set_pos(fb, game->info->_header.addr_vm);
+	file_buf_set_pos(fb, game->_header.addr_vm);
 	while (1) {
-		func = &game->info->_functions[game->info->_nr_functions];
+		func = &game->_functions[game->_nr_functions];
 
 		parse_function(fb, func);
 		if (func->nr_instructions == 0)
 			break;
 
-		game->info->_nr_functions++;
+		game->_nr_functions++;
 	}
 }
 
@@ -218,7 +268,7 @@ static void parse_action_table_vvnn(ComprehendGame * game,
 	*     u8:   noun2
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->_header.addr_actions_vvnn);
+	file_buf_set_pos(fb, game->_header.addr_actions_vvnn);
 	while (1) {
 		file_buf_get_u8(fb, &verb);
 		if (verb == 0)
@@ -226,7 +276,7 @@ static void parse_action_table_vvnn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->_actions[*index];
+			action = &game->_actions[*index];
 			action->type = ACTION_VERB_VERB_NOUN_NOUN;
 
 			action->nr_words = 4;
@@ -262,7 +312,7 @@ static void parse_action_table_vnjn(ComprehendGame * game,
 	*     u8:   noun2
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->_header.addr_actions_vnjn);
+	file_buf_set_pos(fb, game->_header.addr_actions_vnjn);
 	while (1) {
 		file_buf_get_u8(fb, &join);
 		if (join == 0)
@@ -270,7 +320,7 @@ static void parse_action_table_vnjn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->_actions[*index];
+			action = &game->_actions[*index];
 			action->type = ACTION_VERB_NOUN_JOIN_NOUN;
 
 			action->nr_words = 4;
@@ -306,7 +356,7 @@ static void parse_action_table_vjn(ComprehendGame * game,
 	*     u8:   noun
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->_header.addr_actions_vjn);
+	file_buf_set_pos(fb, game->_header.addr_actions_vjn);
 	while (1) {
 		file_buf_get_u8(fb, &join);
 		if (join == 0)
@@ -314,7 +364,7 @@ static void parse_action_table_vjn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->_actions[*index];
+			action = &game->_actions[*index];
 			action->type = ACTION_VERB_JOIN_NOUN;
 			action->word[1] = join;
 
@@ -347,7 +397,7 @@ static void parse_action_table_vdn(ComprehendGame * game,
 	*     u8:   noun
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->_header.addr_actions_vdn);
+	file_buf_set_pos(fb, game->_header.addr_actions_vdn);
 	while (1) {
 		file_buf_get_u8(fb, &verb);
 		if (verb == 0)
@@ -355,7 +405,7 @@ static void parse_action_table_vdn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->_actions[*index];
+			action = &game->_actions[*index];
 			action->type = ACTION_VERB_JOIN_NOUN;
 			action->word[0] = verb;
 
@@ -388,7 +438,7 @@ static void parse_action_table_vnn(ComprehendGame * game,
 	*     u8:   noun2
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->_header.addr_actions_vnn);
+	file_buf_set_pos(fb, game->_header.addr_actions_vnn);
 	while (1) {
 		/* 2-byte header */
 		file_buf_get_u8(fb, &verb);
@@ -397,7 +447,7 @@ static void parse_action_table_vnn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->_actions[*index];
+			action = &game->_actions[*index];
 			action->type = ACTION_VERB_NOUN_NOUN;
 			action->word[0] = verb;
 
@@ -429,7 +479,7 @@ static void parse_action_table_vn(ComprehendGame * game,
 	*     u8:   noun
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->_header.addr_actions_vn);
+	file_buf_set_pos(fb, game->_header.addr_actions_vn);
 	while (1) {
 		/* 2-byte header */
 		file_buf_get_u8(fb, &verb);
@@ -438,7 +488,7 @@ static void parse_action_table_vn(ComprehendGame * game,
 		file_buf_get_u8(fb, &count);
 
 		for (i = 0; i < count; i++) {
-			action = &game->info->_actions[*index];
+			action = &game->_actions[*index];
 			action->type = ACTION_VERB_NOUN;
 			action->word[0] = verb;
 
@@ -468,13 +518,13 @@ static void parse_action_table_v(ComprehendGame * game,
 	* u8: count (num actions)
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->info->_header.addr_actions_v);
+	file_buf_set_pos(fb, game->_header.addr_actions_v);
 	while (1) {
 		file_buf_get_u8(fb, &verb);
 		if (verb == 0)
 			break;
 
-		action = &game->info->_actions[*index];
+		action = &game->_actions[*index];
 		action->type = ACTION_VERB_OPT_NOUN;
 		action->word[0] = verb;
 
@@ -499,20 +549,20 @@ static void parse_action_table_v(ComprehendGame * game,
 
 static void parse_action_table(ComprehendGame * game,
 	                            struct file_buf * fb) {
-	game->info->_nr_actions = 0;
+	game->_nr_actions = 0;
 
-	if (game->info->_comprehendVersion == 1) {
-		parse_action_table_vvnn(game, fb, &game->info->_nr_actions);
-		parse_action_table_vdn(game, fb, &game->info->_nr_actions);
+	if (game->_comprehendVersion == 1) {
+		parse_action_table_vvnn(game, fb, &game->_nr_actions);
+		parse_action_table_vdn(game, fb, &game->_nr_actions);
 	}
-	if (game->info->_comprehendVersion >= 2) {
-		parse_action_table_vnn(game, fb, &game->info->_nr_actions);
+	if (game->_comprehendVersion >= 2) {
+		parse_action_table_vnn(game, fb, &game->_nr_actions);
 	}
 
-	parse_action_table_vnjn(game, fb, &game->info->_nr_actions);
-	parse_action_table_vjn(game, fb, &game->info->_nr_actions);
-	parse_action_table_vn(game, fb, &game->info->_nr_actions);
-	parse_action_table_v(game, fb, &game->info->_nr_actions);
+	parse_action_table_vnjn(game, fb, &game->_nr_actions);
+	parse_action_table_vjn(game, fb, &game->_nr_actions);
+	parse_action_table_vn(game, fb, &game->_nr_actions);
+	parse_action_table_v(game, fb, &game->_nr_actions);
 }
 
 static void parse_dictionary(ComprehendGame * game, struct file_buf * fb) {
@@ -520,11 +570,11 @@ static void parse_dictionary(ComprehendGame * game, struct file_buf * fb) {
 	uint i, j;
 
 	// FIXME - fixed size 0xff array?
-	game->info->_words = (word *)xmalloc(game->info->_nr_words * sizeof(words));
+	game->_words = (word *)xmalloc(game->_nr_words * sizeof(words));
 
-	file_buf_set_pos(fb, game->info->_header.addr_dictionary);
-	for (i = 0; i < game->info->_nr_words; i++) {
-		words = &game->info->_words[i];
+	file_buf_set_pos(fb, game->_header.addr_dictionary);
+	for (i = 0; i < game->_nr_words; i++) {
+		words = &game->_words[i];
 
 		file_buf_get_data(fb, words->_word, 6);
 
@@ -543,15 +593,15 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 	uint8 index, type, dummy;
 	uint i;
 
-	game->info->_nr_word_maps = 0;
-	file_buf_set_pos(fb, game->info->_header.addr_word_map);
+	game->_nr_word_maps = 0;
+	file_buf_set_pos(fb, game->_header.addr_word_map);
 
 	/*
 	* Parse the word pair table. Each entry has a pair of dictionary
 	* index/type values for a first and second word.
 	*/
 	while (1) {
-		map = &game->info->_wordMaps[game->info->_nr_word_maps];
+		map = &game->_wordMaps[game->_nr_word_maps];
 
 		file_buf_get_u8(fb, &index);
 		file_buf_get_u8(fb, &type);
@@ -566,7 +616,7 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 		file_buf_get_u8(fb, &map->word[1].index);
 		file_buf_get_u8(fb, &map->word[1].type);
 
-		game->info->_nr_word_maps++;
+		game->_nr_word_maps++;
 	}
 
 	/* Consume two more null bytes (type and index were also null) */
@@ -578,8 +628,8 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 	* index/type. The first and second words from above map to the
 	* target word here. E.g. 'go north' -> 'north'.
 	*/
-	for (i = 0; i < game->info->_nr_word_maps; i++) {
-		map = &game->info->_wordMaps[i];
+	for (i = 0; i < game->_nr_word_maps; i++) {
+		map = &game->_wordMaps[i];
 
 		file_buf_get_u8(fb, &map->word[2].index);
 		file_buf_get_u8(fb, &map->word[2].type);
@@ -587,58 +637,58 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 }
 
 static void parse_items(ComprehendGame * game, struct file_buf * fb) {
-	size_t nr_items = game->info->_header.nr_items;
+	size_t nr_items = game->_header.nr_items;
 
 	/* Item descriptions */
-	file_buf_set_pos(fb, game->info->_header.addr_item_strings);
-	file_buf_get_array_le16(fb, 0, game->info->_item, string_desc, nr_items);
+	file_buf_set_pos(fb, game->_header.addr_item_strings);
+	file_buf_get_array_le16(fb, 0, game->_items, string_desc, nr_items);
 
-	if (game->info->_comprehendVersion == 2) {
+	if (game->_comprehendVersion == 2) {
 		/* Comprehend version 2 adds long string descriptions */
-		file_buf_set_pos(fb, game->info->_header.addr_item_strings +
-			                        (game->info->_header.nr_items * sizeof(uint16)));
-		file_buf_get_array_le16(fb, 0, game->info->_item, long_string, nr_items);
+		file_buf_set_pos(fb, game->_header.addr_item_strings +
+			                        (game->_header.nr_items * sizeof(uint16)));
+		file_buf_get_array_le16(fb, 0, game->_items, long_string, nr_items);
 	}
 
 	/* Item flags */
-	file_buf_set_pos(fb, game->info->_header.addr_item_flags);
-	file_buf_get_array_u8(fb, 0, game->info->_item, flags, nr_items);
+	file_buf_set_pos(fb, game->_header.addr_item_flags);
+	file_buf_get_array_u8(fb, 0, game->_items, flags, nr_items);
 
 	/* Item word */
-	file_buf_set_pos(fb, game->info->_header.addr_item_word);
-	file_buf_get_array_u8(fb, 0, game->info->_item, word, nr_items);
+	file_buf_set_pos(fb, game->_header.addr_item_word);
+	file_buf_get_array_u8(fb, 0, game->_items, word, nr_items);
 
 	/* Item locations */
-	file_buf_set_pos(fb, game->info->_header.addr_item_locations);
-	file_buf_get_array_u8(fb, 0, game->info->_item, room, nr_items);
+	file_buf_set_pos(fb, game->_header.addr_item_locations);
+	file_buf_get_array_u8(fb, 0, game->_items, room, nr_items);
 
 	/* Item graphic */
-	file_buf_set_pos(fb, game->info->_header.addr_item_graphics);
-	file_buf_get_array_u8(fb, 0, game->info->_item, graphic, nr_items);
+	file_buf_set_pos(fb, game->_header.addr_item_graphics);
+	file_buf_get_array_u8(fb, 0, game->_items, graphic, nr_items);
 }
 
 static void parse_rooms(ComprehendGame * game, struct file_buf * fb) {
-	size_t nr_rooms = game->info->_nr_rooms;
+	size_t nr_rooms = game->_nr_rooms;
 	int i;
 
 	/* Room exit directions */
 	for (i = 0; i < NR_DIRECTIONS; i++) {
-		file_buf_set_pos(fb, game->info->_header.room_direction_table[i]);
-		file_buf_get_array_u8(fb, 1, game->info->_rooms,
+		file_buf_set_pos(fb, game->_header.room_direction_table[i]);
+		file_buf_get_array_u8(fb, 1, game->_rooms,
 			                    direction[i], nr_rooms);
 	}
 
 	/* Room string descriptions */
-	file_buf_set_pos(fb, game->info->_header.room_desc_table);
-	file_buf_get_array_le16(fb, 1, game->info->_rooms, string_desc, nr_rooms);
+	file_buf_set_pos(fb, game->_header.room_desc_table);
+	file_buf_get_array_le16(fb, 1, game->_rooms, string_desc, nr_rooms);
 
 	/* Room flags */
-	file_buf_set_pos(fb, game->info->_header.room_flags_table);
-	file_buf_get_array_u8(fb, 1, game->info->_rooms, flags, nr_rooms);
+	file_buf_set_pos(fb, game->_header.room_flags_table);
+	file_buf_get_array_u8(fb, 1, game->_rooms, flags, nr_rooms);
 
 	/* Room graphic */
-	file_buf_set_pos(fb, game->info->_header.room_graphics_table);
-	file_buf_get_array_u8(fb, 1, game->info->_rooms, graphic, nr_rooms);
+	file_buf_set_pos(fb, game->_header.room_graphics_table);
+	file_buf_get_array_u8(fb, 1, game->_rooms, graphic, nr_rooms);
 }
 
 static uint64 string_get_chunk(uint8 * string) {
@@ -751,18 +801,18 @@ static void parse_string_table(struct file_buf * fb, unsigned start_addr,
 static void parse_variables(ComprehendGame * game, struct file_buf * fb) {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(game->info->_variables); i++)
-		file_buf_get_le16(fb, &game->info->_variables[i]);
+	for (i = 0; i < ARRAY_SIZE(game->_variables); i++)
+		file_buf_get_le16(fb, &game->_variables[i]);
 }
 
 static void parse_flags(ComprehendGame * game, struct file_buf * fb) {
 	int i, bit, flag_index = 0;
 	uint8 bitmask;
 
-	for (i = 0; i < ARRAY_SIZE(game->info->_flags) / 8; i++) {
+	for (i = 0; i < ARRAY_SIZE(game->_flags) / 8; i++) {
 		file_buf_get_u8(fb, &bitmask);
 		for (bit = 7; bit >= 0; bit--) {
-			game->info->_flags[flag_index] = !!(bitmask & (1 << bit));
+			game->_flags[flag_index] = !!(bitmask & (1 << bit));
 			flag_index++;
 		}
 	}
@@ -776,7 +826,7 @@ static void parse_replace_words(ComprehendGame * game,
 	int i;
 
 	/* FIXME - Rename addr_strings_end */
-	file_buf_set_pos(fb, game->info->_header.addr_strings_end);
+	file_buf_set_pos(fb, game->_header.addr_strings_end);
 
 	/* FIXME - what is this for */
 	file_buf_get_le16(fb, &dummy);
@@ -786,12 +836,12 @@ static void parse_replace_words(ComprehendGame * game,
 		if (len == 0)
 			break;
 
-		game->info->_replaceWords[i] = xstrndup((char *)fb->p, len);
+		game->_replaceWords[i] = xstrndup((char *)fb->p, len);
 		file_buf_get_data(fb, NULL, len + (eof ? 0 : 1));
 		if (eof)
 			break;
 	}
-	game->info->_nr_replace_words = i;
+	game->_nr_replace_words = i;
 }
 
 /*
@@ -799,7 +849,7 @@ static void parse_replace_words(ComprehendGame * game,
 * game data is. The offsets have a magic constant value added to them.
 */
 static void parse_header(ComprehendGame * game, struct file_buf * fb) {
-	struct game_header *header = &game->info->_header;
+	struct game_header *header = &game->_header;
 	uint16 dummy, addr_dictionary_end;
 	uint8 dummy8;
 
@@ -808,17 +858,17 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	switch (header->magic) {
 	case 0x2000: /* Transylvania, Crimson Crown disk one */
 	case 0x4800: /* Crimson Crown disk two */
-		game->info->_comprehendVersion = 1;
+		game->_comprehendVersion = 1;
 		magic_offset = (uint16)(-0x5a00 + 0x4);
 		break;
 
 	case 0x93f0: /* OO-Topos */
-		game->info->_comprehendVersion = 2;
+		game->_comprehendVersion = 2;
 		magic_offset = (uint16)-0x5a00;
 		break;
 
 	case 0xa429: /* Talisman */
-		game->info->_comprehendVersion = 2;
+		game->_comprehendVersion = 2;
 		magic_offset = (uint16)-0x5a00;
 		break;
 
@@ -835,14 +885,14 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	*
 	* Layout depends on the comprehend version.
 	*/
-	if (game->info->_comprehendVersion == 1) {
+	if (game->_comprehendVersion == 1) {
 		parse_header_le16(fb, &header->addr_actions_vvnn);
 		parse_header_le16(fb, &header->addr_actions_unknown);
 		parse_header_le16(fb, &header->addr_actions_vnjn);
 		parse_header_le16(fb, &header->addr_actions_vjn);
 		parse_header_le16(fb, &header->addr_actions_vdn);
 	}
-	if (game->info->_comprehendVersion >= 2) {
+	if (game->_comprehendVersion >= 2) {
 		parse_header_le16(fb, &header->addr_actions_vnjn);
 		parse_header_le16(fb, &header->addr_actions_vjn);
 		parse_header_le16(fb, &header->addr_actions_vnn);
@@ -876,7 +926,7 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	*
 	* Layout is dependent on comprehend version.
 	*/
-	if (game->info->_comprehendVersion == 1) {
+	if (game->_comprehendVersion == 1) {
 		parse_header_le16(fb, &header->addr_item_locations);
 		parse_header_le16(fb, &header->addr_item_flags);
 		parse_header_le16(fb, &header->addr_item_word);
@@ -902,16 +952,16 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	parse_header_le16(fb, &header->addr_strings_end);
 
 	file_buf_get_u8(fb, &dummy8);
-	file_buf_get_u8(fb, &game->info->_startRoom);
+	file_buf_get_u8(fb, &game->_startRoom);
 	file_buf_get_u8(fb, &dummy8);
 
 	parse_variables(game, fb);
 	parse_flags(game, fb);
 
-	game->info->_nr_rooms = header->room_direction_table[DIRECTION_SOUTH] -
+	game->_nr_rooms = header->room_direction_table[DIRECTION_SOUTH] -
 		                    header->room_direction_table[DIRECTION_NORTH];
 
-	game->info->_nr_words = (addr_dictionary_end -
+	game->_nr_words = (addr_dictionary_end -
 		                    header->addr_dictionary) /
 		                    8;
 }
@@ -929,7 +979,7 @@ static void load_extra_string_file(ComprehendGame * game,
 		end = fb.size;
 
 	parse_string_table(&fb, string_file->base_offset,
-		                end, &game->info->_strings2);
+		                end, &game->_strings2);
 
 	file_buf_unmap(&fb);
 }
@@ -937,16 +987,16 @@ static void load_extra_string_file(ComprehendGame * game,
 static void load_extra_string_files(ComprehendGame * game) {
 	int i;
 
-	memset(&game->info->_strings2, 0, sizeof(game->info->_strings2));
+	memset(&game->_strings2, 0, sizeof(game->_strings2));
 
 	for (i = 0; i < ARRAY_SIZE(game->_stringFiles); i++) {
 		if (!game->_stringFiles[i].filename)
 			break;
 
 		// HACK - get string offsets correct
-		game->info->_strings2.nr_strings = 0x40 * i;
-		if (game->info->_strings2.nr_strings == 0)
-			game->info->_strings2.nr_strings++;
+		game->_strings2.nr_strings = 0x40 * i;
+		if (game->_strings2.nr_strings == 0)
+			game->_strings2.nr_strings++;
 
 		load_extra_string_file(game, &game->_stringFiles[i]);
 	}
@@ -955,7 +1005,7 @@ static void load_extra_string_files(ComprehendGame * game) {
 static void load_game_data(ComprehendGame * game) {
 	struct file_buf fb;
 
-	memset(game->info, 0, sizeof(*game->info));
+	game->clearInfo();
 	file_buf_map(game->_gameDataFile, &fb);
 
 	parse_header(game, &fb);
@@ -963,10 +1013,10 @@ static void load_game_data(ComprehendGame * game) {
 	parse_items(game, &fb);
 	parse_dictionary(game, &fb);
 	parse_word_map(game, &fb);
-	memset(&game->info->_strings, 0, sizeof(game->info->_strings));
-	parse_string_table(&fb, game->info->_header.addr_strings,
-		                game->info->_header.addr_strings_end,
-		                &game->info->_strings);
+	memset(&game->_strings, 0, sizeof(game->_strings));
+	parse_string_table(&fb, game->_header.addr_strings,
+		                game->_header.addr_strings_end,
+		                &game->_strings);
 	load_extra_string_files(game);
 	parse_vm(game, &fb);
 	parse_action_table(game, &fb);
@@ -986,7 +1036,7 @@ void comprehend_load_game(ComprehendGame * game) {
 	}
 
 	/* FIXME - This can be merged, don't need to keep start room around */
-	game->info->_currentRoom = game->info->_startRoom;
+	game->_currentRoom = game->_startRoom;
 }
 
 #ifdef TODO
@@ -1018,22 +1068,22 @@ void comprehend_save_game(ComprehendGame * game, const char *filename) {
 		return;
 	}
 
-	nr_rooms = game->info->nr_rooms;
-	nr_items = game->info->header.nr_items;
+	nr_rooms = game->nr_rooms;
+	nr_items = game->header.nr_items;
 
 	file_buf_put_u8(fd, 0);
-	file_buf_put_u8(fd, game->info->current_room);
+	file_buf_put_u8(fd, game->current_room);
 	file_buf_put_u8(fd, 0);
 
 	/* Variables */
-	for (i = 0; i < ARRAY_SIZE(game->info->variable); i++)
-		file_buf_put_le16(fd, game->info->variable[i]);
+	for (i = 0; i < ARRAY_SIZE(game->variable); i++)
+		file_buf_put_le16(fd, game->variable[i]);
 
 	/* Flags */
-	for (flag_index = 0, i = 0; i < ARRAY_SIZE(game->info->flags) / 8; i++) {
+	for (flag_index = 0, i = 0; i < ARRAY_SIZE(game->flags) / 8; i++) {
 		bitmask = 0;
 		for (bit = 7; bit >= 0; bit--) {
-			bitmask |= (!!game->info->flags[flag_index]) << bit;
+			bitmask |= (!!game->flags[flag_index]) << bit;
 			flag_index++;
 		}
 
@@ -1048,19 +1098,19 @@ void comprehend_save_game(ComprehendGame * game, const char *filename) {
 	file_buf_put_skip(fd, 0x12c - ftell(fd));
 	file_buf_put_u8(fd, nr_items);
 
-	if (game->info->comprehend_version == 1)
+	if (game->comprehend_version == 1)
 		file_buf_put_skip(fd, 0x230 - ftell(fd));
 	else
 		file_buf_put_skip(fd, 0x130 - ftell(fd));
 
 	/* Rooms */
-	file_buf_put_array_le16(fd, 1, game->info->rooms,
+	file_buf_put_array_le16(fd, 1, game->rooms,
 		                    string_desc, nr_rooms);
 	for (dir = 0; dir < NR_DIRECTIONS; dir++)
-		file_buf_put_array_u8(fd, 1, game->info->rooms,
+		file_buf_put_array_u8(fd, 1, game->rooms,
 			                    direction[dir], nr_rooms);
-	file_buf_put_array_u8(fd, 1, game->info->rooms, flags, nr_rooms);
-	file_buf_put_array_u8(fd, 1, game->info->rooms, graphic, nr_rooms);
+	file_buf_put_array_u8(fd, 1, game->rooms, flags, nr_rooms);
+	file_buf_put_array_u8(fd, 1, game->rooms, graphic, nr_rooms);
 
 	/*
 	* Objects
@@ -1068,18 +1118,18 @@ void comprehend_save_game(ComprehendGame * game, const char *filename) {
 	* Layout differs depending on Comprehend version. Version 2 also
 	* has long string descriptions for each object.
 	*/
-	file_buf_put_array_le16(fd, 0, game->info->item, string_desc, nr_items);
-	if (game->info->comprehend_version == 1) {
-		file_buf_put_array_u8(fd, 0, game->info->item, room, nr_items);
-		file_buf_put_array_u8(fd, 0, game->info->item, flags, nr_items);
-		file_buf_put_array_u8(fd, 0, game->info->item, word, nr_items);
-		file_buf_put_array_u8(fd, 0, game->info->item, graphic, nr_items);
+	file_buf_put_array_le16(fd, 0, game->item, string_desc, nr_items);
+	if (game->comprehend_version == 1) {
+		file_buf_put_array_u8(fd, 0, game->item, room, nr_items);
+		file_buf_put_array_u8(fd, 0, game->item, flags, nr_items);
+		file_buf_put_array_u8(fd, 0, game->item, word, nr_items);
+		file_buf_put_array_u8(fd, 0, game->item, graphic, nr_items);
 	} else {
-		file_buf_put_array_le16(fd, 0, game->info->item, long_string, nr_items);
-		file_buf_put_array_u8(fd, 0, game->info->item, word, nr_items);
-		file_buf_put_array_u8(fd, 0, game->info->item, room, nr_items);
-		file_buf_put_array_u8(fd, 0, game->info->item, flags, nr_items);
-		file_buf_put_array_u8(fd, 0, game->info->item, graphic, nr_items);
+		file_buf_put_array_le16(fd, 0, game->item, long_string, nr_items);
+		file_buf_put_array_u8(fd, 0, game->item, word, nr_items);
+		file_buf_put_array_u8(fd, 0, game->item, room, nr_items);
+		file_buf_put_array_u8(fd, 0, game->item, flags, nr_items);
+		file_buf_put_array_u8(fd, 0, game->item, graphic, nr_items);
 	}
 
 	fclose(fd);
@@ -1101,12 +1151,12 @@ void comprehend_restore_game(ComprehendGame * game, const char *filename) {
 		return;
 	}
 
-	nr_rooms = game->info->nr_rooms;
-	nr_items = game->info->header.nr_items;
+	nr_rooms = game->nr_rooms;
+	nr_items = game->header.nr_items;
 
 	/* Restore starting room */
 	file_buf_set_pos(&fb, 1);
-	file_buf_get_u8(&fb, &game->info->current_room);
+	file_buf_get_u8(&fb, &game->current_room);
 
 	/* Restore flags and variables */
 	file_buf_set_pos(&fb, 3);
@@ -1114,19 +1164,19 @@ void comprehend_restore_game(ComprehendGame * game, const char *filename) {
 	parse_flags(game, &fb);
 
 	/* FIXME - unknown restore data, skip over it */
-	if (game->info->comprehend_version == 1)
+	if (game->comprehend_version == 1)
 		file_buf_set_pos(&fb, 0x230);
 	else
 		file_buf_set_pos(&fb, 0x130);
 
 	/* Restore rooms */
-	file_buf_get_array_le16(&fb, 1, game->info->rooms,
+	file_buf_get_array_le16(&fb, 1, game->rooms,
 		                    string_desc, nr_rooms);
 	for (dir = 0; dir < NR_DIRECTIONS; dir++)
-		file_buf_get_array_u8(&fb, 1, game->info->rooms,
+		file_buf_get_array_u8(&fb, 1, game->rooms,
 			                    direction[dir], nr_rooms);
-	file_buf_get_array_u8(&fb, 1, game->info->rooms, flags, nr_rooms);
-	file_buf_get_array_u8(&fb, 1, game->info->rooms, graphic, nr_rooms);
+	file_buf_get_array_u8(&fb, 1, game->rooms, flags, nr_rooms);
+	file_buf_get_array_u8(&fb, 1, game->rooms, graphic, nr_rooms);
 
 	/*
 	* Restore objects
@@ -1134,18 +1184,18 @@ void comprehend_restore_game(ComprehendGame * game, const char *filename) {
 	* Layout differs depending on Comprehend version. Version 2 also
 	* has long string descriptions for each object.
 	*/
-	file_buf_get_array_le16(&fb, 0, game->info->item, string_desc, nr_items);
-	if (game->info->comprehend_version == 1) {
-		file_buf_get_array_u8(&fb, 0, game->info->item, room, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->info->item, flags, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->info->item, word, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->info->item, graphic, nr_items);
+	file_buf_get_array_le16(&fb, 0, game->item, string_desc, nr_items);
+	if (game->comprehend_version == 1) {
+		file_buf_get_array_u8(&fb, 0, game->item, room, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->item, flags, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->item, word, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->item, graphic, nr_items);
 	} else {
-		file_buf_get_array_le16(&fb, 0, game->info->item, long_string, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->info->item, word, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->info->item, room, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->info->item, flags, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->info->item, graphic, nr_items);
+		file_buf_get_array_le16(&fb, 0, game->item, long_string, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->item, word, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->item, room, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->item, flags, nr_items);
+		file_buf_get_array_u8(&fb, 0, game->item, graphic, nr_items);
 	}
 
 	/*
@@ -1153,9 +1203,9 @@ void comprehend_restore_game(ComprehendGame * game, const char *filename) {
 	*         Not sure what this means, so just mask it out for now.
 	*/
 	for (i = 1; i <= nr_rooms; i++)
-		patch_string_desc(&game->info->rooms[i].string_desc);
+		patch_string_desc(&game->rooms[i].string_desc);
 	for (i = 0; i < nr_items; i++)
-		patch_string_desc(&game->info->item[i].string_desc);
+		patch_string_desc(&game->item[i].string_desc);
 
 	file_buf_unmap(&fb);
 #else
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 6bc13f211a..2e243198f1 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -51,7 +51,11 @@ struct function_state {
 	bool in_command;
 	bool executed;
 
-	function_state();
+	function_state() {
+		clear();
+	}
+
+	void clear();
 };
 
 struct room {
@@ -60,7 +64,11 @@ struct room {
 	uint8 graphic;
 	uint16 string_desc;
 
-	room();
+	room() {
+		clear();
+	}
+
+	void clear();
 };
 
 struct item {
@@ -71,7 +79,11 @@ struct item {
 	uint8 word;
 	uint8 graphic;
 
-	item();
+	item() {
+		clear();
+	}
+
+	void clear();
 };
 
 struct word {
@@ -79,14 +91,24 @@ struct word {
 	uint8 _index;
 	uint8 _type;
 
-	word();
+	word() {
+		clear();
+	}
+
+	void clear();
 };
 
 struct word_index {
 	uint8 index;
 	uint8 type;
 
-	word_index() : index(0), type(0) {}
+	word_index() {
+		clear();
+	}
+
+	void clear() {
+		index = type = 0;
+	}
 };
 
 struct word_map {
@@ -94,7 +116,11 @@ struct word_map {
 	word_index word[3];
 	uint8 flags;
 
-	word_map() : flags(0) {}
+	word_map() {
+		clear();
+	}
+
+	void clear();
 };
 
 struct action {
@@ -105,7 +131,11 @@ struct action {
 	uint8 word_type[4];
 	uint16 function;
 
-	action();
+	action() {
+		clear();
+	}
+
+	void clear();
 };
 
 struct instruction {
@@ -114,21 +144,33 @@ struct instruction {
 	uint8 operand[3];
 	bool is_command;
 
-	instruction();
+	instruction() {
+		clear();
+	}
+
+	void clear();
 };
 
 struct function {
 	instruction instructions[0x100];
 	size_t nr_instructions;
 
-	function() : nr_instructions(0) {}
+	function() {
+		clear();
+	}
+
+	void clear();
 };
 
 struct string_table {
 	char *strings[0xffff];
 	size_t nr_strings;
 
-	string_table();
+	string_table() {
+		clear();
+	}
+
+	void clear();
 };
 
 struct game_header {
@@ -163,10 +205,14 @@ struct game_header {
 
 	uint16 addr_vm; // FIXME - functions
 
-	game_header();
+	game_header() {
+		clear();
+	}
+
+	void clear();
 };
 
-struct game_info {
+struct GameInfo {
 	game_header _header;
 
 	unsigned _comprehendVersion;
@@ -177,7 +223,7 @@ struct game_info {
 	size_t _nr_rooms;
 	uint8 _currentRoom;
 
-	struct item _item[0xff];
+	struct item _items[0xff];
 
 	struct word *_words;
 	size_t _nr_words;
@@ -206,7 +252,11 @@ struct game_info {
 	uint8 _currentReplaceWord;
 	unsigned _updateFlags;
 
-	game_info();
+	GameInfo() {
+		clearInfo();
+	}
+
+	void clearInfo();
 };
 
 struct string_file {
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index 42fb1a0aa3..4e230db896 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -61,11 +61,11 @@ OOToposGame::OOToposGame() : ComprehendGame() {
 
 int OOToposGame::room_is_special(unsigned room_index,
                               unsigned *room_desc_string) {
-	room *room = &info->_rooms[room_index];
+	room *room = &_rooms[room_index];
 
 	/* Is the room dark */
 	if ((room->flags & OO_ROOM_FLAG_DARK) &&
-	    !(info->_flags[OO_FLAG_FLASHLIGHT_ON])) {
+	    !(_flags[OO_FLAG_FLASHLIGHT_ON])) {
 		if (room_desc_string)
 			*room_desc_string = 0xb3;
 		return ROOM_IS_DARK;
@@ -73,7 +73,7 @@ int OOToposGame::room_is_special(unsigned room_index,
 
 	/* Is the room too bright */
 	if (room_index == OO_BRIGHT_ROOM &&
-	    !info->_flags[OO_FLAG_WEARING_GOGGLES]) {
+	    !_flags[OO_FLAG_WEARING_GOGGLES]) {
 		if (room_desc_string)
 			*room_desc_string = 0x1c;
 		return ROOM_IS_TOO_BRIGHT;
@@ -85,26 +85,26 @@ int OOToposGame::room_is_special(unsigned room_index,
 bool OOToposGame::before_turn() {
 	/* FIXME - probably doesn't work correctly with restored games */
 	static bool flashlight_was_on = false, googles_were_worn = false;
-	struct room *room = &info->_rooms[info->_currentRoom];
+	struct room *room = &_rooms[_currentRoom];
 
 	/* 
 	 * Check if the room needs to be redrawn because the flashlight
 	 * was switch off or on.
 	 */
-	if (info->_flags[OO_FLAG_FLASHLIGHT_ON] != flashlight_was_on &&
+	if (_flags[OO_FLAG_FLASHLIGHT_ON] != flashlight_was_on &&
 	    (room->flags & OO_ROOM_FLAG_DARK)) {
-		flashlight_was_on = info->_flags[OO_FLAG_FLASHLIGHT_ON];
-		info->_updateFlags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
+		flashlight_was_on = _flags[OO_FLAG_FLASHLIGHT_ON];
+		_updateFlags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
 	}
 
 	/*
 	 * Check if the room needs to be redrawn because the goggles were
 	 * put on or removed.
 	 */
-	if (info->_flags[OO_FLAG_WEARING_GOGGLES] != googles_were_worn &&
-	    info->_currentRoom == OO_BRIGHT_ROOM) {
-		googles_were_worn = info->_flags[OO_FLAG_WEARING_GOGGLES];
-		info->_updateFlags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
+	if (_flags[OO_FLAG_WEARING_GOGGLES] != googles_were_worn &&
+	    _currentRoom == OO_BRIGHT_ROOM) {
+		googles_were_worn = _flags[OO_FLAG_WEARING_GOGGLES];
+		_updateFlags |= UPDATE_GRAPHICS | UPDATE_ROOM_DESC;
 	}
 
 	return false;
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index e94814aa86..7be0262219 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -69,17 +69,17 @@ void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
 	struct room *room;
 	uint16 turn_count;
 
-	room = &info->_rooms[info->_currentRoom];
-	turn_count = info->_variables[VAR_TURN_COUNT];
+	room = &_rooms[_currentRoom];
+	turn_count = _variables[VAR_TURN_COUNT];
 
 	monster = get_item(this, monster_info->object);
-	if (monster->room == info->_currentRoom) {
+	if (monster->room == _currentRoom) {
 		/* The monster is in the current room - leave it there */
 		return;
 	}
 
 	if ((room->flags & monster_info->room_allow_flag) &&
-	    !info->_flags[monster_info->dead_flag] &&
+	    !_flags[monster_info->dead_flag] &&
 	    turn_count > monster_info->min_turns_before) {
 		/*
 		 * The monster is alive and allowed to move to the current
@@ -87,8 +87,8 @@ void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
 		 * it back to limbo.
 		 */
 		if ((g_comprehend->getRandomNumber(0x7fffffff) % monster_info->randomness) == 0) {
-			move_object(this, monster, info->_currentRoom);
-			info->_variables[0xf] = turn_count + 1;
+			move_object(this, monster, _currentRoom);
+			_variables[0xf] = turn_count + 1;
 		} else {
 			move_object(this, monster, ROOM_NOWHERE);
 		}
@@ -98,7 +98,7 @@ void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
 int TransylvaniaGame::room_is_special(unsigned room_index,
 			      unsigned *room_desc_string)
 {
-	struct room *room = &info->_rooms[room_index];
+	struct room *room = &_rooms[room_index];
 
 	if (room_index == 0x28) {
 		if (room_desc_string)
@@ -151,9 +151,9 @@ void TransylvaniaGame::handle_special_opcode(uint8 operand)
 		 * Show the Zin screen in reponse to doing 'sing some enchanted
 		 * evening' in his cabin.
 		 */
-		draw_location_image(&info->_roomImages, 41);
+		draw_location_image(&_roomImages, 41);
 		console_get_key();
-		info->_updateFlags |= UPDATE_GRAPHICS;
+		_updateFlags |= UPDATE_GRAPHICS;
 		break;
 	}
 }
@@ -179,7 +179,7 @@ void TransylvaniaGame::before_game() {
 	char buffer[128];
 
 	/* Welcome to Transylvania - sign your name */
-	console_println(this, info->_strings.strings[0x20]);
+	console_println(this, _strings.strings[0x20]);
 	read_string(buffer, sizeof(buffer));
 
 	/*
@@ -188,15 +188,15 @@ void TransylvaniaGame::before_game() {
 	 * limited (the original game will break if you put a name in that
 	 * is too long).
 	 */
-	if (!info->_replaceWords[0])
-		info->_replaceWords[0] = xstrndup(buffer, strlen(buffer));
+	if (!_replaceWords[0])
+		_replaceWords[0] = xstrndup(buffer, strlen(buffer));
 	else
-		snprintf(info->_replaceWords[0],
-			 strlen(info->_replaceWords[0]),
+		snprintf(_replaceWords[0],
+			 strlen(_replaceWords[0]),
 			 "%s", buffer);
 
 	/* And your next of kin - This isn't store by the game */
-	console_println(this, info->_strings.strings[0x21]);
+	console_println(this, _strings.strings[0x21]);
 	read_string(buffer, sizeof(buffer));
 }
 
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 77b85167ee..4204001110 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -46,6 +46,12 @@ struct image_context {
 
 static unsigned draw_flags;
 
+void image_data::clear() {
+	fb = nullptr;
+	image_offsets = nullptr;
+	nr_images = 0;
+}
+
 void image_set_draw_flags(unsigned flags)
 {
 	draw_flags |= flags;
@@ -349,10 +355,10 @@ void comprehend_load_image_file(const char *filename, struct image_data *info)
 }
 
 void comprehend_load_images(ComprehendGame *game) {
-	load_image_files(&game->info->_roomImages,
+	load_image_files(&game->_roomImages,
 			 game->_locationGraphicFiles);
 
-	load_image_files(&game->info->_itemImages,
+	load_image_files(&game->_itemImages,
 			 game->_itemGraphicFiles);
 }
 
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
index ece82e98a4..382c90a166 100644
--- a/engines/glk/comprehend/image_data.h
+++ b/engines/glk/comprehend/image_data.h
@@ -35,6 +35,12 @@ struct image_data {
 	file_buf	*fb;
 	uint16	*image_offsets;
 	size_t		nr_images;
+
+	image_data() {
+		clear();
+	}
+
+	void clear();
 };
 
 #define IMAGEF_OP_WAIT_KEYPRESS		(1 << 0)
diff --git a/engines/glk/comprehend/opcode_map.cpp b/engines/glk/comprehend/opcode_map.cpp
index 431ba0c065..03c59206fe 100644
--- a/engines/glk/comprehend/opcode_map.cpp
+++ b/engines/glk/comprehend/opcode_map.cpp
@@ -175,7 +175,7 @@ static uint8 opcode_map_v2[0x100] = {
 
 uint8 *get_opcode_map(ComprehendGame *game)
 {
-	switch (game->info->_comprehendVersion) {
+	switch (game->_comprehendVersion) {
 	case 1:
 		return opcode_map_v1;
 		break;
@@ -183,7 +183,7 @@ uint8 *get_opcode_map(ComprehendGame *game)
 		return opcode_map_v2;
 	default:
 		fatal_error("Unsupported Comprehend version %d\n",
-			    game->info->_comprehendVersion);
+			    game->_comprehendVersion);
 
 		/* Not reached */
 		return NULL;
diff --git a/engines/glk/comprehend/strings.cpp b/engines/glk/comprehend/strings.cpp
index 7ddf1a5059..4b6ddb7f99 100644
--- a/engines/glk/comprehend/strings.cpp
+++ b/engines/glk/comprehend/strings.cpp
@@ -55,8 +55,8 @@ const char *string_lookup(ComprehendGame *game, uint16 index)
 		/* Fall-through */
 	case 0x00:
 	case 0x80:
-		if (string < game->info->_strings.nr_strings)
-			return game->info->_strings.strings[string];
+		if (string < game->_strings.nr_strings)
+			return game->_strings.strings[string];
 		break;
 
 	case 0x83:
@@ -64,8 +64,8 @@ const char *string_lookup(ComprehendGame *game, uint16 index)
 		/* Fall-through */
 	case 0x02:
 	case 0x82:
-		if (string < game->info->_strings2.nr_strings)
-			return game->info->_strings2.strings[string];
+		if (string < game->_strings2.nr_strings)
+			return game->_strings2.strings[string];
 		break;
 	}
 


Commit: fff77194d711e66e64018ba469b76f6f1440661e
    https://github.com/scummvm/scummvm/commit/fff77194d711e66e64018ba469b76f6f1440661e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Converting data loading to be endian safe

Changed paths:
    engines/glk/comprehend/file_buf.cpp
    engines/glk/comprehend/file_buf.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_data.h


diff --git a/engines/glk/comprehend/file_buf.cpp b/engines/glk/comprehend/file_buf.cpp
index 512d88c705..d246bd738f 100644
--- a/engines/glk/comprehend/file_buf.cpp
+++ b/engines/glk/comprehend/file_buf.cpp
@@ -21,119 +21,103 @@
  */
 
 #include "glk/comprehend/file_buf.h"
-#include "glk/comprehend/util.h"
 #include "common/algorithm.h"
 #include "common/file.h"
+#include "glk/comprehend/util.h"
 
 namespace Glk {
 namespace Comprehend {
 
-int file_buf_map_may_fail(const char *filename, struct file_buf *fb)
-{
+FileBuffer::FileBuffer(const Common::String &filename) : _pos(0) {
+	// Open the file
 	Common::File f;
-
-	memset(fb, 0, sizeof(*fb));
-
 	if (!f.open(filename))
-		return -1;
-
-	fb->data = (uint8 *)xmalloc(f.size());
-	fb->size = f.size();
-	f.read(fb->data, fb->size);
-	f.close();
-
-	fb->p = fb->data;
-
-	// FIXME - remove
-	fb->marked = (uint8 *)malloc(fb->size);
-	memset(fb->marked, 0, fb->size);
+		error("Could not open - %s", filename.c_str());
 
-	return 0;
+	_data.resize(f.size());
+	_readBytes.resize(f.size());
+	f.read(&_data[0], f.size());
 }
 
-void file_buf_map(const char *filename, struct file_buf *fb)
-{
-	int err;
-
-	err = file_buf_map_may_fail(filename, fb);
-	if (err)
-		fatal_strerror(errno, "Cannot open file '%s'", filename);
+bool FileBuffer::exists(const Common::String &filename) {
+	return Common::File::exists(filename);
 }
 
-void file_buf_unmap(struct file_buf *fb)
-{
-	free(fb->marked);
-	free(fb->data);
-}
-
-void file_buf_set_pos(struct file_buf *fb, unsigned pos)
-{
-	if (pos > fb->size)
-		error("Bad position set in file (%x > %x)",
-			    pos, fb->size);
+bool FileBuffer::seek(int32 offset, int whence) {
+	switch (whence) {
+	case SEEK_SET:
+		_pos = offset;
+		break;
+	case SEEK_CUR:
+		_pos += offset;
+		break;
+	case SEEK_END:
+		_pos = (int)_data.size() + offset;
+		break;
+	default:
+		break;
+	}
 
-	fb->p = fb->data + pos;
+	return true;
 }
 
-unsigned file_buf_get_pos(struct file_buf *fb)
-{
-	return fb->p - fb->data;
-}
+uint32 FileBuffer::read(void *dataPtr, uint32 dataSize) {
+	int32 bytesRead = CLIP((int32)dataSize, 0, (int32)_data.size() - _pos);
+	if (bytesRead) {
+		Common::fill(&_readBytes[_pos], &_readBytes[_pos + bytesRead], true);
+		Common::copy((byte *)dataPtr, (byte *)dataPtr + bytesRead, (byte *)dataPtr);
+		_pos += bytesRead;
+	}
 
-void *file_buf_data_pointer(struct file_buf *fb)
-{
-	return fb->p;
+	return bytesRead;
 }
 
-size_t file_buf_strlen(struct file_buf *fb, bool *eof)
-{
+size_t FileBuffer::strlen(bool *eof) {
 	uint8 *end;
 
 	if (eof)
 		*eof = false;
 
-	end = (uint8 *)memchr(fb->p, '\0', fb->size - file_buf_get_pos(fb));
+	end = (uint8 *)memchr(&_data[_pos], '\0', size() - _pos);
 	if (!end) {
-		/* No null terminator - string is remaining length */
+		// No null terminator - string is remaining length
 		if (eof)
 			*eof = true;
-		return fb->size - file_buf_get_pos(fb);
+		return size() - _pos;
 	}
 
-	return end - fb->p;
+	return end - &_data[_pos];
+}
+
+
+#ifdef TODO
+void file_buf_unmap(struct FileBuffer *fb) {
+	free(fb->marked);
+	free(fb->data);
+}
+
+unsigned file_buf_get_pos(struct FileBuffer *fb) {
+	return fb->p - fb->data;
 }
 
-void file_buf_get_data(struct file_buf *fb, void *data, size_t data_size)
-{
-	if (file_buf_get_pos(fb) + data_size > fb->size)
+void file_buf_get_data(struct FileBuffer *fb, void *data, size_t data_size) {
+	if (fb->pos() + data_size > fb->size)
 		error("Not enough data in file (%x + %x > %x)",
-			    file_buf_get_pos(fb), data_size, fb->size);
+		      fb->pos(), data_size, fb->size);
 
 	if (data)
 		memcpy(data, fb->p, data_size);
 
 	/* Mark this region of the file as read */
-	memset(fb->marked + file_buf_get_pos(fb), '?', data_size);
+	memset(fb->marked + fb->pos(), '?', data_size);
 
 	fb->p += data_size;
 }
 
-void file_buf_get_u8(struct file_buf *fb, uint8 *val)
-{
-	file_buf_get_data(fb, val, sizeof(*val));
-}
-
-void file_buf_get_le16(struct file_buf *fb, uint16 *val)
-{
-	file_buf_get_data(fb, val, sizeof(*val));
-	*val = READ_LE_UINT16(val);
-}
-
 /*
  * Debugging function to show regions of a file that have not been read.
  */
-void file_buf_show_unmarked(struct file_buf *fb)
-{
+void file_buf_show_unmarked(struct FileBuffer *fb) {
 	int i, start = -1;
 
 	for (i = 0; i < (int)fb->size; i++) {
@@ -141,15 +125,14 @@ void file_buf_show_unmarked(struct file_buf *fb)
 			start = i;
 
 		if ((fb->marked[i] || i == (int)fb->size - 1) && start != -1) {
-			warning("%.4x - %.4x unmarked (%d bytes)\n", 
-			       start, i - 1, i - start);
+			warning("%.4x - %.4x unmarked (%d bytes)\n",
+			        start, i - 1, i - start);
 			start = -1;
 		}
 	}
 }
 
-void file_buf_put_u8(Common::WriteStream *fd, uint8 val)
-{
+void file_buf_put_u8(Common::WriteStream *fd, uint8 val) {
 	fd->writeByte(val);
 }
 
@@ -161,6 +144,7 @@ void file_buf_put_skip(Common::WriteStream *fd, size_t skip) {
 	for (uint i = 0; i < skip; i++)
 		file_buf_put_u8(fd, 0);
 }
+#endif
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/file_buf.h b/engines/glk/comprehend/file_buf.h
index 27d1371034..3f323e3ec2 100644
--- a/engines/glk/comprehend/file_buf.h
+++ b/engines/glk/comprehend/file_buf.h
@@ -23,47 +23,47 @@
 #ifndef GLK_COMPREHEND_FILE_BUF_H
 #define GLK_COMPREHEND_FILE_BUF_H
 
-#include "common/scummsys.h"
+#include "common/array.h"
+#include "common/memstream.h"
 #include "common/stream.h"
 
 namespace Glk {
 namespace Comprehend {
 
-struct file_buf {
-	uint8		*data;
-	size_t		size;
-	uint8		*p;
+struct FileBuffer : public Common::SeekableReadStream {
+private:
+	Common::Array<byte> _data;
+	Common::Array<bool> _readBytes;
+	int32 _pos;
 
-	uint8		*marked;
-};
+public:
+	FileBuffer() : _pos(0) {}
+	FileBuffer(const Common::String &filename);
+	static bool exists(const Common::String &filename);
 
-void file_buf_map(const char *filename, struct file_buf *fb);
-int file_buf_map_may_fail(const char *filename, struct file_buf *fb);
-void file_buf_unmap(struct file_buf *fb);
-void file_buf_show_unmarked(struct file_buf *fb);
+	int32 pos() const override { return _pos; }
+	int32 size() const override { return _data.size(); }
+	bool seek(int32 offset, int whence = SEEK_SET) override;
 
-void *file_buf_data_pointer(struct file_buf *fb);
-void file_buf_set_pos(struct file_buf *fb, unsigned pos);
-unsigned file_buf_get_pos(struct file_buf *fb);
+	bool eos() const override {
+		return _pos >= (int)_data.size();
+	}
+	uint32 read(void *dataPtr, uint32 dataSize) override;
 
-size_t file_buf_strlen(struct file_buf *fb, bool *eof);
+	const byte *dataPtr() const { return &_data[_pos]; }
+	size_t strlen(bool *eof = nullptr);
 
-void file_buf_get_data(struct file_buf *fb, void *data, size_t data_size);
-void file_buf_get_u8(struct file_buf *fb, uint8 *val);
-void file_buf_get_le16(struct file_buf *fb, uint16 *val);
+};
 
-#define file_buf_get_array(fb, type, base, array, member, size)		\
-	do {								\
-		uint __i;						\
-		for (__i = (base); __i < (base) + (size); __i++)	\
-			file_buf_get_##type(fb, &((array)[__i]).member); \
-	} while (0)
+#ifdef TODO
+void file_buf_unmap(struct FileBuffer *fb);
+void file_buf_show_unmarked(struct FileBuffer *fb);
 
-#define file_buf_get_array_u8(fb, base, array, member, size) \
-	file_buf_get_array(fb, u8, base, array, member, size)
+unsigned file_buf_get_pos(struct FileBuffer *fb);
 
-#define file_buf_get_array_le16(fb, base, array, member, size) \
-	file_buf_get_array(fb, le16, base, array, member, size)
+size_t file_buf_strlen(struct FileBuffer *fb, bool *eof);
+
+void file_buf_get_data(struct FileBuffer *fb, void *data, size_t data_size);
 
 void file_buf_put_skip(Common::WriteStream *fd, size_t skip);
 void file_buf_put_u8(Common::WriteStream *fd, uint8 val);
@@ -81,6 +81,21 @@ void file_buf_put_le16(Common::WriteStream *fd, uint16 val);
 
 #define file_buf_put_array_u8(fd, base, array, member, size) \
 	file_buf_put_array(fd, u8, base, array, member, size)
+#endif
+
+#define file_buf_get_array(fb, type, base, array, member, size) \
+	do {                                                        \
+		uint __i;                                               \
+		for (__i = (base); __i < (base) + (size); __i++)        \
+			(array)[__i].member = fb->read##type();    \
+	} while (0)
+
+#define file_buf_get_array_u8(fb, base, array, member, size) \
+	file_buf_get_array(fb, Byte, base, array, member, size)
+
+#define file_buf_get_array_le16(fb, base, array, member, size) \
+	file_buf_get_array(fb, Uint16LE, base, array, member, size)
+
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 482023cd5d..d10414b4ee 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -183,8 +183,8 @@ void GameInfo::clearInfo() {
 	Common::fill(&_replaceWords[0], &_replaceWords[256], (char *)nullptr);
 }
 
-static void parse_header_le16(struct file_buf * fb, uint16 * val) {
-	file_buf_get_le16(fb, val);
+static void parse_header_le16(FileBuffer *fb, uint16 *val) {
+	*val = fb->readUint16LE();
 	*val += (uint16)magic_offset;
 }
 
@@ -198,31 +198,30 @@ static bool opcode_is_command(uint8 opcode) {
 	return opcode & 0x80;
 }
 
-static uint8 parse_vm_instruction(struct file_buf * fb,
-	                                struct instruction * instr) {
+static uint8 parse_vm_instruction(FileBuffer *fb,
+		instruction *instr) {
 	uint i;
 
 	/* Get the opcode */
-	file_buf_get_u8(fb, &instr->opcode);
+	instr->opcode = fb->readByte();
 	instr->nr_operands = opcode_nr_operands(instr->opcode);
 
 	/* Get the operands */
 	for (i = 0; i < instr->nr_operands; i++)
-		file_buf_get_u8(fb, &instr->operand[i]);
+		instr->operand[i] = fb->readByte();
 
 	instr->is_command = opcode_is_command(instr->opcode);
 
 	return instr->opcode;
 }
 
-static void parse_function(struct file_buf * fb, struct function * func) {
+static void parse_function(struct FileBuffer * fb, struct function * func) {
 	struct instruction *instruction;
 	uint8 *p, opcode;
 
-	p = (uint8 *)memchr(file_buf_data_pointer(fb), 0x00,
-		                fb->size - file_buf_get_pos(fb));
+	p = (uint8 *)memchr(fb->dataPtr(), 0x00, fb->size() - fb->pos());
 	if (!p)
-		fatal_error("bad function @ %.4x", file_buf_get_pos(fb));
+		fatal_error("bad function @ %.4x", fb->pos());
 
 	while (1) {
 		instruction = &func->instructions[func->nr_instructions];
@@ -237,10 +236,10 @@ static void parse_function(struct file_buf * fb, struct function * func) {
 	}
 }
 
-static void parse_vm(ComprehendGame * game, struct file_buf * fb) {
-	struct function *func;
+static void parse_vm(ComprehendGame *game, struct FileBuffer * fb) {
+	function *func;
 
-	file_buf_set_pos(fb, game->_header.addr_vm);
+	fb->seek(game->_header.addr_vm);
 	while (1) {
 		func = &game->_functions[game->_nr_functions];
 
@@ -252,8 +251,8 @@ static void parse_vm(ComprehendGame * game, struct file_buf * fb) {
 	}
 }
 
-static void parse_action_table_vvnn(ComprehendGame * game,
-	                                struct file_buf * fb, size_t * index) {
+static void parse_action_table_vvnn(ComprehendGame *game,
+	                                struct FileBuffer * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
 	int i, j;
@@ -268,12 +267,12 @@ static void parse_action_table_vvnn(ComprehendGame * game,
 	*     u8:   noun2
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->_header.addr_actions_vvnn);
+	fb->seek(game->_header.addr_actions_vvnn);
 	while (1) {
-		file_buf_get_u8(fb, &verb);
+		verb = fb->readByte();
 		if (verb == 0)
 			break;
-		file_buf_get_u8(fb, &count);
+		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
 			action = &game->_actions[*index];
@@ -288,16 +287,16 @@ static void parse_action_table_vvnn(ComprehendGame * game,
 			action->word[0] = verb;
 
 			for (j = 0; j < 3; j++)
-				file_buf_get_u8(fb, &action->word[j + 1]);
-			file_buf_get_le16(fb, &action->function);
+				action->word[j + 1] = fb->readByte();
+			action->function = fb->readUint16LE();
 
 			(*index)++;
 		}
 	}
 }
 
-static void parse_action_table_vnjn(ComprehendGame * game,
-	                                struct file_buf * fb, size_t * index) {
+static void parse_action_table_vnjn(ComprehendGame *game,
+	                                struct FileBuffer * fb, size_t * index) {
 	struct action *action;
 	uint8 join, count;
 	int i;
@@ -312,12 +311,12 @@ static void parse_action_table_vnjn(ComprehendGame * game,
 	*     u8:   noun2
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->_header.addr_actions_vnjn);
+	fb->seek(game->_header.addr_actions_vnjn);
 	while (1) {
-		file_buf_get_u8(fb, &join);
+		join = fb->readByte();
 		if (join == 0)
 			break;
-		file_buf_get_u8(fb, &count);
+		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
 			action = &game->_actions[*index];
@@ -331,18 +330,18 @@ static void parse_action_table_vnjn(ComprehendGame * game,
 
 			action->word[2] = join;
 
-			file_buf_get_u8(fb, &action->word[0]);
-			file_buf_get_u8(fb, &action->word[1]);
-			file_buf_get_u8(fb, &action->word[3]);
-			file_buf_get_le16(fb, &action->function);
+			action->word[0] = fb->readByte();
+			action->word[1] = fb->readByte();
+			action->word[3] = fb->readByte();
+			action->function = fb->readUint16LE();
 
 			(*index)++;
 		}
 	}
 }
 
-static void parse_action_table_vjn(ComprehendGame * game,
-	                                struct file_buf * fb, size_t * index) {
+static void parse_action_table_vjn(ComprehendGame *game,
+	                                struct FileBuffer * fb, size_t * index) {
 	struct action *action;
 	uint8 join, count;
 	int i;
@@ -356,12 +355,12 @@ static void parse_action_table_vjn(ComprehendGame * game,
 	*     u8:   noun
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->_header.addr_actions_vjn);
+	fb->seek(game->_header.addr_actions_vjn);
 	while (1) {
-		file_buf_get_u8(fb, &join);
+		join = fb->readByte();
 		if (join == 0)
 			break;
-		file_buf_get_u8(fb, &count);
+		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
 			action = &game->_actions[*index];
@@ -373,17 +372,17 @@ static void parse_action_table_vjn(ComprehendGame * game,
 			action->word_type[1] = WORD_TYPE_JOIN;
 			action->word_type[2] = WORD_TYPE_NOUN_MASK;
 
-			file_buf_get_u8(fb, &action->word[0]);
-			file_buf_get_u8(fb, &action->word[2]);
-			file_buf_get_le16(fb, &action->function);
+			action->word[0] = fb->readByte();
+			action->word[2] = fb->readByte();
+			action->function = fb->readUint16LE();
 
 			(*index)++;
 		}
 	}
 }
 
-static void parse_action_table_vdn(ComprehendGame * game,
-	                                struct file_buf * fb, size_t * index) {
+static void parse_action_table_vdn(ComprehendGame *game,
+	                                struct FileBuffer * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
 	int i;
@@ -397,12 +396,12 @@ static void parse_action_table_vdn(ComprehendGame * game,
 	*     u8:   noun
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->_header.addr_actions_vdn);
+	fb->seek(game->_header.addr_actions_vdn);
 	while (1) {
-		file_buf_get_u8(fb, &verb);
+		verb = fb->readByte();
 		if (verb == 0)
 			break;
-		file_buf_get_u8(fb, &count);
+		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
 			action = &game->_actions[*index];
@@ -414,17 +413,17 @@ static void parse_action_table_vdn(ComprehendGame * game,
 			action->word_type[1] = WORD_TYPE_VERB;
 			action->word_type[2] = WORD_TYPE_NOUN_MASK;
 
-			file_buf_get_u8(fb, &action->word[1]);
-			file_buf_get_u8(fb, &action->word[2]);
-			file_buf_get_le16(fb, &action->function);
+			action->word[1] = fb->readByte();
+			action->word[2] = fb->readByte();
+			action->function = fb->readUint16LE();
 
 			(*index)++;
 		}
 	}
 }
 
-static void parse_action_table_vnn(ComprehendGame * game,
-	                                struct file_buf * fb, size_t * index) {
+static void parse_action_table_vnn(ComprehendGame *game,
+	                                struct FileBuffer * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
 	int i;
@@ -438,13 +437,13 @@ static void parse_action_table_vnn(ComprehendGame * game,
 	*     u8:   noun2
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->_header.addr_actions_vnn);
+	fb->seek(game->_header.addr_actions_vnn);
 	while (1) {
 		/* 2-byte header */
-		file_buf_get_u8(fb, &verb);
+		verb = fb->readByte();
 		if (verb == 0)
 			break;
-		file_buf_get_u8(fb, &count);
+		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
 			action = &game->_actions[*index];
@@ -456,17 +455,17 @@ static void parse_action_table_vnn(ComprehendGame * game,
 			action->word_type[1] = WORD_TYPE_NOUN_MASK;
 			action->word_type[2] = WORD_TYPE_NOUN_MASK;
 
-			file_buf_get_u8(fb, &action->word[1]);
-			file_buf_get_u8(fb, &action->word[2]);
-			file_buf_get_le16(fb, &action->function);
+			action->word[1] = fb->readByte();
+			action->word[2] = fb->readByte();
+			action->function = fb->readUint16LE();
 
 			(*index)++;
 		}
 	}
 }
 
-static void parse_action_table_vn(ComprehendGame * game,
-	                                struct file_buf * fb, size_t * index) {
+static void parse_action_table_vn(ComprehendGame *game,
+	                                struct FileBuffer * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, count;
 	int i;
@@ -479,13 +478,13 @@ static void parse_action_table_vn(ComprehendGame * game,
 	*     u8:   noun
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->_header.addr_actions_vn);
+	fb->seek(game->_header.addr_actions_vn);
 	while (1) {
 		/* 2-byte header */
-		file_buf_get_u8(fb, &verb);
+		verb = fb->readByte();
 		if (verb == 0)
 			break;
-		file_buf_get_u8(fb, &count);
+		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
 			action = &game->_actions[*index];
@@ -496,16 +495,16 @@ static void parse_action_table_vn(ComprehendGame * game,
 			action->word_type[0] = WORD_TYPE_VERB;
 			action->word_type[1] = WORD_TYPE_NOUN_MASK;
 
-			file_buf_get_u8(fb, &action->word[1]);
-			file_buf_get_le16(fb, &action->function);
+			action->word[1] = fb->readByte();
+			action->function = fb->readUint16LE();
 
 			(*index)++;
 		}
 	}
 }
 
-static void parse_action_table_v(ComprehendGame * game,
-	                                struct file_buf * fb, size_t * index) {
+static void parse_action_table_v(ComprehendGame *game,
+	                                struct FileBuffer * fb, size_t * index) {
 	struct action *action;
 	uint8 verb, nr_funcs;
 	uint16 func;
@@ -518,9 +517,9 @@ static void parse_action_table_v(ComprehendGame * game,
 	* u8: count (num actions)
 	*     le16: action
 	*/
-	file_buf_set_pos(fb, game->_header.addr_actions_v);
+	fb->seek(game->_header.addr_actions_v);
 	while (1) {
-		file_buf_get_u8(fb, &verb);
+		verb = fb->readByte();
 		if (verb == 0)
 			break;
 
@@ -536,9 +535,9 @@ static void parse_action_table_v(ComprehendGame * game,
 		* Default actions can have more than one function, but only
 		* the first one actually seems to be used?
 		*/
-		file_buf_get_u8(fb, &nr_funcs);
+		nr_funcs = fb->readByte();
 		for (i = 0; i < nr_funcs; i++) {
-			file_buf_get_le16(fb, &func);
+			func = fb->readUint16LE();
 			if (i == 0)
 				action->function = func;
 		}
@@ -547,8 +546,8 @@ static void parse_action_table_v(ComprehendGame * game,
 	}
 }
 
-static void parse_action_table(ComprehendGame * game,
-	                            struct file_buf * fb) {
+static void parse_action_table(ComprehendGame *game,
+	                            struct FileBuffer * fb) {
 	game->_nr_actions = 0;
 
 	if (game->_comprehendVersion == 1) {
@@ -565,36 +564,36 @@ static void parse_action_table(ComprehendGame * game,
 	parse_action_table_v(game, fb, &game->_nr_actions);
 }
 
-static void parse_dictionary(ComprehendGame * game, struct file_buf * fb) {
+static void parse_dictionary(ComprehendGame *game, struct FileBuffer * fb) {
 	word *words;
 	uint i, j;
 
 	// FIXME - fixed size 0xff array?
 	game->_words = (word *)xmalloc(game->_nr_words * sizeof(words));
 
-	file_buf_set_pos(fb, game->_header.addr_dictionary);
+	fb->seek(game->_header.addr_dictionary);
 	for (i = 0; i < game->_nr_words; i++) {
 		words = &game->_words[i];
-
-		file_buf_get_data(fb, words->_word, 6);
+ 
+		fb->read(words->_word, 6);
 
 		/* Decode */
 		for (j = 0; j < 6; j++)
 			words->_word[j] ^= 0x8a;
 		words->_word[6] = '\0';
 
-		file_buf_get_u8(fb, &words->_index);
-		file_buf_get_u8(fb, &words->_type);
+		words->_index = fb->readByte();
+		words->_type = fb->readByte();
 	}
 }
 
-static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
+static void parse_word_map(ComprehendGame *game, struct FileBuffer * fb) {
 	struct word_map *map;
 	uint8 index, type, dummy;
 	uint i;
 
 	game->_nr_word_maps = 0;
-	file_buf_set_pos(fb, game->_header.addr_word_map);
+	fb->seek(game->_header.addr_word_map);
 
 	/*
 	* Parse the word pair table. Each entry has a pair of dictionary
@@ -603,8 +602,8 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 	while (1) {
 		map = &game->_wordMaps[game->_nr_word_maps];
 
-		file_buf_get_u8(fb, &index);
-		file_buf_get_u8(fb, &type);
+		index = fb->readByte();
+		type = fb->readByte();
 		if (type == 0 && index == 0) {
 			/* End of pairs */
 			break;
@@ -612,16 +611,16 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 
 		map->word[0].index = index;
 		map->word[0].type = type;
-		file_buf_get_u8(fb, &map->flags);
-		file_buf_get_u8(fb, &map->word[1].index);
-		file_buf_get_u8(fb, &map->word[1].type);
+		map->flags = fb->readByte();
+		map->word[1].index = fb->readByte();
+		map->word[1].type = fb->readByte();
 
 		game->_nr_word_maps++;
 	}
 
 	/* Consume two more null bytes (type and index were also null) */
-	file_buf_get_u8(fb, &dummy);
-	file_buf_get_u8(fb, &dummy);
+	dummy = fb->readByte();
+	dummy = fb->readByte();
 
 	/*
 	* Parse the target word table. Each entry has a dictionary
@@ -631,63 +630,63 @@ static void parse_word_map(ComprehendGame * game, struct file_buf * fb) {
 	for (i = 0; i < game->_nr_word_maps; i++) {
 		map = &game->_wordMaps[i];
 
-		file_buf_get_u8(fb, &map->word[2].index);
-		file_buf_get_u8(fb, &map->word[2].type);
+		map->word[2].index = fb->readByte();
+		map->word[2].type = fb->readByte();
 	}
 }
 
-static void parse_items(ComprehendGame * game, struct file_buf * fb) {
+static void parse_items(ComprehendGame *game, struct FileBuffer * fb) {
 	size_t nr_items = game->_header.nr_items;
 
 	/* Item descriptions */
-	file_buf_set_pos(fb, game->_header.addr_item_strings);
+	fb->seek(game->_header.addr_item_strings);
 	file_buf_get_array_le16(fb, 0, game->_items, string_desc, nr_items);
 
 	if (game->_comprehendVersion == 2) {
 		/* Comprehend version 2 adds long string descriptions */
-		file_buf_set_pos(fb, game->_header.addr_item_strings +
+		fb->seek(game->_header.addr_item_strings +
 			                        (game->_header.nr_items * sizeof(uint16)));
 		file_buf_get_array_le16(fb, 0, game->_items, long_string, nr_items);
 	}
 
 	/* Item flags */
-	file_buf_set_pos(fb, game->_header.addr_item_flags);
+	fb->seek(game->_header.addr_item_flags);
 	file_buf_get_array_u8(fb, 0, game->_items, flags, nr_items);
 
 	/* Item word */
-	file_buf_set_pos(fb, game->_header.addr_item_word);
+	fb->seek(game->_header.addr_item_word);
 	file_buf_get_array_u8(fb, 0, game->_items, word, nr_items);
 
 	/* Item locations */
-	file_buf_set_pos(fb, game->_header.addr_item_locations);
+	fb->seek(game->_header.addr_item_locations);
 	file_buf_get_array_u8(fb, 0, game->_items, room, nr_items);
 
 	/* Item graphic */
-	file_buf_set_pos(fb, game->_header.addr_item_graphics);
+	fb->seek(game->_header.addr_item_graphics);
 	file_buf_get_array_u8(fb, 0, game->_items, graphic, nr_items);
 }
 
-static void parse_rooms(ComprehendGame * game, struct file_buf * fb) {
+static void parse_rooms(ComprehendGame *game, struct FileBuffer * fb) {
 	size_t nr_rooms = game->_nr_rooms;
 	int i;
 
 	/* Room exit directions */
 	for (i = 0; i < NR_DIRECTIONS; i++) {
-		file_buf_set_pos(fb, game->_header.room_direction_table[i]);
+		fb->seek(game->_header.room_direction_table[i]);
 		file_buf_get_array_u8(fb, 1, game->_rooms,
 			                    direction[i], nr_rooms);
 	}
 
 	/* Room string descriptions */
-	file_buf_set_pos(fb, game->_header.room_desc_table);
+	fb->seek(game->_header.room_desc_table);
 	file_buf_get_array_le16(fb, 1, game->_rooms, string_desc, nr_rooms);
 
 	/* Room flags */
-	file_buf_set_pos(fb, game->_header.room_flags_table);
+	fb->seek(game->_header.room_flags_table);
 	file_buf_get_array_u8(fb, 1, game->_rooms, flags, nr_rooms);
 
 	/* Room graphic */
-	file_buf_set_pos(fb, game->_header.room_graphics_table);
+	fb->seek(game->_header.room_graphics_table);
 	file_buf_get_array_u8(fb, 1, game->_rooms, graphic, nr_rooms);
 }
 
@@ -739,7 +738,7 @@ static char decode_string_elem(uint8 c, bool capital, bool special) {
 * specifier). If a character has the value 0x1f then the next character is
 * taken from the symbols table.
 */
-static char *parse_string(struct file_buf * fb) {
+static char *parse_string(struct FileBuffer * fb) {
 	bool capital_next = false, special_next = false;
 	unsigned i, j, k = 0;
 	uint64 chunk;
@@ -747,17 +746,17 @@ static char *parse_string(struct file_buf * fb) {
 	char *string, c;
 	size_t encoded_len;
 
-	encoded_len = file_buf_strlen(fb, NULL);
+	encoded_len = fb->strlen();
 	string = (char *)xmalloc(encoded_len * 2);
 
 	/* Get the encoded string */
 	encoded = (uint8 *)xmalloc(encoded_len + 5);
 	memset(encoded, 0, encoded_len);
-	file_buf_get_data(fb, encoded, encoded_len);
+	fb->read(encoded, encoded_len);
 
 	/* Skip over the zero byte */
-	if (file_buf_get_pos(fb) < fb->size)
-		file_buf_get_u8(fb, NULL);
+	if (fb->pos() < fb->size())
+		fb->skip(1);
 
 	for (i = 0; i < encoded_len; i += 5) {
 		chunk = string_get_chunk(&encoded[i]);
@@ -788,29 +787,29 @@ done:
 	return string;
 }
 
-static void parse_string_table(struct file_buf * fb, unsigned start_addr,
+static void parse_string_table(struct FileBuffer * fb, unsigned start_addr,
 	                            uint32 end_addr, struct string_table *table) {
-	file_buf_set_pos(fb, start_addr);
+	fb->seek(start_addr);
 	while (1) {
 		table->strings[table->nr_strings++] = parse_string(fb);
-		if (file_buf_get_pos(fb) >= end_addr)
+		if (fb->pos() >= (int32)end_addr)
 			break;
 	}
 }
 
-static void parse_variables(ComprehendGame * game, struct file_buf * fb) {
+static void parse_variables(ComprehendGame *game, struct FileBuffer * fb) {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(game->_variables); i++)
-		file_buf_get_le16(fb, &game->_variables[i]);
+		game->_variables[i] = fb->readUint16LE();
 }
 
-static void parse_flags(ComprehendGame * game, struct file_buf * fb) {
+static void parse_flags(ComprehendGame *game, struct FileBuffer * fb) {
 	int i, bit, flag_index = 0;
 	uint8 bitmask;
 
 	for (i = 0; i < ARRAY_SIZE(game->_flags) / 8; i++) {
-		file_buf_get_u8(fb, &bitmask);
+		bitmask = fb->readByte();
 		for (bit = 7; bit >= 0; bit--) {
 			game->_flags[flag_index] = !!(bitmask & (1 << bit));
 			flag_index++;
@@ -818,26 +817,26 @@ static void parse_flags(ComprehendGame * game, struct file_buf * fb) {
 	}
 }
 
-static void parse_replace_words(ComprehendGame * game,
-	                            struct file_buf * fb) {
+static void parse_replace_words(ComprehendGame *game,
+	                            struct FileBuffer * fb) {
 	uint16 dummy;
 	size_t len;
 	bool eof;
 	int i;
 
 	/* FIXME - Rename addr_strings_end */
-	file_buf_set_pos(fb, game->_header.addr_strings_end);
+	fb->seek(game->_header.addr_strings_end);
 
 	/* FIXME - what is this for */
-	file_buf_get_le16(fb, &dummy);
+	dummy = fb->readUint16LE();
 
 	for (i = 0;; i++) {
-		len = file_buf_strlen(fb, &eof);
+		len = fb->strlen(&eof);
 		if (len == 0)
 			break;
 
-		game->_replaceWords[i] = xstrndup((char *)fb->p, len);
-		file_buf_get_data(fb, NULL, len + (eof ? 0 : 1));
+		game->_replaceWords[i] = xstrndup((const char *)fb->dataPtr(), len);
+		fb->read(NULL, len + (eof ? 0 : 1));
 		if (eof)
 			break;
 	}
@@ -848,13 +847,13 @@ static void parse_replace_words(ComprehendGame * game,
 * The main game data file header has the offsets for where each bit of
 * game data is. The offsets have a magic constant value added to them.
 */
-static void parse_header(ComprehendGame * game, struct file_buf * fb) {
+static void parse_header(ComprehendGame *game, struct FileBuffer * fb) {
 	struct game_header *header = &game->_header;
 	uint16 dummy, addr_dictionary_end;
 	uint8 dummy8;
 
-	file_buf_set_pos(fb, 0);
-	file_buf_get_le16(fb, &header->magic);
+	fb->seek(0);
+	header->magic = fb->readUint16LE();
 	switch (header->magic) {
 	case 0x2000: /* Transylvania, Crimson Crown disk one */
 	case 0x4800: /* Crimson Crown disk two */
@@ -951,9 +950,9 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 	parse_header_le16(fb, &dummy);
 	parse_header_le16(fb, &header->addr_strings_end);
 
-	file_buf_get_u8(fb, &dummy8);
-	file_buf_get_u8(fb, &game->_startRoom);
-	file_buf_get_u8(fb, &dummy8);
+	dummy8 = fb->readByte();
+	game->_startRoom = fb->readByte();
+	dummy8 = fb->readByte();
 
 	parse_variables(game, fb);
 	parse_flags(game, fb);
@@ -966,25 +965,21 @@ static void parse_header(ComprehendGame * game, struct file_buf * fb) {
 		                    8;
 }
 
-static void load_extra_string_file(ComprehendGame * game,
+static void load_extra_string_file(ComprehendGame *game,
 	                                string_file * string_file) {
-	struct file_buf fb;
+	FileBuffer fb(string_file->filename);
 	unsigned end;
 
-	file_buf_map(string_file->filename, &fb);
-
 	if (string_file->end_offset)
 		end = string_file->end_offset;
 	else
-		end = fb.size;
+		end = fb.size();
 
 	parse_string_table(&fb, string_file->base_offset,
 		                end, &game->_strings2);
-
-	file_buf_unmap(&fb);
 }
 
-static void load_extra_string_files(ComprehendGame * game) {
+static void load_extra_string_files(ComprehendGame *game) {
 	int i;
 
 	memset(&game->_strings2, 0, sizeof(game->_strings2));
@@ -1002,11 +997,10 @@ static void load_extra_string_files(ComprehendGame * game) {
 	}
 }
 
-static void load_game_data(ComprehendGame * game) {
-	struct file_buf fb;
+static void load_game_data(ComprehendGame *game) {
+	FileBuffer fb(game->_gameDataFile);
 
 	game->clearInfo();
-	file_buf_map(game->_gameDataFile, &fb);
 
 	parse_header(game, &fb);
 	parse_rooms(game, &fb);
@@ -1021,11 +1015,9 @@ static void load_game_data(ComprehendGame * game) {
 	parse_vm(game, &fb);
 	parse_action_table(game, &fb);
 	parse_replace_words(game, &fb);
-
-	file_buf_unmap(&fb);
 }
 
-void comprehend_load_game(ComprehendGame * game) {
+void comprehend_load_game(ComprehendGame *game) {
 	/* Load the main game data file */
 	load_game_data(game);
 
@@ -1054,7 +1046,7 @@ static void patch_string_desc(uint16 * desc) {
 }
 #endif
 
-void comprehend_save_game(ComprehendGame * game, const char *filename) {
+void comprehend_save_game(ComprehendGame *game, const char *filename) {
 #ifdef TODO
 	FILE *fd;
 	uint8 bitmask;
@@ -1138,9 +1130,9 @@ void comprehend_save_game(ComprehendGame * game, const char *filename) {
 #endif
 }
 
-void comprehend_restore_game(ComprehendGame * game, const char *filename) {
+void comprehend_restore_game(ComprehendGame *game, const char *filename) {
 #ifdef TODO
-	struct file_buf fb;
+	struct FileBuffer fb;
 	size_t nr_rooms, nr_items;
 	uint err, dir, i;
 
@@ -1156,7 +1148,7 @@ void comprehend_restore_game(ComprehendGame * game, const char *filename) {
 
 	/* Restore starting room */
 	file_buf_set_pos(&fb, 1);
-	file_buf_get_u8(&fb, &game->current_room);
+	game->current_room = fb->readByte();
 
 	/* Restore flags and variables */
 	file_buf_set_pos(&fb, 3);
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 4204001110..db2e6ffaae 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -57,22 +57,22 @@ void image_set_draw_flags(unsigned flags)
 	draw_flags |= flags;
 }
 
-static uint16 image_get_operand(struct file_buf *fb)
+static uint16 image_get_operand(FileBuffer *fb)
 {
 	uint8 val;
 
-	file_buf_get_u8(fb, &val);
+	val = fb->readByte();
 	return val;
 }
 
-static bool do_image_op(struct file_buf *fb, struct image_context *ctx)
+static bool do_image_op(struct FileBuffer *fb, struct image_context *ctx)
 {
 	uint8 opcode;
 	uint16 a, b;
 
-	file_buf_get_u8(fb, &opcode);
+	opcode = fb->readByte();
 	debug_printf(DEBUG_IMAGE_DRAW,
-		     "  %.4x [%.2x]: ", file_buf_get_pos(fb) - 1, opcode);
+		     "  %.4x [%.2x]: ", fb->pos() - 1, opcode);
 
 	switch (opcode) {
 	case IMAGE_OP_SCENE_END:
@@ -257,7 +257,7 @@ static bool do_image_op(struct file_buf *fb, struct image_context *ctx)
 void draw_image(struct image_data *info, unsigned index)
 {
 	unsigned file_num;
-	struct file_buf *fb;
+	struct FileBuffer *fb;
 	bool done = false;
 	image_context ctx = {
 		0, 0, G_COLOR_BLACK, G_COLOR_BLACK, IMAGE_OP_SHAPE_CIRCLE_LARGE
@@ -272,7 +272,7 @@ void draw_image(struct image_data *info, unsigned index)
 		return;
 	}
 
-	file_buf_set_pos(fb, info->image_offsets[index]);
+	fb->seek(info->image_offsets[index]);
 	while (!done) {
 		done = do_image_op(fb, &ctx);
 		if (!done && (draw_flags & IMAGEF_OP_WAIT_KEYPRESS)) {
@@ -304,30 +304,28 @@ static void load_image_file(struct image_data *info, const char *filename,
 			    unsigned file_num)
 {
 	unsigned base = file_num * IMAGES_PER_FILE;
-	struct file_buf *fb;
+	struct FileBuffer *fb;
 	uint16 version;
 	int i;
 
-	fb = &info->fb[file_num];
-	file_buf_map(filename, fb);
+	info->fb[file_num] = FileBuffer(filename);
 
 	/*
 	 * In earlier versions of Comprehend the first word is 0x1000 and
 	 * the image offsets start four bytes in. In newer versions the
 	 * image offsets start at the beginning of the image file.
 	 */
-	file_buf_get_le16(fb, &version);
+	version = fb->readUint16LE();
 	if (version == 0x1000)
-		file_buf_set_pos(fb, 4);
+		fb->seek(4);
 	else
-		file_buf_set_pos(fb, 0);
+		fb->seek(0);
 
 	/* Get the image offsets in the file */
 	for (i = 0; i < IMAGES_PER_FILE; i++) {
-		file_buf_get_le16(fb, &info->image_offsets[base + i]); {
-			if (version == 0x1000)
-				info->image_offsets[base + i] += 4;
-		}
+		info->image_offsets[base + i] = fb->readUint16LE();
+		if (version == 0x1000)
+			info->image_offsets[base + i] += 4;
 	}
 }
 
@@ -338,7 +336,7 @@ static void load_image_files(struct image_data *info,
 	memset(info, 0, sizeof(*info));
 
 	info->nr_images = filenames.size() * IMAGES_PER_FILE;
-	info->fb = (file_buf *)xmalloc(info->nr_images * sizeof(*info->fb));
+	info->fb = (FileBuffer *)xmalloc(info->nr_images * sizeof(*info->fb));
 	info->image_offsets = (uint16 *)xmalloc(info->nr_images * sizeof(uint16));
 
 	for (i = 0; i < filenames.size(); i++) {
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
index 382c90a166..cb165e9fdb 100644
--- a/engines/glk/comprehend/image_data.h
+++ b/engines/glk/comprehend/image_data.h
@@ -29,10 +29,10 @@ namespace Glk {
 namespace Comprehend {
 
 class ComprehendGame;
-struct file_buf;
+struct FileBuffer;
 
 struct image_data {
-	file_buf	*fb;
+	FileBuffer	*fb;
 	uint16	*image_offsets;
 	size_t		nr_images;
 


Commit: 5023e261ed6aac0d32b8d72bb2df726cd89db76d
    https://github.com/scummvm/scummvm/commit/5023e261ed6aac0d32b8d72bb2df726cd89db76d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Removal of redundant struct prefixes

Changed paths:
    engines/glk/comprehend/game_data.cpp


diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index d10414b4ee..c28813e19f 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -215,8 +215,8 @@ static uint8 parse_vm_instruction(FileBuffer *fb,
 	return instr->opcode;
 }
 
-static void parse_function(struct FileBuffer * fb, struct function * func) {
-	struct instruction *instruction;
+static void parse_function(FileBuffer *fb, function * func) {
+	instruction *instruction;
 	uint8 *p, opcode;
 
 	p = (uint8 *)memchr(fb->dataPtr(), 0x00, fb->size() - fb->pos());
@@ -236,7 +236,7 @@ static void parse_function(struct FileBuffer * fb, struct function * func) {
 	}
 }
 
-static void parse_vm(ComprehendGame *game, struct FileBuffer * fb) {
+static void parse_vm(ComprehendGame *game, FileBuffer *fb) {
 	function *func;
 
 	fb->seek(game->_header.addr_vm);
@@ -252,8 +252,8 @@ static void parse_vm(ComprehendGame *game, struct FileBuffer * fb) {
 }
 
 static void parse_action_table_vvnn(ComprehendGame *game,
-	                                struct FileBuffer * fb, size_t * index) {
-	struct action *action;
+	                                FileBuffer *fb, size_t * index) {
+	action *action;
 	uint8 verb, count;
 	int i, j;
 
@@ -296,8 +296,8 @@ static void parse_action_table_vvnn(ComprehendGame *game,
 }
 
 static void parse_action_table_vnjn(ComprehendGame *game,
-	                                struct FileBuffer * fb, size_t * index) {
-	struct action *action;
+	                                FileBuffer *fb, size_t * index) {
+	action *action;
 	uint8 join, count;
 	int i;
 
@@ -341,8 +341,8 @@ static void parse_action_table_vnjn(ComprehendGame *game,
 }
 
 static void parse_action_table_vjn(ComprehendGame *game,
-	                                struct FileBuffer * fb, size_t * index) {
-	struct action *action;
+	                                FileBuffer *fb, size_t * index) {
+	action *action;
 	uint8 join, count;
 	int i;
 
@@ -382,8 +382,8 @@ static void parse_action_table_vjn(ComprehendGame *game,
 }
 
 static void parse_action_table_vdn(ComprehendGame *game,
-	                                struct FileBuffer * fb, size_t * index) {
-	struct action *action;
+	                                FileBuffer *fb, size_t * index) {
+	action *action;
 	uint8 verb, count;
 	int i;
 
@@ -423,8 +423,8 @@ static void parse_action_table_vdn(ComprehendGame *game,
 }
 
 static void parse_action_table_vnn(ComprehendGame *game,
-	                                struct FileBuffer * fb, size_t * index) {
-	struct action *action;
+	                                FileBuffer *fb, size_t * index) {
+	action *action;
 	uint8 verb, count;
 	int i;
 
@@ -465,8 +465,8 @@ static void parse_action_table_vnn(ComprehendGame *game,
 }
 
 static void parse_action_table_vn(ComprehendGame *game,
-	                                struct FileBuffer * fb, size_t * index) {
-	struct action *action;
+	                                FileBuffer *fb, size_t * index) {
+	action *action;
 	uint8 verb, count;
 	int i;
 
@@ -504,8 +504,8 @@ static void parse_action_table_vn(ComprehendGame *game,
 }
 
 static void parse_action_table_v(ComprehendGame *game,
-	                                struct FileBuffer * fb, size_t * index) {
-	struct action *action;
+	                                FileBuffer *fb, size_t * index) {
+	action *action;
 	uint8 verb, nr_funcs;
 	uint16 func;
 	int i;
@@ -547,7 +547,7 @@ static void parse_action_table_v(ComprehendGame *game,
 }
 
 static void parse_action_table(ComprehendGame *game,
-	                            struct FileBuffer * fb) {
+	                            FileBuffer *fb) {
 	game->_nr_actions = 0;
 
 	if (game->_comprehendVersion == 1) {
@@ -564,7 +564,7 @@ static void parse_action_table(ComprehendGame *game,
 	parse_action_table_v(game, fb, &game->_nr_actions);
 }
 
-static void parse_dictionary(ComprehendGame *game, struct FileBuffer * fb) {
+static void parse_dictionary(ComprehendGame *game, FileBuffer *fb) {
 	word *words;
 	uint i, j;
 
@@ -587,8 +587,8 @@ static void parse_dictionary(ComprehendGame *game, struct FileBuffer * fb) {
 	}
 }
 
-static void parse_word_map(ComprehendGame *game, struct FileBuffer * fb) {
-	struct word_map *map;
+static void parse_word_map(ComprehendGame *game, FileBuffer *fb) {
+	word_map *map;
 	uint8 index, type, dummy;
 	uint i;
 
@@ -635,7 +635,7 @@ static void parse_word_map(ComprehendGame *game, struct FileBuffer * fb) {
 	}
 }
 
-static void parse_items(ComprehendGame *game, struct FileBuffer * fb) {
+static void parse_items(ComprehendGame *game, FileBuffer *fb) {
 	size_t nr_items = game->_header.nr_items;
 
 	/* Item descriptions */
@@ -666,7 +666,7 @@ static void parse_items(ComprehendGame *game, struct FileBuffer * fb) {
 	file_buf_get_array_u8(fb, 0, game->_items, graphic, nr_items);
 }
 
-static void parse_rooms(ComprehendGame *game, struct FileBuffer * fb) {
+static void parse_rooms(ComprehendGame *game, FileBuffer *fb) {
 	size_t nr_rooms = game->_nr_rooms;
 	int i;
 
@@ -738,7 +738,7 @@ static char decode_string_elem(uint8 c, bool capital, bool special) {
 * specifier). If a character has the value 0x1f then the next character is
 * taken from the symbols table.
 */
-static char *parse_string(struct FileBuffer * fb) {
+static char *parse_string(FileBuffer *fb) {
 	bool capital_next = false, special_next = false;
 	unsigned i, j, k = 0;
 	uint64 chunk;
@@ -787,8 +787,8 @@ done:
 	return string;
 }
 
-static void parse_string_table(struct FileBuffer * fb, unsigned start_addr,
-	                            uint32 end_addr, struct string_table *table) {
+static void parse_string_table(FileBuffer *fb, unsigned start_addr,
+	                            uint32 end_addr, string_table *table) {
 	fb->seek(start_addr);
 	while (1) {
 		table->strings[table->nr_strings++] = parse_string(fb);
@@ -797,14 +797,14 @@ static void parse_string_table(struct FileBuffer * fb, unsigned start_addr,
 	}
 }
 
-static void parse_variables(ComprehendGame *game, struct FileBuffer * fb) {
+static void parse_variables(ComprehendGame *game, FileBuffer *fb) {
 	int i;
 
 	for (i = 0; i < ARRAY_SIZE(game->_variables); i++)
 		game->_variables[i] = fb->readUint16LE();
 }
 
-static void parse_flags(ComprehendGame *game, struct FileBuffer * fb) {
+static void parse_flags(ComprehendGame *game, FileBuffer *fb) {
 	int i, bit, flag_index = 0;
 	uint8 bitmask;
 
@@ -818,7 +818,7 @@ static void parse_flags(ComprehendGame *game, struct FileBuffer * fb) {
 }
 
 static void parse_replace_words(ComprehendGame *game,
-	                            struct FileBuffer * fb) {
+	                            FileBuffer *fb) {
 	uint16 dummy;
 	size_t len;
 	bool eof;
@@ -847,8 +847,8 @@ static void parse_replace_words(ComprehendGame *game,
 * The main game data file header has the offsets for where each bit of
 * game data is. The offsets have a magic constant value added to them.
 */
-static void parse_header(ComprehendGame *game, struct FileBuffer * fb) {
-	struct game_header *header = &game->_header;
+static void parse_header(ComprehendGame *game, FileBuffer *fb) {
+	game_header *header = &game->_header;
 	uint16 dummy, addr_dictionary_end;
 	uint8 dummy8;
 
@@ -1132,7 +1132,7 @@ void comprehend_save_game(ComprehendGame *game, const char *filename) {
 
 void comprehend_restore_game(ComprehendGame *game, const char *filename) {
 #ifdef TODO
-	struct FileBuffer fb;
+	FileBuffer fb;
 	size_t nr_rooms, nr_items;
 	uint err, dir, i;
 


Commit: 269b83f31ee17ecedc771aa9e6ef3ce04f3d06bc
    https://github.com/scummvm/scummvm/commit/269b83f31ee17ecedc771aa9e6ef3ce04f3d06bc
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Removal of redundant struct prefixes

Changed paths:
  R engines/glk/comprehend/recomprehend.cpp
  R engines/glk/comprehend/recomprehend.h
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/dictionary.cpp
    engines/glk/comprehend/dictionary.h
    engines/glk/comprehend/dump_game_data.cpp
    engines/glk/comprehend/dump_game_data.h
    engines/glk/comprehend/file_buf.cpp
    engines/glk/comprehend/file_buf.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/graphics.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_view.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 2f0d317eef..3ca90b7b28 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -58,7 +58,7 @@ static const dump_option dump_options[] = {
 
 #ifdef TODO
 int main(int argc, char **argv) {
-	struct option long_opts[] = {
+	option long_opts[] = {
 	    {"debug", no_argument, 0, 'd'},
 	    {"dump", required_argument, 0, 'D'},
 	    {"no-play", no_argument, 0, 'p'},
diff --git a/engines/glk/comprehend/dictionary.cpp b/engines/glk/comprehend/dictionary.cpp
index 1421763198..2f6e4cf025 100644
--- a/engines/glk/comprehend/dictionary.cpp
+++ b/engines/glk/comprehend/dictionary.cpp
@@ -28,7 +28,7 @@
 namespace Glk {
 namespace Comprehend {
 
-static bool word_match(struct word *word, const char *string)
+static bool word_match(word *word, const char *string)
 {
 	/* Words less than 6 characters must match exactly */
 	if (strlen(word->_word) < 6 && strlen(string) != strlen(word->_word))
@@ -52,7 +52,7 @@ word *dict_find_word_by_string(ComprehendGame *game,
 	return NULL;
 }
 
-struct word *dict_find_word_by_index_type(ComprehendGame *game,
+word *dict_find_word_by_index_type(ComprehendGame *game,
 					  uint8 index, uint8 type)
 {
 	uint i;
@@ -66,7 +66,7 @@ struct word *dict_find_word_by_index_type(ComprehendGame *game,
 	return NULL;
 }
 
-struct word *find_dict_word_by_index(ComprehendGame *game,
+word *find_dict_word_by_index(ComprehendGame *game,
 				     uint8 index, uint8 type_mask)
 {
 	uint i;
diff --git a/engines/glk/comprehend/dictionary.h b/engines/glk/comprehend/dictionary.h
index cdf4add8a8..f685513811 100644
--- a/engines/glk/comprehend/dictionary.h
+++ b/engines/glk/comprehend/dictionary.h
@@ -29,11 +29,11 @@ namespace Comprehend {
 class ComprehendGame;
 struct word;
 
-struct word *find_dict_word_by_index(ComprehendGame *game,
+word *find_dict_word_by_index(ComprehendGame *game,
 				     uint8 index, uint8 type_mask);
-struct word *dict_find_word_by_index_type(ComprehendGame *game,
+word *dict_find_word_by_index_type(ComprehendGame *game,
 					  uint8 index, uint8 type);
-struct word *dict_find_word_by_string(ComprehendGame *game,
+word *dict_find_word_by_string(ComprehendGame *game,
 				      const char *string);
 bool dict_match_index_type(ComprehendGame *game, const char *word,
 			   uint8 index, uint8 type_mask);
diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
index d33f8cb62e..bd99a5d4f3 100644
--- a/engines/glk/comprehend/dump_game_data.cpp
+++ b/engines/glk/comprehend/dump_game_data.cpp
@@ -114,8 +114,8 @@ static const char *opcode_names[] = {
 };
 
 void dump_instruction(ComprehendGame *game,
-		      struct function_state *func_state,
-		      struct instruction *instr)
+		      function_state *func_state,
+		      instruction *instr)
 {
 	uint i;
 	int str_index, str_table;
@@ -169,7 +169,7 @@ void dump_instruction(ComprehendGame *game,
 
 static void dump_functions(ComprehendGame *game)
 {
-	struct function *func;
+	function *func;
 	uint i, j;
 
 	debugN("Functions (%zd entries)\n", game->_nr_functions);
@@ -185,8 +185,8 @@ static void dump_functions(ComprehendGame *game)
 
 static void dump_action_table(ComprehendGame *game)
 {
-	struct action *action;
-	struct word *word;
+	action *action;
+	word *word;
 	uint i, j;
 
 	debugN("Action table (%zd entries)\n", game->_nr_actions);
@@ -265,9 +265,9 @@ static void dump_dictionary(ComprehendGame *game)
 
 static void dump_word_map(ComprehendGame *game)
 {
-	struct word *word[3];
+	word *word[3];
 	char str[3][6];
-	struct word_map *map;
+	word_map *map;
 	uint i, j;
 
 	debugN("Word pairs (%zd entries)\n", game->_nr_word_maps);
@@ -292,7 +292,7 @@ static void dump_word_map(ComprehendGame *game)
 
 static void dump_rooms(ComprehendGame *game)
 {
-	struct room *room;
+	room *room;
 	uint i;
 
 	/* Room zero acts as the players inventory */
@@ -319,7 +319,7 @@ static void dump_rooms(ComprehendGame *game)
 
 static void dump_items(ComprehendGame *game)
 {
-	struct item *item;
+	item *item;
 	uint i, j;
 
 	debugN("Items (%zd entries)\n", game->_header.nr_items);
@@ -348,7 +348,7 @@ static void dump_items(ComprehendGame *game)
 	}
 }
 
-static void dump_string_table(struct string_table *table)
+static void dump_string_table(string_table *table)
 {
 	uint i;
 
@@ -382,7 +382,7 @@ static void dump_replace_words(ComprehendGame *game)
 
 static void dump_header(ComprehendGame *game)
 {
-	struct game_header *header = &game->_header;
+	game_header *header = &game->_header;
 	uint16 *dir_table = header->room_direction_table;
 
 	debugN("Game header:\n");
@@ -425,7 +425,7 @@ struct dumper {
 	unsigned	flag;
 };
 
-static struct dumper dumpers[] = {
+static dumper dumpers[] = {
 	{dump_header,			DUMP_HEADER},
 	{dump_game_data_strings,	DUMP_STRINGS},
 	{dump_extra_strings,		DUMP_EXTRA_STRINGS},
diff --git a/engines/glk/comprehend/dump_game_data.h b/engines/glk/comprehend/dump_game_data.h
index bb91757d15..06c6609e6c 100644
--- a/engines/glk/comprehend/dump_game_data.h
+++ b/engines/glk/comprehend/dump_game_data.h
@@ -43,8 +43,8 @@ struct instruction;
 #define DUMP_ALL (~0U)
 
 void dump_instruction(ComprehendGame *game,
-                      struct function_state *func_state,
-                      struct instruction *instr);
+                      function_state *func_state,
+                      instruction *instr);
 void dump_game_data(ComprehendGame *game, unsigned flags);
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/file_buf.cpp b/engines/glk/comprehend/file_buf.cpp
index d246bd738f..76b70cc82d 100644
--- a/engines/glk/comprehend/file_buf.cpp
+++ b/engines/glk/comprehend/file_buf.cpp
@@ -89,42 +89,14 @@ size_t FileBuffer::strlen(bool *eof) {
 	return end - &_data[_pos];
 }
 
-
-#ifdef TODO
-void file_buf_unmap(struct FileBuffer *fb) {
-	free(fb->marked);
-	free(fb->data);
-}
-
-unsigned file_buf_get_pos(struct FileBuffer *fb) {
-	return fb->p - fb->data;
-}
-
-void file_buf_get_data(struct FileBuffer *fb, void *data, size_t data_size) {
-	if (fb->pos() + data_size > fb->size)
-		error("Not enough data in file (%x + %x > %x)",
-		      fb->pos(), data_size, fb->size);
-
-	if (data)
-		memcpy(data, fb->p, data_size);
-
-	/* Mark this region of the file as read */
-	memset(fb->marked + fb->pos(), '?', data_size);
-
-	fb->p += data_size;
-}
-
-/*
- * Debugging function to show regions of a file that have not been read.
- */
-void file_buf_show_unmarked(struct FileBuffer *fb) {
+void FileBuffer::showUnmarked() {
 	int i, start = -1;
 
-	for (i = 0; i < (int)fb->size; i++) {
-		if (!fb->marked[i] && start == -1)
+	for (i = 0; i < (int)_data.size(); i++) {
+		if (!_readBytes[i] && start == -1)
 			start = i;
 
-		if ((fb->marked[i] || i == (int)fb->size - 1) && start != -1) {
+		if ((_readBytes[i] || i == (int)_data.size() - 1) && start != -1) {
 			warning("%.4x - %.4x unmarked (%d bytes)\n",
 			        start, i - 1, i - start);
 			start = -1;
@@ -132,19 +104,5 @@ void file_buf_show_unmarked(struct FileBuffer *fb) {
 	}
 }
 
-void file_buf_put_u8(Common::WriteStream *fd, uint8 val) {
-	fd->writeByte(val);
-}
-
-void file_buf_put_le16(Common::WriteStream *fd, uint16 val) {
-	fd->writeUint16LE(val);
-}
-
-void file_buf_put_skip(Common::WriteStream *fd, size_t skip) {
-	for (uint i = 0; i < skip; i++)
-		file_buf_put_u8(fd, 0);
-}
-#endif
-
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/file_buf.h b/engines/glk/comprehend/file_buf.h
index 3f323e3ec2..0805842809 100644
--- a/engines/glk/comprehend/file_buf.h
+++ b/engines/glk/comprehend/file_buf.h
@@ -53,36 +53,12 @@ public:
 	const byte *dataPtr() const { return &_data[_pos]; }
 	size_t strlen(bool *eof = nullptr);
 
+	/*
+	 * Debugging function to show regions of a file that have not been read.
+	 */
+	void showUnmarked();
 };
 
-#ifdef TODO
-void file_buf_unmap(struct FileBuffer *fb);
-void file_buf_show_unmarked(struct FileBuffer *fb);
-
-unsigned file_buf_get_pos(struct FileBuffer *fb);
-
-size_t file_buf_strlen(struct FileBuffer *fb, bool *eof);
-
-void file_buf_get_data(struct FileBuffer *fb, void *data, size_t data_size);
-
-void file_buf_put_skip(Common::WriteStream *fd, size_t skip);
-void file_buf_put_u8(Common::WriteStream *fd, uint8 val);
-void file_buf_put_le16(Common::WriteStream *fd, uint16 val);
-
-#define file_buf_put_array(fd, type, base, array, member, size)		\
-	do {								\
-		int __i;						\
-		for (__i = (base); __i < (base) + (size); __i++)	\
-			file_buf_put_##type(fd, (array)[__i].member);	\
-	} while (0)
-
-#define file_buf_put_array_le16(fd, base, array, member, size) \
-	file_buf_put_array(fd, le16, base, array, member, size)
-
-#define file_buf_put_array_u8(fd, base, array, member, size) \
-	file_buf_put_array(fd, u8, base, array, member, size)
-#endif
-
 #define file_buf_get_array(fb, type, base, array, member, size) \
 	do {                                                        \
 		uint __i;                                               \
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index b1440c979c..a41842497e 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -34,14 +34,14 @@ namespace Glk {
 namespace Comprehend {
 
 struct sentence {
-	struct word words[4];
+	word words[4];
 	size_t nr_words;
 };
 
 struct winsize {
 	uint ws_col;
 };
-static struct winsize console_winsize;
+static winsize console_winsize;
 
 ComprehendGame::ComprehendGame() : _gameName(nullptr),
                                      _shortName(nullptr),
@@ -157,7 +157,7 @@ void console_println(ComprehendGame *game, const char *text) {
 	printf("\n");
 }
 
-static struct room *get_room(ComprehendGame *game, uint16 index) {
+static room *get_room(ComprehendGame *game, uint16 index) {
 	/* Room zero is reserved for the players inventory */
 	if (index == 0)
 		fatal_error("Room index 0 (player inventory) is invalid");
@@ -168,7 +168,7 @@ static struct room *get_room(ComprehendGame *game, uint16 index) {
 	return &game->_rooms[index];
 }
 
-struct item *get_item(ComprehendGame *game, uint16 index) {
+item *get_item(ComprehendGame *game, uint16 index) {
 	if (index >= game->_header.nr_items)
 		fatal_error("Bad item %d\n", index);
 
@@ -225,9 +225,9 @@ void game_restart(ComprehendGame *game) {
 	game->_updateFlags = UPDATE_ALL;
 }
 
-static struct word_index *is_word_pair(ComprehendGame *game,
-                                       struct word *word1, struct word *word2) {
-	struct word_map *map;
+static word_index *is_word_pair(ComprehendGame *game,
+                                       word *word1, word *word2) {
+	word_map *map;
 	uint i;
 
 	/* Check if this is a word pair */
@@ -244,8 +244,8 @@ static struct word_index *is_word_pair(ComprehendGame *game,
 	return NULL;
 }
 
-static struct item *get_item_by_noun(ComprehendGame *game,
-                                     struct word *noun) {
+static item *get_item_by_noun(ComprehendGame *game,
+                                     word *noun) {
 	uint i;
 
 	if (!noun || !(noun->_type & WORD_TYPE_NOUN_MASK))
@@ -264,8 +264,8 @@ static struct item *get_item_by_noun(ComprehendGame *game,
 }
 
 static void update_graphics(ComprehendGame *game) {
-	struct item *item;
-	struct room *room;
+	item *item;
+	room *room;
 	int type;
 	uint i;
 
@@ -308,7 +308,7 @@ static void update_graphics(ComprehendGame *game) {
 }
 
 static void describe_objects_in_current_room(ComprehendGame *game) {
-	struct item *item;
+	item *item;
 	size_t count = 0;
 	uint i;
 
@@ -334,7 +334,7 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 }
 
 static void update(ComprehendGame *game) {
-	struct room *room = get_room(game, game->_currentRoom);
+	room *room = get_room(game, game->_currentRoom);
 	unsigned room_type, room_desc_string;
 
 	update_graphics(game);
@@ -363,7 +363,7 @@ static void move_to(ComprehendGame *game, uint8 room) {
 	                            UPDATE_ITEM_LIST);
 }
 
-static void func_set_test_result(struct function_state *func_state, bool value) {
+static void func_set_test_result(function_state *func_state, bool value) {
 	if (func_state->or_count == 0) {
 		/* And */
 		if (func_state->_and) {
@@ -391,7 +391,7 @@ static size_t num_objects_in_room(ComprehendGame *game, int room) {
 	return count;
 }
 
-void move_object(ComprehendGame *game, struct item *item, int new_room) {
+void move_object(ComprehendGame *game, item *item, int new_room) {
 	unsigned obj_weight = item->flags & ITEMF_WEIGHT_MASK;
 
 	if (item->room == new_room)
@@ -423,12 +423,12 @@ void move_object(ComprehendGame *game, struct item *item, int new_room) {
 }
 
 static void eval_instruction(ComprehendGame *game,
-                             struct function_state *func_state,
-                             struct instruction *instr,
-                             struct word *verb, struct word *noun) {
+                             function_state *func_state,
+                             instruction *instr,
+                             word *verb, word *noun) {
 	uint8 *opcode_map;
-	struct room *room;
-	struct item *item;
+	room *room;
+	item *item;
 	uint16 index;
 	bool test;
 	uint i, count;
@@ -981,9 +981,9 @@ static void eval_instruction(ComprehendGame *game,
  * is reached. Otherwise the commands instructions are skipped over and the
  * next test sequence (if there is one) is tried.
  */
-void eval_function(ComprehendGame *game, struct function *func,
-                   struct word *verb, struct word *noun) {
-	struct function_state func_state;
+void eval_function(ComprehendGame *game, function *func,
+                   word *verb, word *noun) {
+	function_state func_state;
 	uint i;
 
 	func_state.else_result = true;
@@ -1056,9 +1056,9 @@ static void handle_debug_command(ComprehendGame *game,
 #endif
 
 static bool handle_sentence(ComprehendGame *game,
-                            struct sentence *sentence) {
-	struct function *func;
-	struct action *action;
+                            sentence *sentence) {
+	function *func;
+	action *action;
 	uint i, j;
 
 	if (sentence->nr_words == 0)
@@ -1102,11 +1102,11 @@ static bool handle_sentence(ComprehendGame *game,
 }
 
 static void read_sentence(ComprehendGame *game, char **line,
-                          struct sentence *sentence) {
+                          sentence *sentence) {
 	bool sentence_end = false;
 	char *word_string, *p = *line;
-	struct word_index *pair;
-	struct word *word;
+	word_index *pair;
+	word *word;
 	int index;
 
 	memset(sentence, 0, sizeof(*sentence));
@@ -1178,7 +1178,7 @@ static void after_turn(ComprehendGame *game) {
 
 static void read_input(ComprehendGame *game) {
 #ifdef TODO
-	struct sentence sentence;
+	sentence sentence;
 	char *line = NULL, buffer[1024];
 	bool handled;
 
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 86fde90347..583f333f53 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -69,10 +69,10 @@ public:
 void console_println(ComprehendGame *game, const char *text);
 int console_get_key(void);
 
-struct item *get_item(ComprehendGame *game, uint16 index);
-void move_object(ComprehendGame *game, struct item *item, int new_room);
-void eval_function(ComprehendGame *game, struct function *func,
-                   struct word *verb, struct word *noun);
+item *get_item(ComprehendGame *game, uint16 index);
+void move_object(ComprehendGame *game, item *item, int new_room);
+void eval_function(ComprehendGame *game, function *func,
+                   word *verb, word *noun);
 
 void comprehend_play_game(ComprehendGame *game);
 void game_save(ComprehendGame *game);
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index 8eb79938a3..4b1a5feab7 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -26,10 +26,10 @@
 namespace Glk {
 namespace Comprehend {
 
-static struct game_strings cc1_strings = {0x9};
+static game_strings cc1_strings = {0x9};
 
 #ifdef TODO
-static struct game_ops cc2_ops = {
+static game_ops cc2_ops = {
     nullptr,
     cc2_before_prompt,
     nullptr,
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index 4e230db896..b1faa9c705 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -85,7 +85,7 @@ int OOToposGame::room_is_special(unsigned room_index,
 bool OOToposGame::before_turn() {
 	/* FIXME - probably doesn't work correctly with restored games */
 	static bool flashlight_was_on = false, googles_were_worn = false;
-	struct room *room = &_rooms[_currentRoom];
+	room *room = &_rooms[_currentRoom];
 
 	/* 
 	 * Check if the room needs to be redrawn because the flashlight
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 7be0262219..041b4dfef0 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -36,7 +36,7 @@ const tr_monster TransylvaniaGame::VAMPIRE = {
 	0x26, 5, (1 << 7), 0, 5
 };
 
-static struct game_strings tr_strings = {
+static game_strings tr_strings = {
     EXTRA_STRING_TABLE(0x8a)
 };
 
@@ -65,8 +65,8 @@ TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
 };
 
 void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
-	struct item *monster;
-	struct room *room;
+	item *monster;
+	room *room;
 	uint16 turn_count;
 
 	room = &_rooms[_currentRoom];
@@ -98,7 +98,7 @@ void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
 int TransylvaniaGame::room_is_special(unsigned room_index,
 			      unsigned *room_desc_string)
 {
-	struct room *room = &_rooms[room_index];
+	room *room = &_rooms[room_index];
 
 	if (room_index == 0x28) {
 		if (room_desc_string)
diff --git a/engines/glk/comprehend/graphics.cpp b/engines/glk/comprehend/graphics.cpp
index b62df4d2fc..cb37182dc2 100644
--- a/engines/glk/comprehend/graphics.cpp
+++ b/engines/glk/comprehend/graphics.cpp
@@ -63,7 +63,7 @@ struct graphics_context {
 	//	SDL_Surface	*surface;
 };
 
-static struct graphics_context ctx;
+static graphics_context ctx;
 
 unsigned g_set_pen_color(uint8 opcode) {
 	return pen_colors[opcode - IMAGE_OP_PEN_COLOR_A];
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index db2e6ffaae..1a5be26d62 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -65,7 +65,7 @@ static uint16 image_get_operand(FileBuffer *fb)
 	return val;
 }
 
-static bool do_image_op(struct FileBuffer *fb, struct image_context *ctx)
+static bool do_image_op(FileBuffer *fb, image_context *ctx)
 {
 	uint8 opcode;
 	uint16 a, b;
@@ -254,10 +254,10 @@ static bool do_image_op(struct FileBuffer *fb, struct image_context *ctx)
 	return false;
 }
 
-void draw_image(struct image_data *info, unsigned index)
+void draw_image(image_data *info, unsigned index)
 {
 	unsigned file_num;
-	struct FileBuffer *fb;
+	FileBuffer *fb;
 	bool done = false;
 	image_context ctx = {
 		0, 0, G_COLOR_BLACK, G_COLOR_BLACK, IMAGE_OP_SHAPE_CIRCLE_LARGE
@@ -294,17 +294,17 @@ void draw_bright_room(void)
 	g_clear_screen(G_COLOR_WHITE);
 }
 
-void draw_location_image(struct image_data *info, unsigned index)
+void draw_location_image(image_data *info, unsigned index)
 {
 	g_clear_screen(G_COLOR_WHITE);
 	draw_image(info, index);
 }
 
-static void load_image_file(struct image_data *info, const char *filename,
+static void load_image_file(image_data *info, const char *filename,
 			    unsigned file_num)
 {
 	unsigned base = file_num * IMAGES_PER_FILE;
-	struct FileBuffer *fb;
+	FileBuffer *fb;
 	uint16 version;
 	int i;
 
@@ -329,7 +329,7 @@ static void load_image_file(struct image_data *info, const char *filename,
 	}
 }
 
-static void load_image_files(struct image_data *info,
+static void load_image_files(image_data *info,
 	const Common::Array<const char *> filenames) {
 	uint i;
 
@@ -344,7 +344,7 @@ static void load_image_files(struct image_data *info,
 	}
 }
 
-void comprehend_load_image_file(const char *filename, struct image_data *info)
+void comprehend_load_image_file(const char *filename, image_data *info)
 {
 	Common::Array<const char *> filenames;
 	filenames.push_back(filename);
diff --git a/engines/glk/comprehend/image_view.cpp b/engines/glk/comprehend/image_view.cpp
index c056e4b27d..c059316e80 100644
--- a/engines/glk/comprehend/image_view.cpp
+++ b/engines/glk/comprehend/image_view.cpp
@@ -59,7 +59,7 @@ int main(int argc, char **argv)
 		{NULL,			0,			0, 0},
 	};
 	const char *short_opts = "w:h:c:t:spfd?";
-	struct image_data info;
+	image_data info;
 	const char *filename;
 	unsigned index, clear_color = G_COLOR_WHITE,
 		graphics_width = G_RENDER_WIDTH,
diff --git a/engines/glk/comprehend/recomprehend.cpp b/engines/glk/comprehend/recomprehend.cpp
deleted file mode 100644
index 193bdad487..0000000000
--- a/engines/glk/comprehend/recomprehend.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/* 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 "glk/comprehend/comprehend.h"
-#include "glk/comprehend/dump_game_data.h"
-#include "glk/comprehend/game_data.h"
-#include "glk/comprehend/graphics.h"
-#include "glk/comprehend/game.h"
-#include "glk/comprehend/util.h"
-
-namespace Glk {
-namespace Comprehend {
-
-extern ComprehendGame game_transylvania;
-extern ComprehendGame game_crimson_crown_1;
-extern ComprehendGame game_crimson_crown_2;
-extern ComprehendGame game_oo_topos;
-extern ComprehendGame game_talisman;
-
-static ComprehendGame *ComprehendGames[] = {
-	&game_transylvania,
-	&game_crimson_crown_1,
-	&game_crimson_crown_2,
-	&game_oo_topos,
-	&game_talisman,
-};
-
-struct dump_option {
-	const char	*option;
-	unsigned	flag;
-};
-
-static struct dump_option dump_options[] = {
-	{"strings",		DUMP_STRINGS},
-	{"extra-strings",	DUMP_EXTRA_STRINGS},
-	{"rooms",		DUMP_ROOMS},
-	{"items",		DUMP_ITEMS},
-	{"dictionary",		DUMP_DICTIONARY},
-	{"word-pairs",		DUMP_WORD_PAIRS},
-	{"actions",		DUMP_ACTIONS},
-	{"functions",		DUMP_FUNCTIONS},
-	{"replace-words",	DUMP_REPLACE_WORDS},
-	{"header",		DUMP_HEADER},
-	{"all",			DUMP_ALL},
-};
-
-static void usage(const char *progname)
-{
-	int i;
-
-	printf("Usage %s [OPTION]... GAME_NAME GAME_DIR\n", progname);
-	printf("\nOptions:\n");
-	printf("  -d, --debug                   Enable debugging\n");
-	printf("  -D, --dump=OPTION             Dump game data\n");
-	for (i = 0; i < ARRAY_SIZE(dump_options); i++)
-		printf("        %s\n", dump_options[i].option);
-	printf("  -p, --no-play                 Don't run the interpreter\n");
-	printf("  -g, --no-graphics             Disable graphics\n");
-	printf("  -f, --no-floodfill            Disable floodfill\n");
-	printf("  -w, --graphics-width=WIDTH    Graphics width\n");
-	printf("  -h, --graphics-height=HEIGHT  Graphics height\n");
-
-	printf("\nSupported games:\n");
-	for (i = 0; i < ARRAY_SIZE(ComprehendGames); i++)
-		printf("    %-10s %s\n", ComprehendGames[i]->short_name,
-		       ComprehendGames[i]->game_name);
-
-	exit(EXIT_FAILURE);
-}
-
-int main(int argc, char **argv)
-{
-	struct option long_opts[] = {
-		{"debug",		no_argument,		0, 'd'},
-		{"dump",		required_argument,	0, 'D'},
-		{"no-play",		no_argument,		0, 'p'},
-		{"no-graphics",		no_argument,		0, 'g'},
-		{"no-floodfill",	no_argument,		0, 'f'},
-		{"graphics-width",	required_argument,	0, 'w'},
-		{"graphics-height",	required_argument,	0, 'h'},
-		{"help",		no_argument,		0, '?'},
-		{NULL,			0,			0, 0},
-	};
-	const char *short_opts = "dD:pgfw:h:?";
-	ComprehendGame *game;
-	const char *game_name, *game_dir;
-	unsigned dump_flags = 0;
-	int i, c, opt_index;
-	unsigned graphics_width = G_RENDER_WIDTH,
-		graphics_height = G_RENDER_HEIGHT;
-	bool play_game = true, graphics_enabled = true;
-
-	while (1) {
-		c = getopt_long(argc, argv, short_opts, long_opts, &opt_index);
-		if (c == -1)
-			break;
-
-		switch (c) {
-		case 'd':
-			// FIXME
-			debug_enable(DEBUG_FUNCTIONS);
-			break;
-
-		case 'D':
-			for (i = 0; i < ARRAY_SIZE(dump_options); i++)
-				if (strcmp(optarg, dump_options[i].option) == 0)
-					break;
-			if (i == ARRAY_SIZE(dump_options)) {
-				printf("Invalid dump option '%s'\n", optarg);
-				usage(argv[0]);
-			}
-
-			dump_flags |= dump_options[i].flag;
-			break;
-
-		case 'p':
-			play_game = false;
-			break;
-
-		case 'g':
-			graphics_enabled = false;
-			break;
-
-		case 'f':
-			image_set_draw_flags(IMAGEF_NO_FLOODFILL);
-			break;
-
-		case 'w':
-			graphics_width = strtoul(optarg, NULL, 0);
-			break;
-
-		case 'h':
-			graphics_height = strtoul(optarg, NULL, 0);
-			break;
-
-		case '?':
-			usage(argv[0]);
-			break;
-
-		default:
-			printf("Invalid option\n");
-			usage(argv[0]);
-			break;
-		}
-	}
-
-	if (optind >= argc || argc - optind != 2)
-		usage(argv[0]);
-
-	game_name = argv[optind++];
-	game_dir = argv[optind++];
-
-	/* Lookup game */
-	game = NULL;
-	for (i = 0; i < ARRAY_SIZE(ComprehendGames); i++) {
-		if (strcmp(game_name, ComprehendGames[i]->short_name) == 0) {
-			game = ComprehendGames[i];
-			break;
-		}
-	}
-	if (!game) {
-		printf("Unknown game '%s'\n", game_name);
-		usage(argv[0]);
-	}
-
-	if (graphics_enabled)
-		g_init(graphics_width, graphics_height);
-
-	game->info = xmalloc(sizeof(*game->info));
-	comprehend_load_game(game, game_dir);
-
-	if (dump_flags)
-		dump_game_data(game, dump_flags);
-
-	if (play_game)
-		comprehend_play_game(game);
-
-	exit(EXIT_SUCCESS);
-}
-
-} // namespace Comprehend
-} // namespace Glk
diff --git a/engines/glk/comprehend/recomprehend.h b/engines/glk/comprehend/recomprehend.h
deleted file mode 100644
index fd0fe31f80..0000000000
--- a/engines/glk/comprehend/recomprehend.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 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.
- *
- */
-
-#ifndef GLK_COMPREHEND_RECOMPREHEND_H
-#define GLK_COMPREHEND_RECOMPREHEND_H
-
-namespace Glk {
-namespace Comprehend {
-
-} // namespace Comprehend
-} // namespace Glk
-
-#endif


Commit: ec99b086fcc5e04e51f0c0536b0e67cb08786ad1
    https://github.com/scummvm/scummvm/commit/ec99b086fcc5e04e51f0c0536b0e67cb08786ad1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Capitalizing class names

Changed paths:
    engines/glk/adrift/scobjcts.cpp
    engines/glk/adrift/scprotos.h
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/dictionary.cpp
    engines/glk/comprehend/dictionary.h
    engines/glk/comprehend/dump_game_data.cpp
    engines/glk/comprehend/dump_game_data.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/game_tr.h
    engines/glk/comprehend/graphics.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_data.h


diff --git a/engines/glk/adrift/scobjcts.cpp b/engines/glk/adrift/scobjcts.cpp
index 1c94874f60..66c2e1e4ed 100644
--- a/engines/glk/adrift/scobjcts.cpp
+++ b/engines/glk/adrift/scobjcts.cpp
@@ -757,15 +757,15 @@ static sc_bool obj_indirectly_in_room_internal(sc_gameref_t game, sc_int object,
 	}
 }
 
-sc_bool obj_indirectly_in_room(sc_gameref_t game, sc_int object, sc_int room) {
+sc_bool obj_indirectly_in_room(sc_gameref_t game, sc_int object, sc_int Room) {
 	sc_bool result;
 
 	/* Check, trace result, and return. */
-	result = obj_indirectly_in_room_internal(game, object, room);
+	result = obj_indirectly_in_room_internal(game, object, Room);
 
 	if (obj_trace) {
 		sc_trace("Object: checking for object %ld indirectly in room %ld, %s\n",
-		         object, room, result ? "true" : "false");
+		         object, Room, result ? "true" : "false");
 	}
 
 	return result;
diff --git a/engines/glk/adrift/scprotos.h b/engines/glk/adrift/scprotos.h
index 6b8a6f3845..efd7bb2ed3 100644
--- a/engines/glk/adrift/scprotos.h
+++ b/engines/glk/adrift/scprotos.h
@@ -91,7 +91,7 @@ extern sc_bool sc_strempty(const sc_char *string);
 extern sc_char *sc_trim_string(sc_char *string);
 extern sc_char *sc_normalize_string(sc_char *string);
 extern sc_bool sc_compare_word(const sc_char *string,
-                               const sc_char *word, sc_int length);
+                               const sc_char *Word, sc_int length);
 extern sc_uint sc_hash(const sc_char *string);
 
 /* TAF file reader/decompressor enumerations, opaque typedef and functions. */
@@ -281,7 +281,7 @@ extern void gs_copy(sc_gameref_t to, sc_gameref_t from);
 extern void gs_destroy(sc_gameref_t game);
 
 /* Game state accessors and mutators. */
-extern void gs_move_player_to_room(sc_gameref_t game, sc_int room);
+extern void gs_move_player_to_room(sc_gameref_t game, sc_int Room);
 extern sc_bool gs_player_in_room(sc_gameref_t game, sc_int room);
 extern sc_var_setref_t gs_get_vars(sc_gameref_t gs);
 extern sc_prop_setref_t gs_get_bundle(sc_gameref_t gs);
@@ -300,8 +300,8 @@ extern sc_int gs_event_state(sc_gameref_t gs, sc_int event);
 extern sc_int gs_event_time(sc_gameref_t gs, sc_int event);
 extern void gs_decrement_event_time(sc_gameref_t gs, sc_int event);
 extern sc_int gs_room_count(sc_gameref_t gs);
-extern void gs_set_room_seen(sc_gameref_t gs, sc_int room, sc_bool seen);
-extern sc_bool gs_room_seen(sc_gameref_t gs, sc_int room);
+extern void gs_set_room_seen(sc_gameref_t gs, sc_int Room, sc_bool seen);
+extern sc_bool gs_room_seen(sc_gameref_t gs, sc_int Room);
 extern sc_int gs_task_count(sc_gameref_t gs);
 extern void gs_set_task_done(sc_gameref_t gs, sc_int task, sc_bool done);
 extern void gs_set_task_scored(sc_gameref_t gs, sc_int task, sc_bool scored);
@@ -367,9 +367,9 @@ enum {
 
 extern void lib_warn_battle_system(void);
 extern sc_int lib_random_roomgroup_member(sc_gameref_t game, sc_int roomgroup);
-extern const sc_char *lib_get_room_name(sc_gameref_t game, sc_int room);
-extern void lib_print_room_name(sc_gameref_t game, sc_int room);
-extern void lib_print_room_description(sc_gameref_t game, sc_int room);
+extern const sc_char *lib_get_room_name(sc_gameref_t game, sc_int Room);
+extern void lib_print_room_name(sc_gameref_t game, sc_int Room);
+extern void lib_print_room_description(sc_gameref_t game, sc_int Room);
 extern sc_bool lib_cmd_go_north(sc_gameref_t game);
 extern sc_bool lib_cmd_go_east(sc_gameref_t game);
 extern sc_bool lib_cmd_go_south(sc_gameref_t game);
@@ -690,8 +690,8 @@ enum {
 	NPC_NEUTER = 2
 };
 
-extern sc_bool npc_in_room(sc_gameref_t game, sc_int npc, sc_int room);
-extern sc_int npc_count_in_room(sc_gameref_t game, sc_int room);
+extern sc_bool npc_in_room(sc_gameref_t game, sc_int npc, sc_int Room);
+extern sc_int npc_count_in_room(sc_gameref_t game, sc_int Room);
 extern void npc_setup_initial(sc_gameref_t game);
 extern void npc_start_npc_walk(sc_gameref_t game, sc_int npc, sc_int walk);
 extern void npc_tick_npcs(sc_gameref_t game);
@@ -712,10 +712,10 @@ extern sc_bool obj_is_surface(sc_gameref_t game, sc_int object);
 extern sc_int obj_container_object(sc_gameref_t game, sc_int n);
 extern sc_int obj_surface_object(sc_gameref_t game, sc_int n);
 extern sc_bool obj_indirectly_in_room(sc_gameref_t game,
-                                      sc_int object, sc_int room);
+                                      sc_int object, sc_int Room);
 extern sc_bool obj_indirectly_held_by_player(sc_gameref_t game, sc_int object);
 extern sc_bool obj_directly_in_room(sc_gameref_t game,
-                                    sc_int object, sc_int room);
+                                    sc_int object, sc_int Room);
 extern sc_int obj_stateful_object(sc_gameref_t game, sc_int n);
 extern sc_int obj_dynamic_object(sc_gameref_t game, sc_int n);
 extern sc_int obj_wearable_object(sc_gameref_t game, sc_int n);
diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 3ca90b7b28..6b0c68507b 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -37,12 +37,12 @@ namespace Comprehend {
 
 Comprehend *g_comprehend;
 
-struct dump_option {
+struct DumpOption {
 	const char *const option;
 	unsigned flag;
 };
 
-static const dump_option dump_options[] = {
+static const DumpOption dump_options[] = {
     {"strings", DUMP_STRINGS},
     {"extra-strings", DUMP_EXTRA_STRINGS},
     {"rooms", DUMP_ROOMS},
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index d77f549182..c961438d72 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -40,11 +40,11 @@ namespace Comprehend {
 #define PATH_MAX 256
 
 struct GameInfo;
-struct game_state;
+struct gameState;
 
 #define EXTRA_STRING_TABLE(x) (0x8200 | (x))
 
-struct game_strings {
+struct GameStrings {
 	uint16 game_restart;
 };
 
diff --git a/engines/glk/comprehend/dictionary.cpp b/engines/glk/comprehend/dictionary.cpp
index 2f6e4cf025..70959a889e 100644
--- a/engines/glk/comprehend/dictionary.cpp
+++ b/engines/glk/comprehend/dictionary.cpp
@@ -28,7 +28,7 @@
 namespace Glk {
 namespace Comprehend {
 
-static bool word_match(word *word, const char *string)
+static bool word_match(Word *word, const char *string)
 {
 	/* Words less than 6 characters must match exactly */
 	if (strlen(word->_word) < 6 && strlen(string) != strlen(word->_word))
@@ -37,7 +37,7 @@ static bool word_match(word *word, const char *string)
 	return strncmp(word->_word, string, strlen(word->_word)) == 0;
 }
 
-word *dict_find_word_by_string(ComprehendGame *game,
+Word *dict_find_word_by_string(ComprehendGame *game,
 				      const char *string)
 {
 	uint i;
@@ -52,7 +52,7 @@ word *dict_find_word_by_string(ComprehendGame *game,
 	return NULL;
 }
 
-word *dict_find_word_by_index_type(ComprehendGame *game,
+Word *dict_find_word_by_index_type(ComprehendGame *game,
 					  uint8 index, uint8 type)
 {
 	uint i;
@@ -66,7 +66,7 @@ word *dict_find_word_by_index_type(ComprehendGame *game,
 	return NULL;
 }
 
-word *find_dict_word_by_index(ComprehendGame *game,
+Word *find_dict_word_by_index(ComprehendGame *game,
 				     uint8 index, uint8 type_mask)
 {
 	uint i;
diff --git a/engines/glk/comprehend/dictionary.h b/engines/glk/comprehend/dictionary.h
index f685513811..ed8fb56908 100644
--- a/engines/glk/comprehend/dictionary.h
+++ b/engines/glk/comprehend/dictionary.h
@@ -27,13 +27,13 @@ namespace Glk {
 namespace Comprehend {
 
 class ComprehendGame;
-struct word;
+struct Word;
 
-word *find_dict_word_by_index(ComprehendGame *game,
+Word *find_dict_word_by_index(ComprehendGame *game,
 				     uint8 index, uint8 type_mask);
-word *dict_find_word_by_index_type(ComprehendGame *game,
+Word *dict_find_word_by_index_type(ComprehendGame *game,
 					  uint8 index, uint8 type);
-word *dict_find_word_by_string(ComprehendGame *game,
+Word *dict_find_word_by_string(ComprehendGame *game,
 				      const char *string);
 bool dict_match_index_type(ComprehendGame *game, const char *word,
 			   uint8 index, uint8 type_mask);
diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
index bd99a5d4f3..bef4f9ef0a 100644
--- a/engines/glk/comprehend/dump_game_data.cpp
+++ b/engines/glk/comprehend/dump_game_data.cpp
@@ -114,8 +114,8 @@ static const char *opcode_names[] = {
 };
 
 void dump_instruction(ComprehendGame *game,
-		      function_state *func_state,
-		      instruction *instr)
+		      FunctionState *func_state,
+		      Instruction *instr)
 {
 	uint i;
 	int str_index, str_table;
@@ -169,7 +169,7 @@ void dump_instruction(ComprehendGame *game,
 
 static void dump_functions(ComprehendGame *game)
 {
-	function *func;
+	Function *func;
 	uint i, j;
 
 	debugN("Functions (%zd entries)\n", game->_nr_functions);
@@ -185,8 +185,8 @@ static void dump_functions(ComprehendGame *game)
 
 static void dump_action_table(ComprehendGame *game)
 {
-	action *action;
-	word *word;
+	Action *action;
+	Word *word;
 	uint i, j;
 
 	debugN("Action table (%zd entries)\n", game->_nr_actions);
@@ -231,7 +231,7 @@ static void dump_action_table(ComprehendGame *game)
 
 static int word_index_compare(const void *a, const void *b)
 {
-	const word *word_a = (const word *)a, *word_b = (const word *)b;
+	const Word *word_a = (const Word *)a, *word_b = (const Word *)b;
 
 	if (word_a->_index > word_b->_index)
 		return 1;
@@ -242,12 +242,12 @@ static int word_index_compare(const void *a, const void *b)
 
 static void dump_dictionary(ComprehendGame *game)
 {
-	word *dictionary;
-	word *words;
+	Word *dictionary;
+	Word *words;
 	uint i;
 
 	/* Sort the dictionary by index */
-	dictionary = (word *)xmalloc(sizeof(*words) * game->_nr_words);
+	dictionary = (Word *)xmalloc(sizeof(*words) * game->_nr_words);
 	memcpy(dictionary, game->_words,
 	       sizeof(*words) * game->_nr_words);
 	qsort(dictionary, game->_nr_words, sizeof(*words),
@@ -265,9 +265,9 @@ static void dump_dictionary(ComprehendGame *game)
 
 static void dump_word_map(ComprehendGame *game)
 {
-	word *word[3];
+	Word *word[3];
 	char str[3][6];
-	word_map *map;
+	WordMap *map;
 	uint i, j;
 
 	debugN("Word pairs (%zd entries)\n", game->_nr_word_maps);
@@ -292,7 +292,7 @@ static void dump_word_map(ComprehendGame *game)
 
 static void dump_rooms(ComprehendGame *game)
 {
-	room *room;
+	Room *room;
 	uint i;
 
 	/* Room zero acts as the players inventory */
@@ -319,7 +319,7 @@ static void dump_rooms(ComprehendGame *game)
 
 static void dump_items(ComprehendGame *game)
 {
-	item *item;
+	Item *item;
 	uint i, j;
 
 	debugN("Items (%zd entries)\n", game->_header.nr_items);
@@ -348,7 +348,7 @@ static void dump_items(ComprehendGame *game)
 	}
 }
 
-static void dump_string_table(string_table *table)
+static void dump_string_table(StringTable *table)
 {
 	uint i;
 
@@ -382,7 +382,7 @@ static void dump_replace_words(ComprehendGame *game)
 
 static void dump_header(ComprehendGame *game)
 {
-	game_header *header = &game->_header;
+	GameHeader *header = &game->_header;
 	uint16 *dir_table = header->room_direction_table;
 
 	debugN("Game header:\n");
@@ -420,12 +420,12 @@ static void dump_header(ComprehendGame *game)
 
 typedef void (*dump_func_t)(ComprehendGame *game);
 
-struct dumper {
+struct Dumper {
 	dump_func_t	dump_func;
 	unsigned	flag;
 };
 
-static dumper dumpers[] = {
+static Dumper dumpers[] = {
 	{dump_header,			DUMP_HEADER},
 	{dump_game_data_strings,	DUMP_STRINGS},
 	{dump_extra_strings,		DUMP_EXTRA_STRINGS},
diff --git a/engines/glk/comprehend/dump_game_data.h b/engines/glk/comprehend/dump_game_data.h
index 06c6609e6c..311ff2b139 100644
--- a/engines/glk/comprehend/dump_game_data.h
+++ b/engines/glk/comprehend/dump_game_data.h
@@ -27,8 +27,8 @@ namespace Glk {
 namespace Comprehend {
 
 class ComprehendGame;
-struct function_state;
-struct instruction;
+struct FunctionState;
+struct Instruction;
 
 #define DUMP_STRINGS (1 << 0)
 #define DUMP_EXTRA_STRINGS (1 << 1)
@@ -43,8 +43,8 @@ struct instruction;
 #define DUMP_ALL (~0U)
 
 void dump_instruction(ComprehendGame *game,
-                      function_state *func_state,
-                      instruction *instr);
+                      FunctionState *func_state,
+                      Instruction *instr);
 void dump_game_data(ComprehendGame *game, unsigned flags);
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index a41842497e..2022656364 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -33,15 +33,15 @@
 namespace Glk {
 namespace Comprehend {
 
-struct sentence {
-	word words[4];
+struct Sentence {
+	Word words[4];
 	size_t nr_words;
 };
 
-struct winsize {
+struct WinSize {
 	uint ws_col;
 };
-static winsize console_winsize;
+static WinSize console_winsize;
 
 ComprehendGame::ComprehendGame() : _gameName(nullptr),
                                      _shortName(nullptr),
@@ -157,7 +157,7 @@ void console_println(ComprehendGame *game, const char *text) {
 	printf("\n");
 }
 
-static room *get_room(ComprehendGame *game, uint16 index) {
+static Room *get_room(ComprehendGame *game, uint16 index) {
 	/* Room zero is reserved for the players inventory */
 	if (index == 0)
 		fatal_error("Room index 0 (player inventory) is invalid");
@@ -168,7 +168,7 @@ static room *get_room(ComprehendGame *game, uint16 index) {
 	return &game->_rooms[index];
 }
 
-item *get_item(ComprehendGame *game, uint16 index) {
+Item *get_item(ComprehendGame *game, uint16 index) {
 	if (index >= game->_header.nr_items)
 		fatal_error("Bad item %d\n", index);
 
@@ -225,9 +225,9 @@ void game_restart(ComprehendGame *game) {
 	game->_updateFlags = UPDATE_ALL;
 }
 
-static word_index *is_word_pair(ComprehendGame *game,
-                                       word *word1, word *word2) {
-	word_map *map;
+static WordIndex *is_word_pair(ComprehendGame *game,
+                                       Word *word1, Word *word2) {
+	WordMap *map;
 	uint i;
 
 	/* Check if this is a word pair */
@@ -244,8 +244,8 @@ static word_index *is_word_pair(ComprehendGame *game,
 	return NULL;
 }
 
-static item *get_item_by_noun(ComprehendGame *game,
-                                     word *noun) {
+static Item *get_item_by_noun(ComprehendGame *game,
+                                     Word *noun) {
 	uint i;
 
 	if (!noun || !(noun->_type & WORD_TYPE_NOUN_MASK))
@@ -264,8 +264,8 @@ static item *get_item_by_noun(ComprehendGame *game,
 }
 
 static void update_graphics(ComprehendGame *game) {
-	item *item;
-	room *room;
+	Item *item;
+	Room *room;
 	int type;
 	uint i;
 
@@ -308,7 +308,7 @@ static void update_graphics(ComprehendGame *game) {
 }
 
 static void describe_objects_in_current_room(ComprehendGame *game) {
-	item *item;
+	Item *item;
 	size_t count = 0;
 	uint i;
 
@@ -334,7 +334,7 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 }
 
 static void update(ComprehendGame *game) {
-	room *room = get_room(game, game->_currentRoom);
+	Room *room = get_room(game, game->_currentRoom);
 	unsigned room_type, room_desc_string;
 
 	update_graphics(game);
@@ -363,7 +363,7 @@ static void move_to(ComprehendGame *game, uint8 room) {
 	                            UPDATE_ITEM_LIST);
 }
 
-static void func_set_test_result(function_state *func_state, bool value) {
+static void func_set_test_result(FunctionState *func_state, bool value) {
 	if (func_state->or_count == 0) {
 		/* And */
 		if (func_state->_and) {
@@ -391,7 +391,7 @@ static size_t num_objects_in_room(ComprehendGame *game, int room) {
 	return count;
 }
 
-void move_object(ComprehendGame *game, item *item, int new_room) {
+void move_object(ComprehendGame *game, Item *item, int new_room) {
 	unsigned obj_weight = item->flags & ITEMF_WEIGHT_MASK;
 
 	if (item->room == new_room)
@@ -423,12 +423,12 @@ void move_object(ComprehendGame *game, item *item, int new_room) {
 }
 
 static void eval_instruction(ComprehendGame *game,
-                             function_state *func_state,
-                             instruction *instr,
-                             word *verb, word *noun) {
+                             FunctionState *func_state,
+                             Instruction *instr,
+                             Word *verb, Word *noun) {
 	uint8 *opcode_map;
-	room *room;
-	item *item;
+	Room *room;
+	Item *item;
 	uint16 index;
 	bool test;
 	uint i, count;
@@ -615,7 +615,7 @@ static void eval_instruction(ComprehendGame *game,
 
 		if (noun) {
 			for (i = 0; i < game->_header.nr_items; i++) {
-				struct item *itemP = &game->_items[i];
+				Item *itemP = &game->_items[i];
 
 				if (itemP->word == noun->_index &&
 				    itemP->room == instr->operand[0]) {
@@ -981,9 +981,9 @@ static void eval_instruction(ComprehendGame *game,
  * is reached. Otherwise the commands instructions are skipped over and the
  * next test sequence (if there is one) is tried.
  */
-void eval_function(ComprehendGame *game, function *func,
-                   word *verb, word *noun) {
-	function_state func_state;
+void eval_function(ComprehendGame *game, Function *func,
+                   Word *verb, Word *noun) {
+	FunctionState func_state;
 	uint i;
 
 	func_state.else_result = true;
@@ -1056,9 +1056,9 @@ static void handle_debug_command(ComprehendGame *game,
 #endif
 
 static bool handle_sentence(ComprehendGame *game,
-                            sentence *sentence) {
-	function *func;
-	action *action;
+                            Sentence *sentence) {
+	Function *func;
+	Action *action;
 	uint i, j;
 
 	if (sentence->nr_words == 0)
@@ -1102,11 +1102,11 @@ static bool handle_sentence(ComprehendGame *game,
 }
 
 static void read_sentence(ComprehendGame *game, char **line,
-                          sentence *sentence) {
+                          Sentence *sentence) {
 	bool sentence_end = false;
 	char *word_string, *p = *line;
-	word_index *pair;
-	word *word;
+	WordIndex *pair;
+	Word *word;
 	int index;
 
 	memset(sentence, 0, sizeof(*sentence));
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 583f333f53..ce4689a32a 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -39,13 +39,13 @@ public:
 	const char *_shortName;
 
 	const char *_gameDataFile;
-	Common::Array<string_file> _stringFiles;
+	Common::Array<StringFile> _stringFiles;
 	Common::Array<const char *> _locationGraphicFiles;
 	Common::Array<const char *> _itemGraphicFiles;
 	const char *_savegameFileFormat;
 	unsigned _colorTable;
 
-	struct game_strings *_gameStrings;
+	struct GameStrings *_gameStrings;
 
 public:
 	ComprehendGame();
@@ -69,10 +69,10 @@ public:
 void console_println(ComprehendGame *game, const char *text);
 int console_get_key(void);
 
-item *get_item(ComprehendGame *game, uint16 index);
-void move_object(ComprehendGame *game, item *item, int new_room);
-void eval_function(ComprehendGame *game, function *func,
-                   word *verb, word *noun);
+Item *get_item(ComprehendGame *game, uint16 index);
+void move_object(ComprehendGame *game, Item *item, int new_room);
+void eval_function(ComprehendGame *game, Function *func,
+                   Word *verb, Word *noun);
 
 void comprehend_play_game(ComprehendGame *game);
 void game_save(ComprehendGame *game);
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index 4b1a5feab7..da416aa32d 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -26,7 +26,7 @@
 namespace Glk {
 namespace Comprehend {
 
-static game_strings cc1_strings = {0x9};
+static GameStrings cc1_strings = {0x9};
 
 #ifdef TODO
 static game_ops cc2_ops = {
@@ -43,7 +43,7 @@ CrimsonCrownGame::CrimsonCrownGame() : ComprehendGame() {
 	_shortName = "cc1";
 	_gameDataFile = "cc1.gda";
 
-	_stringFiles.push_back(string_file("ma.ms1", 0x89));
+	_stringFiles.push_back(StringFile("ma.ms1", 0x89));
 	_locationGraphicFiles.push_back("RA.MS1");
 	_locationGraphicFiles.push_back("RB.MS1");
 	_locationGraphicFiles.push_back("RC.MS1");
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index c28813e19f..db9d1d6eec 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -38,7 +38,7 @@ static char special_charset[] = "[]\n!\"#$%&'(),-/0123456789:;?<>";
 
 static uint16 magic_offset;
 
-void function_state::clear() {
+void FunctionState::clear() {
 	test_result = true;
 	else_result = false;
 	or_count = 0;
@@ -49,7 +49,7 @@ void function_state::clear() {
 
 /*-------------------------------------------------------*/
 
-void room::clear() {
+void Room::clear() {
 	flags = 0;
     graphic = 0;
 	string_desc = 0;
@@ -58,7 +58,7 @@ void room::clear() {
 
 /*-------------------------------------------------------*/
 
-void item::clear() {
+void Item::clear() {
 	string_desc = 0;
     long_string = 0;
     room = 0;
@@ -69,7 +69,7 @@ void item::clear() {
 
 /*-------------------------------------------------------*/
 
-void word::clear() {
+void Word::clear() {
 	_index = 0;
 	_type = 0;
 	Common::fill(&_word[0], &_word[7], '\0');
@@ -77,7 +77,7 @@ void word::clear() {
 
 /*-------------------------------------------------------*/
 
-void word_map::clear() {
+void WordMap::clear() {
 	flags = 0;
 	for (int idx = 0; idx < 3; ++idx)
 		word[idx].clear();
@@ -85,7 +85,7 @@ void word_map::clear() {
 
 /*-------------------------------------------------------*/
 
-void action::clear() {
+void Action::clear() {
 	type = 0;
 	nr_words = 0;
 	function = 0;
@@ -95,7 +95,7 @@ void action::clear() {
 
 /*-------------------------------------------------------*/
 
-void instruction::clear() {
+void Instruction::clear() {
 	opcode = 0;
 	nr_operands = 0;
 	is_command= false;
@@ -104,7 +104,7 @@ void instruction::clear() {
 
 /*-------------------------------------------------------*/
 
-void function::clear() {
+void Function::clear() {
 	nr_instructions = 0;
 	for (int idx = 0; idx < 0x100; ++idx)
 		instructions[idx].clear();
@@ -112,14 +112,14 @@ void function::clear() {
 
 /*-------------------------------------------------------*/
 
-void string_table::clear() {
+void StringTable::clear() {
 	nr_strings = 0;	
 	Common::fill(&strings[0], &strings[0xffff], nullptr);
 }
 
 /*-------------------------------------------------------*/
 
-void game_header::clear() {
+void GameHeader::clear() {
 	magic = 0;
 	room_desc_table = 0;
 	room_flags_table = 0;
@@ -199,7 +199,7 @@ static bool opcode_is_command(uint8 opcode) {
 }
 
 static uint8 parse_vm_instruction(FileBuffer *fb,
-		instruction *instr) {
+		Instruction *instr) {
 	uint i;
 
 	/* Get the opcode */
@@ -215,8 +215,8 @@ static uint8 parse_vm_instruction(FileBuffer *fb,
 	return instr->opcode;
 }
 
-static void parse_function(FileBuffer *fb, function * func) {
-	instruction *instruction;
+static void parse_function(FileBuffer *fb, Function * func) {
+	Instruction *instruction;
 	uint8 *p, opcode;
 
 	p = (uint8 *)memchr(fb->dataPtr(), 0x00, fb->size() - fb->pos());
@@ -237,7 +237,7 @@ static void parse_function(FileBuffer *fb, function * func) {
 }
 
 static void parse_vm(ComprehendGame *game, FileBuffer *fb) {
-	function *func;
+	Function *func;
 
 	fb->seek(game->_header.addr_vm);
 	while (1) {
@@ -253,7 +253,7 @@ static void parse_vm(ComprehendGame *game, FileBuffer *fb) {
 
 static void parse_action_table_vvnn(ComprehendGame *game,
 	                                FileBuffer *fb, size_t * index) {
-	action *action;
+	Action *action;
 	uint8 verb, count;
 	int i, j;
 
@@ -297,7 +297,7 @@ static void parse_action_table_vvnn(ComprehendGame *game,
 
 static void parse_action_table_vnjn(ComprehendGame *game,
 	                                FileBuffer *fb, size_t * index) {
-	action *action;
+	Action *action;
 	uint8 join, count;
 	int i;
 
@@ -342,7 +342,7 @@ static void parse_action_table_vnjn(ComprehendGame *game,
 
 static void parse_action_table_vjn(ComprehendGame *game,
 	                                FileBuffer *fb, size_t * index) {
-	action *action;
+	Action *action;
 	uint8 join, count;
 	int i;
 
@@ -383,7 +383,7 @@ static void parse_action_table_vjn(ComprehendGame *game,
 
 static void parse_action_table_vdn(ComprehendGame *game,
 	                                FileBuffer *fb, size_t * index) {
-	action *action;
+	Action *action;
 	uint8 verb, count;
 	int i;
 
@@ -424,7 +424,7 @@ static void parse_action_table_vdn(ComprehendGame *game,
 
 static void parse_action_table_vnn(ComprehendGame *game,
 	                                FileBuffer *fb, size_t * index) {
-	action *action;
+	Action *action;
 	uint8 verb, count;
 	int i;
 
@@ -466,7 +466,7 @@ static void parse_action_table_vnn(ComprehendGame *game,
 
 static void parse_action_table_vn(ComprehendGame *game,
 	                                FileBuffer *fb, size_t * index) {
-	action *action;
+	Action *action;
 	uint8 verb, count;
 	int i;
 
@@ -505,7 +505,7 @@ static void parse_action_table_vn(ComprehendGame *game,
 
 static void parse_action_table_v(ComprehendGame *game,
 	                                FileBuffer *fb, size_t * index) {
-	action *action;
+	Action *action;
 	uint8 verb, nr_funcs;
 	uint16 func;
 	int i;
@@ -565,11 +565,11 @@ static void parse_action_table(ComprehendGame *game,
 }
 
 static void parse_dictionary(ComprehendGame *game, FileBuffer *fb) {
-	word *words;
+	Word *words;
 	uint i, j;
 
 	// FIXME - fixed size 0xff array?
-	game->_words = (word *)xmalloc(game->_nr_words * sizeof(words));
+	game->_words = (Word *)xmalloc(game->_nr_words * sizeof(words));
 
 	fb->seek(game->_header.addr_dictionary);
 	for (i = 0; i < game->_nr_words; i++) {
@@ -588,7 +588,7 @@ static void parse_dictionary(ComprehendGame *game, FileBuffer *fb) {
 }
 
 static void parse_word_map(ComprehendGame *game, FileBuffer *fb) {
-	word_map *map;
+	WordMap *map;
 	uint8 index, type, dummy;
 	uint i;
 
@@ -788,7 +788,7 @@ done:
 }
 
 static void parse_string_table(FileBuffer *fb, unsigned start_addr,
-	                            uint32 end_addr, string_table *table) {
+	                            uint32 end_addr, StringTable *table) {
 	fb->seek(start_addr);
 	while (1) {
 		table->strings[table->nr_strings++] = parse_string(fb);
@@ -848,7 +848,7 @@ static void parse_replace_words(ComprehendGame *game,
 * game data is. The offsets have a magic constant value added to them.
 */
 static void parse_header(ComprehendGame *game, FileBuffer *fb) {
-	game_header *header = &game->_header;
+	GameHeader *header = &game->_header;
 	uint16 dummy, addr_dictionary_end;
 	uint8 dummy8;
 
@@ -966,7 +966,7 @@ static void parse_header(ComprehendGame *game, FileBuffer *fb) {
 }
 
 static void load_extra_string_file(ComprehendGame *game,
-	                                string_file * string_file) {
+	                                StringFile * string_file) {
 	FileBuffer fb(string_file->filename);
 	unsigned end;
 
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 2e243198f1..95c4c6a028 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -43,7 +43,7 @@ enum {
 	NR_DIRECTIONS,
 };
 
-struct function_state {
+struct FunctionState {
 	bool test_result;
 	bool else_result;
 	unsigned or_count;
@@ -51,27 +51,27 @@ struct function_state {
 	bool in_command;
 	bool executed;
 
-	function_state() {
+	FunctionState() {
 		clear();
 	}
 
 	void clear();
 };
 
-struct room {
+struct Room {
 	uint8 direction[NR_DIRECTIONS];
 	uint8 flags;
 	uint8 graphic;
 	uint16 string_desc;
 
-	room() {
+	Room() {
 		clear();
 	}
 
 	void clear();
 };
 
-struct item {
+struct Item {
 	uint16 string_desc;
 	uint16 long_string; /* Only used by version 2 */
 	uint8 room;
@@ -79,30 +79,30 @@ struct item {
 	uint8 word;
 	uint8 graphic;
 
-	item() {
+	Item() {
 		clear();
 	}
 
 	void clear();
 };
 
-struct word {
+struct Word {
 	char _word[7];
 	uint8 _index;
 	uint8 _type;
 
-	word() {
+	Word() {
 		clear();
 	}
 
 	void clear();
 };
 
-struct word_index {
+struct WordIndex {
 	uint8 index;
 	uint8 type;
 
-	word_index() {
+	WordIndex() {
 		clear();
 	}
 
@@ -111,19 +111,19 @@ struct word_index {
 	}
 };
 
-struct word_map {
+struct WordMap {
 	/* <word[0]>, <word[1]> == <word[2]> */
-	word_index word[3];
+	WordIndex word[3];
 	uint8 flags;
 
-	word_map() {
+	WordMap() {
 		clear();
 	}
 
 	void clear();
 };
 
-struct action {
+struct Action {
 	int type;
 	size_t nr_words;
 	// FIXME - use struct word_index here.
@@ -131,49 +131,49 @@ struct action {
 	uint8 word_type[4];
 	uint16 function;
 
-	action() {
+	Action() {
 		clear();
 	}
 
 	void clear();
 };
 
-struct instruction {
+struct Instruction {
 	uint8 opcode;
 	size_t nr_operands;
 	uint8 operand[3];
 	bool is_command;
 
-	instruction() {
+	Instruction() {
 		clear();
 	}
 
 	void clear();
 };
 
-struct function {
-	instruction instructions[0x100];
+struct Function {
+	Instruction instructions[0x100];
 	size_t nr_instructions;
 
-	function() {
+	Function() {
 		clear();
 	}
 
 	void clear();
 };
 
-struct string_table {
+struct StringTable {
 	char *strings[0xffff];
 	size_t nr_strings;
 
-	string_table() {
+	StringTable() {
 		clear();
 	}
 
 	void clear();
 };
 
-struct game_header {
+struct GameHeader {
 	uint16 magic;
 
 	uint16 room_desc_table;
@@ -205,7 +205,7 @@ struct game_header {
 
 	uint16 addr_vm; // FIXME - functions
 
-	game_header() {
+	GameHeader() {
 		clear();
 	}
 
@@ -213,35 +213,35 @@ struct game_header {
 };
 
 struct GameInfo {
-	game_header _header;
+	GameHeader _header;
 
 	unsigned _comprehendVersion;
 
 	uint8 _startRoom;
 
-	room _rooms[0x100];
+	Room _rooms[0x100];
 	size_t _nr_rooms;
 	uint8 _currentRoom;
 
-	struct item _items[0xff];
+	struct Item _items[0xff];
 
-	struct word *_words;
+	struct Word *_words;
 	size_t _nr_words;
 
-	struct word_map _wordMaps[0xff];
+	struct WordMap _wordMaps[0xff];
 	size_t _nr_word_maps;
 
-	struct string_table _strings;
-	struct string_table _strings2;
+	struct StringTable _strings;
+	struct StringTable _strings2;
 
-	struct action _actions[0xffff];
+	struct Action _actions[0xffff];
 	size_t _nr_actions;
 
-	struct function _functions[0xffff];
+	struct Function _functions[0xffff];
 	size_t _nr_functions;
 
-	struct image_data _roomImages;
-	struct image_data _itemImages;
+	struct ImageData _roomImages;
+	struct ImageData _itemImages;
 
 	bool _flags[MAX_FLAGS];
 	uint16 _variables[MAX_VARIABLES];
@@ -259,13 +259,13 @@ struct GameInfo {
 	void clearInfo();
 };
 
-struct string_file {
+struct StringFile {
 	const char *filename;
 	uint32 base_offset;
 	uint32 end_offset;
 
-	string_file() : filename(nullptr), base_offset(0), end_offset(0) {}
-	string_file(const char *fname, uint32 baseOfs, uint32 endO = 0) : filename(fname), base_offset(baseOfs), end_offset(endO) {
+	StringFile() : filename(nullptr), base_offset(0), end_offset(0) {}
+	StringFile(const char *fname, uint32 baseOfs, uint32 endO = 0) : filename(fname), base_offset(baseOfs), end_offset(endO) {
 	}
 };
 
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index b1faa9c705..124f8d6e08 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -40,11 +40,11 @@ OOToposGame::OOToposGame() : ComprehendGame() {
 	_gameDataFile = "g0";
 
 	// Extra strings are (annoyingly) stored in the game binary
-	_stringFiles.push_back(string_file("NOVEL.EXE", 0x16564, 0x17640));
-	_stringFiles.push_back(string_file("NOVEL.EXE", 0x17702, 0x18600));
-	_stringFiles.push_back(string_file("NOVEL.EXE", 0x186b2, 0x19b80));
-	_stringFiles.push_back(string_file("NOVEL.EXE", 0x19c62, 0x1a590));
-	_stringFiles.push_back(string_file("NOVEL.EXE", 0x1a634, 0x1b080));
+	_stringFiles.push_back(StringFile("NOVEL.EXE", 0x16564, 0x17640));
+	_stringFiles.push_back(StringFile("NOVEL.EXE", 0x17702, 0x18600));
+	_stringFiles.push_back(StringFile("NOVEL.EXE", 0x186b2, 0x19b80));
+	_stringFiles.push_back(StringFile("NOVEL.EXE", 0x19c62, 0x1a590));
+	_stringFiles.push_back(StringFile("NOVEL.EXE", 0x1a634, 0x1b080));
 	_locationGraphicFiles.push_back("RA");
 	_locationGraphicFiles.push_back("RB");
 	_locationGraphicFiles.push_back("RC");
@@ -61,7 +61,7 @@ OOToposGame::OOToposGame() : ComprehendGame() {
 
 int OOToposGame::room_is_special(unsigned room_index,
                               unsigned *room_desc_string) {
-	room *room = &_rooms[room_index];
+	Room *room = &_rooms[room_index];
 
 	/* Is the room dark */
 	if ((room->flags & OO_ROOM_FLAG_DARK) &&
@@ -85,7 +85,7 @@ int OOToposGame::room_is_special(unsigned room_index,
 bool OOToposGame::before_turn() {
 	/* FIXME - probably doesn't work correctly with restored games */
 	static bool flashlight_was_on = false, googles_were_worn = false;
-	room *room = &_rooms[_currentRoom];
+	Room *room = &_rooms[_currentRoom];
 
 	/* 
 	 * Check if the room needs to be redrawn because the flashlight
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 041b4dfef0..66a9a890b3 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -28,15 +28,15 @@
 namespace Glk {
 namespace Comprehend {
 
-const tr_monster TransylvaniaGame::WEREWOLF = {
+const TransylvaniaMonster TransylvaniaGame::WEREWOLF = {
 	0x21, 7, (1 << 6), 5, 5
 };
 
-const tr_monster TransylvaniaGame::VAMPIRE = {
+const TransylvaniaMonster TransylvaniaGame::VAMPIRE = {
 	0x26, 5, (1 << 7), 0, 5
 };
 
-static game_strings tr_strings = {
+static GameStrings tr_strings = {
     EXTRA_STRING_TABLE(0x8a)
 };
 
@@ -46,11 +46,11 @@ TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
 	_shortName = "tr";
 	_gameDataFile = "tr.gda";
 
-	_stringFiles.push_back(string_file("MA.MS1", 0x88));
-	_stringFiles.push_back(string_file("MB.MS1", 0x88));
-	_stringFiles.push_back(string_file("MC.MS1", 0x88));
-	_stringFiles.push_back(string_file("MD.MS1", 0x88));
-	_stringFiles.push_back(string_file("ME.MS1", 0x88));
+	_stringFiles.push_back(StringFile("MA.MS1", 0x88));
+	_stringFiles.push_back(StringFile("MB.MS1", 0x88));
+	_stringFiles.push_back(StringFile("MC.MS1", 0x88));
+	_stringFiles.push_back(StringFile("MD.MS1", 0x88));
+	_stringFiles.push_back(StringFile("ME.MS1", 0x88));
 
     _locationGraphicFiles.push_back("RA.MS1");
 	_locationGraphicFiles.push_back("RB.MS1");
@@ -64,9 +64,9 @@ TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
 	_gameStrings = &tr_strings;
 };
 
-void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
-	item *monster;
-	room *room;
+void TransylvaniaGame::update_monster(const TransylvaniaMonster *monster_info) {
+	Item *monster;
+	Room *room;
 	uint16 turn_count;
 
 	room = &_rooms[_currentRoom];
@@ -98,7 +98,7 @@ void TransylvaniaGame::update_monster(const tr_monster *monster_info) {
 int TransylvaniaGame::room_is_special(unsigned room_index,
 			      unsigned *room_desc_string)
 {
-	room *room = &_rooms[room_index];
+	Room *room = &_rooms[room_index];
 
 	if (room_index == 0x28) {
 		if (room_desc_string)
diff --git a/engines/glk/comprehend/game_tr.h b/engines/glk/comprehend/game_tr.h
index 634588c58f..c9d4fdddb7 100644
--- a/engines/glk/comprehend/game_tr.h
+++ b/engines/glk/comprehend/game_tr.h
@@ -28,7 +28,7 @@
 namespace Glk {
 namespace Comprehend {
 
-struct tr_monster {
+struct TransylvaniaMonster {
 	uint8 object;
 	uint8 dead_flag;
 	unsigned min_turns_before;
@@ -38,10 +38,10 @@ struct tr_monster {
 
 class TransylvaniaGame : public ComprehendGame {
 private:
-	static const tr_monster WEREWOLF;
-	static const tr_monster VAMPIRE;
+	static const TransylvaniaMonster WEREWOLF;
+	static const TransylvaniaMonster VAMPIRE;
 
-	void update_monster(const tr_monster *monster_info);
+	void update_monster(const TransylvaniaMonster *monster_info);
 
 public:
 	TransylvaniaGame();
diff --git a/engines/glk/comprehend/graphics.cpp b/engines/glk/comprehend/graphics.cpp
index cb37182dc2..b053aceb5b 100644
--- a/engines/glk/comprehend/graphics.cpp
+++ b/engines/glk/comprehend/graphics.cpp
@@ -48,7 +48,7 @@ static unsigned pen_colors[] = {
     RGB(0xff, 0x00, 0x00),
 };
 
-struct graphics_context {
+struct GraphicsContext {
 	Window *screen;
 
 	/*
@@ -63,7 +63,7 @@ struct graphics_context {
 	//	SDL_Surface	*surface;
 };
 
-static graphics_context ctx;
+static GraphicsContext ctx;
 
 unsigned g_set_pen_color(uint8 opcode) {
 	return pen_colors[opcode - IMAGE_OP_PEN_COLOR_A];
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 1a5be26d62..9a44b21e8d 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -33,7 +33,7 @@ namespace Comprehend {
 
 #define IMAGES_PER_FILE	16
 
-struct image_context {
+struct ImageContext {
 	unsigned	x;
 	unsigned	y;
 	unsigned	pen_color;
@@ -46,7 +46,7 @@ struct image_context {
 
 static unsigned draw_flags;
 
-void image_data::clear() {
+void ImageData::clear() {
 	fb = nullptr;
 	image_offsets = nullptr;
 	nr_images = 0;
@@ -65,7 +65,7 @@ static uint16 image_get_operand(FileBuffer *fb)
 	return val;
 }
 
-static bool do_image_op(FileBuffer *fb, image_context *ctx)
+static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 {
 	uint8 opcode;
 	uint16 a, b;
@@ -254,12 +254,12 @@ static bool do_image_op(FileBuffer *fb, image_context *ctx)
 	return false;
 }
 
-void draw_image(image_data *info, unsigned index)
+void draw_image(ImageData *info, unsigned index)
 {
 	unsigned file_num;
 	FileBuffer *fb;
 	bool done = false;
-	image_context ctx = {
+	ImageContext ctx = {
 		0, 0, G_COLOR_BLACK, G_COLOR_BLACK, IMAGE_OP_SHAPE_CIRCLE_LARGE
 	};
 
@@ -294,13 +294,13 @@ void draw_bright_room(void)
 	g_clear_screen(G_COLOR_WHITE);
 }
 
-void draw_location_image(image_data *info, unsigned index)
+void draw_location_image(ImageData *info, unsigned index)
 {
 	g_clear_screen(G_COLOR_WHITE);
 	draw_image(info, index);
 }
 
-static void load_image_file(image_data *info, const char *filename,
+static void load_image_file(ImageData *info, const char *filename,
 			    unsigned file_num)
 {
 	unsigned base = file_num * IMAGES_PER_FILE;
@@ -329,7 +329,7 @@ static void load_image_file(image_data *info, const char *filename,
 	}
 }
 
-static void load_image_files(image_data *info,
+static void load_image_files(ImageData *info,
 	const Common::Array<const char *> filenames) {
 	uint i;
 
@@ -344,7 +344,7 @@ static void load_image_files(image_data *info,
 	}
 }
 
-void comprehend_load_image_file(const char *filename, image_data *info)
+void comprehend_load_image_file(const char *filename, ImageData *info)
 {
 	Common::Array<const char *> filenames;
 	filenames.push_back(filename);
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
index cb165e9fdb..718b57c9aa 100644
--- a/engines/glk/comprehend/image_data.h
+++ b/engines/glk/comprehend/image_data.h
@@ -31,12 +31,12 @@ namespace Comprehend {
 class ComprehendGame;
 struct FileBuffer;
 
-struct image_data {
+struct ImageData {
 	FileBuffer	*fb;
 	uint16	*image_offsets;
 	size_t		nr_images;
 
-	image_data() {
+	ImageData() {
 		clear();
 	}
 
@@ -93,10 +93,10 @@ void image_set_draw_flags(unsigned flags);
 
 void draw_dark_room(void);
 void draw_bright_room(void);
-void draw_image(image_data *info, unsigned index);
-void draw_location_image(image_data *info, unsigned index);
+void draw_image(ImageData *info, unsigned index);
+void draw_location_image(ImageData *info, unsigned index);
 
-void comprehend_load_image_file(const char *filename, image_data *info);
+void comprehend_load_image_file(const char *filename, ImageData *info);
 void comprehend_load_images(ComprehendGame *game);
 
 } // namespace Comprehend


Commit: eca27789b1f019ccf443cb81716ba9b9d8fcf938
    https://github.com/scummvm/scummvm/commit/eca27789b1f019ccf443cb81716ba9b9d8fcf938
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Data loading fixes

Changed paths:
    engines/glk/comprehend/file_buf.cpp
    engines/glk/comprehend/game_data.cpp


diff --git a/engines/glk/comprehend/file_buf.cpp b/engines/glk/comprehend/file_buf.cpp
index 76b70cc82d..28b20b69c4 100644
--- a/engines/glk/comprehend/file_buf.cpp
+++ b/engines/glk/comprehend/file_buf.cpp
@@ -65,7 +65,7 @@ uint32 FileBuffer::read(void *dataPtr, uint32 dataSize) {
 	int32 bytesRead = CLIP((int32)dataSize, 0, (int32)_data.size() - _pos);
 	if (bytesRead) {
 		Common::fill(&_readBytes[_pos], &_readBytes[_pos + bytesRead], true);
-		Common::copy((byte *)dataPtr, (byte *)dataPtr + bytesRead, (byte *)dataPtr);
+		Common::copy(&_data[_pos], &_data[_pos + bytesRead], (byte *)dataPtr);
 		_pos += bytesRead;
 	}
 
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index db9d1d6eec..8b0ea5936b 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -982,8 +982,6 @@ static void load_extra_string_file(ComprehendGame *game,
 static void load_extra_string_files(ComprehendGame *game) {
 	int i;
 
-	memset(&game->_strings2, 0, sizeof(game->_strings2));
-
 	for (i = 0; i < ARRAY_SIZE(game->_stringFiles); i++) {
 		if (!game->_stringFiles[i].filename)
 			break;
@@ -1007,7 +1005,6 @@ static void load_game_data(ComprehendGame *game) {
 	parse_items(game, &fb);
 	parse_dictionary(game, &fb);
 	parse_word_map(game, &fb);
-	memset(&game->_strings, 0, sizeof(game->_strings));
 	parse_string_table(&fb, game->_header.addr_strings,
 		                game->_header.addr_strings_end,
 		                &game->_strings);


Commit: 16c36841aa0020bde71e690b9e00ed8ae7bc9e01
    https://github.com/scummvm/scummvm/commit/16c36841aa0020bde71e690b9e00ed8ae7bc9e01
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: gcc compilation fixes

Changed paths:
    engines/glk/comprehend/dump_game_data.cpp
    engines/glk/comprehend/file_buf.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/graphics.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/util.cpp
    engines/glk/comprehend/util.h


diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
index bef4f9ef0a..04b59c4d5b 100644
--- a/engines/glk/comprehend/dump_game_data.cpp
+++ b/engines/glk/comprehend/dump_game_data.cpp
@@ -172,11 +172,11 @@ static void dump_functions(ComprehendGame *game)
 	Function *func;
 	uint i, j;
 
-	debugN("Functions (%zd entries)\n", game->_nr_functions);
+	debugN("Functions (%u entries)\n", (uint)game->_nr_functions);
 	for (i = 0; i < game->_nr_functions; i++) {
 		func = &game->_functions[i];
 
-		debugN("[%.4x] (%zd instructions)\n", i, func->nr_instructions);
+		debugN("[%.4x] (%u instructions)\n", i, (uint)func->nr_instructions);
 		for (j = 0; j < func->nr_instructions; j++)
 			dump_instruction(game, NULL, &func->instructions[j]);
 		debugN("\n");
@@ -189,7 +189,7 @@ static void dump_action_table(ComprehendGame *game)
 	Word *word;
 	uint i, j;
 
-	debugN("Action table (%zd entries)\n", game->_nr_actions);
+	debugN("Action table (%u entries)\n", (uint)game->_nr_actions);
 	for (i = 0; i < game->_nr_actions; i++) {
 		action = &game->_actions[i];
 
@@ -253,7 +253,7 @@ static void dump_dictionary(ComprehendGame *game)
 	qsort(dictionary, game->_nr_words, sizeof(*words),
 	      word_index_compare);
 
-	debugN("Dictionary (%zd words)\n", game->_nr_words);
+	debugN("Dictionary (%u words)\n", (uint)game->_nr_words);
 	for (i = 0; i < game->_nr_words; i++) {
 		words = &dictionary[i];
 		debugN("  [%.2x] %.2x %s\n", words->_index, words->_type,
@@ -270,7 +270,7 @@ static void dump_word_map(ComprehendGame *game)
 	WordMap *map;
 	uint i, j;
 
-	debugN("Word pairs (%zd entries)\n", game->_nr_word_maps);
+	debugN("Word pairs (%u entries)\n", (uint)game->_nr_word_maps);
 	for (i = 0; i < game->_nr_word_maps; i++) {
 		map = &game->_wordMaps[i];
 
@@ -296,7 +296,7 @@ static void dump_rooms(ComprehendGame *game)
 	uint i;
 
 	/* Room zero acts as the players inventory */
-	debugN("Rooms (%zd entries)\n", game->_nr_rooms);
+	debugN("Rooms (%u entries)\n", (uint)game->_nr_rooms);
 	for (i = 1; i <= game->_nr_rooms; i++) {
 		room = &game->_rooms[i];
 
@@ -322,7 +322,7 @@ static void dump_items(ComprehendGame *game)
 	Item *item;
 	uint i, j;
 
-	debugN("Items (%zd entries)\n", game->_header.nr_items);
+	debugN("Items (%u entries)\n", (uint)game->_header.nr_items);
 	for (i = 0; i < game->_header.nr_items; i++) {
 		item = &game->_items[i];
 
@@ -358,15 +358,15 @@ static void dump_string_table(StringTable *table)
 
 static void dump_game_data_strings(ComprehendGame *game)
 {
-	debugN("Main string table (%zd entries)\n",
-	       game->_strings.nr_strings);
+	debugN("Main string table (%u entries)\n",
+	       (uint)game->_strings.nr_strings);
 	dump_string_table(&game->_strings);
 }
 
 static void dump_extra_strings(ComprehendGame *game)
 {
-	debugN("Extra strings (%zd entries)\n",
-	       game->_strings2.nr_strings);
+	debugN("Extra strings (%u entries)\n",
+	       (uint)game->_strings2.nr_strings);
 	dump_string_table(&game->_strings2);
 }
 
@@ -374,8 +374,8 @@ static void dump_replace_words(ComprehendGame *game)
 {
 	uint i;
 
-	debugN("Replacement words (%zd entries)\n",
-	       game->_nr_replace_words);
+	debugN("Replacement words (%u entries)\n",
+	       (uint)game->_nr_replace_words);
 	for (i = 0; i < game->_nr_replace_words; i++)
 		debugN("  [%.2x] %s\n", i + 1, game->_replaceWords[i]);
 }
@@ -440,7 +440,7 @@ static Dumper dumpers[] = {
 
 void dump_game_data(ComprehendGame *game, unsigned flags)
 {
-	int i;
+	uint i;
 
 	for (i = 0; i < ARRAY_SIZE(dumpers); i++)
 		if (flags & dumpers[i].flag) {
diff --git a/engines/glk/comprehend/file_buf.cpp b/engines/glk/comprehend/file_buf.cpp
index 28b20b69c4..d22fd2495d 100644
--- a/engines/glk/comprehend/file_buf.cpp
+++ b/engines/glk/comprehend/file_buf.cpp
@@ -64,8 +64,8 @@ bool FileBuffer::seek(int32 offset, int whence) {
 uint32 FileBuffer::read(void *dataPtr, uint32 dataSize) {
 	int32 bytesRead = CLIP((int32)dataSize, 0, (int32)_data.size() - _pos);
 	if (bytesRead) {
-		Common::fill(&_readBytes[_pos], &_readBytes[_pos + bytesRead], true);
-		Common::copy(&_data[_pos], &_data[_pos + bytesRead], (byte *)dataPtr);
+		Common::fill(&_readBytes[_pos], &_readBytes[_pos] + bytesRead, true);
+		Common::copy(&_data[_pos], &_data[_pos] + bytesRead, (byte *)dataPtr);
 		_pos += bytesRead;
 	}
 
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 2022656364..8fed83a1f0 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -890,7 +890,7 @@ static void eval_instruction(ComprehendGame *game,
 			index += 256;
 		if (index >= game->_nr_functions)
 			fatal_error("Bad function %.4x >= %.4x\n",
-			            index, game->_nr_functions);
+			            index, (uint)game->_nr_functions);
 
 		debug_printf(DEBUG_FUNCTIONS,
 		             "Calling subfunction %.4x\n", index);
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 8b0ea5936b..fee2c9b46d 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -51,7 +51,7 @@ void FunctionState::clear() {
 
 void Room::clear() {
 	flags = 0;
-    graphic = 0;
+	graphic = 0;
 	string_desc = 0;
 	Common::fill(&direction[0], &direction[NR_DIRECTIONS], 0);
 }
@@ -60,11 +60,11 @@ void Room::clear() {
 
 void Item::clear() {
 	string_desc = 0;
-    long_string = 0;
-    room = 0;
-    flags = 0;
-    word = 0;
-    graphic = 0;
+	long_string = 0;
+	room = 0;
+	flags = 0;
+	word = 0;
+	graphic = 0;
 }
 
 /*-------------------------------------------------------*/
@@ -75,6 +75,18 @@ void Word::clear() {
 	Common::fill(&_word[0], &_word[7], '\0');
 }
 
+void Word::load(FileBuffer *fb) {
+	fb->read(_word, 6);
+
+	// Decode
+	for (int j = 0; j < 6; j++)
+		_word[j] ^= 0x8a;
+	_word[6] = '\0';
+
+	_index = fb->readByte();
+	_type = fb->readByte();
+}
+
 /*-------------------------------------------------------*/
 
 void WordMap::clear() {
@@ -98,7 +110,7 @@ void Action::clear() {
 void Instruction::clear() {
 	opcode = 0;
 	nr_operands = 0;
-	is_command= false;
+	is_command = false;
 	Common::fill(&operand[0], &operand[3], 0);
 }
 
@@ -113,8 +125,8 @@ void Function::clear() {
 /*-------------------------------------------------------*/
 
 void StringTable::clear() {
-	nr_strings = 0;	
-	Common::fill(&strings[0], &strings[0xffff], nullptr);
+	nr_strings = 0;
+	Common::fill(&strings[0], &strings[0xffff], (char *)nullptr);
 }
 
 /*-------------------------------------------------------*/
@@ -199,7 +211,7 @@ static bool opcode_is_command(uint8 opcode) {
 }
 
 static uint8 parse_vm_instruction(FileBuffer *fb,
-		Instruction *instr) {
+                                  Instruction *instr) {
 	uint i;
 
 	/* Get the opcode */
@@ -215,11 +227,12 @@ static uint8 parse_vm_instruction(FileBuffer *fb,
 	return instr->opcode;
 }
 
-static void parse_function(FileBuffer *fb, Function * func) {
+static void parse_function(FileBuffer *fb, Function *func) {
 	Instruction *instruction;
-	uint8 *p, opcode;
+	const uint8 *p;
+	uint8 opcode;
 
-	p = (uint8 *)memchr(fb->dataPtr(), 0x00, fb->size() - fb->pos());
+	p = (const uint8 *)memchr(fb->dataPtr(), 0x00, fb->size() - fb->pos());
 	if (!p)
 		fatal_error("bad function @ %.4x", fb->pos());
 
@@ -252,7 +265,7 @@ static void parse_vm(ComprehendGame *game, FileBuffer *fb) {
 }
 
 static void parse_action_table_vvnn(ComprehendGame *game,
-	                                FileBuffer *fb, size_t * index) {
+                                    FileBuffer *fb, size_t *index) {
 	Action *action;
 	uint8 verb, count;
 	int i, j;
@@ -296,7 +309,7 @@ static void parse_action_table_vvnn(ComprehendGame *game,
 }
 
 static void parse_action_table_vnjn(ComprehendGame *game,
-	                                FileBuffer *fb, size_t * index) {
+                                    FileBuffer *fb, size_t *index) {
 	Action *action;
 	uint8 join, count;
 	int i;
@@ -341,7 +354,7 @@ static void parse_action_table_vnjn(ComprehendGame *game,
 }
 
 static void parse_action_table_vjn(ComprehendGame *game,
-	                                FileBuffer *fb, size_t * index) {
+                                   FileBuffer *fb, size_t *index) {
 	Action *action;
 	uint8 join, count;
 	int i;
@@ -382,7 +395,7 @@ static void parse_action_table_vjn(ComprehendGame *game,
 }
 
 static void parse_action_table_vdn(ComprehendGame *game,
-	                                FileBuffer *fb, size_t * index) {
+                                   FileBuffer *fb, size_t *index) {
 	Action *action;
 	uint8 verb, count;
 	int i;
@@ -423,7 +436,7 @@ static void parse_action_table_vdn(ComprehendGame *game,
 }
 
 static void parse_action_table_vnn(ComprehendGame *game,
-	                                FileBuffer *fb, size_t * index) {
+                                   FileBuffer *fb, size_t *index) {
 	Action *action;
 	uint8 verb, count;
 	int i;
@@ -465,7 +478,7 @@ static void parse_action_table_vnn(ComprehendGame *game,
 }
 
 static void parse_action_table_vn(ComprehendGame *game,
-	                                FileBuffer *fb, size_t * index) {
+                                  FileBuffer *fb, size_t *index) {
 	Action *action;
 	uint8 verb, count;
 	int i;
@@ -504,7 +517,7 @@ static void parse_action_table_vn(ComprehendGame *game,
 }
 
 static void parse_action_table_v(ComprehendGame *game,
-	                                FileBuffer *fb, size_t * index) {
+                                 FileBuffer *fb, size_t *index) {
 	Action *action;
 	uint8 verb, nr_funcs;
 	uint16 func;
@@ -547,7 +560,7 @@ static void parse_action_table_v(ComprehendGame *game,
 }
 
 static void parse_action_table(ComprehendGame *game,
-	                            FileBuffer *fb) {
+                               FileBuffer *fb) {
 	game->_nr_actions = 0;
 
 	if (game->_comprehendVersion == 1) {
@@ -565,31 +578,19 @@ static void parse_action_table(ComprehendGame *game,
 }
 
 static void parse_dictionary(ComprehendGame *game, FileBuffer *fb) {
-	Word *words;
-	uint i, j;
+	uint i;
 
 	// FIXME - fixed size 0xff array?
-	game->_words = (Word *)xmalloc(game->_nr_words * sizeof(words));
+	game->_words = (Word *)xmalloc(game->_nr_words * sizeof(Word));
 
 	fb->seek(game->_header.addr_dictionary);
-	for (i = 0; i < game->_nr_words; i++) {
-		words = &game->_words[i];
- 
-		fb->read(words->_word, 6);
-
-		/* Decode */
-		for (j = 0; j < 6; j++)
-			words->_word[j] ^= 0x8a;
-		words->_word[6] = '\0';
-
-		words->_index = fb->readByte();
-		words->_type = fb->readByte();
-	}
+	for (i = 0; i < game->_nr_words; i++)
+		game->_words[i].load(fb);
 }
 
 static void parse_word_map(ComprehendGame *game, FileBuffer *fb) {
 	WordMap *map;
-	uint8 index, type, dummy;
+	uint8 index, type;
 	uint i;
 
 	game->_nr_word_maps = 0;
@@ -619,8 +620,7 @@ static void parse_word_map(ComprehendGame *game, FileBuffer *fb) {
 	}
 
 	/* Consume two more null bytes (type and index were also null) */
-	dummy = fb->readByte();
-	dummy = fb->readByte();
+	fb->skip(2);
 
 	/*
 	* Parse the target word table. Each entry has a dictionary
@@ -645,7 +645,7 @@ static void parse_items(ComprehendGame *game, FileBuffer *fb) {
 	if (game->_comprehendVersion == 2) {
 		/* Comprehend version 2 adds long string descriptions */
 		fb->seek(game->_header.addr_item_strings +
-			                        (game->_header.nr_items * sizeof(uint16)));
+		         (game->_header.nr_items * sizeof(uint16)));
 		file_buf_get_array_le16(fb, 0, game->_items, long_string, nr_items);
 	}
 
@@ -674,7 +674,7 @@ static void parse_rooms(ComprehendGame *game, FileBuffer *fb) {
 	for (i = 0; i < NR_DIRECTIONS; i++) {
 		fb->seek(game->_header.room_direction_table[i]);
 		file_buf_get_array_u8(fb, 1, game->_rooms,
-			                    direction[i], nr_rooms);
+		                      direction[i], nr_rooms);
 	}
 
 	/* Room string descriptions */
@@ -690,7 +690,7 @@ static void parse_rooms(ComprehendGame *game, FileBuffer *fb) {
 	file_buf_get_array_u8(fb, 1, game->_rooms, graphic, nr_rooms);
 }
 
-static uint64 string_get_chunk(uint8 * string) {
+static uint64 string_get_chunk(uint8 *string) {
 	uint64 c, val = 0;
 	int i;
 
@@ -772,7 +772,7 @@ static char *parse_string(FileBuffer *fb) {
 				special_next = true;
 			} else {
 				c = decode_string_elem(elem, capital_next,
-					                    special_next);
+				                       special_next);
 				special_next = false;
 				capital_next = false;
 				string[k++] = c;
@@ -788,7 +788,7 @@ done:
 }
 
 static void parse_string_table(FileBuffer *fb, unsigned start_addr,
-	                            uint32 end_addr, StringTable *table) {
+                               uint32 end_addr, StringTable *table) {
 	fb->seek(start_addr);
 	while (1) {
 		table->strings[table->nr_strings++] = parse_string(fb);
@@ -798,14 +798,15 @@ static void parse_string_table(FileBuffer *fb, unsigned start_addr,
 }
 
 static void parse_variables(ComprehendGame *game, FileBuffer *fb) {
-	int i;
+	uint i;
 
 	for (i = 0; i < ARRAY_SIZE(game->_variables); i++)
 		game->_variables[i] = fb->readUint16LE();
 }
 
 static void parse_flags(ComprehendGame *game, FileBuffer *fb) {
-	int i, bit, flag_index = 0;
+	uint i, flag_index = 0;
+	int bit;
 	uint8 bitmask;
 
 	for (i = 0; i < ARRAY_SIZE(game->_flags) / 8; i++) {
@@ -818,8 +819,7 @@ static void parse_flags(ComprehendGame *game, FileBuffer *fb) {
 }
 
 static void parse_replace_words(ComprehendGame *game,
-	                            FileBuffer *fb) {
-	uint16 dummy;
+                                FileBuffer *fb) {
 	size_t len;
 	bool eof;
 	int i;
@@ -828,7 +828,7 @@ static void parse_replace_words(ComprehendGame *game,
 	fb->seek(game->_header.addr_strings_end);
 
 	/* FIXME - what is this for */
-	dummy = fb->readUint16LE();
+	fb->skip(2);
 
 	for (i = 0;; i++) {
 		len = fb->strlen(&eof);
@@ -836,7 +836,7 @@ static void parse_replace_words(ComprehendGame *game,
 			break;
 
 		game->_replaceWords[i] = xstrndup((const char *)fb->dataPtr(), len);
-		fb->read(NULL, len + (eof ? 0 : 1));
+		fb->skip(len + (eof ? 0 : 1));
 		if (eof)
 			break;
 	}
@@ -850,7 +850,6 @@ static void parse_replace_words(ComprehendGame *game,
 static void parse_header(ComprehendGame *game, FileBuffer *fb) {
 	GameHeader *header = &game->_header;
 	uint16 dummy, addr_dictionary_end;
-	uint8 dummy8;
 
 	fb->seek(0);
 	header->magic = fb->readUint16LE();
@@ -933,7 +932,7 @@ static void parse_header(ComprehendGame *game, FileBuffer *fb) {
 		parse_header_le16(fb, &header->addr_item_graphics);
 
 		header->nr_items = (header->addr_item_word -
-			                header->addr_item_flags);
+		                    header->addr_item_flags);
 
 	} else {
 		parse_header_le16(fb, &header->addr_item_strings);
@@ -943,30 +942,30 @@ static void parse_header(ComprehendGame *game, FileBuffer *fb) {
 		parse_header_le16(fb, &header->addr_item_graphics);
 
 		header->nr_items = (header->addr_item_flags -
-			                header->addr_item_locations);
+		                    header->addr_item_locations);
 	}
 
 	parse_header_le16(fb, &header->addr_strings);
 	parse_header_le16(fb, &dummy);
 	parse_header_le16(fb, &header->addr_strings_end);
 
-	dummy8 = fb->readByte();
+	fb->skip(1);
 	game->_startRoom = fb->readByte();
-	dummy8 = fb->readByte();
+	fb->skip(1);
 
 	parse_variables(game, fb);
 	parse_flags(game, fb);
 
 	game->_nr_rooms = header->room_direction_table[DIRECTION_SOUTH] -
-		                    header->room_direction_table[DIRECTION_NORTH];
+	                  header->room_direction_table[DIRECTION_NORTH];
 
 	game->_nr_words = (addr_dictionary_end -
-		                    header->addr_dictionary) /
-		                    8;
+	                   header->addr_dictionary) /
+	                  8;
 }
 
 static void load_extra_string_file(ComprehendGame *game,
-	                                StringFile * string_file) {
+                                   StringFile *string_file) {
 	FileBuffer fb(string_file->filename);
 	unsigned end;
 
@@ -976,11 +975,11 @@ static void load_extra_string_file(ComprehendGame *game,
 		end = fb.size();
 
 	parse_string_table(&fb, string_file->base_offset,
-		                end, &game->_strings2);
+	                   end, &game->_strings2);
 }
 
 static void load_extra_string_files(ComprehendGame *game) {
-	int i;
+	uint i;
 
 	for (i = 0; i < ARRAY_SIZE(game->_stringFiles); i++) {
 		if (!game->_stringFiles[i].filename)
@@ -1006,8 +1005,8 @@ static void load_game_data(ComprehendGame *game) {
 	parse_dictionary(game, &fb);
 	parse_word_map(game, &fb);
 	parse_string_table(&fb, game->_header.addr_strings,
-		                game->_header.addr_strings_end,
-		                &game->_strings);
+	                   game->_header.addr_strings_end,
+	                   &game->_strings);
 	load_extra_string_files(game);
 	parse_vm(game, &fb);
 	parse_action_table(game, &fb);
@@ -1029,7 +1028,7 @@ void comprehend_load_game(ComprehendGame *game) {
 }
 
 #ifdef TODO
-static void patch_string_desc(uint16 * desc) {
+static void patch_string_desc(uint16 *desc) {
 	/*
 	* String descriptors in the save file sometimes are encoded as a
 	* table/index value like the instruction opcodes used, and other
@@ -1053,7 +1052,7 @@ void comprehend_save_game(ComprehendGame *game, const char *filename) {
 	fd = fopen(filename, "w");
 	if (!fd) {
 		printf("Error: Failed to open save file '%s': %s\n",
-			    filename, strerror(errno));
+		       filename, strerror(errno));
 		return;
 	}
 
@@ -1094,10 +1093,10 @@ void comprehend_save_game(ComprehendGame *game, const char *filename) {
 
 	/* Rooms */
 	file_buf_put_array_le16(fd, 1, game->rooms,
-		                    string_desc, nr_rooms);
+	                        string_desc, nr_rooms);
 	for (dir = 0; dir < NR_DIRECTIONS; dir++)
 		file_buf_put_array_u8(fd, 1, game->rooms,
-			                    direction[dir], nr_rooms);
+		                      direction[dir], nr_rooms);
 	file_buf_put_array_u8(fd, 1, game->rooms, flags, nr_rooms);
 	file_buf_put_array_u8(fd, 1, game->rooms, graphic, nr_rooms);
 
@@ -1136,7 +1135,7 @@ void comprehend_restore_game(ComprehendGame *game, const char *filename) {
 	err = file_buf_map_may_fail(filename, &fb);
 	if (err) {
 		printf("Error: Failed to open save file '%s': %s\n",
-			    filename, strerror(-err));
+		       filename, strerror(-err));
 		return;
 	}
 
@@ -1160,10 +1159,10 @@ void comprehend_restore_game(ComprehendGame *game, const char *filename) {
 
 	/* Restore rooms */
 	file_buf_get_array_le16(&fb, 1, game->rooms,
-		                    string_desc, nr_rooms);
+	                        string_desc, nr_rooms);
 	for (dir = 0; dir < NR_DIRECTIONS; dir++)
 		file_buf_get_array_u8(&fb, 1, game->rooms,
-			                    direction[dir], nr_rooms);
+		                      direction[dir], nr_rooms);
 	file_buf_get_array_u8(&fb, 1, game->rooms, flags, nr_rooms);
 	file_buf_get_array_u8(&fb, 1, game->rooms, graphic, nr_rooms);
 
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 95c4c6a028..f8a6e6f0fe 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -40,7 +40,7 @@ enum {
 	DIRECTION_DOWN,
 	DIRECTION_IN,
 	DIRECTION_OUT,
-	NR_DIRECTIONS,
+	NR_DIRECTIONS
 };
 
 struct FunctionState {
@@ -96,6 +96,8 @@ struct Word {
 	}
 
 	void clear();
+
+	void load(FileBuffer *fb);
 };
 
 struct WordIndex {
@@ -225,7 +227,7 @@ struct GameInfo {
 
 	struct Item _items[0xff];
 
-	struct Word *_words;
+	Word *_words;
 	size_t _nr_words;
 
 	struct WordMap _wordMaps[0xff];
@@ -337,7 +339,7 @@ enum {
 	OPCODE_CURRENT_IS_OBJECT,
 	OPCODE_DRAW_ROOM,
 	OPCODE_DRAW_OBJECT,
-	OPCODE_WAIT_KEY,
+	OPCODE_WAIT_KEY
 };
 
 /* Game state update flags */
@@ -355,7 +357,7 @@ enum {
 	ACTION_VERB_DIR_NOUN,
 	ACTION_VERB_NOUN_NOUN,
 	ACTION_VERB_NOUN,
-	ACTION_VERB_OPT_NOUN,
+	ACTION_VERB_OPT_NOUN
 };
 
 /* Standard strings (main string table) */
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 66a9a890b3..fe2c0fb880 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -62,7 +62,7 @@ TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
 
 	_savegameFileFormat = "G%d.MS0";
 	_gameStrings = &tr_strings;
-};
+}
 
 void TransylvaniaGame::update_monster(const TransylvaniaMonster *monster_info) {
 	Item *monster;
diff --git a/engines/glk/comprehend/graphics.cpp b/engines/glk/comprehend/graphics.cpp
index b053aceb5b..7d8937423d 100644
--- a/engines/glk/comprehend/graphics.cpp
+++ b/engines/glk/comprehend/graphics.cpp
@@ -63,7 +63,9 @@ struct GraphicsContext {
 	//	SDL_Surface	*surface;
 };
 
+#ifdef TODO
 static GraphicsContext ctx;
+#endif
 
 unsigned g_set_pen_color(uint8 opcode) {
 	return pen_colors[opcode - IMAGE_OP_PEN_COLOR_A];
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 9a44b21e8d..a256f33ccd 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -260,15 +260,15 @@ void draw_image(ImageData *info, unsigned index)
 	FileBuffer *fb;
 	bool done = false;
 	ImageContext ctx = {
-		0, 0, G_COLOR_BLACK, G_COLOR_BLACK, IMAGE_OP_SHAPE_CIRCLE_LARGE
+		0, 0, G_COLOR_BLACK, G_COLOR_BLACK, IMAGE_OP_SHAPE_CIRCLE_LARGE, 0, 0
 	};
 
 	file_num = index / IMAGES_PER_FILE;
 	fb = &info->fb[file_num];
 
 	if (index >= info->nr_images) {
-		printf("WARNING: Bad image index %.8x (max=%.8zx)\n", index,
-		       info->nr_images);
+		warning("Bad image index %.8x (max=%.8x)\n", index,
+		       (uint)info->nr_images);
 		return;
 	}
 
@@ -309,6 +309,7 @@ static void load_image_file(ImageData *info, const char *filename,
 	int i;
 
 	info->fb[file_num] = FileBuffer(filename);
+	fb = &info->fb[file_num];
 
 	/*
 	 * In earlier versions of Comprehend the first word is 0x1000 and
diff --git a/engines/glk/comprehend/util.cpp b/engines/glk/comprehend/util.cpp
index 5740b69215..2a64d1d0c2 100644
--- a/engines/glk/comprehend/util.cpp
+++ b/engines/glk/comprehend/util.cpp
@@ -64,7 +64,7 @@ void debug_printf(unsigned flags, const char *fmt, ...) {
 
 	if (debug_flags & flags) {
 		va_start(args, fmt);
-		Common::String msg = Common::String(fmt, args);
+		Common::String msg = Common::String::vformat(fmt, args);
 		va_end(args);
 
 		debug(1, "%s", msg.c_str());
diff --git a/engines/glk/comprehend/util.h b/engines/glk/comprehend/util.h
index 947317aa71..335b7b5132 100644
--- a/engines/glk/comprehend/util.h
+++ b/engines/glk/comprehend/util.h
@@ -23,6 +23,8 @@
 #ifndef GLK_COMPREHEND_UTIL_H
 #define GLK_COMPREHEND_UTIL_H
 
+#include "common/scummsys.h"
+
 namespace Glk {
 namespace Comprehend {
 


Commit: fbf8e0a23b15cbb01dcae76ada6609e2a1c1422c
    https://github.com/scummvm/scummvm/commit/fbf8e0a23b15cbb01dcae76ada6609e2a1c1422c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Fix opcode map definition

Changed paths:
    engines/glk/comprehend/dump_game_data.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/opcode_map.cpp
    engines/glk/comprehend/opcode_map.h


diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
index 04b59c4d5b..93ef85fe8f 100644
--- a/engines/glk/comprehend/dump_game_data.cpp
+++ b/engines/glk/comprehend/dump_game_data.cpp
@@ -126,7 +126,7 @@ void dump_instruction(ComprehendGame *game,
 		       func_state->or_count, func_state->_and,
 		       func_state->test_result, func_state->else_result);
 
-	opcode_map = get_opcode_map(game);
+	opcode_map = game->_opcodeMap;
 	opcode = opcode_map[instr->opcode];
 
 	debugN("  [%.2x] ", instr->opcode);
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 8fed83a1f0..ef21951c9b 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -44,11 +44,11 @@ struct WinSize {
 static WinSize console_winsize;
 
 ComprehendGame::ComprehendGame() : _gameName(nullptr),
-                                     _shortName(nullptr),
-                                     _gameDataFile(nullptr),
-                                     _savegameFileFormat(nullptr),
-                                     _colorTable(0),
-                                     _gameStrings(nullptr) {
+                                   _shortName(nullptr),
+                                   _gameDataFile(nullptr),
+                                   _savegameFileFormat(nullptr),
+                                   _colorTable(0),
+                                   _gameStrings(nullptr) {
 }
 
 ComprehendGame::~ComprehendGame() {
@@ -426,7 +426,7 @@ static void eval_instruction(ComprehendGame *game,
                              FunctionState *func_state,
                              Instruction *instr,
                              Word *verb, Word *noun) {
-	uint8 *opcode_map;
+	const byte *opcode_map = game->_opcodeMap;
 	Room *room;
 	Item *item;
 	uint16 index;
@@ -477,7 +477,6 @@ static void eval_instruction(ComprehendGame *game,
 		}
 	}
 
-	opcode_map = get_opcode_map(game);
 	switch (opcode_map[instr->opcode]) {
 	case OPCODE_VAR_ADD:
 		game->_variables[instr->operand[0]] +=
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index ce4689a32a..30d906ccf7 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -25,6 +25,7 @@
 
 #include "common/array.h"
 #include "glk/comprehend/game_data.h"
+#include "glk/comprehend/opcode_map.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -33,7 +34,7 @@ namespace Comprehend {
 #define ROOM_IS_DARK 1
 #define ROOM_IS_TOO_BRIGHT 2
 
-class ComprehendGame : public GameInfo {
+class ComprehendGame : public GameInfo, public OpcodeMap {
 public:
 	const char *_gameName;
 	const char *_shortName;
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index fee2c9b46d..4bc7b42a02 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -875,6 +875,8 @@ static void parse_header(ComprehendGame *game, FileBuffer *fb) {
 		break;
 	}
 
+	game->loadOpcodes(game->_comprehendVersion);
+
 	/* FIXME - Second word in header has unknown usage */
 	parse_header_le16(fb, &dummy);
 
diff --git a/engines/glk/comprehend/opcode_map.cpp b/engines/glk/comprehend/opcode_map.cpp
index 03c59206fe..c327ef63fe 100644
--- a/engines/glk/comprehend/opcode_map.cpp
+++ b/engines/glk/comprehend/opcode_map.cpp
@@ -1,193 +1,169 @@
 /* ScummVM - Graphic Adventure Engine
  *
- * ScummVM is the legal property of its developers, whose names
+ * 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.
+ * of the License; or (at your option) any later version.
  *
- * This program is distributed in the hope that it will be useful,
+ * 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.
+ * along with this program; if not; write to the Free Software
+ * Foundation; Inc.; 51 Franklin Street; Fifth Floor; Boston; MA 02110-1301; USA.
  *
  */
 
-#include "glk/comprehend/comprehend.h"
-#include "glk/comprehend/game.h"
+#include "glk/comprehend/opcode_map.h"
 #include "glk/comprehend/game_data.h"
-#include "glk/comprehend/util.h"
+#include "common/algorithm.h"
+#include "common/textconsole.h"
 
 namespace Glk {
 namespace Comprehend {
 
-/*
- * Version 2 of the Comprehend engine (OO-Topos) changes some of the opcode
- * numbers and adds new opcodes. Use tables to translate the opcodes used
- * in the original games into a generic version used by Re-Comprehend.
- *
- * FIXME - unimplemented/unknown ocpodes:
- *
- * d5(obj): Make object visible. This will print a "you see: object" when the
- *          object is in the room.
- */
-static uint8 opcode_map_v1[0x100] = {
-#ifdef TODO
-	[0x01] = OPCODE_HAVE_OBJECT,
-	[0x04] = OPCODE_OR,
-	[0x05] = OPCODE_IN_ROOM,
-	[0x06] = OPCODE_VAR_EQ,
-	[0x08] = OPCODE_CURRENT_OBJECT_TAKEABLE,
-	[0x09] = OPCODE_OBJECT_PRESENT,
-	[0x0c] = OPCODE_ELSE,
-	[0x0e] = OPCODE_OBJECT_IN_ROOM,
-	[0x14] = OPCODE_OBJECT_NOT_VALID,
-	[0x18] = OPCODE_INVENTORY_FULL,
-	[0x19] = OPCODE_TEST_FLAG,
-	[0x1d] = OPCODE_CURRENT_OBJECT_IN_ROOM,
-	[0x20] = OPCODE_HAVE_CURRENT_OBJECT,
-	[0x21] = OPCODE_OBJECT_IS_NOT_NOWHERE,
-	[0x24] = OPCODE_CURRENT_OBJECT_PRESENT,
-	[0x31] = OPCODE_TEST_ROOM_FLAG,
-	[0x41] = OPCODE_NOT_HAVE_OBJECT,
-	[0x45] = OPCODE_NOT_IN_ROOM,
-	[0x48] = OPCODE_CURRENT_OBJECT_IS_NOWHERE,
-	[0x49] = OPCODE_OBJECT_NOT_PRESENT,
-	[0x43] = OPCODE_OBJECT_NOT_IN_ROOM,
-	[0x50] = OPCODE_TEST_FALSE,
-	[0x59] = OPCODE_TEST_NOT_FLAG,
-	[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT,
-	[0x61] = OPCODE_OBJECT_IS_NOWHERE,
-	[0x64] = OPCODE_CURRENT_OBJECT_NOT_PRESENT,
-	[0x68] = OPCODE_CURRENT_OBJECT_NOT_TAKEABLE,
-	[0x71] = OPCODE_TEST_NOT_ROOM_FLAG,
-	[0x80] = OPCODE_INVENTORY,
-	[0x81] = OPCODE_TAKE_OBJECT,
-	[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM,
-	[0x84] = OPCODE_SAVE_ACTION,
-	[0x85] = OPCODE_MOVE_TO_ROOM,
-	[0x86] = OPCODE_VAR_ADD,
-	[0x87] = OPCODE_SET_ROOM_DESCRIPTION,
-	[0x89] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM,
-	[0x8a] = OPCODE_VAR_SUB,
-	[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION,
-	[0x8c] = OPCODE_MOVE,
-	[0x8e] = OPCODE_PRINT,
-	[0x95] = OPCODE_REMOVE_OBJECT,
-	[0x99] = OPCODE_SET_FLAG,
-	[0x92] = OPCODE_CALL_FUNC,
-	[0x98] = OPCODE_TURN_TICK,
-	[0x9d] = OPCODE_CLEAR_FLAG,
-	[0x9e] = OPCODE_INVENTORY_ROOM,
-	[0xa0] = OPCODE_TAKE_CURRENT_OBJECT,
-	[0xa1] = OPCODE_SPECIAL,
-	[0xa4] = OPCODE_DROP_CURRENT_OBJECT,
-	[0xa2] = OPCODE_SET_ROOM_GRAPHIC,
-	[0xb0] = OPCODE_REMOVE_CURRENT_OBJECT,
-	[0xb1] = OPCODE_DO_VERB,
-	[0xb9] = OPCODE_SET_STRING_REPLACEMENT,
-	[0xbd] = OPCODE_VAR_INC,
-	[0xc1] = OPCODE_VAR_DEC,
-	[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM
-#else
-	0
-	#endif
-};
+void OpcodeMap::loadOpcodes(int version) {
+	Common::fill(&_opcodeMap[0], &_opcodeMap[0x100], 0);
 
-static uint8 opcode_map_v2[0x100] = {
-#ifdef TODO
-	[0x01] = OPCODE_HAVE_OBJECT,
-	[0x04] = OPCODE_OR,
-	[0x05] = OPCODE_IN_ROOM,
-	[0x06] = OPCODE_VAR_EQ,
-	[0x08] = OPCODE_CURRENT_IS_OBJECT,
-	[0x09] = OPCODE_OBJECT_PRESENT,
-	[0x0c] = OPCODE_ELSE,
-	[0x11] = OPCODE_OBJECT_IS_NOWHERE,
-	[0x14] = OPCODE_OBJECT_NOT_VALID,
-	[0x19] = OPCODE_TEST_FLAG,
-	[0x1d] = OPCODE_TEST_ROOM_FLAG,
-	[0x20] = OPCODE_HAVE_CURRENT_OBJECT,
-	[0x21] = OPCODE_OBJECT_PRESENT,
-	[0x22] = OPCODE_OBJECT_IN_ROOM,
-	[0x30] = OPCODE_CURRENT_OBJECT_PRESENT,
-	[0x31] = OPCODE_TEST_ROOM_FLAG,
-	[0x38] = OPCODE_INVENTORY_FULL,
-	[0x41] = OPCODE_NOT_HAVE_OBJECT,
-	[0x45] = OPCODE_NOT_IN_ROOM,
-	[0x48] = OPCODE_CURRENT_OBJECT_IS_NOWHERE,
-	[0x43] = OPCODE_OBJECT_NOT_IN_ROOM,
-	[0x59] = OPCODE_TEST_NOT_FLAG,
-	[0x5d] = OPCODE_TEST_NOT_ROOM_FLAG,
-	[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT,
-	[0x61] = OPCODE_OBJECT_NOT_PRESENT,
-	[0x70] = OPCODE_CURRENT_OBJECT_NOT_PRESENT,
-	[0x74] = OPCODE_CURRENT_NOT_OBJECT,
-	[0x80] = OPCODE_INVENTORY,
-	[0x81] = OPCODE_TAKE_OBJECT,
-	[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM,
-	[0x84] = OPCODE_SAVE_ACTION,
-	[0x85] = OPCODE_MOVE_TO_ROOM,
-	[0x86] = OPCODE_VAR_ADD,
-	[0x87] = OPCODE_SET_ROOM_DESCRIPTION,
-	[0x89] = OPCODE_SPECIAL,
-	[0x8a] = OPCODE_VAR_SUB,
-	[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION,
-	[0x8c] = OPCODE_MOVE,
-	[0x8e] = OPCODE_PRINT,
-	[0x8f] = OPCODE_SET_OBJECT_LONG_DESCRIPTION,
-	[0x90] = OPCODE_WAIT_KEY,
-	[0x92] = OPCODE_CALL_FUNC,
-	[0x95] = OPCODE_REMOVE_OBJECT,
-	[0x98] = OPCODE_TURN_TICK,
-	[0x99] = OPCODE_SET_FLAG,
-	[0x9d] = OPCODE_CLEAR_FLAG,
-	[0x9e] = OPCODE_INVENTORY_ROOM,
-	[0xa0] = OPCODE_TAKE_CURRENT_OBJECT,
-	[0xa2] = OPCODE_SET_OBJECT_GRAPHIC,
-	[0xb1] = OPCODE_DO_VERB,
-	[0xb5] = OPCODE_DESCRIBE_CURRENT_OBJECT,
-	[0xc1] = OPCODE_VAR_DEC,
-	[0xc2] = OPCODE_SET_ROOM_GRAPHIC,
-	[0xc5] = OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT,
-	[0xc6] = OPCODE_SET_OBJECT_GRAPHIC,
-	[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM,
-	[0xcd] = OPCODE_SET_STRING_REPLACEMENT,
-	[0xd1] = OPCODE_MOVE_DIRECTION,
-	[0xd5] = OPCODE_DRAW_ROOM,
-	[0xd9] = OPCODE_DRAW_OBJECT,
-	[0xdd] = OPCODE_VAR_INC,
-	[0xe1] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM,
-	[0xed] = OPCODE_REMOVE_OBJECT,
-	[0xf0] = OPCODE_DROP_CURRENT_OBJECT,
-	[0xfc] = OPCODE_REMOVE_CURRENT_OBJECT
-#else
-	0
-	#endif
-};
+	if (version == 1)
+		loadVersion1();
+	else if (version == 2)
+		loadVersion2();
+	else
+		error("Invalid version");
+}
 
-uint8 *get_opcode_map(ComprehendGame *game)
-{
-	switch (game->_comprehendVersion) {
-	case 1:
-		return opcode_map_v1;
-		break;
-	case 2:
-		return opcode_map_v2;
-	default:
-		fatal_error("Unsupported Comprehend version %d\n",
-			    game->_comprehendVersion);
+void OpcodeMap::loadVersion1() {
+	_opcodeMap[0x01] = OPCODE_HAVE_OBJECT;
+	_opcodeMap[0x04] = OPCODE_OR;
+	_opcodeMap[0x05] = OPCODE_IN_ROOM;
+	_opcodeMap[0x06] = OPCODE_VAR_EQ;
+	_opcodeMap[0x08] = OPCODE_CURRENT_OBJECT_TAKEABLE;
+	_opcodeMap[0x09] = OPCODE_OBJECT_PRESENT;
+	_opcodeMap[0x0c] = OPCODE_ELSE;
+	_opcodeMap[0x0e] = OPCODE_OBJECT_IN_ROOM;
+	_opcodeMap[0x14] = OPCODE_OBJECT_NOT_VALID;
+	_opcodeMap[0x18] = OPCODE_INVENTORY_FULL;
+	_opcodeMap[0x19] = OPCODE_TEST_FLAG;
+	_opcodeMap[0x1d] = OPCODE_CURRENT_OBJECT_IN_ROOM;
+	_opcodeMap[0x20] = OPCODE_HAVE_CURRENT_OBJECT;
+	_opcodeMap[0x21] = OPCODE_OBJECT_IS_NOT_NOWHERE;
+	_opcodeMap[0x24] = OPCODE_CURRENT_OBJECT_PRESENT;
+	_opcodeMap[0x31] = OPCODE_TEST_ROOM_FLAG;
+	_opcodeMap[0x41] = OPCODE_NOT_HAVE_OBJECT;
+	_opcodeMap[0x45] = OPCODE_NOT_IN_ROOM;
+	_opcodeMap[0x48] = OPCODE_CURRENT_OBJECT_IS_NOWHERE;
+	_opcodeMap[0x49] = OPCODE_OBJECT_NOT_PRESENT;
+	_opcodeMap[0x43] = OPCODE_OBJECT_NOT_IN_ROOM;
+	_opcodeMap[0x50] = OPCODE_TEST_FALSE;
+	_opcodeMap[0x59] = OPCODE_TEST_NOT_FLAG;
+	_opcodeMap[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT;
+	_opcodeMap[0x61] = OPCODE_OBJECT_IS_NOWHERE;
+	_opcodeMap[0x64] = OPCODE_CURRENT_OBJECT_NOT_PRESENT;
+	_opcodeMap[0x68] = OPCODE_CURRENT_OBJECT_NOT_TAKEABLE;
+	_opcodeMap[0x71] = OPCODE_TEST_NOT_ROOM_FLAG;
+	_opcodeMap[0x80] = OPCODE_INVENTORY;
+	_opcodeMap[0x81] = OPCODE_TAKE_OBJECT;
+	_opcodeMap[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM;
+	_opcodeMap[0x84] = OPCODE_SAVE_ACTION;
+	_opcodeMap[0x85] = OPCODE_MOVE_TO_ROOM;
+	_opcodeMap[0x86] = OPCODE_VAR_ADD;
+	_opcodeMap[0x87] = OPCODE_SET_ROOM_DESCRIPTION;
+	_opcodeMap[0x89] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM;
+	_opcodeMap[0x8a] = OPCODE_VAR_SUB;
+	_opcodeMap[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION;
+	_opcodeMap[0x8c] = OPCODE_MOVE;
+	_opcodeMap[0x8e] = OPCODE_PRINT;
+	_opcodeMap[0x95] = OPCODE_REMOVE_OBJECT;
+	_opcodeMap[0x99] = OPCODE_SET_FLAG;
+	_opcodeMap[0x92] = OPCODE_CALL_FUNC;
+	_opcodeMap[0x98] = OPCODE_TURN_TICK;
+	_opcodeMap[0x9d] = OPCODE_CLEAR_FLAG;
+	_opcodeMap[0x9e] = OPCODE_INVENTORY_ROOM;
+	_opcodeMap[0xa0] = OPCODE_TAKE_CURRENT_OBJECT;
+	_opcodeMap[0xa1] = OPCODE_SPECIAL;
+	_opcodeMap[0xa4] = OPCODE_DROP_CURRENT_OBJECT;
+	_opcodeMap[0xa2] = OPCODE_SET_ROOM_GRAPHIC;
+	_opcodeMap[0xb0] = OPCODE_REMOVE_CURRENT_OBJECT;
+	_opcodeMap[0xb1] = OPCODE_DO_VERB;
+	_opcodeMap[0xb9] = OPCODE_SET_STRING_REPLACEMENT;
+	_opcodeMap[0xbd] = OPCODE_VAR_INC;
+	_opcodeMap[0xc1] = OPCODE_VAR_DEC;
+	_opcodeMap[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM;
+}
 
-		/* Not reached */
-		return NULL;
-	}
+void OpcodeMap::loadVersion2() {
+	_opcodeMap[0x01] = OPCODE_HAVE_OBJECT;
+	_opcodeMap[0x04] = OPCODE_OR;
+	_opcodeMap[0x05] = OPCODE_IN_ROOM;
+	_opcodeMap[0x06] = OPCODE_VAR_EQ;
+	_opcodeMap[0x08] = OPCODE_CURRENT_IS_OBJECT;
+	_opcodeMap[0x09] = OPCODE_OBJECT_PRESENT;
+	_opcodeMap[0x0c] = OPCODE_ELSE;
+	_opcodeMap[0x11] = OPCODE_OBJECT_IS_NOWHERE;
+	_opcodeMap[0x14] = OPCODE_OBJECT_NOT_VALID;
+	_opcodeMap[0x19] = OPCODE_TEST_FLAG;
+	_opcodeMap[0x1d] = OPCODE_TEST_ROOM_FLAG;
+	_opcodeMap[0x20] = OPCODE_HAVE_CURRENT_OBJECT;
+	_opcodeMap[0x21] = OPCODE_OBJECT_PRESENT;
+	_opcodeMap[0x22] = OPCODE_OBJECT_IN_ROOM;
+	_opcodeMap[0x30] = OPCODE_CURRENT_OBJECT_PRESENT;
+	_opcodeMap[0x31] = OPCODE_TEST_ROOM_FLAG;
+	_opcodeMap[0x38] = OPCODE_INVENTORY_FULL;
+	_opcodeMap[0x41] = OPCODE_NOT_HAVE_OBJECT;
+	_opcodeMap[0x45] = OPCODE_NOT_IN_ROOM;
+	_opcodeMap[0x48] = OPCODE_CURRENT_OBJECT_IS_NOWHERE;
+	_opcodeMap[0x43] = OPCODE_OBJECT_NOT_IN_ROOM;
+	_opcodeMap[0x59] = OPCODE_TEST_NOT_FLAG;
+	_opcodeMap[0x5d] = OPCODE_TEST_NOT_ROOM_FLAG;
+	_opcodeMap[0x60] = OPCODE_NOT_HAVE_CURRENT_OBJECT;
+	_opcodeMap[0x61] = OPCODE_OBJECT_NOT_PRESENT;
+	_opcodeMap[0x70] = OPCODE_CURRENT_OBJECT_NOT_PRESENT;
+	_opcodeMap[0x74] = OPCODE_CURRENT_NOT_OBJECT;
+	_opcodeMap[0x80] = OPCODE_INVENTORY;
+	_opcodeMap[0x81] = OPCODE_TAKE_OBJECT;
+	_opcodeMap[0x82] = OPCODE_MOVE_OBJECT_TO_ROOM;
+	_opcodeMap[0x84] = OPCODE_SAVE_ACTION;
+	_opcodeMap[0x85] = OPCODE_MOVE_TO_ROOM;
+	_opcodeMap[0x86] = OPCODE_VAR_ADD;
+	_opcodeMap[0x87] = OPCODE_SET_ROOM_DESCRIPTION;
+	_opcodeMap[0x89] = OPCODE_SPECIAL;
+	_opcodeMap[0x8a] = OPCODE_VAR_SUB;
+	_opcodeMap[0x8b] = OPCODE_SET_OBJECT_DESCRIPTION;
+	_opcodeMap[0x8c] = OPCODE_MOVE;
+	_opcodeMap[0x8e] = OPCODE_PRINT;
+	_opcodeMap[0x8f] = OPCODE_SET_OBJECT_LONG_DESCRIPTION;
+	_opcodeMap[0x90] = OPCODE_WAIT_KEY;
+	_opcodeMap[0x92] = OPCODE_CALL_FUNC;
+	_opcodeMap[0x95] = OPCODE_REMOVE_OBJECT;
+	_opcodeMap[0x98] = OPCODE_TURN_TICK;
+	_opcodeMap[0x99] = OPCODE_SET_FLAG;
+	_opcodeMap[0x9d] = OPCODE_CLEAR_FLAG;
+	_opcodeMap[0x9e] = OPCODE_INVENTORY_ROOM;
+	_opcodeMap[0xa0] = OPCODE_TAKE_CURRENT_OBJECT;
+	_opcodeMap[0xa2] = OPCODE_SET_OBJECT_GRAPHIC;
+	_opcodeMap[0xb1] = OPCODE_DO_VERB;
+	_opcodeMap[0xb5] = OPCODE_DESCRIBE_CURRENT_OBJECT;
+	_opcodeMap[0xc1] = OPCODE_VAR_DEC;
+	_opcodeMap[0xc2] = OPCODE_SET_ROOM_GRAPHIC;
+	_opcodeMap[0xc5] = OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT;
+	_opcodeMap[0xc6] = OPCODE_SET_OBJECT_GRAPHIC;
+	_opcodeMap[0xc9] = OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM;
+	_opcodeMap[0xcd] = OPCODE_SET_STRING_REPLACEMENT;
+	_opcodeMap[0xd1] = OPCODE_MOVE_DIRECTION;
+	_opcodeMap[0xd5] = OPCODE_DRAW_ROOM;
+	_opcodeMap[0xd9] = OPCODE_DRAW_OBJECT;
+	_opcodeMap[0xdd] = OPCODE_VAR_INC;
+	_opcodeMap[0xe1] = OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM;
+	_opcodeMap[0xed] = OPCODE_REMOVE_OBJECT;
+	_opcodeMap[0xf0] = OPCODE_DROP_CURRENT_OBJECT;
+	_opcodeMap[0xfc] = OPCODE_REMOVE_CURRENT_OBJECT;
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/opcode_map.h b/engines/glk/comprehend/opcode_map.h
index 102a88dee6..909183ddb6 100644
--- a/engines/glk/comprehend/opcode_map.h
+++ b/engines/glk/comprehend/opcode_map.h
@@ -23,12 +23,32 @@
 #ifndef GLK_COMPREHEND_OPCODE_MAP_H
 #define GLK_COMPREHEND_OPCODE_MAP_H
 
-#include "glk/comprehend/game.h"
+#include "common/scummsys.h"
 
 namespace Glk {
 namespace Comprehend {
 
-uint8 *get_opcode_map(ComprehendGame *game);
+/*
+ * Version 2 of the Comprehend engine (OO-Topos) changes some of the opcode
+ * numbers and adds new opcodes. This class encapsulates a table to translate
+ * the opcodes used in the original games into a generic version used by the engine
+ *
+ * FIXME - unimplemented/unknown ocpodes:
+ *
+ * d5(obj): Make object visible. This will print a "you see: object" when the
+ *          object is in the room.
+ */
+class OpcodeMap {
+public:
+	byte _opcodeMap[0x100];
+
+private:
+	void loadVersion1();
+	void loadVersion2();
+
+public:
+	void loadOpcodes(int version);
+};
 
 } // namespace Comprehend
 } // namespace Glk


Commit: e55aaa91da4a17d64801b30e604ac809dc598959
    https://github.com/scummvm/scummvm/commit/e55aaa91da4a17d64801b30e604ac809dc598959
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Adding method to print text to text buffer

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 6b0c68507b..0ca0a020f1 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -167,6 +167,7 @@ void Comprehend::initialize() {
 	_graphicsWindow = (GraphicsWindow *)glk_window_open(
 	    _textBufferWindow, winmethod_Above | winmethod_Proportional,
 	    160, wintype_Graphics, 0);
+	glk_set_window(_textBufferWindow);
 }
 
 void Comprehend::deinitialize() {
@@ -187,5 +188,15 @@ ComprehendGame *Comprehend::createGame() {
 	error("Unknown game");
 }
 
+void Comprehend::print(const char *fmt, ...) {
+	va_list argp;
+	va_start(argp, fmt);
+	Common::String msg = Common::String::vformat(fmt, argp);
+	va_end(argp);
+
+	glk_put_string_stream(glk_window_get_stream(_textBufferWindow),
+		msg.c_str());
+}
+
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index c961438d72..607d80d634 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -102,6 +102,8 @@ public:
 	Common::Error writeGameData(Common::WriteStream *ws) override {
 		return Common::kWritingFailed;
 	}
+
+	void print(const char *fmt, ...);
 };
 
 extern Comprehend *g_comprehend;
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index ef21951c9b..7b75567d01 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -38,11 +38,6 @@ struct Sentence {
 	size_t nr_words;
 };
 
-struct WinSize {
-	uint ws_col;
-};
-static WinSize console_winsize;
-
 ComprehendGame::ComprehendGame() : _gameName(nullptr),
                                    _shortName(nullptr),
                                    _gameDataFile(nullptr),
@@ -73,7 +68,6 @@ int console_get_key(void) {
 void console_println(ComprehendGame *game, const char *text) {
 	const char *replace, *word = nullptr, *p = text;
 	char bad_word[64];
-	size_t line_length = 0;
 	int word_len = 0;
 
 	if (!text) {
@@ -86,7 +80,6 @@ void console_println(ComprehendGame *game, const char *text) {
 		case '\n':
 			word = NULL;
 			word_len = 0;
-			line_length = 0;
 			printf("\n");
 			p++;
 			break;
@@ -126,26 +119,19 @@ void console_println(ComprehendGame *game, const char *text) {
 
 		if (!word || !word_len)
 			continue;
-
+#ifdef DEPRECATED
 		/* Print this word */
 		if (line_length + word_len > console_winsize.ws_col) {
 			/* Too long - insert a line break */
 			printf("\n");
 			line_length = 0;
 		}
-
-		printf("%.*s", word_len, word);
-		line_length += word_len;
+#endif
+		Common::String wordStr(word, word_len);
+		g_comprehend->print("%s", wordStr.c_str());
 
 		if (*p == ' ') {
-			if (line_length >= console_winsize.ws_col) {
-				/* Newline, don't print the space */
-				printf("\n");
-				line_length = 0;
-			} else {
-				printf(" ");
-				line_length++;
-			}
+			g_comprehend->print(" ");
 			p++;
 
 			/* Skip any double spaces */
@@ -154,7 +140,7 @@ void console_println(ComprehendGame *game, const char *text) {
 		}
 	}
 
-	printf("\n");
+	g_comprehend->print("\n");
 }
 
 static Room *get_room(ComprehendGame *game, uint16 index) {


Commit: 51ff674d99df013a4891ce9d733d7605c240331d
    https://github.com/scummvm/scummvm/commit/51ff674d99df013a4891ce9d733d7605c240331d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Adding method for reading text

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game_tr.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 0ca0a020f1..dccfc5a969 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -163,16 +163,16 @@ void Comprehend::runGame() {
 }
 
 void Comprehend::initialize() {
-	_textBufferWindow = (TextBufferWindow *)glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
-	_graphicsWindow = (GraphicsWindow *)glk_window_open(
-	    _textBufferWindow, winmethod_Above | winmethod_Proportional,
-	    160, wintype_Graphics, 0);
-	glk_set_window(_textBufferWindow);
+	_topWindow = (GraphicsWindow *)glk_window_open(0, 0, 0, wintype_Graphics, 1);
+	_bottomWindow = (TextBufferWindow *)glk_window_open(
+	    _topWindow, winmethod_Below | winmethod_Fixed,
+	    80, wintype_TextBuffer, 0);
+	glk_set_window(_bottomWindow);
 }
 
 void Comprehend::deinitialize() {
-	glk_window_close(_graphicsWindow);
-	glk_window_close(_textBufferWindow);
+	glk_window_close(_topWindow);
+	glk_window_close(_bottomWindow);
 }
 
 ComprehendGame *Comprehend::createGame() {
@@ -194,9 +194,27 @@ void Comprehend::print(const char *fmt, ...) {
 	Common::String msg = Common::String::vformat(fmt, argp);
 	va_end(argp);
 
-	glk_put_string_stream(glk_window_get_stream(_textBufferWindow),
+	glk_put_string_stream(glk_window_get_stream(_bottomWindow),
 		msg.c_str());
 }
 
+void Comprehend::readLine(char *buffer, size_t maxLen) {
+	event_t ev;
+
+	glk_request_line_event(_bottomWindow, buffer, maxLen - 1, 0);
+
+	for (;;) {
+		glk_select(&ev);
+		if (ev.type == evtype_Quit) {
+			glk_cancel_line_event(_bottomWindow, &ev);
+			return;
+		} else if (ev.type == evtype_LineInput)
+			break;
+	}
+
+	buffer[ev.val1] = 0;
+}
+
+
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 607d80d634..3e76f07bc8 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -55,8 +55,8 @@ class Comprehend : public GlkAPI {
 private:
 	int _saveSlot;		 ///< Save slot when loading savegame from launcher
 public:
-	GraphicsWindow *_graphicsWindow;
-	TextBufferWindow *_textBufferWindow;
+	GraphicsWindow *_topWindow;
+	TextBufferWindow *_bottomWindow;
 private:
 	/**
 	 * Initialization code
@@ -103,7 +103,15 @@ public:
 		return Common::kWritingFailed;
 	}
 
+	/**
+	 * Print string to the buffer window
+	 */
 	void print(const char *fmt, ...);
+
+	/**
+	 * Read an input line
+	 */
+	void readLine(char *buffer, size_t maxLen);
 };
 
 extern Comprehend *g_comprehend;
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index fe2c0fb880..b014d9dec6 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -158,29 +158,12 @@ void TransylvaniaGame::handle_special_opcode(uint8 operand)
 	}
 }
 
-static void read_string(char *buffer, size_t size)
-{
-#ifdef TODO
-	char *p;
-
-	printf("> ");
-	fgets(buffer, size, stdin);
-
-	/* Remove trailing newline */
-	p = strchr(buffer, '\n');
-	if (p)
-		*p = '\0';
-#else
-	error("TODO");
-#endif
-}
-
 void TransylvaniaGame::before_game() {
 	char buffer[128];
 
-	/* Welcome to Transylvania - sign your name */
+	// Welcome to Transylvania - sign your name
 	console_println(this, _strings.strings[0x20]);
-	read_string(buffer, sizeof(buffer));
+	g_comprehend->readLine(buffer, sizeof(buffer));
 
 	/*
 	 * Transylvania uses replace word 0 as the player's name, the game
@@ -195,9 +178,9 @@ void TransylvaniaGame::before_game() {
 			 strlen(_replaceWords[0]),
 			 "%s", buffer);
 
-	/* And your next of kin - This isn't store by the game */
+	// And your next of kin - This isn't stored by the game
 	console_println(this, _strings.strings[0x21]);
-	read_string(buffer, sizeof(buffer));
+	g_comprehend->readLine(buffer, sizeof(buffer));
 }
 
 } // namespace Comprehend


Commit: 7a88a18d472d38b3e52d3892e17ded8cbf4bcf72
    https://github.com/scummvm/scummvm/commit/7a88a18d472d38b3e52d3892e17ded8cbf4bcf72
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Implement action line input

Changed paths:
    engines/glk/comprehend/game.cpp


diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 7b75567d01..14b1e42d5e 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -998,13 +998,12 @@ static void skip_non_whitespace(char **p) {
 		(*p)++;
 }
 
-#ifdef TODO
 static void handle_debug_command(ComprehendGame *game,
                                  const char *line) {
 	int i;
 
 	if (strncmp(line, "quit", 4) == 0) {
-		error("Quit");
+		g_comprehend->quitGame();
 
 	} else if (strncmp(line, "debug", 5) == 0) {
 		if (debugging_enabled())
@@ -1020,25 +1019,24 @@ static void handle_debug_command(ComprehendGame *game,
 		dump_game_data(game, DUMP_ROOMS);
 
 	} else if (strncmp(line, "dump state", 10) == 0) {
-		printf("Current room: %.2x\n", game->current_room);
+		printf("Current room: %.2x\n", game->_currentRoom);
 		printf("Carry weight %d/%d\n\n",
-		       game->variable[VAR_INVENTORY_WEIGHT],
-		       game->variable[VAR_INVENTORY_LIMIT]);
+		       game->_variables[VAR_INVENTORY_WEIGHT],
+		       game->_variables[VAR_INVENTORY_LIMIT]);
 
 		printf("Flags:\n");
-		for (i = 0; i < ARRAY_SIZE(game->flags); i++)
-			printf("  [%.2x]: %d\n", i, game->flags[i]);
+		for (i = 0; i < ARRAY_SIZE(game->_flags); i++)
+			printf("  [%.2x]: %d\n", i, game->_flags[i]);
 		printf("\n");
 
 		printf("Variables:\n");
-		for (i = 0; i < ARRAY_SIZE(game->variable); i++)
+		for (i = 0; i < ARRAY_SIZE(game->_variables); i++)
 			printf("  [%.2x]: %5d (0x%.4x)\n",
-			       i, game->variable[i],
-			       game->variable[i]);
+			       i, game->_variables[i],
+			       game->_variables[i]);
 		printf("\n");
 	}
 }
-#endif
 
 static bool handle_sentence(ComprehendGame *game,
                             Sentence *sentence) {
@@ -1162,21 +1160,20 @@ static void after_turn(ComprehendGame *game) {
 }
 
 static void read_input(ComprehendGame *game) {
-#ifdef TODO
-	sentence sentence;
+	Sentence sentence;
 	char *line = NULL, buffer[1024];
 	bool handled;
 
-	if (game->ops->before_prompt)
-		game->ops->before_prompt(game);
+	game->before_prompt();
 	before_turn(game);
 
-	while (!line) {
-		printf("> ");
-		line = fgets(buffer, sizeof(buffer), stdin);
-	}
+	g_comprehend->print("> ");
+	g_comprehend->readLine(buffer, sizeof(buffer));
+	if (g_comprehend->shouldQuit())
+		return;
 
 	// Re-comprehend special commands start with '!'
+	line = &buffer[0];
 	if (*line == '!') {
 		handle_debug_command(game, &line[1]);
 		return;
@@ -1196,9 +1193,6 @@ static void read_input(ComprehendGame *game) {
 		if (handled)
 			before_turn(game);
 	}
-#else
-	error("TODO: read_input");
-#endif
 }
 
 void comprehend_play_game(ComprehendGame *game) {


Commit: 21462c57f67fbcb2ea47e5f8784d88e1e5be7f07
    https://github.com/scummvm/scummvm/commit/21462c57f67fbcb2ea47e5f8784d88e1e5be7f07
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:09-07:00

Commit Message:
GLK: COMPREHEND: Creating debugger to hold dumping methods

Changed paths:
  A engines/glk/comprehend/debugger.cpp
  A engines/glk/comprehend/debugger.h
  A engines/glk/comprehend/debugger_dumper.cpp
  A engines/glk/comprehend/debugger_dumper.h
  R engines/glk/comprehend/dump_game_data.cpp
  R engines/glk/comprehend/dump_game_data.h
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/util.cpp
    engines/glk/comprehend/util.h
    engines/glk/glk.cpp
    engines/glk/glk.h
    engines/glk/module.mk


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index dccfc5a969..0ead807108 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -23,7 +23,7 @@
 #include "glk/comprehend/comprehend.h"
 #include "common/config-manager.h"
 #include "common/translation.h"
-#include "glk/comprehend/dump_game_data.h"
+#include "glk/comprehend/debugger.h"
 #include "glk/comprehend/game.h"
 #include "glk/comprehend/game_cc.h"
 #include "glk/comprehend/game_data.h"
@@ -37,25 +37,6 @@ namespace Comprehend {
 
 Comprehend *g_comprehend;
 
-struct DumpOption {
-	const char *const option;
-	unsigned flag;
-};
-
-static const DumpOption dump_options[] = {
-    {"strings", DUMP_STRINGS},
-    {"extra-strings", DUMP_EXTRA_STRINGS},
-    {"rooms", DUMP_ROOMS},
-    {"items", DUMP_ITEMS},
-    {"dictionary", DUMP_DICTIONARY},
-    {"word-pairs", DUMP_WORD_PAIRS},
-    {"actions", DUMP_ACTIONS},
-    {"functions", DUMP_FUNCTIONS},
-    {"replace-words", DUMP_REPLACE_WORDS},
-    {"header", DUMP_HEADER},
-    {"all", DUMP_ALL},
-};
-
 #ifdef TODO
 int main(int argc, char **argv) {
 	option long_opts[] = {
@@ -140,12 +121,14 @@ int main(int argc, char **argv) {
 }
 #endif
 
-Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc),
-                                                                            _saveSlot(-1) {
+Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) :
+		GlkAPI(syst, gameDesc), _saveSlot(-1), _game(nullptr) {
 	g_comprehend = this;
 }
 
 Comprehend::~Comprehend() {
+	delete _game;
+
 	g_comprehend = nullptr;
 }
 
@@ -153,12 +136,11 @@ void Comprehend::runGame() {
 	initialize();
 
 	// Lookup game
-	ComprehendGame *game = createGame();
+	createGame();
 
-	comprehend_load_game(game);
-	comprehend_play_game(game);
+	comprehend_load_game(_game);
+	comprehend_play_game(_game);
 
-	delete game;
 	deinitialize();
 }
 
@@ -175,17 +157,21 @@ void Comprehend::deinitialize() {
 	glk_window_close(_bottomWindow);
 }
 
-ComprehendGame *Comprehend::createGame() {
+void Comprehend::createDebugger() {
+	setDebugger(new Debugger());
+}
+
+void Comprehend::createGame() {
 	if (_gameDescription._gameId == "crimsoncrown")
-		return new CrimsonCrownGame();
+		_game = new CrimsonCrownGame();
 	if (_gameDescription._gameId == "ootopis")
-		return new OOToposGame();
+		_game = new OOToposGame();
 	if (_gameDescription._gameId == "talisman")
-		return new OOToposGame();
+		_game = new OOToposGame();
 	if (_gameDescription._gameId == "transylvania")
-		return new TransylvaniaGame();
-
-	error("Unknown game");
+		_game = new TransylvaniaGame();
+	else
+		error("Unknown game");
 }
 
 void Comprehend::print(const char *fmt, ...) {
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 3e76f07bc8..3f1bee6eb6 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -57,6 +57,8 @@ private:
 public:
 	GraphicsWindow *_topWindow;
 	TextBufferWindow *_bottomWindow;
+	ComprehendGame *_game;
+
 private:
 	/**
 	 * Initialization code
@@ -68,7 +70,15 @@ private:
 	 */
 	void deinitialize();
 
-	ComprehendGame *createGame();
+	/**
+	 * Create the debugger
+	 */
+	void createDebugger() override;
+
+	/**
+	 * Creates the appropriate game class
+	 */
+	void createGame();
 
 public:
 	/**
diff --git a/engines/glk/comprehend/dump_game_data.h b/engines/glk/comprehend/debugger.cpp
similarity index 59%
rename from engines/glk/comprehend/dump_game_data.h
rename to engines/glk/comprehend/debugger.cpp
index 311ff2b139..63d3e9f8d8 100644
--- a/engines/glk/comprehend/dump_game_data.h
+++ b/engines/glk/comprehend/debugger.cpp
@@ -20,34 +20,41 @@
  *
  */
 
-#ifndef GLK_COMPREHEND_DUMP_GAME_DATA_H
-#define GLK_COMPREHEND_DUMP_GAME_DATA_H
+#include "glk/comprehend/debugger.h"
+#include "glk/comprehend/comprehend.h"
 
 namespace Glk {
 namespace Comprehend {
 
-class ComprehendGame;
-struct FunctionState;
-struct Instruction;
-
-#define DUMP_STRINGS (1 << 0)
-#define DUMP_EXTRA_STRINGS (1 << 1)
-#define DUMP_ROOMS (1 << 2)
-#define DUMP_ITEMS (1 << 3)
-#define DUMP_DICTIONARY (1 << 4)
-#define DUMP_WORD_PAIRS (1 << 5)
-#define DUMP_ACTIONS (1 << 6)
-#define DUMP_FUNCTIONS (1 << 7)
-#define DUMP_REPLACE_WORDS (1 << 8)
-#define DUMP_HEADER (1 << 9)
-#define DUMP_ALL (~0U)
-
-void dump_instruction(ComprehendGame *game,
-                      FunctionState *func_state,
-                      Instruction *instr);
-void dump_game_data(ComprehendGame *game, unsigned flags);
+Debugger *g_debugger;
+
+Debugger::Debugger() : Glk::Debugger() {
+	g_debugger = this;
+	registerCmd("dump", WRAP_METHOD(Debugger, cmdDump));
+}
+
+Debugger::~Debugger() {
+	g_debugger = nullptr;
+}
+
+void Debugger::print(const char *fmt, ...) {
+	va_list argp;
+	va_start(argp, fmt);
+	Common::String msg = Common::String::vformat(fmt, argp);
+	va_end(argp);
+
+	debugPrintf("%s", msg.c_str());
+}
+
+bool Debugger::cmdDump(int argc, const char **argv) {
+	Common::String param = (argc == 2) ? argv[1] : "";
+	ComprehendGame *game = g_comprehend->_game;
+
+	if (!dumpGameData(game, param))
+		debugPrintf("Unknown dump option\n");
+
+	return true;
+}
 
 } // namespace Comprehend
 } // namespace Glk
-
-#endif
diff --git a/engines/glk/comprehend/debugger.h b/engines/glk/comprehend/debugger.h
new file mode 100644
index 0000000000..d42a953d78
--- /dev/null
+++ b/engines/glk/comprehend/debugger.h
@@ -0,0 +1,52 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_DEBUGGER_H
+#define GLK_COMPREHEND_DEBUGGER_H
+
+#include "glk/debugger.h"
+#include "glk/comprehend/debugger_dumper.h"
+
+namespace Glk {
+namespace Comprehend {
+
+class Debugger : public Glk::Debugger, public DebuggerDumper {
+private:
+	/**
+	 * Dump data
+	 */
+	bool cmdDump(int argc, const char **argv);
+
+protected:
+	void print(const char *fmt, ...) override;
+
+public:
+	Debugger();
+	~Debugger();
+};
+
+extern Debugger *g_debugger;
+
+} // End of namespace Comprehend
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
new file mode 100644
index 0000000000..362031efc6
--- /dev/null
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -0,0 +1,461 @@
+/* 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 "glk/comprehend/debugger_dumper.h"
+#include "glk/comprehend/dictionary.h"
+#include "glk/comprehend/game.h"
+#include "glk/comprehend/strings.h"
+#include "glk/comprehend/util.h"
+
+namespace Glk {
+namespace Comprehend {
+
+DebuggerDumper::DebuggerDumper() : _game(nullptr) {
+	_opcodes[OPCODE_UNKNOWN] = "unknown";
+
+	_opcodes[OPCODE_HAVE_OBJECT] = "have_object";
+	_opcodes[OPCODE_NOT_HAVE_OBJECT] = "not_have_object";
+	_opcodes[OPCODE_HAVE_CURRENT_OBJECT] = "have_current_object";
+	_opcodes[OPCODE_NOT_HAVE_CURRENT_OBJECT] = "not_have_current_object";
+
+	_opcodes[OPCODE_OBJECT_IS_NOT_NOWHERE] = "object_is_not_nowhere";
+
+	_opcodes[OPCODE_CURRENT_OBJECT_TAKEABLE] = "current_object_takeable";
+	_opcodes[OPCODE_CURRENT_OBJECT_NOT_TAKEABLE] = "current_object_not_takeable";
+
+	_opcodes[OPCODE_CURRENT_OBJECT_IS_NOWHERE] = "current_object_is_nowhere";
+
+	_opcodes[OPCODE_CURRENT_OBJECT_NOT_PRESENT] = "current_object_not_present";
+
+	_opcodes[OPCODE_TAKE_OBJECT] = "take_object";
+	_opcodes[OPCODE_TAKE_CURRENT_OBJECT] = "take_current_object";
+	_opcodes[OPCODE_DROP_OBJECT] = "drop_object";
+	_opcodes[OPCODE_DROP_CURRENT_OBJECT] = "drop_current_object";
+
+	_opcodes[OPCODE_OR] = "or";
+	_opcodes[OPCODE_IN_ROOM] = "in_room";
+	_opcodes[OPCODE_VAR_EQ] = "var_eq";
+	_opcodes[OPCODE_OBJECT_NOT_VALID] = "object_not_valid";
+	_opcodes[OPCODE_INVENTORY_FULL] = "inventory_full";
+	_opcodes[OPCODE_OBJECT_PRESENT] = "object_present";
+	_opcodes[OPCODE_ELSE] = "else";
+	_opcodes[OPCODE_OBJECT_IN_ROOM] = "object_in_room";
+	_opcodes[OPCODE_TEST_FLAG] = "test_flag";
+	_opcodes[OPCODE_CURRENT_OBJECT_IN_ROOM] = "current_object_in_room";
+	_opcodes[OPCODE_CURRENT_OBJECT_PRESENT] = "current_object_present";
+	_opcodes[OPCODE_TEST_ROOM_FLAG] = "test_room_flag";
+	_opcodes[OPCODE_NOT_IN_ROOM] = "not_in_room";
+	_opcodes[OPCODE_OBJECT_NOT_PRESENT] = "object_not_present";
+	_opcodes[OPCODE_OBJECT_NOT_IN_ROOM] = "object_not_in_room";
+	_opcodes[OPCODE_TEST_NOT_FLAG] = "test_not_flag";
+	_opcodes[OPCODE_OBJECT_IS_NOWHERE] = "object_is_nowhere";
+	_opcodes[OPCODE_TEST_NOT_ROOM_FLAG] = "test_not_room_flag";
+	_opcodes[OPCODE_INVENTORY] = "inventory";
+	_opcodes[OPCODE_MOVE_OBJECT_TO_ROOM] = "move_object_to_room";
+	_opcodes[OPCODE_SAVE_ACTION] = "save_action";
+	_opcodes[OPCODE_MOVE_TO_ROOM] = "move_to_room";
+	_opcodes[OPCODE_VAR_ADD] = "var_add";
+	_opcodes[OPCODE_SET_ROOM_DESCRIPTION] = "set_room_description";
+	_opcodes[OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM] = "move_object_to_current_room";
+	_opcodes[OPCODE_VAR_SUB] = "var_sub";
+	_opcodes[OPCODE_SET_OBJECT_DESCRIPTION] = "set_object_description";
+	_opcodes[OPCODE_SET_OBJECT_LONG_DESCRIPTION] = "set_object_long_description";
+	_opcodes[OPCODE_MOVE] = "move";
+	_opcodes[OPCODE_PRINT] = "print";
+	_opcodes[OPCODE_REMOVE_OBJECT] = "remove_object";
+	_opcodes[OPCODE_SET_FLAG] = "set_flag";
+	_opcodes[OPCODE_CALL_FUNC] = "call_func";
+	_opcodes[OPCODE_TURN_TICK] = "turn_tick";
+	_opcodes[OPCODE_CLEAR_FLAG] = "clear_flag";
+	_opcodes[OPCODE_INVENTORY_ROOM] = "inventory_room";
+	_opcodes[OPCODE_SPECIAL] = "special";
+	_opcodes[OPCODE_SET_ROOM_GRAPHIC] = "set_room_graphic";
+	_opcodes[OPCODE_SET_OBJECT_GRAPHIC] = "set_object_graphic";
+	_opcodes[OPCODE_REMOVE_CURRENT_OBJECT] = "remove_current_object";
+	_opcodes[OPCODE_DO_VERB] = "do_verb";
+	_opcodes[OPCODE_VAR_INC] = "var_inc";
+	_opcodes[OPCODE_VAR_DEC] = "var_dec";
+	_opcodes[OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM] = "move_current_object_to_room";
+	_opcodes[OPCODE_DESCRIBE_CURRENT_OBJECT] = "describe_current_object";
+	_opcodes[OPCODE_SET_STRING_REPLACEMENT] = "set_string_replacement";
+	_opcodes[OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT] = "set_current_noun_string_replacement";
+	_opcodes[OPCODE_CURRENT_NOT_OBJECT] = "current_not_object";
+	_opcodes[OPCODE_CURRENT_IS_OBJECT] = "current_is_object";
+	_opcodes[OPCODE_DRAW_ROOM] = "draw_room";
+	_opcodes[OPCODE_DRAW_OBJECT] = "draw_object";
+	_opcodes[OPCODE_WAIT_KEY] = "wait_key";
+}
+
+Common::String DebuggerDumper::dumpInstruction(ComprehendGame *game,
+		FunctionState *func_state, Instruction *instr) {
+	uint i;
+	int str_index, str_table;
+	uint8 *opcode_map, opcode;
+	Common::String line;
+
+	if (func_state)
+		line = Common::String::format("[or=%d,and=%d,test=%d,else=%d]",
+		      func_state->or_count, func_state->_and,
+		      func_state->test_result, func_state->else_result);
+
+	opcode_map = game->_opcodeMap;
+	opcode = opcode_map[instr->opcode];
+
+	line += "  [%.2x] ", instr->opcode;
+	if (_opcodes.contains(opcode))
+		line += _opcodes[opcode];
+	else
+		line += "unknown";
+
+	if (instr->nr_operands) {
+		line += "(";
+		for (i = 0; i < instr->nr_operands; i++)
+			line += "%.2x%s", instr->operand[i],
+			      i == instr->nr_operands - 1 ? ")" : ", ";
+	}
+
+	switch (opcode) {
+	case OPCODE_PRINT:
+	case OPCODE_SET_ROOM_DESCRIPTION:
+	case OPCODE_SET_OBJECT_DESCRIPTION:
+	case OPCODE_SET_OBJECT_LONG_DESCRIPTION:
+
+		if (opcode == OPCODE_PRINT) {
+			str_index = instr->operand[0];
+			str_table = instr->operand[1];
+		} else {
+			str_index = instr->operand[1];
+			str_table = instr->operand[2];
+		}
+
+		line += " %s", instr_lookup_string(game, str_index, str_table);
+		break;
+
+	case OPCODE_SET_STRING_REPLACEMENT:
+		line += " %s", game->_replaceWords[instr->operand[0] - 1];
+		break;
+	}
+
+	line += "\n";
+	return line;
+}
+
+void DebuggerDumper::dumpFunctions() {
+	Function *func;
+	uint i, j;
+
+	print("Functions (%u entries)\n", (uint)_game->_nr_functions);
+	for (i = 0; i < _game->_nr_functions; i++) {
+		func = &_game->_functions[i];
+
+		print("[%.4x] (%u instructions)\n", i, (uint)func->nr_instructions);
+		for (j = 0; j < func->nr_instructions; j++) {
+			Common::String line = dumpInstruction(_game, NULL, &func->instructions[j]);
+			print("%s", line.c_str());
+		}
+		print("\n");
+	}
+}
+
+void DebuggerDumper::dumpActionTable() {
+	Action *action;
+	Word *word;
+	uint i, j;
+
+	print("Action table (%u entries)\n", (uint)_game->_nr_actions);
+	for (i = 0; i < _game->_nr_actions; i++) {
+		action = &_game->_actions[i];
+
+		print("(");
+		for (j = 0; j < 4; j++) {
+			if (j < action->nr_words) {
+				switch (action->word_type[j]) {
+				case WORD_TYPE_VERB:
+					print("v");
+					break;
+				case WORD_TYPE_JOIN:
+					print("j");
+					break;
+				case WORD_TYPE_NOUN_MASK:
+					print("n");
+					break;
+				default:
+					print("?");
+					break;
+				}
+			} else {
+				print(" ");
+			}
+		}
+
+		print(") [%.4x] ", i);
+
+		for (j = 0; j < action->nr_words; j++)
+			print("%.2x:%.2x ",
+			      action->word[j], action->word_type[j]);
+
+		print("| ");
+
+		for (j = 0; j < action->nr_words; j++) {
+			word = find_dict_word_by_index(_game, action->word[j],
+			                               action->word_type[j]);
+			if (word)
+				print("%-6s ", word->_word);
+			else
+				print("%.2x:%.2x  ", action->word[j],
+				      action->word_type[j]);
+		}
+
+		print("-> %.4x\n", action->function);
+	}
+}
+
+int DebuggerDumper::wordIndexCompare(const void *a, const void *b) {
+	const Word *word_a = (const Word *)a, *word_b = (const Word *)b;
+
+	if (word_a->_index > word_b->_index)
+		return 1;
+	if (word_a->_index < word_b->_index)
+		return -1;
+	return 0;
+}
+
+void DebuggerDumper::dumpDictionary() {
+	Word *dictionary;
+	Word *words;
+	uint i;
+
+	/* Sort the dictionary by index */
+	dictionary = (Word *)xmalloc(sizeof(*words) * _game->_nr_words);
+	memcpy(dictionary, _game->_words,
+	       sizeof(*words) * _game->_nr_words);
+	qsort(dictionary, _game->_nr_words, sizeof(*words),
+	      wordIndexCompare);
+
+	print("Dictionary (%u words)\n", (uint)_game->_nr_words);
+	for (i = 0; i < _game->_nr_words; i++) {
+		words = &dictionary[i];
+		print("  [%.2x] %.2x %s\n", words->_index, words->_type,
+		      words->_word);
+	}
+
+	free(dictionary);
+}
+
+void DebuggerDumper::dumpWordMap() {
+	Word *word[3];
+	char str[3][6];
+	WordMap *map;
+	uint i, j;
+
+	print("Word pairs (%u entries)\n", (uint)_game->_nr_word_maps);
+	for (i = 0; i < _game->_nr_word_maps; i++) {
+		map = &_game->_wordMaps[i];
+
+		for (j = 0; j < 3; j++) {
+			word[j] = dict_find_word_by_index_type(
+			    _game, map->word[j].index, map->word[j].type);
+			if (word[j])
+				snprintf(str[j], sizeof(str[j]),
+				         "%s", word[j]->_word);
+			else
+				snprintf(str[j], sizeof(str[j]), "%.2x:%.2x ",
+				         map->word[j].index, map->word[j].type);
+		}
+
+		print("  [%.2x] %-6s %-6s -> %-6s\n",
+		      i, str[0], str[1], str[2]);
+	}
+}
+
+void DebuggerDumper::dumpRooms() {
+	Room *room;
+	uint i;
+
+	/* Room zero acts as the players inventory */
+	print("Rooms (%u entries)\n", (uint)_game->_nr_rooms);
+	for (i = 1; i <= _game->_nr_rooms; i++) {
+		room = &_game->_rooms[i];
+
+		print("  [%.2x] flags=%.2x, graphic=%.2x\n",
+		      i, room->flags, room->graphic);
+		print("    %s\n", string_lookup(_game, room->string_desc));
+		print("    n: %.2x  s: %.2x  e: %.2x  w: %.2x\n",
+		      room->direction[DIRECTION_NORTH],
+		      room->direction[DIRECTION_SOUTH],
+		      room->direction[DIRECTION_EAST],
+		      room->direction[DIRECTION_WEST]);
+		print("    u: %.2x  d: %.2x  i: %.2x  o: %.2x\n",
+		      room->direction[DIRECTION_UP],
+		      room->direction[DIRECTION_DOWN],
+		      room->direction[DIRECTION_IN],
+		      room->direction[DIRECTION_OUT]);
+		print("\n");
+	}
+}
+
+void DebuggerDumper::dumpItems() {
+	Item *item;
+	uint i, j;
+
+	print("Items (%u entries)\n", (uint)_game->_header.nr_items);
+	for (i = 0; i < _game->_header.nr_items; i++) {
+		item = &_game->_items[i];
+
+		print("  [%.2x] %s\n", i + 1,
+		      item->string_desc ? string_lookup(_game, item->string_desc) : "");
+		if (_game->_comprehendVersion == 2)
+			print("    long desc: %s\n",
+			      string_lookup(_game, item->long_string));
+
+		print("    words: ");
+		for (j = 0; j < _game->_nr_words; j++)
+			if (_game->_words[j]._index == item->word &&
+			    (_game->_words[j]._type & WORD_TYPE_NOUN_MASK))
+				print("%s ", _game->_words[j]._word);
+		print("\n");
+		print("    flags=%.2x (takeable=%d, weight=%d)\n",
+		      item->flags, !!(item->flags & ITEMF_CAN_TAKE),
+		      (item->flags & ITEMF_WEIGHT_MASK));
+		print("    room=%.2x, graphic=%.2x\n",
+		      item->room, item->graphic);
+		print("\n");
+	}
+}
+
+void DebuggerDumper::dumpStringTable(StringTable *table) {
+	uint i;
+
+	for (i = 0; i < table->nr_strings; i++)
+		print("[%.4x] %s\n", i, table->strings[i]);
+}
+
+void DebuggerDumper::dumpGameDataStrings() {
+	print("Main string table (%u entries)\n",
+	      (uint)_game->_strings.nr_strings);
+	dumpStringTable(&_game->_strings);
+}
+
+void DebuggerDumper::dumpExtraStrings() {
+	print("Extra strings (%u entries)\n",
+	      (uint)_game->_strings2.nr_strings);
+	dumpStringTable(&_game->_strings2);
+}
+
+void DebuggerDumper::dumpReplaceWords() {
+	uint i;
+
+	print("Replacement words (%u entries)\n",
+	      (uint)_game->_nr_replace_words);
+	for (i = 0; i < _game->_nr_replace_words; i++)
+		print("  [%.2x] %s\n", i + 1, _game->_replaceWords[i]);
+}
+
+void DebuggerDumper::dumpHeader() {
+	GameHeader *header = &_game->_header;
+	uint16 *dir_table = header->room_direction_table;
+
+	print("Game header:\n");
+	print("  magic:                %.4x\n", header->magic);
+	print("  action(vvnn):         %.4x\n", header->addr_actions_vvnn);
+	print("  actions(?):\n");
+	print("  actions(vnjn):        %.4x\n", header->addr_actions_vnjn);
+	print("  actions(vjn):         %.4x\n", header->addr_actions_vjn);
+	print("  actions(vdn):         %.4x\n", header->addr_actions_vdn);
+	print("  actions(vnn):         %.4x\n", header->addr_actions_vnn);
+	print("  actions(vn):          %.4x\n", header->addr_actions_vn);
+	print("  actions(v):           %.4x\n", header->addr_actions_v);
+	print("  functions:            %.4x\n", header->addr_vm);
+	print("  dictionary:           %.4x\n", header->addr_dictionary);
+	print("  word map pairs:       %.4x\n", header->addr_word_map);
+	print("  room desc strings:    %.4x\n", header->room_desc_table);
+	print("  room north:           %.4x\n", dir_table[DIRECTION_NORTH]);
+	print("  room south:           %.4x\n", dir_table[DIRECTION_SOUTH]);
+	print("  room east:            %.4x\n", dir_table[DIRECTION_EAST]);
+	print("  room west:            %.4x\n", dir_table[DIRECTION_WEST]);
+	print("  room up:              %.4x\n", dir_table[DIRECTION_UP]);
+	print("  room down:            %.4x\n", dir_table[DIRECTION_DOWN]);
+	print("  room in:              %.4x\n", dir_table[DIRECTION_IN]);
+	print("  room out:             %.4x\n", dir_table[DIRECTION_OUT]);
+	print("  room flags:           %.4x\n", header->room_flags_table);
+	print("  room images:          %.4x\n", header->room_graphics_table);
+	print("  item locations:       %.4x\n", header->addr_item_locations);
+	print("  item flags:           %.4x\n", header->addr_item_flags);
+	print("  item words:           %.4x\n", header->addr_item_word);
+	print("  item desc strings:    %.4x\n", header->addr_item_strings);
+	print("  item images:          %.4x\n", header->addr_item_graphics);
+	print("  string table:         %.4x\n", header->addr_strings);
+	print("  string table end:     %.4x\n", header->addr_strings_end);
+}
+
+void DebuggerDumper::dumpState() {
+	print("Current room: %.2x\n", _game->_currentRoom);
+	print("Carry weight %d/%d\n\n",
+	      _game->_variables[VAR_INVENTORY_WEIGHT],
+	      _game->_variables[VAR_INVENTORY_LIMIT]);
+
+	print("Flags:\n");
+	for (uint i = 0; i < ARRAY_SIZE(_game->_flags); i++)
+		print("  [%.2x]: %d\n", i, _game->_flags[i]);
+	print("\n");
+
+	print("Variables:\n");
+	for (uint i = 0; i < ARRAY_SIZE(_game->_variables); i++)
+		print("  [%.2x]: %5d (0x%.4x)\n",
+		      i, _game->_variables[i],
+		      _game->_variables[i]);
+	print("\n");
+}
+
+bool DebuggerDumper::dumpGameData(ComprehendGame *game, const Common::String &type) {
+	_game = game;
+
+	if (type == "header")
+		dumpHeader();
+	else if (type == "strings")
+		dumpGameDataStrings();
+	else if (type == "extra_strings")
+		dumpExtraStrings();
+	else if (type == "rooms")
+		dumpRooms();
+	else if (type == "items")
+		dumpItems();
+	else if (type == "dictionary")
+		dumpDictionary();
+	else if (type == "word_map")
+		dumpWordMap();
+	else if (type == "actions")
+		dumpActionTable();
+	else if (type == "functions")
+		dumpFunctions();
+	else if (type == "replace_words")
+		dumpReplaceWords();
+	else if (type == "state")
+		dumpState();
+	else
+		return false;
+
+	return true;
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/debugger_dumper.h b/engines/glk/comprehend/debugger_dumper.h
new file mode 100644
index 0000000000..add248e94d
--- /dev/null
+++ b/engines/glk/comprehend/debugger_dumper.h
@@ -0,0 +1,74 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_DEBUGGER_DUMPER_H
+#define GLK_COMPREHEND_DEBUGGER_DUMPER_H
+
+#include "common/hashmap.h"
+
+namespace Glk {
+namespace Comprehend {
+
+class ComprehendGame;
+struct FunctionState;
+struct Instruction;
+struct StringTable;
+
+class DebuggerDumper {
+private:
+	Common::HashMap<byte, Common::String> _opcodes;
+	ComprehendGame *_game;
+
+private:
+	void dumpFunctions();
+	void dumpActionTable();
+	static int wordIndexCompare(const void *a, const void *b);
+	void dumpDictionary();
+	void dumpWordMap();
+	void dumpRooms();
+	void dumpItems();
+	void dumpStringTable(StringTable *table);
+	void dumpGameDataStrings();
+	void dumpExtraStrings();
+	void dumpReplaceWords();
+	void dumpHeader();
+	void dumpState();
+
+protected:
+	/**
+	 * Prints out dumped text
+	 */
+	virtual void print(const char *fmt, ...) = 0;
+
+public:
+	DebuggerDumper();
+
+	Common::String dumpInstruction(ComprehendGame *game,
+		FunctionState *func_state, Instruction *instr);
+
+	bool dumpGameData(ComprehendGame *game, const Common::String &type);
+};
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/dump_game_data.cpp b/engines/glk/comprehend/dump_game_data.cpp
deleted file mode 100644
index 93ef85fe8f..0000000000
--- a/engines/glk/comprehend/dump_game_data.cpp
+++ /dev/null
@@ -1,453 +0,0 @@
-/* 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 "glk/comprehend/comprehend.h"
-#include "glk/comprehend/game_data.h"
-#include "glk/comprehend/dump_game_data.h"
-#include "glk/comprehend/dictionary.h"
-#include "glk/comprehend/file_buf.h"
-#include "glk/comprehend/strings.h"
-#include "glk/comprehend/game.h"
-#include "glk/comprehend/util.h"
-#include "glk/comprehend/opcode_map.h"
-
-namespace Glk {
-namespace Comprehend {
-
-static const char *opcode_names[] = {
-#ifdef TODO
-	[OPCODE_UNKNOWN]			= "unknown",
-
-	[OPCODE_HAVE_OBJECT]			= "have_object",
-	[OPCODE_NOT_HAVE_OBJECT]		= "not_have_object",
-	[OPCODE_HAVE_CURRENT_OBJECT]		= "have_current_object",
-	[OPCODE_NOT_HAVE_CURRENT_OBJECT]	= "not_have_current_object",
-
-	[OPCODE_OBJECT_IS_NOT_NOWHERE]		= "object_is_not_nowhere",
-
-	[OPCODE_CURRENT_OBJECT_TAKEABLE]	= "current_object_takeable",
-	[OPCODE_CURRENT_OBJECT_NOT_TAKEABLE]	= "current_object_not_takeable",
-
-	[OPCODE_CURRENT_OBJECT_IS_NOWHERE]	= "current_object_is_nowhere",
-
-	[OPCODE_CURRENT_OBJECT_NOT_PRESENT]	= "current_object_not_present",
-
-	[OPCODE_TAKE_OBJECT]			= "take_object",
-	[OPCODE_TAKE_CURRENT_OBJECT]		= "take_current_object",
-	[OPCODE_DROP_OBJECT]			= "drop_object",
-	[OPCODE_DROP_CURRENT_OBJECT]		= "drop_current_object",
-
-	[OPCODE_OR]				= "or",
-	[OPCODE_IN_ROOM]			= "in_room",
-	[OPCODE_VAR_EQ]				= "var_eq",
-	[OPCODE_OBJECT_NOT_VALID]	        = "object_not_valid",
-	[OPCODE_INVENTORY_FULL]			= "inventory_full",
-	[OPCODE_OBJECT_PRESENT]			= "object_present",
-	[OPCODE_ELSE]				= "else",
-	[OPCODE_OBJECT_IN_ROOM]			= "object_in_room",
-	[OPCODE_TEST_FLAG]			= "test_flag",
-	[OPCODE_CURRENT_OBJECT_IN_ROOM]		= "current_object_in_room",
-	[OPCODE_CURRENT_OBJECT_PRESENT]		= "current_object_present",
-	[OPCODE_TEST_ROOM_FLAG]			= "test_room_flag",
-	[OPCODE_NOT_IN_ROOM]			= "not_in_room",
-	[OPCODE_OBJECT_NOT_PRESENT]		= "object_not_present",
-	[OPCODE_OBJECT_NOT_IN_ROOM]		= "object_not_in_room",
-	[OPCODE_TEST_NOT_FLAG]			= "test_not_flag",
-	[OPCODE_OBJECT_IS_NOWHERE]		= "object_is_nowhere",
-	[OPCODE_TEST_NOT_ROOM_FLAG]		= "test_not_room_flag",
-	[OPCODE_INVENTORY]			= "inventory",
-	[OPCODE_MOVE_OBJECT_TO_ROOM]		= "move_object_to_room",
-	[OPCODE_SAVE_ACTION]			= "save_action",
-	[OPCODE_MOVE_TO_ROOM]			= "move_to_room",
-	[OPCODE_VAR_ADD]			= "var_add",
-	[OPCODE_SET_ROOM_DESCRIPTION]		= "set_room_description",
-	[OPCODE_MOVE_OBJECT_TO_CURRENT_ROOM]	= "move_object_to_current_room",
-	[OPCODE_VAR_SUB]			= "var_sub",
-	[OPCODE_SET_OBJECT_DESCRIPTION]		= "set_object_description",
-	[OPCODE_SET_OBJECT_LONG_DESCRIPTION]	= "set_object_long_description",
-	[OPCODE_MOVE]				= "move",
-	[OPCODE_PRINT]				= "print",
-	[OPCODE_REMOVE_OBJECT]			= "remove_object",
-	[OPCODE_SET_FLAG]			= "set_flag",
-	[OPCODE_CALL_FUNC]			= "call_func",
-	[OPCODE_TURN_TICK]			= "turn_tick",
-	[OPCODE_CLEAR_FLAG]			= "clear_flag",
-	[OPCODE_INVENTORY_ROOM]			= "inventory_room",
-	[OPCODE_SPECIAL]			= "special",
-	[OPCODE_SET_ROOM_GRAPHIC]		= "set_room_graphic",
-	[OPCODE_SET_OBJECT_GRAPHIC]		= "set_object_graphic",
-	[OPCODE_REMOVE_CURRENT_OBJECT]		= "remove_current_object",
-	[OPCODE_DO_VERB]			= "do_verb",
-	[OPCODE_VAR_INC]			= "var_inc",
-	[OPCODE_VAR_DEC]			= "var_dec",
-	[OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM]	= "move_current_object_to_room",
-	[OPCODE_DESCRIBE_CURRENT_OBJECT]	= "describe_current_object",
-	[OPCODE_SET_STRING_REPLACEMENT]		= "set_string_replacement",
-	[OPCODE_SET_CURRENT_NOUN_STRING_REPLACEMENT] = "set_current_noun_string_replacement",
-	[OPCODE_CURRENT_NOT_OBJECT]		= "current_not_object",
-	[OPCODE_CURRENT_IS_OBJECT]		= "current_is_object",
-	[OPCODE_DRAW_ROOM]			= "draw_room",
-	[OPCODE_DRAW_OBJECT]			= "draw_object",
-	[OPCODE_WAIT_KEY]			= "wait_key",
-#else
-	"TODO"
-#endif
-};
-
-void dump_instruction(ComprehendGame *game,
-		      FunctionState *func_state,
-		      Instruction *instr)
-{
-	uint i;
-	int str_index, str_table;
-	uint8 *opcode_map, opcode;
-
-	if (func_state)
-		debugN("[or=%d,and=%d,test=%d,else=%d]",
-		       func_state->or_count, func_state->_and,
-		       func_state->test_result, func_state->else_result);
-
-	opcode_map = game->_opcodeMap;
-	opcode = opcode_map[instr->opcode];
-
-	debugN("  [%.2x] ", instr->opcode);
-	if (opcode < ARRAY_SIZE(opcode_names) && opcode_names[opcode])
-		debugN("%s", opcode_names[opcode]);
-	else
-		debugN("unknown");
-
-	if (instr->nr_operands) {
-		debugN("(");
-		for (i = 0; i < instr->nr_operands; i++)
-			debugN("%.2x%s", instr->operand[i],
-			       i == instr->nr_operands - 1 ? ")" : ", ");
-	}
-
-	switch (opcode) {
-	case OPCODE_PRINT:
-	case OPCODE_SET_ROOM_DESCRIPTION:
-	case OPCODE_SET_OBJECT_DESCRIPTION:
-	case OPCODE_SET_OBJECT_LONG_DESCRIPTION:
-
-		if (opcode == OPCODE_PRINT) {
-			str_index = instr->operand[0];
-			str_table = instr->operand[1];
-		} else {
-			str_index = instr->operand[1];
-			str_table = instr->operand[2];
-		}
-
-		debugN(" %s", instr_lookup_string(game, str_index, str_table));
-		break;
-
-	case OPCODE_SET_STRING_REPLACEMENT:
-		debugN(" %s", game->_replaceWords[instr->operand[0] - 1]);
-		break;
-	}
-
-	debugN("\n");
-}
-
-static void dump_functions(ComprehendGame *game)
-{
-	Function *func;
-	uint i, j;
-
-	debugN("Functions (%u entries)\n", (uint)game->_nr_functions);
-	for (i = 0; i < game->_nr_functions; i++) {
-		func = &game->_functions[i];
-
-		debugN("[%.4x] (%u instructions)\n", i, (uint)func->nr_instructions);
-		for (j = 0; j < func->nr_instructions; j++)
-			dump_instruction(game, NULL, &func->instructions[j]);
-		debugN("\n");
-	}
-}
-
-static void dump_action_table(ComprehendGame *game)
-{
-	Action *action;
-	Word *word;
-	uint i, j;
-
-	debugN("Action table (%u entries)\n", (uint)game->_nr_actions);
-	for (i = 0; i < game->_nr_actions; i++) {
-		action = &game->_actions[i];
-
-		debugN("(");
-		for (j = 0; j < 4; j++) {
-			if (j < action->nr_words) {
-				switch (action->word_type[j]) {
-				case WORD_TYPE_VERB: debugN("v"); break;
-				case WORD_TYPE_JOIN: debugN("j"); break;
-				case WORD_TYPE_NOUN_MASK: debugN("n"); break;
-				default: debugN("?"); break;
-				}
-			} else {
-				debugN(" ");
-			}
-		}
-
-		debugN(") [%.4x] ", i );
-
-		for (j = 0; j < action->nr_words; j++)
-			debugN("%.2x:%.2x ",
-			       action->word[j], action->word_type[j]);
-
-		debugN("| ");
-
-		for (j = 0; j < action->nr_words; j++) {
-			word = find_dict_word_by_index(game, action->word[j],
-						       action->word_type[j]);
-			if (word)
-				debugN("%-6s ", word->_word);
-			else
-				debugN("%.2x:%.2x  ", action->word[j],
-				       action->word_type[j]);
-		}
-
-		debugN("-> %.4x\n", action->function);
-	}
-}
-
-static int word_index_compare(const void *a, const void *b)
-{
-	const Word *word_a = (const Word *)a, *word_b = (const Word *)b;
-
-	if (word_a->_index > word_b->_index)
-		return 1;
-	if (word_a->_index < word_b->_index)
-		return -1;
-	return 0;
-}
-
-static void dump_dictionary(ComprehendGame *game)
-{
-	Word *dictionary;
-	Word *words;
-	uint i;
-
-	/* Sort the dictionary by index */
-	dictionary = (Word *)xmalloc(sizeof(*words) * game->_nr_words);
-	memcpy(dictionary, game->_words,
-	       sizeof(*words) * game->_nr_words);
-	qsort(dictionary, game->_nr_words, sizeof(*words),
-	      word_index_compare);
-
-	debugN("Dictionary (%u words)\n", (uint)game->_nr_words);
-	for (i = 0; i < game->_nr_words; i++) {
-		words = &dictionary[i];
-		debugN("  [%.2x] %.2x %s\n", words->_index, words->_type,
-		       words->_word);
-	}
-
-	free(dictionary);
-}
-
-static void dump_word_map(ComprehendGame *game)
-{
-	Word *word[3];
-	char str[3][6];
-	WordMap *map;
-	uint i, j;
-
-	debugN("Word pairs (%u entries)\n", (uint)game->_nr_word_maps);
-	for (i = 0; i < game->_nr_word_maps; i++) {
-		map = &game->_wordMaps[i];
-
-		for (j = 0; j < 3; j++) {
-			word[j] = dict_find_word_by_index_type(
-				game, map->word[j].index, map->word[j].type);
-			if (word[j])
-				snprintf(str[j], sizeof(str[j]),
-				         "%s", word[j]->_word);
-			else
-				snprintf(str[j], sizeof(str[j]), "%.2x:%.2x ",
-					 map->word[j].index, map->word[j].type);
-		}
-
-		debugN("  [%.2x] %-6s %-6s -> %-6s\n",
-		       i, str[0], str[1], str[2]);
-	}
-}
-
-static void dump_rooms(ComprehendGame *game)
-{
-	Room *room;
-	uint i;
-
-	/* Room zero acts as the players inventory */
-	debugN("Rooms (%u entries)\n", (uint)game->_nr_rooms);
-	for (i = 1; i <= game->_nr_rooms; i++) {
-		room = &game->_rooms[i];
-
-		debugN("  [%.2x] flags=%.2x, graphic=%.2x\n",
-		       i, room->flags, room->graphic);
-		debugN("    %s\n", string_lookup(game, room->string_desc));
-		debugN("    n: %.2x  s: %.2x  e: %.2x  w: %.2x\n",
-		       room->direction[DIRECTION_NORTH],
-		       room->direction[DIRECTION_SOUTH],
-		       room->direction[DIRECTION_EAST],
-		       room->direction[DIRECTION_WEST]);
-		debugN("    u: %.2x  d: %.2x  i: %.2x  o: %.2x\n",
-		       room->direction[DIRECTION_UP],
-		       room->direction[DIRECTION_DOWN],
-		       room->direction[DIRECTION_IN],
-		       room->direction[DIRECTION_OUT]);
-		debugN("\n");
-	}
-}
-
-static void dump_items(ComprehendGame *game)
-{
-	Item *item;
-	uint i, j;
-
-	debugN("Items (%u entries)\n", (uint)game->_header.nr_items);
-	for (i = 0; i < game->_header.nr_items; i++) {
-		item = &game->_items[i];
-
-		debugN("  [%.2x] %s\n", i + 1,
-		       item->string_desc ?
-		       string_lookup(game, item->string_desc) : "");
-		if (game->_comprehendVersion == 2)
-			debugN("    long desc: %s\n",
-			       string_lookup(game, item->long_string));
-
-		debugN("    words: ");
-		for (j = 0; j < game->_nr_words; j++)
-			if (game->_words[j]._index == item->word &&
-			    (game->_words[j]._type & WORD_TYPE_NOUN_MASK))
-				debugN("%s ", game->_words[j]._word);
-		debugN("\n");
-		debugN("    flags=%.2x (takeable=%d, weight=%d)\n",
-		       item->flags, !!(item->flags & ITEMF_CAN_TAKE),
-		       (item->flags & ITEMF_WEIGHT_MASK));
-		debugN("    room=%.2x, graphic=%.2x\n",
-		       item->room, item->graphic);
-		debugN("\n");
-	}
-}
-
-static void dump_string_table(StringTable *table)
-{
-	uint i;
-
-	for (i = 0; i < table->nr_strings; i++)
-		debugN("[%.4x] %s\n", i, table->strings[i]);
-}
-
-static void dump_game_data_strings(ComprehendGame *game)
-{
-	debugN("Main string table (%u entries)\n",
-	       (uint)game->_strings.nr_strings);
-	dump_string_table(&game->_strings);
-}
-
-static void dump_extra_strings(ComprehendGame *game)
-{
-	debugN("Extra strings (%u entries)\n",
-	       (uint)game->_strings2.nr_strings);
-	dump_string_table(&game->_strings2);
-}
-
-static void dump_replace_words(ComprehendGame *game)
-{
-	uint i;
-
-	debugN("Replacement words (%u entries)\n",
-	       (uint)game->_nr_replace_words);
-	for (i = 0; i < game->_nr_replace_words; i++)
-		debugN("  [%.2x] %s\n", i + 1, game->_replaceWords[i]);
-}
-
-static void dump_header(ComprehendGame *game)
-{
-	GameHeader *header = &game->_header;
-	uint16 *dir_table = header->room_direction_table;
-
-	debugN("Game header:\n");
-	debugN("  magic:                %.4x\n", header->magic);
-	debugN("  action(vvnn):         %.4x\n", header->addr_actions_vvnn);
-	debugN("  actions(?):\n");
-	debugN("  actions(vnjn):        %.4x\n", header->addr_actions_vnjn);
-	debugN("  actions(vjn):         %.4x\n", header->addr_actions_vjn);
-	debugN("  actions(vdn):         %.4x\n", header->addr_actions_vdn);
-	debugN("  actions(vnn):         %.4x\n", header->addr_actions_vnn);
-	debugN("  actions(vn):          %.4x\n", header->addr_actions_vn);
-	debugN("  actions(v):           %.4x\n", header->addr_actions_v);
-	debugN("  functions:            %.4x\n", header->addr_vm);
-	debugN("  dictionary:           %.4x\n", header->addr_dictionary);
-	debugN("  word map pairs:       %.4x\n", header->addr_word_map);
-	debugN("  room desc strings:    %.4x\n", header->room_desc_table);
-	debugN("  room north:           %.4x\n", dir_table[DIRECTION_NORTH]);
-	debugN("  room south:           %.4x\n", dir_table[DIRECTION_SOUTH]);
-	debugN("  room east:            %.4x\n", dir_table[DIRECTION_EAST]);
-	debugN("  room west:            %.4x\n", dir_table[DIRECTION_WEST]);
-	debugN("  room up:              %.4x\n", dir_table[DIRECTION_UP]);
-	debugN("  room down:            %.4x\n", dir_table[DIRECTION_DOWN]);
-	debugN("  room in:              %.4x\n", dir_table[DIRECTION_IN]);
-	debugN("  room out:             %.4x\n", dir_table[DIRECTION_OUT]);
-	debugN("  room flags:           %.4x\n", header->room_flags_table);
-	debugN("  room images:          %.4x\n", header->room_graphics_table);
-	debugN("  item locations:       %.4x\n", header->addr_item_locations);
-	debugN("  item flags:           %.4x\n", header->addr_item_flags);
-	debugN("  item words:           %.4x\n", header->addr_item_word);
-	debugN("  item desc strings:    %.4x\n", header->addr_item_strings);
-	debugN("  item images:          %.4x\n", header->addr_item_graphics);
-	debugN("  string table:         %.4x\n", header->addr_strings);
-	debugN("  string table end:     %.4x\n", header->addr_strings_end);
-}
-
-typedef void (*dump_func_t)(ComprehendGame *game);
-
-struct Dumper {
-	dump_func_t	dump_func;
-	unsigned	flag;
-};
-
-static Dumper dumpers[] = {
-	{dump_header,			DUMP_HEADER},
-	{dump_game_data_strings,	DUMP_STRINGS},
-	{dump_extra_strings,		DUMP_EXTRA_STRINGS},
-	{dump_rooms,			DUMP_ROOMS},
-	{dump_items,			DUMP_ITEMS},
-	{dump_dictionary,		DUMP_DICTIONARY},
-	{dump_word_map,			DUMP_WORD_PAIRS},
-	{dump_action_table,		DUMP_ACTIONS},
-	{dump_functions,		DUMP_FUNCTIONS},
-	{dump_replace_words,		DUMP_REPLACE_WORDS},
-};
-
-void dump_game_data(ComprehendGame *game, unsigned flags)
-{
-	uint i;
-
-	for (i = 0; i < ARRAY_SIZE(dumpers); i++)
-		if (flags & dumpers[i].flag) {
-			dumpers[i].dump_func(game);
-			debugN("\n\n");
-		}
-}
-
-} // namespace Comprehend
-} // namespace Glk
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 14b1e42d5e..60c9384cf0 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -22,8 +22,8 @@
 
 #include "glk/comprehend/game.h"
 #include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/debugger.h"
 #include "glk/comprehend/dictionary.h"
-#include "glk/comprehend/dump_game_data.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/graphics.h"
 #include "glk/comprehend/opcode_map.h"
@@ -421,17 +421,19 @@ static void eval_instruction(ComprehendGame *game,
 
 	room = get_room(game, game->_currentRoom);
 
-	if (debugging_enabled()) {
+	if (gDebugLevel > 0) {
+		Common::String line;
 		if (!instr->is_command) {
-			printf("? ");
+			line += "? ";
 		} else {
 			if (func_state->test_result)
-				printf("+ ");
+				line += "+ ";
 			else
-				printf("- ");
+				line += "- ";
 		}
 
-		dump_instruction(game, func_state, instr);
+		line += g_debugger->dumpInstruction(game, func_state, instr);
+		debug("%s", line.c_str());
 	}
 
 	if (func_state->or_count)
@@ -998,46 +1000,6 @@ static void skip_non_whitespace(char **p) {
 		(*p)++;
 }
 
-static void handle_debug_command(ComprehendGame *game,
-                                 const char *line) {
-	int i;
-
-	if (strncmp(line, "quit", 4) == 0) {
-		g_comprehend->quitGame();
-
-	} else if (strncmp(line, "debug", 5) == 0) {
-		if (debugging_enabled())
-			debug_disable(DEBUG_ALL);
-		else
-			debug_enable(DEBUG_FUNCTIONS);
-		printf("Debugging %s\n", debugging_enabled() ? "on" : "off");
-
-	} else if (strncmp(line, "dump objects", 12) == 0) {
-		dump_game_data(game, DUMP_ITEMS);
-
-	} else if (strncmp(line, "dump rooms", 10) == 0) {
-		dump_game_data(game, DUMP_ROOMS);
-
-	} else if (strncmp(line, "dump state", 10) == 0) {
-		printf("Current room: %.2x\n", game->_currentRoom);
-		printf("Carry weight %d/%d\n\n",
-		       game->_variables[VAR_INVENTORY_WEIGHT],
-		       game->_variables[VAR_INVENTORY_LIMIT]);
-
-		printf("Flags:\n");
-		for (i = 0; i < ARRAY_SIZE(game->_flags); i++)
-			printf("  [%.2x]: %d\n", i, game->_flags[i]);
-		printf("\n");
-
-		printf("Variables:\n");
-		for (i = 0; i < ARRAY_SIZE(game->_variables); i++)
-			printf("  [%.2x]: %5d (0x%.4x)\n",
-			       i, game->_variables[i],
-			       game->_variables[i]);
-		printf("\n");
-	}
-}
-
 static bool handle_sentence(ComprehendGame *game,
                             Sentence *sentence) {
 	Function *func;
@@ -1167,17 +1129,15 @@ static void read_input(ComprehendGame *game) {
 	game->before_prompt();
 	before_turn(game);
 
-	g_comprehend->print("> ");
-	g_comprehend->readLine(buffer, sizeof(buffer));
-	if (g_comprehend->shouldQuit())
-		return;
+	do {
+		g_comprehend->print("> ");
+		g_comprehend->readLine(buffer, sizeof(buffer));
+		if (g_comprehend->shouldQuit())
+			return;
+	} while (strlen(buffer) == 0);
 
 	// Re-comprehend special commands start with '!'
 	line = &buffer[0];
-	if (*line == '!') {
-		handle_debug_command(game, &line[1]);
-		return;
-	}
 
 	while (1) {
 		read_sentence(game, &line, &sentence);
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 4bc7b42a02..0914a777b4 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -23,7 +23,6 @@
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/dictionary.h"
-#include "glk/comprehend/dump_game_data.h"
 #include "glk/comprehend/file_buf.h"
 #include "glk/comprehend/game.h"
 #include "glk/comprehend/graphics.h"
diff --git a/engines/glk/comprehend/util.cpp b/engines/glk/comprehend/util.cpp
index 2a64d1d0c2..62abe26163 100644
--- a/engines/glk/comprehend/util.cpp
+++ b/engines/glk/comprehend/util.cpp
@@ -28,8 +28,6 @@
 namespace Glk {
 namespace Comprehend {
 
-static unsigned debug_flags;
-
 void __fatal_error(const char *func, unsigned line, const char *fmt, ...) {
 	error("TODO");
 }
@@ -60,6 +58,7 @@ char *xstrndup(const char *str, size_t len) {
 }
 
 void debug_printf(unsigned flags, const char *fmt, ...) {
+#ifdef TODO
 	va_list args;
 
 	if (debug_flags & flags) {
@@ -69,19 +68,7 @@ void debug_printf(unsigned flags, const char *fmt, ...) {
 
 		debug(1, "%s", msg.c_str());
 	}
-}
-
-void debug_enable(unsigned flags) {
-	debug_flags |= flags;
-}
-
-void debug_disable(unsigned flags) {
-	debug_flags &= ~flags;
-}
-
-bool debugging_enabled(void) {
-	// FIXME
-	return debug_flags;
+	#endif
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/util.h b/engines/glk/comprehend/util.h
index 335b7b5132..f979d17937 100644
--- a/engines/glk/comprehend/util.h
+++ b/engines/glk/comprehend/util.h
@@ -43,9 +43,6 @@ void *xmalloc(size_t size);
 char *xstrndup(const char *str, size_t size);
 
 void debug_printf(unsigned flags, const char *fmt, ...);
-void debug_enable(unsigned flags);
-void debug_disable(unsigned flags);
-bool debugging_enabled(void);
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/glk.cpp b/engines/glk/glk.cpp
index 3f092e3232..6441f44421 100644
--- a/engines/glk/glk.cpp
+++ b/engines/glk/glk.cpp
@@ -78,7 +78,7 @@ GlkEngine::~GlkEngine() {
 
 void GlkEngine::initialize() {
 	initGraphicsMode();
-	setDebugger(new Debugger());
+	createDebugger();
 
 	_conf = new Conf(getInterpreterType());
 	_screen = createScreen();
@@ -116,6 +116,10 @@ void GlkEngine::initGraphicsMode() {
 	initGraphics(width, height, &format);
 }
 
+void GlkEngine::createDebugger() {
+	setDebugger(new Debugger());
+}
+
 Common::Error GlkEngine::run() {
 	// Open up the game file
 	Common::String filename = getFilename();
diff --git a/engines/glk/glk.h b/engines/glk/glk.h
index fe4d6b8411..0593565914 100644
--- a/engines/glk/glk.h
+++ b/engines/glk/glk.h
@@ -94,6 +94,11 @@ protected:
 	 */
 	virtual void initGraphicsMode();
 
+	/**
+	 * Create the debugger
+	 */
+	virtual void createDebugger();
+
 	/**
 	 * Create the screen
 	 */
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index d4fb6f873d..5bce6774f5 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -167,9 +167,10 @@ MODULE_OBJS := \
 	archetype/timestamp.o \
 	archetype/token.o \
 	comprehend/comprehend.o \
+	comprehend/debugger.o \
+	comprehend/debugger_dumper.o \
 	comprehend/detection.o \
 	comprehend/dictionary.o \
-	comprehend/dump_game_data.o \
 	comprehend/file_buf.o \
 	comprehend/game.o \
 	comprehend/game_cc.o \


Commit: 0f411b62dddefa83e72f367e0a7c45189601ea68
    https://github.com/scummvm/scummvm/commit/0f411b62dddefa83e72f367e0a7c45189601ea68
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Improved graphic vs text area setup

Changed paths:
    engines/glk/comprehend/comprehend.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 0ead807108..c32a0f0875 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -121,8 +121,7 @@ int main(int argc, char **argv) {
 }
 #endif
 
-Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) :
-		GlkAPI(syst, gameDesc), _saveSlot(-1), _game(nullptr) {
+Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc), _saveSlot(-1), _game(nullptr) {
 	g_comprehend = this;
 }
 
@@ -143,13 +142,17 @@ void Comprehend::runGame() {
 
 	deinitialize();
 }
-
 void Comprehend::initialize() {
-	_topWindow = (GraphicsWindow *)glk_window_open(0, 0, 0, wintype_Graphics, 1);
-	_bottomWindow = (TextBufferWindow *)glk_window_open(
-	    _topWindow, winmethod_Below | winmethod_Fixed,
-	    80, wintype_TextBuffer, 0);
+	g_conf->_wMarginX = 0;
+	g_conf->_wMarginY = 0;
+
+	_bottomWindow = (TextBufferWindow *)glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
+	_topWindow = (GraphicsWindow *)glk_window_open(_bottomWindow,
+	                                               winmethod_Above | winmethod_Fixed,
+	                                               400, wintype_Graphics, 2);
+
 	glk_set_window(_bottomWindow);
+	_topWindow->fillRect(0, Rect(0, 0, _topWindow->_w, _topWindow->_h));
 }
 
 void Comprehend::deinitialize() {
@@ -181,7 +184,7 @@ void Comprehend::print(const char *fmt, ...) {
 	va_end(argp);
 
 	glk_put_string_stream(glk_window_get_stream(_bottomWindow),
-		msg.c_str());
+	                      msg.c_str());
 }
 
 void Comprehend::readLine(char *buffer, size_t maxLen) {
@@ -201,6 +204,5 @@ void Comprehend::readLine(char *buffer, size_t maxLen) {
 	buffer[ev.val1] = 0;
 }
 
-
 } // namespace Comprehend
 } // namespace Glk


Commit: 0944b7aa6a60feadf2eed7f1095bf142796e5c7b
    https://github.com/scummvm/scummvm/commit/0944b7aa6a60feadf2eed7f1095bf142796e5c7b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Implementing some graphic primitives

Changed paths:
    engines/glk/comprehend/graphics.cpp
    engines/glk/window_graphics.cpp
    engines/glk/window_graphics.h


diff --git a/engines/glk/comprehend/graphics.cpp b/engines/glk/comprehend/graphics.cpp
index 7d8937423d..bb5441c15e 100644
--- a/engines/glk/comprehend/graphics.cpp
+++ b/engines/glk/comprehend/graphics.cpp
@@ -424,36 +424,14 @@ static void set_color(unsigned color) {
 
 void g_draw_box(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
                 unsigned color) {
-#ifdef TODO
-	SDL_Rect rect;
-	int i;
-
-	rect.x = x1;
-	rect.y = y1;
-	rect.w = x2 - x1;
-	rect.h = y2 - y1;
-
-	set_color(color);
-	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
-		SDL_RenderDrawRect(ctx.renderer[i], &rect);
-#endif
+	Rect r(x1, y1, x2, y2);
+	g_comprehend->_topWindow->frameRect(color, r);
 }
 
 static void g_draw_filled_box(unsigned x1, unsigned y1,
                               unsigned x2, unsigned y2, unsigned color) {
-#ifdef TODO
-	SDL_Rect rect;
-	int i;
-
-	rect.x = x1;
-	rect.y = y1;
-	rect.w = x2 - x1;
-	rect.h = y2 - y1;
-
-	set_color(color);
-	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
-		SDL_RenderFillRect(ctx.renderer[i], &rect);
-#endif
+	Rect r(x1, y1, x2, y2);
+	g_comprehend->_topWindow->fillRect(color, r);
 }
 
 unsigned g_get_pixel_color(int x, int y) {
@@ -481,15 +459,8 @@ void g_draw_pixel(unsigned x, unsigned y, unsigned color) {
 }
 
 void g_draw_line(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
-		 unsigned color)
-{
-#ifdef TODO
-	int i;
-
-	set_color(color);
-	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
-		SDL_RenderDrawLine(ctx.renderer[i], x1, y1, x2, y2);
-#endif
+		 unsigned color) {
+	g_comprehend->_topWindow->drawLine(color, Point(x1, y1), Point(x2, y2));
 }
 
 void g_draw_shape(int x, int y, int shape_type, unsigned fill_color)
@@ -630,27 +601,18 @@ void g_floodfill(int x, int y, unsigned fill_color,
 
 }
 
-void g_flip_buffers(void)
-{
+void g_flip_buffers(void) {
 #ifdef TODO
 	SDL_RenderPresent(ctx.renderer[RENDERER_SCREEN]);
 #endif
 }
 
 void g_clear_screen(unsigned color) {
-	#ifdef TODO
-	int i;
-
-	set_color(color);
-	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
-		SDL_RenderClear(ctx.renderer[i]);
-
-	SDL_RenderPresent(ctx.renderer[RENDERER_SCREEN]);
-#endif
+	GraphicsWindow *win = g_comprehend->_topWindow;
+	win->fillRect(color, Rect(0, 0, win->_w, win->_h));
 }
 
-void g_init(unsigned width, unsigned height)
-{
+void g_init(unsigned width, unsigned height) {
 	#ifdef TODO
 	int err;
 
diff --git a/engines/glk/window_graphics.cpp b/engines/glk/window_graphics.cpp
index f9fd43a878..2090165441 100644
--- a/engines/glk/window_graphics.cpp
+++ b/engines/glk/window_graphics.cpp
@@ -177,6 +177,16 @@ void GraphicsWindow::fillRect(uint color, const Rect &box) {
 	touch();
 }
 
+void GraphicsWindow::frameRect(uint color, const Rect &box) {
+	_surface->frameRect(box, color);
+	touch();
+}
+
+void GraphicsWindow::drawLine(uint color, const Point &from, const Point &to) {
+	_surface->drawLine(from.x, from.y, to.x, to.y, color);
+	touch();
+}
+
 void GraphicsWindow::drawPicture(Picture *src, int x0, int y0, int width, int height, uint linkval) {
 	if (width != src->w || height != src->h) {
 		src = g_vm->_pictures->scale(src, width, height);
diff --git a/engines/glk/window_graphics.h b/engines/glk/window_graphics.h
index 6fdc74ea62..7a3eb9bc48 100644
--- a/engines/glk/window_graphics.h
+++ b/engines/glk/window_graphics.h
@@ -103,8 +103,21 @@ public:
 
 	void eraseRect(bool whole, const Rect &box) override;
 
+	/**
+	 * Fill an area of the window
+	 */
 	void fillRect(uint color, const Rect &box) override;
 
+	/**
+	 * Draw a rectangle in the given area
+	 */
+	void frameRect(uint color, const Rect &box);
+
+	/**
+	 * Draws a line between two points
+	 */
+	void drawLine(uint color, const Point &from, const Point &to);
+
 	void getSize(uint *width, uint *height) const override;
 
 	void setBackgroundColor(uint color) override;


Commit: 687ed8be0408aaf8f943b88928e9c408c342a7ae
    https://github.com/scummvm/scummvm/commit/687ed8be0408aaf8f943b88928e9c408c342a7ae
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Objectifying image file methods

Changed paths:
  R engines/glk/comprehend/image_view.cpp
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/file_buf.cpp
    engines/glk/comprehend/file_buf.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/graphics.cpp
    engines/glk/comprehend/graphics.h
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_data.h
    engines/glk/module.mk


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index c32a0f0875..e9e54ad241 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -30,6 +30,7 @@
 #include "glk/comprehend/game_oo.h"
 #include "glk/comprehend/game_tm.h"
 #include "glk/comprehend/game_tr.h"
+#include "glk/comprehend/graphics.h"
 #include "glk/quetzal.h"
 
 namespace Glk {
@@ -153,6 +154,8 @@ void Comprehend::initialize() {
 
 	glk_set_window(_bottomWindow);
 	_topWindow->fillRect(0, Rect(0, 0, _topWindow->_w, _topWindow->_h));
+
+	g_init();
 }
 
 void Comprehend::deinitialize() {
diff --git a/engines/glk/comprehend/file_buf.cpp b/engines/glk/comprehend/file_buf.cpp
index d22fd2495d..426cbf4672 100644
--- a/engines/glk/comprehend/file_buf.cpp
+++ b/engines/glk/comprehend/file_buf.cpp
@@ -43,6 +43,12 @@ bool FileBuffer::exists(const Common::String &filename) {
 	return Common::File::exists(filename);
 }
 
+void FileBuffer::close() {
+	_data.clear();
+	_readBytes.clear();
+	_pos = 0;
+}
+
 bool FileBuffer::seek(int32 offset, int whence) {
 	switch (whence) {
 	case SEEK_SET:
diff --git a/engines/glk/comprehend/file_buf.h b/engines/glk/comprehend/file_buf.h
index 0805842809..ed66911a36 100644
--- a/engines/glk/comprehend/file_buf.h
+++ b/engines/glk/comprehend/file_buf.h
@@ -40,6 +40,7 @@ public:
 	FileBuffer() : _pos(0) {}
 	FileBuffer(const Common::String &filename);
 	static bool exists(const Common::String &filename);
+	void close();
 
 	int32 pos() const override { return _pos; }
 	int32 size() const override { return _data.size(); }
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 0914a777b4..a5c60bd699 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -1019,7 +1019,10 @@ void comprehend_load_game(ComprehendGame *game) {
 	load_game_data(game);
 
 	if (g_enabled()) {
-		comprehend_load_images(game);
+		// Set up image files
+		game->_roomImages.load(game->_locationGraphicFiles);
+		game->_itemImages.load(game->_itemGraphicFiles);
+
 		if (game->_colorTable)
 			g_set_color_table(game->_colorTable);
 	}
diff --git a/engines/glk/comprehend/graphics.cpp b/engines/glk/comprehend/graphics.cpp
index bb5441c15e..13d215d10d 100644
--- a/engines/glk/comprehend/graphics.cpp
+++ b/engines/glk/comprehend/graphics.cpp
@@ -612,32 +612,7 @@ void g_clear_screen(unsigned color) {
 	win->fillRect(color, Rect(0, 0, win->_w, win->_h));
 }
 
-void g_init(unsigned width, unsigned height) {
-	#ifdef TODO
-	int err;
-
-	err = SDL_Init(SDL_INIT_VIDEO);
-	if (err == -1)
-		fatal_error("Failed to initialize graphics\n");
-
-	SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "2");
-
-	ctx.screen = SDL_CreateWindow("Re-Comprehend",
-				      SDL_WINDOWPOS_CENTERED,
-				      SDL_WINDOWPOS_CENTERED,
-				      width, height, 0);
-
-	ctx.renderer[RENDERER_SCREEN] =
-		SDL_CreateRenderer(ctx.screen, -1, SDL_RENDERER_ACCELERATED);
-	SDL_RenderSetLogicalSize(ctx.renderer[RENDERER_SCREEN],
-				 G_RENDER_WIDTH, G_RENDER_HEIGHT);
-
-	ctx.surface = SDL_CreateRGBSurface(0, G_RENDER_WIDTH, G_RENDER_HEIGHT,
-					   32, 0x000000ff, 0x0000ff00,
-					   0x00ff0000, 0xff000000);
-	ctx.renderer[RENDERER_PIXEL_DATA] =
-		SDL_CreateSoftwareRenderer(ctx.surface);
-#endif
+void g_init() {
 	graphics_enabled = true;
 }
 
diff --git a/engines/glk/comprehend/graphics.h b/engines/glk/comprehend/graphics.h
index 414850cbc1..99815b6b56 100644
--- a/engines/glk/comprehend/graphics.h
+++ b/engines/glk/comprehend/graphics.h
@@ -79,7 +79,7 @@ void g_floodfill(int x, int y, unsigned fill_color, unsigned old_color);
 
 void g_clear_screen(unsigned color);
 void g_flip_buffers(void);
-void g_init(unsigned width, unsigned height);
+void g_init();
 bool g_enabled(void);
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index a256f33ccd..50893e6c37 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -46,33 +46,53 @@ struct ImageContext {
 
 static unsigned draw_flags;
 
-void ImageData::clear() {
-	fb = nullptr;
-	image_offsets = nullptr;
-	nr_images = 0;
-}
+/*-------------------------------------------------------*/
 
-void image_set_draw_flags(unsigned flags)
-{
-	draw_flags |= flags;
+void ImageFileData::load(const char *filename) {
+	uint16 version;
+	int i;
+
+	_fb = FileBuffer(filename);
+
+	/*
+	 * In earlier versions of Comprehend the first word is 0x1000 and
+	 * the image offsets start four bytes in. In newer versions the
+	 * image offsets start at the beginning of the image file.
+	 */
+	version = _fb.readUint16LE();
+	if (version == 0x1000)
+		_fb.seek(4);
+	else
+		_fb.seek(0);
+
+	// Get the image offsets in the file
+	_imageOffsets.resize(IMAGES_PER_FILE);
+	for (i = 0; i < IMAGES_PER_FILE; i++) {
+		_imageOffsets[i] = _fb.readUint16LE();
+		if (version == 0x1000)
+			_imageOffsets[i] += 4;
+	}
 }
 
-static uint16 image_get_operand(FileBuffer *fb)
-{
-	uint8 val;
+void ImageFileData::draw(uint index, ImageContext *ctx) {
+	_fb.seek(_imageOffsets[index]);
 
-	val = fb->readByte();
-	return val;
+	for (bool done = false; !done;) {
+		done = doImageOp(ctx);
+		if (!done && (draw_flags & IMAGEF_OP_WAIT_KEYPRESS)) {
+			getchar();
+			g_flip_buffers();
+		}
+	}
 }
 
-static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
-{
+bool ImageFileData::doImageOp(ImageContext *ctx) {
 	uint8 opcode;
 	uint16 a, b;
 
-	opcode = fb->readByte();
+	opcode = _fb.readByte();
 	debug_printf(DEBUG_IMAGE_DRAW,
-		     "  %.4x [%.2x]: ", fb->pos() - 1, opcode);
+	             "  %.4x [%.2x]: ", _fb.pos() - 1, opcode);
 
 	switch (opcode) {
 	case IMAGE_OP_SCENE_END:
@@ -94,15 +114,15 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 
 	case IMAGE_OP_DRAW_LINE:
 	case IMAGE_OP_DRAW_LINE_FAR:
-		a = image_get_operand(fb);
-		b = image_get_operand(fb);
+		a = imageGetOperand();
+		b = imageGetOperand();
 
 		if (opcode & 0x1)
 			a += 255;
 
 		debug_printf(DEBUG_IMAGE_DRAW,
-			     "draw_line (%d, %d) - (%d, %d)\n", opcode,
-			     ctx->x, ctx->y, a, b);
+		             "draw_line (%d, %d) - (%d, %d)\n", opcode,
+		             ctx->x, ctx->y, a, b);
 		g_draw_line(ctx->x, ctx->y, a, b, ctx->pen_color);
 
 		ctx->x = a;
@@ -111,15 +131,15 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 
 	case IMAGE_OP_DRAW_BOX:
 	case IMAGE_OP_DRAW_BOX_FAR:
-		a = image_get_operand(fb);
-		b = image_get_operand(fb);
+		a = imageGetOperand();
+		b = imageGetOperand();
 
 		if (opcode & 0x1)
 			a += 255;
 
 		debug_printf(DEBUG_IMAGE_DRAW,
-			     "draw_box (%d, %d) - (%d, %d)\n", opcode,
-			     ctx->x, ctx->y, a, b);
+		             "draw_box (%d, %d) - (%d, %d)\n", opcode,
+		             ctx->x, ctx->y, a, b);
 
 		g_draw_box(ctx->x, ctx->y, a, b, ctx->pen_color);
 		break;
@@ -127,8 +147,8 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 	case IMAGE_OP_MOVE_TO:
 	case IMAGE_OP_MOVE_TO_FAR:
 		/* Move to */
-		a = image_get_operand(fb);
-		b = image_get_operand(fb);
+		a = imageGetOperand();
+		b = imageGetOperand();
 
 		if (opcode & 0x1)
 			a += 255;
@@ -147,7 +167,7 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 	case IMAGE_OP_SHAPE_A:
 	case IMAGE_OP_SHAPE_SPRAY:
 		debug_printf(DEBUG_IMAGE_DRAW,
-			     "set_shape_type(%.2x)\n", opcode - 0x40);
+		             "set_shape_type(%.2x)\n", opcode - 0x40);
 		ctx->shape = opcode;
 		break;
 
@@ -162,15 +182,15 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 
 	case IMAGE_OP_DRAW_SHAPE:
 	case IMAGE_OP_DRAW_SHAPE_FAR:
-		a = image_get_operand(fb);
-		b = image_get_operand(fb);
+		a = imageGetOperand();
+		b = imageGetOperand();
 
 		if (opcode & 0x1)
 			a += 255;
 
 		debug_printf(DEBUG_IMAGE_DRAW,
-			     "draw_shape(%d, %d), style=%.2x, fill=%.2x\n",
-			     a, b, ctx->shape, ctx->fill_color);
+		             "draw_shape(%d, %d), style=%.2x, fill=%.2x\n",
+		             a, b, ctx->shape, ctx->fill_color);
 
 		g_draw_shape(a, b, ctx->shape, ctx->fill_color);
 		break;
@@ -178,8 +198,8 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 	case IMAGE_OP_PAINT:
 	case IMAGE_OP_PAINT_FAR:
 		/* Paint */
-		a = image_get_operand(fb);
-		b = image_get_operand(fb);
+		a = imageGetOperand();
+		b = imageGetOperand();
 
 		if (opcode & 0x1)
 			a += 255;
@@ -187,18 +207,18 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 		debug_printf(DEBUG_IMAGE_DRAW, "paint(%d, %d)\n", a, b);
 		if (!(draw_flags & IMAGEF_NO_FLOODFILL))
 			g_floodfill(a, b, ctx->fill_color,
-				    g_get_pixel_color(a, b));
+			            g_get_pixel_color(a, b));
 		break;
 
 	case IMAGE_OP_FILL_COLOR:
-		a = image_get_operand(fb);
+		a = imageGetOperand();
 		debug_printf(DEBUG_IMAGE_DRAW, "set_fill_color(%.2x)\n", a);
 		ctx->fill_color = g_set_fill_color(a);
 		break;
 
 	case IMAGE_OP_SET_TEXT_POS:
-		a = image_get_operand(fb);
-		b = image_get_operand(fb);
+		a = imageGetOperand();
+		b = imageGetOperand();
 		debug_printf(DEBUG_IMAGE_DRAW, "set_text_pos(%d, %d)\n", a, b);
 
 		ctx->text_x = a;
@@ -206,12 +226,12 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 		break;
 
 	case IMAGE_OP_DRAW_CHAR:
-		a = image_get_operand(fb);
+		a = imageGetOperand();
 		debug_printf(DEBUG_IMAGE_DRAW, "draw_char(%c)\n",
-			     a >= 0x20 && a < 0x7f ? a : '?');
+		             a >= 0x20 && a < 0x7f ? a : '?');
 
 		g_draw_box(ctx->text_x, ctx->text_y,
-			   ctx->text_x + 6, ctx->text_y + 7, ctx->fill_color);
+		           ctx->text_x + 6, ctx->text_y + 7, ctx->fill_color);
 		ctx->text_x += 8;
 		break;
 
@@ -234,19 +254,19 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 	case 0xb0:
 	case 0xd0:
 		/* FIXME - unknown, one argument */
-		a = image_get_operand(fb);
+		a = imageGetOperand();
 		debug_printf(DEBUG_IMAGE_DRAW, "unknown %.2x: (%.2x) '%c'\n",
-			     opcode, a,
-			     a >= 0x20 && a < 0x7f ? a : '?');
+		             opcode, a,
+		             a >= 0x20 && a < 0x7f ? a : '?');
 		break;
 
 	default:
 		/* FIXME - Unknown, two arguments */
-		a = image_get_operand(fb);
-		b = image_get_operand(fb);
+		a = imageGetOperand();
+		b = imageGetOperand();
 
 		debug_printf(DEBUG_IMAGE_DRAW,
-			     "unknown(%.2x, %.2x)\n", a, b);
+		             "unknown(%.2x, %.2x)\n", a, b);
 		g_draw_pixel(a, b, 0x00ff00ff);
 		break;
 	}
@@ -254,34 +274,48 @@ static bool do_image_op(FileBuffer *fb, ImageContext *ctx)
 	return false;
 }
 
-void draw_image(ImageData *info, unsigned index)
-{
-	unsigned file_num;
-	FileBuffer *fb;
-	bool done = false;
+uint16 ImageFileData::imageGetOperand() {
+	return _fb.readByte();
+}
+
+/*-------------------------------------------------------*/
+
+ImageData::ImageData() {
+}
+
+
+void ImageData::clear() {
+	_files.clear();
+}
+
+void ImageData::load(const Common::Array<const char *> &filenames) {
+	// Set up files array
+	clear();
+	_files.resize(filenames.size());
+
+	// Iterate through loading each file
+	for (uint idx = 0; idx < filenames.size(); ++idx)
+		_files[idx].load(filenames[idx]);
+}
+
+/*-------------------------------------------------------*/
+
+void image_set_draw_flags(unsigned flags) {
+	draw_flags |= flags;
+}
+
+void draw_image(ImageData *info, unsigned index) {
 	ImageContext ctx = {
 		0, 0, G_COLOR_BLACK, G_COLOR_BLACK, IMAGE_OP_SHAPE_CIRCLE_LARGE, 0, 0
 	};
 
-	file_num = index / IMAGES_PER_FILE;
-	fb = &info->fb[file_num];
-
-	if (index >= info->nr_images) {
+	if (index >= (info->size() * IMAGES_PER_FILE)) {
 		warning("Bad image index %.8x (max=%.8x)\n", index,
-		       (uint)info->nr_images);
+		       (uint)info->size());
 		return;
 	}
 
-	fb->seek(info->image_offsets[index]);
-	while (!done) {
-		done = do_image_op(fb, &ctx);
-		if (!done && (draw_flags & IMAGEF_OP_WAIT_KEYPRESS)) {
-			getchar();
-			g_flip_buffers();
-		}
-	}
-
-	g_flip_buffers();
+	(*info)[index / IMAGES_PER_FILE].draw(index % IMAGES_PER_FILE, &ctx);
 }
 
 void draw_dark_room(void)
@@ -300,66 +334,5 @@ void draw_location_image(ImageData *info, unsigned index)
 	draw_image(info, index);
 }
 
-static void load_image_file(ImageData *info, const char *filename,
-			    unsigned file_num)
-{
-	unsigned base = file_num * IMAGES_PER_FILE;
-	FileBuffer *fb;
-	uint16 version;
-	int i;
-
-	info->fb[file_num] = FileBuffer(filename);
-	fb = &info->fb[file_num];
-
-	/*
-	 * In earlier versions of Comprehend the first word is 0x1000 and
-	 * the image offsets start four bytes in. In newer versions the
-	 * image offsets start at the beginning of the image file.
-	 */
-	version = fb->readUint16LE();
-	if (version == 0x1000)
-		fb->seek(4);
-	else
-		fb->seek(0);
-
-	/* Get the image offsets in the file */
-	for (i = 0; i < IMAGES_PER_FILE; i++) {
-		info->image_offsets[base + i] = fb->readUint16LE();
-		if (version == 0x1000)
-			info->image_offsets[base + i] += 4;
-	}
-}
-
-static void load_image_files(ImageData *info,
-	const Common::Array<const char *> filenames) {
-	uint i;
-
-	memset(info, 0, sizeof(*info));
-
-	info->nr_images = filenames.size() * IMAGES_PER_FILE;
-	info->fb = (FileBuffer *)xmalloc(info->nr_images * sizeof(*info->fb));
-	info->image_offsets = (uint16 *)xmalloc(info->nr_images * sizeof(uint16));
-
-	for (i = 0; i < filenames.size(); i++) {
-		load_image_file(info, filenames[i], i);
-	}
-}
-
-void comprehend_load_image_file(const char *filename, ImageData *info)
-{
-	Common::Array<const char *> filenames;
-	filenames.push_back(filename);
-
-	load_image_files(info, filenames);
-}
-
-void comprehend_load_images(ComprehendGame *game) {
-	load_image_files(&game->_roomImages,
-			 game->_locationGraphicFiles);
-
-	load_image_files(&game->_itemImages,
-			 game->_itemGraphicFiles);
-}
-
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
index 718b57c9aa..30b40175b9 100644
--- a/engines/glk/comprehend/image_data.h
+++ b/engines/glk/comprehend/image_data.h
@@ -23,6 +23,7 @@
 #ifndef GLK_COMPREHEND_IMAGE_DATA_H
 #define GLK_COMPREHEND_IMAGE_DATA_H
 
+#include "glk/comprehend/file_buf.h"
 #include "common/scummsys.h"
 
 namespace Glk {
@@ -30,17 +31,35 @@ namespace Comprehend {
 
 class ComprehendGame;
 struct FileBuffer;
+struct ImageContext;
 
-struct ImageData {
-	FileBuffer	*fb;
-	uint16	*image_offsets;
-	size_t		nr_images;
+struct ImageFileData {
+private:
+	Common::Array<uint16> _imageOffsets;
+	FileBuffer _fb;
+
+private:
+	bool doImageOp(ImageContext *ctx);
+	uint16 imageGetOperand();
 
-	ImageData() {
-		clear();
-	}
+	public:
+	void load(const char *filename);
 
+	void draw(uint index, ImageContext *ctx);
+};
+
+struct ImageData {
+private:
+	Common::Array<ImageFileData> _files;
+
+public:
+	ImageData();
 	void clear();
+
+	uint size() const { return _files.size(); }
+	ImageFileData &operator[](uint index) { return _files[index]; }
+
+	void load(const Common::Array<const char *> &filenames);
 };
 
 #define IMAGEF_OP_WAIT_KEYPRESS		(1 << 0)
@@ -96,9 +115,6 @@ void draw_bright_room(void);
 void draw_image(ImageData *info, unsigned index);
 void draw_location_image(ImageData *info, unsigned index);
 
-void comprehend_load_image_file(const char *filename, ImageData *info);
-void comprehend_load_images(ComprehendGame *game);
-
 } // namespace Comprehend
 } // namespace Glk
 
diff --git a/engines/glk/comprehend/image_view.cpp b/engines/glk/comprehend/image_view.cpp
deleted file mode 100644
index c059316e80..0000000000
--- a/engines/glk/comprehend/image_view.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-/* 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 "glk/comprehend/image_data.h"
-#include "glk/comprehend/graphics.h"
-#include "glk/comprehend/util.h"
-#include "glk/comprehend/comprehend.h"
-
-namespace Glk {
-namespace Comprehend {
-
-#ifdef TODO
-static void usage(const char *progname)
-{
-	printf("%s: [OPTION]... FILENAME INDEX\n", progname);
-	printf("\nOptions:\n");
-	printf("  -w, --width=WIDTH       Graphics width\n");
-	printf("  -h, --height=HEIGHT     Graphics height\n");
-	printf("  -c, --clear=COLOR       Graphics clear color\n");
-	printf("  -t, --color-table=INDEX Color table\n");
-	printf("  -s, --sequence          Disable sequence of images\n");
-	printf("  -p, --pause             Wait for keypress after each draw operation\n");
-	printf("  -f, --floodfill-disable Disable floodfill operation\n");
-	printf("  -d, --debug             Enable debugging\n");
-	exit(EXIT_FAILURE);
-}
-
-int main(int argc, char **argv)
-{
-	struct option long_opts[] = {
-		{"width",		required_argument,	0, 'w'},
-		{"height",		required_argument,	0, 'h'},
-		{"clear",		required_argument,	0, 'c'},
-		{"color-table",		required_argument,	0, 't'},
-		{"sequence",		no_argument,		0, 's'},
-		{"pause",		no_argument,		0, 'p'},
-		{"floodfill-disable",	no_argument,		0, 'f'},
-		{"debug",		no_argument,		0, 'd'},
-		{"help",		no_argument,		0, '?'},
-		{NULL,			0,			0, 0},
-	};
-	const char *short_opts = "w:h:c:t:spfd?";
-	image_data info;
-	const char *filename;
-	unsigned index, clear_color = G_COLOR_WHITE,
-		graphics_width = G_RENDER_WIDTH,
-		graphics_height = G_RENDER_HEIGHT,
-		color_table = 0;
-	bool sequence = false;
-	int c, opt_index;
-
-	while (1) {
-		c = getopt_long(argc, argv, short_opts, long_opts, &opt_index);
-		if (c == -1)
-			break;
-
-		switch (c) {
-		case 'w':
-			graphics_width = strtoul(optarg, NULL, 0);
-			break;
-
-		case 'h':
-			graphics_height = strtoul(optarg, NULL, 0);
-			break;
-
-		case 'c':
-			clear_color = strtoul(optarg, NULL, 0);
-			break;
-
-		case 't':
-			color_table = strtoul(optarg, NULL, 0);
-			break;
-
-		case 's':
-			sequence = true;
-			break;
-
-		case 'p':
-			image_set_draw_flags(IMAGEF_OP_WAIT_KEYPRESS);
-			break;
-
-		case 'f':
-			image_set_draw_flags(IMAGEF_NO_FLOODFILL);
-			break;
-
-		case 'd':
-			debug_enable(DEBUG_IMAGE_DRAW);
-			break;
-
-		case '?':
-			usage(argv[0]);
-			break;
-
-		default:
-			printf("Invalid option\n");
-			usage(argv[0]);
-			break;
-		}
-	}
-
-	if (optind >= argc || argc - optind != 2)
-		usage(argv[0]);
-
-	filename = argv[optind++];
-	index = strtoul(argv[optind++], NULL, 0);
-
-	g_init(graphics_width, graphics_height);
-	g_set_color_table(color_table);
-	comprehend_load_image_file(filename, &info);
-
-	while (index < 16) {
-		g_clear_screen(clear_color);
-		draw_image(&info, index);
-
-		c = getchar();
-		if (!sequence || c == 'q' || c == 'Q')
-			break;
-
-		index++;
-		printf("Image %d\n", index);
-	}
-
-	exit(EXIT_SUCCESS);
-}
-#endif
-
-} // namespace Comprehend
-} // namespace Glk
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 5bce6774f5..95b099f24a 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -180,7 +180,6 @@ MODULE_OBJS := \
 	comprehend/game_tr.o \
 	comprehend/graphics.o \
 	comprehend/image_data.o \
-	comprehend/image_view.o \
 	comprehend/opcode_map.o \
 	comprehend/strings.o \
 	comprehend/util.o \


Commit: 4fc86e1bc9a4c4e0d71fe52488144c8356764275
    https://github.com/scummvm/scummvm/commit/4fc86e1bc9a4c4e0d71fe52488144c8356764275
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Refactoring drawing code

Changed paths:
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/graphics.cpp
    engines/glk/comprehend/graphics.h
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_data.h
    graphics/font.h


diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index a5c60bd699..668f8b6438 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -1024,7 +1024,7 @@ void comprehend_load_game(ComprehendGame *game) {
 		game->_itemImages.load(game->_itemGraphicFiles);
 
 		if (game->_colorTable)
-			g_set_color_table(game->_colorTable);
+			DrawSurface::setColorTable(game->_colorTable);
 	}
 
 	/* FIXME - This can be merged, don't need to keep start room around */
diff --git a/engines/glk/comprehend/graphics.cpp b/engines/glk/comprehend/graphics.cpp
index 13d215d10d..4f2268be7a 100644
--- a/engines/glk/comprehend/graphics.cpp
+++ b/engines/glk/comprehend/graphics.cpp
@@ -37,7 +37,7 @@ namespace Comprehend {
 
 static bool graphics_enabled;
 
-static unsigned pen_colors[] = {
+const uint32 DrawSurface::PEN_COLORS[8] = {
     G_COLOR_BLACK,
     RGB(0x00, 0x66, 0x00),
     RGB(0x00, 0xff, 0x00),
@@ -48,31 +48,8 @@ static unsigned pen_colors[] = {
     RGB(0xff, 0x00, 0x00),
 };
 
-struct GraphicsContext {
-	Window *screen;
-
-	/*
-	 * FIXME - Currently using two renderers. One for drawing the (possibly
-	 *         scaled) image to the screen and the other for getting pixel
-	 *         data for floodfill boundaries. This is almost certainly not
-	 *         the best way to do this.
-	 */
-	//	SDL_Renderer	*renderer[2];
-
-	/* Used for pixel access for flood fills */
-	//	SDL_Surface	*surface;
-};
-
-#ifdef TODO
-static GraphicsContext ctx;
-#endif
-
-unsigned g_set_pen_color(uint8 opcode) {
-	return pen_colors[opcode - IMAGE_OP_PEN_COLOR_A];
-}
-
 /* Used by Transylvania and Crimson Crown */
-static unsigned default_color_table[] = {
+const uint32 DrawSurface::DEFAULT_COLOR_TABLE[256] = {
     G_COLOR_WHITE,     // 00
     G_COLOR_DARK_BLUE, // 01
     G_COLOR_GRAY1,     // 02
@@ -117,55 +94,10 @@ static unsigned default_color_table[] = {
 
 /* Used by OO-topos */
 /* FIXME - incomplete */
-static unsigned color_table_1[] = {
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
+const uint32 DrawSurface::COLOR_TABLE_1[256] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     0,
     0,
     0,
@@ -234,172 +166,44 @@ static unsigned color_table_1[] = {
     0,
     0,
 
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-    0,
-};
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
 
-static unsigned *color_tables[] = {
-    default_color_table,
-    color_table_1,
+const uint32 *DrawSurface::COLOR_TABLES[2] = {
+    DEFAULT_COLOR_TABLE,
+    COLOR_TABLE_1,
 };
 
-static unsigned *color_table = default_color_table;
+const uint32 *DrawSurface::_colorTable = DEFAULT_COLOR_TABLE;
+
+uint32 DrawSurface::_renderColor;
+
+/*-------------------------------------------------------*/
+
+void DrawSurface::reset() {
+	create(G_RENDER_WIDTH, G_RENDER_HEIGHT,
+	       Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
+}
 
-void g_set_color_table(unsigned index) {
-	if (index >= ARRAY_SIZE(color_tables)) {
-		printf("Bad color table %d - using default\n", index);
-		color_table = default_color_table;
+void DrawSurface::setColorTable(uint index) {
+	if (index >= ARRAY_SIZE(COLOR_TABLES)) {
+		warning("Bad color table %d - using default", index);
+		_colorTable = DEFAULT_COLOR_TABLE;
 	}
 
-	color_table = color_tables[index];
+	_colorTable = COLOR_TABLES[index];
 }
 
-unsigned g_set_fill_color(uint8 index) {
+uint DrawSurface::getPenColor(uint8 opcode) const {
+	return PEN_COLORS[opcode - IMAGE_OP_PEN_COLOR_A];
+}
+
+uint32 DrawSurface::getFillColor(uint8 index) {
 	unsigned color;
 
-	color = color_table[index];
+	color = _colorTable[index];
 	if (!color) {
 		/* Unknown color - use ugly purple */
 		debug_printf(DEBUG_IMAGE_DRAW, "Unknown color %.2x\n", index);
@@ -409,155 +213,119 @@ unsigned g_set_fill_color(uint8 index) {
 	return color;
 }
 
-#ifdef TODO
-static void set_color(unsigned color) {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
-		SDL_SetRenderDrawColor(ctx.renderer[i],
-		                       (color >> 24) & 0xff,
-		                       (color >> 16) & 0xff,
-		                       (color >> 8) & 0xff,
-		                       (color >> 0) & 0xff);
+void DrawSurface::drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint32 color) {
+	Graphics::ManagedSurface::drawLine(x1, y1, x2, y2, color);
 }
-#endif
 
-void g_draw_box(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
-                unsigned color) {
-	Rect r(x1, y1, x2, y2);
-	g_comprehend->_topWindow->frameRect(color, r);
+void DrawSurface::drawBox(uint16 x1, uint16 y1, uint16 x2, uint16 y2,
+                          uint32 color) {
+	Common::Rect r(x1, y1, x2, y2);
+	frameRect(r, color);
 }
 
-static void g_draw_filled_box(unsigned x1, unsigned y1,
-                              unsigned x2, unsigned y2, unsigned color) {
-	Rect r(x1, y1, x2, y2);
-	g_comprehend->_topWindow->fillRect(color, r);
+void DrawSurface::drawFilledBox(uint16 x1, uint16 y1,
+                                uint16 x2, uint16 y2, uint32 color) {
+	Common::Rect r(x1, y1, x2, y2);
+	fillRect(r, color);
 }
 
-unsigned g_get_pixel_color(int x, int y) {
-#ifdef TODO
-	uint32 *pixels, val;
-
-	pixels = ctx.surface->pixels;
-	val = pixels[(y * G_RENDER_WIDTH) + x];
-
-	/* FIXME - correct endianess on all platforms? */
-	return be32toh(val);
-#else
-	return 0;
-#endif
-}
-
-void g_draw_pixel(unsigned x, unsigned y, unsigned color) {
-#ifdef TODO
-	int i;
-
-	set_color(color);
-	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
-		SDL_RenderDrawPoint(ctx.renderer[i], x, y);
-#endif
-}
-
-void g_draw_line(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
-		 unsigned color) {
-	g_comprehend->_topWindow->drawLine(color, Point(x1, y1), Point(x2, y2));
-}
-
-void g_draw_shape(int x, int y, int shape_type, unsigned fill_color)
-{
+void DrawSurface::drawShape(int x, int y, int shape_type, uint32 fill_color) {
 	int i, j;
 
 	switch (shape_type) {
 	case IMAGE_OP_SHAPE_PIXEL:
-		x += 7; y += 7;
-		g_draw_pixel(x, y, fill_color);
+		x += 7;
+		y += 7;
+		drawPixel(x, y, fill_color);
 		break;
 
 	case IMAGE_OP_SHAPE_BOX:
-		x += 6; y += 7;
-		g_draw_filled_box(x, y, x + 2, y + 2, fill_color);
+		x += 6;
+		y += 7;
+		drawFilledBox(x, y, x + 2, y + 2, fill_color);
 		break;
 
 	case IMAGE_OP_SHAPE_CIRCLE_TINY:
 		x += 5;
 		y += 5;
-		g_draw_filled_box(x + 1, y, x + 3, y + 4, fill_color);
-		g_draw_filled_box(x, y + 1, x + 4, y + 3, fill_color);
+		drawFilledBox(x + 1, y, x + 3, y + 4, fill_color);
+		drawFilledBox(x, y + 1, x + 4, y + 3, fill_color);
 		break;
 
 	case IMAGE_OP_SHAPE_CIRCLE_SMALL:
-		x += 4; y += 4;
-		g_draw_filled_box(x + 1, y, x + 5, y + 6, fill_color);
-		g_draw_filled_box(x, y + 1, x + 6, y + 5, fill_color);
+		x += 4;
+		y += 4;
+		drawFilledBox(x + 1, y, x + 5, y + 6, fill_color);
+		drawFilledBox(x, y + 1, x + 6, y + 5, fill_color);
 		break;
 
 	case IMAGE_OP_SHAPE_CIRCLE_MED:
-		x += 1; y += 1;
-		g_draw_filled_box(x + 1,
-				  y + 1,
-				  x + 1 + (2 + 4 + 2),
-				  y + 1 + (2 + 4 + 2),
-				  fill_color);
-		g_draw_filled_box(x + 3,
-				  y,
-				  x + 3 + 4,
-				  y + (1 + 2 + 4 + 2 + 1),
-				  fill_color);
-		g_draw_filled_box(x,
-				  y + 3,
-				  x + (1 + 2 + 4 + 2 + 1),
-				  y + 3 + 4,
-				  fill_color);
+		x += 1;
+		y += 1;
+		drawFilledBox(x + 1,
+		              y + 1,
+		              x + 1 + (2 + 4 + 2),
+		              y + 1 + (2 + 4 + 2),
+		              fill_color);
+		drawFilledBox(x + 3,
+		              y,
+		              x + 3 + 4,
+		              y + (1 + 2 + 4 + 2 + 1),
+		              fill_color);
+		drawFilledBox(x,
+		              y + 3,
+		              x + (1 + 2 + 4 + 2 + 1),
+		              y + 3 + 4,
+		              fill_color);
 		break;
 
 	case IMAGE_OP_SHAPE_CIRCLE_LARGE:
-		g_draw_filled_box(x + 2,
-				  y + 1,
-				  x + 2 + (3 + 4 + 3),
-				  y + 1 + (1 + 3 + 4 + 3 + 1),
-				  fill_color);
-		g_draw_filled_box(x + 1,
-				  y + 2,
-				  x + 1 + (1 + 3 + 4 + 3 + 1),
-				  y + 2 + (3 + 4 + 3),
-				  fill_color);
-		g_draw_filled_box(x + 5,
-				  y,
-				  x + 5 + 4,
-				  y + 1 + 1 + 3 + 4 + 3 + 1 + 1,
-				  fill_color);
-		g_draw_filled_box(x,
-				  y + 5,
-				  x + 1 + 1 + 3 + 4 + 3 + 1 + 1,
-				  y + 5 + 4,
-				  fill_color);
+		drawFilledBox(x + 2,
+		              y + 1,
+		              x + 2 + (3 + 4 + 3),
+		              y + 1 + (1 + 3 + 4 + 3 + 1),
+		              fill_color);
+		drawFilledBox(x + 1,
+		              y + 2,
+		              x + 1 + (1 + 3 + 4 + 3 + 1),
+		              y + 2 + (3 + 4 + 3),
+		              fill_color);
+		drawFilledBox(x + 5,
+		              y,
+		              x + 5 + 4,
+		              y + 1 + 1 + 3 + 4 + 3 + 1 + 1,
+		              fill_color);
+		drawFilledBox(x,
+		              y + 5,
+		              x + 1 + 1 + 3 + 4 + 3 + 1 + 1,
+		              y + 5 + 4,
+		              fill_color);
 		break;
 
 	case IMAGE_OP_SHAPE_A:
 		/* FIXME - very large circle? */
 		break;
 
-	case IMAGE_OP_SHAPE_SPRAY:
-	{
+	case IMAGE_OP_SHAPE_SPRAY: {
 		char spray[13][13] = {
-			{0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
-			{0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
-			{0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1},
-			{0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
-			{1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0},
-			{0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0},
-			{0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0},
-			{1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0},
-			{0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0},
-			{1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0},
-			{0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0},
-			{0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
-			{0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0},
+		    {0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
+		    {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
+		    {0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1},
+		    {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
+		    {1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0},
+		    {0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0},
+		    {0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0},
+		    {1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0},
+		    {0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0},
+		    {1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0},
+		    {0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0},
+		    {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+		    {0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0},
 		};
 		for (i = 0; i < 13; i++)
 			for (j = 0; j < 13; j++)
 				if (spray[i][j])
-					g_draw_pixel(x + i, y + j, fill_color);
+					drawPixel(x + i, y + j, fill_color);
 		break;
 	}
 
@@ -567,57 +335,79 @@ void g_draw_shape(int x, int y, int shape_type, unsigned fill_color)
 	}
 }
 
-void g_floodfill(int x, int y, unsigned fill_color,
-			unsigned old_color)
-{
+void DrawSurface::floodFill(int x, int y, uint32 fill_color, uint32 old_color) {
 	int x1, x2, i;
 
-	if (g_get_pixel_color(x, y) != old_color || fill_color == old_color)
+	if (getPixelColor(x, y) != old_color || fill_color == old_color)
 		return;
 
 	/* Left end of scanline */
 	for (x1 = x; x1 > 0; x1--)
-		if (g_get_pixel_color(x1 - 1, y) != old_color)
+		if (getPixelColor(x1 - 1, y) != old_color)
 			break;
 
 	/* Right end of scanline */
 	for (x2 = x; x2 < RENDER_X_MAX; x2++)
-		if (g_get_pixel_color(x2 + 1, y) != old_color)
+		if (getPixelColor(x2 + 1, y) != old_color)
 			break;
 
-	g_draw_line(x1, y, x2, y, fill_color);
+	drawLine(x1, y, x2, y, fill_color);
 #ifdef TODO
 	SDL_RenderPresent(ctx.renderer[RENDERER_SCREEN]);
 #endif
 	/* Scanline above */
 	for (i = x1; i < x2; i++)
-		if (y > 0 && g_get_pixel_color(i, y - 1) == old_color)
-			g_floodfill(i, y - 1, fill_color, old_color);
+		if (y > 0 && getPixelColor(i, y - 1) == old_color)
+			floodFill(i, y - 1, fill_color, old_color);
 
 	/* Scanline below */
 	for (i = x1; i < x2; i++)
-		if (y < RENDER_Y_MAX && g_get_pixel_color(i, y + 1) == old_color)
-			g_floodfill(i, y + 1, fill_color, old_color);
+		if (y < RENDER_Y_MAX && getPixelColor(i, y + 1) == old_color)
+			floodFill(i, y + 1, fill_color, old_color);
+}
 
+void DrawSurface::drawPixel(uint16 x, uint16 y, uint32 color) {
+	uint32 *ptr = (uint32 *)getBasePtr(x, y);
+	*ptr = color;
 }
 
-void g_flip_buffers(void) {
-#ifdef TODO
-	SDL_RenderPresent(ctx.renderer[RENDERER_SCREEN]);
-#endif
+uint32 DrawSurface::getPixelColor(uint16 x, uint16 y) {
+	uint32 *ptr = (uint32 *)getBasePtr(x, y);
+	return *ptr;
 }
 
-void g_clear_screen(unsigned color) {
+void DrawSurface::clearScreen(uint32 color) {
+	fillRect(Common::Rect(0, 0, this->w, this->h), color);
+	render();
+}
+
+void DrawSurface::render() {
 	GraphicsWindow *win = g_comprehend->_topWindow;
-	win->fillRect(color, Rect(0, 0, win->_w, win->_h));
+	win->drawPicture(*this, (uint)-2, 0, 0, win->_w, win->_h);
+}
+
+/*-------------------------------------------------------*/
+
+#ifdef TODO
+static void set_color(unsigned color) {
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
+		SDL_SetRenderDrawColor(ctx.renderer[i],
+		                       (color >> 24) & 0xff,
+		                       (color >> 16) & 0xff,
+		                       (color >> 8) & 0xff,
+		                       (color >> 0) & 0xff);
 }
+#endif
 
 void g_init() {
 	graphics_enabled = true;
+	DrawSurface::setColorTable(0);
+	DrawSurface::_renderColor = 0;
 }
 
-bool g_enabled(void)
-{
+bool g_enabled(void) {
 	return graphics_enabled;
 }
 
diff --git a/engines/glk/comprehend/graphics.h b/engines/glk/comprehend/graphics.h
index 99815b6b56..3c27491935 100644
--- a/engines/glk/comprehend/graphics.h
+++ b/engines/glk/comprehend/graphics.h
@@ -24,6 +24,7 @@
 #define GLK_COMPREHEND_GRAPHICS_H
 
 #include "common/scummsys.h"
+#include "graphics/managed_surface.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -62,23 +63,45 @@ namespace Comprehend {
 #define G_COLOR_BROWN1		0x7a5200ff
 #define G_COLOR_BROWN2		0x663300ff
 
-void g_set_color_table(unsigned index);
+class DrawSurface : public Graphics::ManagedSurface {
+private:
+	static const uint32 PEN_COLORS[8];
+	static const uint32 DEFAULT_COLOR_TABLE[256];
+	static const uint32 COLOR_TABLE_1[256];
+	static const uint32 *COLOR_TABLES[2];
+	static const uint32 *_colorTable;
+
+public:
+	static uint32 _renderColor;
+public:
+	DrawSurface() {
+		reset();
+	}
+
+	/**
+	 * Sets up the surface to the correct size and pixel format
+	 */
+	void reset();
+
+	static void setColorTable(uint index);
+	uint getPenColor(uint8 opcode) const;
+	uint32 getFillColor(uint8 index);
+
+	void drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint32 color);
+	void drawBox(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint32 color);
+	void drawFilledBox(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint32 color);
+	void drawShape(int x, int y, int shape_type, uint32 fill_color);
+	void floodFill(int x, int y, uint32 fill_color, uint32 old_color);
+	void drawPixel(uint16 x, uint16 y, uint32 color);
+	uint32 getPixelColor(uint16 x, uint16 y);
+	void clearScreen(uint32 color);
+
+	/**
+	 * Render the surface to the screen's picture window
+	 */
+	void render();
+};
 
-unsigned g_set_fill_color(uint8 index);
-unsigned g_set_pen_color(uint8 opcode);
-
-unsigned g_get_pixel_color(int x, int y);
-
-void g_draw_pixel(unsigned x, unsigned y, unsigned color);
-void g_draw_line(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
-		 unsigned color);
-void g_draw_box(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
-		unsigned color);
-void g_draw_shape(int x, int y, int shape_type, unsigned fill_color);
-void g_floodfill(int x, int y, unsigned fill_color, unsigned old_color);
-
-void g_clear_screen(unsigned color);
-void g_flip_buffers(void);
 void g_init();
 bool g_enabled(void);
 
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 50893e6c37..391145abf7 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -34,9 +34,9 @@ namespace Comprehend {
 #define IMAGES_PER_FILE	16
 
 struct ImageContext {
-	unsigned	x;
-	unsigned	y;
-	unsigned	pen_color;
+	unsigned	_x;
+	unsigned	_y;
+	unsigned	_penColor;
 	unsigned	fill_color;
 	unsigned	shape;
 
@@ -76,17 +76,18 @@ void ImageFileData::load(const char *filename) {
 
 void ImageFileData::draw(uint index, ImageContext *ctx) {
 	_fb.seek(_imageOffsets[index]);
+	DrawSurface ds;
 
 	for (bool done = false; !done;) {
-		done = doImageOp(ctx);
+		done = doImageOp(&ds, ctx);
 		if (!done && (draw_flags & IMAGEF_OP_WAIT_KEYPRESS)) {
 			getchar();
-			g_flip_buffers();
+			ds.render();
 		}
 	}
 }
 
-bool ImageFileData::doImageOp(ImageContext *ctx) {
+bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 	uint8 opcode;
 	uint16 a, b;
 
@@ -109,7 +110,7 @@ bool ImageFileData::doImageOp(ImageContext *ctx) {
 	case IMAGE_OP_PEN_COLOR_G:
 	case IMAGE_OP_PEN_COLOR_H:
 		debug_printf(DEBUG_IMAGE_DRAW, "set_pen_color(%.2x)\n", opcode);
-		ctx->pen_color = g_set_pen_color(opcode);
+		ctx->_penColor = ds->getPenColor(opcode);
 		break;
 
 	case IMAGE_OP_DRAW_LINE:
@@ -122,11 +123,11 @@ bool ImageFileData::doImageOp(ImageContext *ctx) {
 
 		debug_printf(DEBUG_IMAGE_DRAW,
 		             "draw_line (%d, %d) - (%d, %d)\n", opcode,
-		             ctx->x, ctx->y, a, b);
-		g_draw_line(ctx->x, ctx->y, a, b, ctx->pen_color);
+		             ctx->_x, ctx->_y, a, b);
+		ds->drawLine(ctx->_x, ctx->_y, a, b, ctx->_penColor);
 
-		ctx->x = a;
-		ctx->y = b;
+		ctx->_x = a;
+		ctx->_y = b;
 		break;
 
 	case IMAGE_OP_DRAW_BOX:
@@ -139,9 +140,9 @@ bool ImageFileData::doImageOp(ImageContext *ctx) {
 
 		debug_printf(DEBUG_IMAGE_DRAW,
 		             "draw_box (%d, %d) - (%d, %d)\n", opcode,
-		             ctx->x, ctx->y, a, b);
+		             ctx->_x, ctx->_y, a, b);
 
-		g_draw_box(ctx->x, ctx->y, a, b, ctx->pen_color);
+		ds->drawBox(ctx->_x, ctx->_y, a, b, ctx->_penColor);
 		break;
 
 	case IMAGE_OP_MOVE_TO:
@@ -154,8 +155,8 @@ bool ImageFileData::doImageOp(ImageContext *ctx) {
 			a += 255;
 
 		debug_printf(DEBUG_IMAGE_DRAW, "move_to(%d, %d)\n", a, b);
-		ctx->x = a;
-		ctx->y = b;
+		ctx->_x = a;
+		ctx->_y = b;
 		break;
 
 	case IMAGE_OP_SHAPE_PIXEL:
@@ -192,7 +193,7 @@ bool ImageFileData::doImageOp(ImageContext *ctx) {
 		             "draw_shape(%d, %d), style=%.2x, fill=%.2x\n",
 		             a, b, ctx->shape, ctx->fill_color);
 
-		g_draw_shape(a, b, ctx->shape, ctx->fill_color);
+		ds->drawShape(a, b, ctx->shape, ctx->fill_color);
 		break;
 
 	case IMAGE_OP_PAINT:
@@ -206,14 +207,14 @@ bool ImageFileData::doImageOp(ImageContext *ctx) {
 
 		debug_printf(DEBUG_IMAGE_DRAW, "paint(%d, %d)\n", a, b);
 		if (!(draw_flags & IMAGEF_NO_FLOODFILL))
-			g_floodfill(a, b, ctx->fill_color,
-			            g_get_pixel_color(a, b));
+			ds->floodFill(a, b, ctx->fill_color,
+			            ds->getPixelColor(a, b));
 		break;
 
 	case IMAGE_OP_FILL_COLOR:
 		a = imageGetOperand();
 		debug_printf(DEBUG_IMAGE_DRAW, "set_fill_color(%.2x)\n", a);
-		ctx->fill_color = g_set_fill_color(a);
+		ctx->fill_color = ds->getFillColor(a);
 		break;
 
 	case IMAGE_OP_SET_TEXT_POS:
@@ -230,7 +231,7 @@ bool ImageFileData::doImageOp(ImageContext *ctx) {
 		debug_printf(DEBUG_IMAGE_DRAW, "draw_char(%c)\n",
 		             a >= 0x20 && a < 0x7f ? a : '?');
 
-		g_draw_box(ctx->text_x, ctx->text_y,
+		ds->drawBox(ctx->text_x, ctx->text_y,
 		           ctx->text_x + 6, ctx->text_y + 7, ctx->fill_color);
 		ctx->text_x += 8;
 		break;
@@ -267,7 +268,7 @@ bool ImageFileData::doImageOp(ImageContext *ctx) {
 
 		debug_printf(DEBUG_IMAGE_DRAW,
 		             "unknown(%.2x, %.2x)\n", a, b);
-		g_draw_pixel(a, b, 0x00ff00ff);
+		ds->drawPixel(a, b, 0x00ff00ff);
 		break;
 	}
 
@@ -318,19 +319,19 @@ void draw_image(ImageData *info, unsigned index) {
 	(*info)[index / IMAGES_PER_FILE].draw(index % IMAGES_PER_FILE, &ctx);
 }
 
-void draw_dark_room(void)
-{
-	g_clear_screen(G_COLOR_BLACK);
+void draw_dark_room() {
+	DrawSurface ds;
+	ds.clearScreen(G_COLOR_BLACK);
 }
 
-void draw_bright_room(void)
-{
-	g_clear_screen(G_COLOR_WHITE);
+void draw_bright_room() {
+	DrawSurface ds;
+	ds.clearScreen(G_COLOR_WHITE);
 }
 
-void draw_location_image(ImageData *info, unsigned index)
-{
-	g_clear_screen(G_COLOR_WHITE);
+void draw_location_image(ImageData *info, unsigned index) {
+	DrawSurface ds;
+	ds.clearScreen(G_COLOR_WHITE);
 	draw_image(info, index);
 }
 
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
index 30b40175b9..b048090629 100644
--- a/engines/glk/comprehend/image_data.h
+++ b/engines/glk/comprehend/image_data.h
@@ -24,6 +24,7 @@
 #define GLK_COMPREHEND_IMAGE_DATA_H
 
 #include "glk/comprehend/file_buf.h"
+#include "glk/comprehend/graphics.h"
 #include "common/scummsys.h"
 
 namespace Glk {
@@ -39,7 +40,7 @@ private:
 	FileBuffer _fb;
 
 private:
-	bool doImageOp(ImageContext *ctx);
+	bool doImageOp(DrawSurface *ds, ImageContext *ctx);
 	uint16 imageGetOperand();
 
 	public:
diff --git a/graphics/font.h b/graphics/font.h
index d9f81cca8c..4f5923e349 100644
--- a/graphics/font.h
+++ b/graphics/font.h
@@ -119,7 +119,7 @@ public:
 	 * @return The actual area where the string is drawn.
 	 */
 	Common::Rect getBoundingBox(const Common::String &str, int x = 0, int y = 0, const int w = 0, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = false) const;
-	Common::Rect getBoundingBox(const Common::U32String &str, int x = 0, int y = 0, const int w = 0, TextAlign align = kTextAlignLeft) const;
+	Common::Rect getBoundingBox(const Common::U32String &str, int x = 0, int _y = 0, const int w = 0, TextAlign align = kTextAlignLeft) const;
 
 	/**
 	 * Draw a character at a specific point on a surface.
@@ -147,7 +147,7 @@ public:
 	// TODO: Add doxygen comments to this
 	void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
 	void drawString(Surface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0) const;
-	void drawString(ManagedSurface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
+	void drawString(ManagedSurface *dst, const Common::String &str, int x, int _y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const;
 	void drawString(ManagedSurface *dst, const Common::U32String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0) const;
 
 	/**


Commit: 207e8f4ba241b56f3d1227edd6ff4c6b334c0fb3
    https://github.com/scummvm/scummvm/commit/207e8f4ba241b56f3d1227edd6ff4c6b334c0fb3
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Further refactoring of drawing

Changed paths:
  A engines/glk/comprehend/draw_surface.cpp
  A engines/glk/comprehend/draw_surface.h
  R engines/glk/comprehend/graphics.cpp
  R engines/glk/comprehend/graphics.h
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/image_data.h
    engines/glk/module.mk


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index e9e54ad241..f5581d1527 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -24,13 +24,13 @@
 #include "common/config-manager.h"
 #include "common/translation.h"
 #include "glk/comprehend/debugger.h"
+#include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/game.h"
 #include "glk/comprehend/game_cc.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/game_oo.h"
 #include "glk/comprehend/game_tm.h"
 #include "glk/comprehend/game_tr.h"
-#include "glk/comprehend/graphics.h"
 #include "glk/quetzal.h"
 
 namespace Glk {
@@ -122,7 +122,9 @@ int main(int argc, char **argv) {
 }
 #endif
 
-Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc), _saveSlot(-1), _game(nullptr) {
+Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) :
+		GlkAPI(syst, gameDesc), _saveSlot(-1), _game(nullptr),
+		_graphicsEnabled(true) {
 	g_comprehend = this;
 }
 
@@ -144,6 +146,7 @@ void Comprehend::runGame() {
 	deinitialize();
 }
 void Comprehend::initialize() {
+	// Set up the GLK windows
 	g_conf->_wMarginX = 0;
 	g_conf->_wMarginY = 0;
 
@@ -155,7 +158,9 @@ void Comprehend::initialize() {
 	glk_set_window(_bottomWindow);
 	_topWindow->fillRect(0, Rect(0, 0, _topWindow->_w, _topWindow->_h));
 
-	g_init();
+	// Initialize drawing
+	DrawSurface::setColorTable(0);
+	DrawSurface::_renderColor = 0;
 }
 
 void Comprehend::deinitialize() {
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 3f1bee6eb6..9e80fe9fa0 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -58,6 +58,7 @@ public:
 	GraphicsWindow *_topWindow;
 	TextBufferWindow *_bottomWindow;
 	ComprehendGame *_game;
+	bool _graphicsEnabled;
 
 private:
 	/**
diff --git a/engines/glk/comprehend/graphics.cpp b/engines/glk/comprehend/draw_surface.cpp
similarity index 98%
rename from engines/glk/comprehend/graphics.cpp
rename to engines/glk/comprehend/draw_surface.cpp
index 4f2268be7a..70516c3083 100644
--- a/engines/glk/comprehend/graphics.cpp
+++ b/engines/glk/comprehend/draw_surface.cpp
@@ -20,7 +20,7 @@
  *
  */
 
-#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/image_data.h"
 #include "glk/comprehend/util.h"
@@ -401,15 +401,5 @@ static void set_color(unsigned color) {
 }
 #endif
 
-void g_init() {
-	graphics_enabled = true;
-	DrawSurface::setColorTable(0);
-	DrawSurface::_renderColor = 0;
-}
-
-bool g_enabled(void) {
-	return graphics_enabled;
-}
-
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/graphics.h b/engines/glk/comprehend/draw_surface.h
similarity index 98%
rename from engines/glk/comprehend/graphics.h
rename to engines/glk/comprehend/draw_surface.h
index 3c27491935..5e1c95ffc4 100644
--- a/engines/glk/comprehend/graphics.h
+++ b/engines/glk/comprehend/draw_surface.h
@@ -102,9 +102,6 @@ public:
 	void render();
 };
 
-void g_init();
-bool g_enabled(void);
-
 } // namespace Comprehend
 } // namespace Glk
 
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 60c9384cf0..7b6bdf5169 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -25,7 +25,7 @@
 #include "glk/comprehend/debugger.h"
 #include "glk/comprehend/dictionary.h"
 #include "glk/comprehend/game_data.h"
-#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/opcode_map.h"
 #include "glk/comprehend/strings.h"
 #include "glk/comprehend/util.h"
@@ -255,7 +255,7 @@ static void update_graphics(ComprehendGame *game) {
 	int type;
 	uint i;
 
-	if (!g_enabled())
+	if (!g_comprehend->_graphicsEnabled)
 		return;
 
 	type = game->room_is_special(game->_currentRoom, NULL);
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 668f8b6438..dabef81ce6 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -25,7 +25,7 @@
 #include "glk/comprehend/dictionary.h"
 #include "glk/comprehend/file_buf.h"
 #include "glk/comprehend/game.h"
-#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/strings.h"
 #include "glk/comprehend/util.h"
 
@@ -1018,7 +1018,7 @@ void comprehend_load_game(ComprehendGame *game) {
 	/* Load the main game data file */
 	load_game_data(game);
 
-	if (g_enabled()) {
+	if (g_comprehend->_graphicsEnabled) {
 		// Set up image files
 		game->_roomImages.load(game->_locationGraphicFiles);
 		game->_itemImages.load(game->_itemGraphicFiles);
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index 124f8d6e08..343c5549f2 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -22,7 +22,7 @@
 
 #include "glk/comprehend/game_oo.h"
 #include "glk/comprehend/comprehend.h"
-#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/draw_surface.h"
 
 namespace Glk {
 namespace Comprehend {
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 391145abf7..73c5f4b077 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -25,7 +25,7 @@
 #include "glk/comprehend/game.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/image_data.h"
-#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/util.h"
 
 namespace Glk {
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
index b048090629..3ea4f2e92b 100644
--- a/engines/glk/comprehend/image_data.h
+++ b/engines/glk/comprehend/image_data.h
@@ -24,7 +24,7 @@
 #define GLK_COMPREHEND_IMAGE_DATA_H
 
 #include "glk/comprehend/file_buf.h"
-#include "glk/comprehend/graphics.h"
+#include "glk/comprehend/draw_surface.h"
 #include "common/scummsys.h"
 
 namespace Glk {
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 95b099f24a..aab0ec1e32 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -171,6 +171,7 @@ MODULE_OBJS := \
 	comprehend/debugger_dumper.o \
 	comprehend/detection.o \
 	comprehend/dictionary.o \
+	comprehend/draw_surface.o \
 	comprehend/file_buf.o \
 	comprehend/game.o \
 	comprehend/game_cc.o \
@@ -178,7 +179,6 @@ MODULE_OBJS := \
 	comprehend/game_oo.o \
 	comprehend/game_tm.o \
 	comprehend/game_tr.o \
-	comprehend/graphics.o \
 	comprehend/image_data.o \
 	comprehend/opcode_map.o \
 	comprehend/strings.o \


Commit: 645b2132d74ac9d92fa44a4b304b641144500438
    https://github.com/scummvm/scummvm/commit/645b2132d74ac9d92fa44a4b304b641144500438
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Change debug_printf to use debugC

Changed paths:
    engines/glk/comprehend/draw_surface.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/comprehend/util.cpp
    engines/glk/comprehend/util.h


diff --git a/engines/glk/comprehend/draw_surface.cpp b/engines/glk/comprehend/draw_surface.cpp
index 70516c3083..f3cd999fa7 100644
--- a/engines/glk/comprehend/draw_surface.cpp
+++ b/engines/glk/comprehend/draw_surface.cpp
@@ -206,7 +206,7 @@ uint32 DrawSurface::getFillColor(uint8 index) {
 	color = _colorTable[index];
 	if (!color) {
 		/* Unknown color - use ugly purple */
-		debug_printf(DEBUG_IMAGE_DRAW, "Unknown color %.2x\n", index);
+		debugC(kDebugGraphics, "Unknown color %.2x", index);
 		return RGB(0xff, 0x00, 0xff);
 	}
 
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 7b6bdf5169..242f5fc019 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -29,6 +29,7 @@
 #include "glk/comprehend/opcode_map.h"
 #include "glk/comprehend/strings.h"
 #include "glk/comprehend/util.h"
+#include "common/debug-channels.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -421,7 +422,7 @@ static void eval_instruction(ComprehendGame *game,
 
 	room = get_room(game, game->_currentRoom);
 
-	if (gDebugLevel > 0) {
+	if (DebugMan.isDebugChannelEnabled(kDebugScripts)) {
 		Common::String line;
 		if (!instr->is_command) {
 			line += "? ";
@@ -433,7 +434,7 @@ static void eval_instruction(ComprehendGame *game,
 		}
 
 		line += g_debugger->dumpInstruction(game, func_state, instr);
-		debug("%s", line.c_str());
+		debugC(kDebugScripts, "%s", line.c_str());
 	}
 
 	if (func_state->or_count)
@@ -879,8 +880,7 @@ static void eval_instruction(ComprehendGame *game,
 			fatal_error("Bad function %.4x >= %.4x\n",
 			            index, (uint)game->_nr_functions);
 
-		debug_printf(DEBUG_FUNCTIONS,
-		             "Calling subfunction %.4x\n", index);
+		debugC(kDebugScripts, "Calling subfunction %.4x", index);
 		eval_function(game, &game->_functions[index], verb, noun);
 		break;
 
@@ -946,12 +946,12 @@ static void eval_instruction(ComprehendGame *game,
 
 	default:
 		if (instr->opcode & 0x80) {
-			debug_printf(DEBUG_FUNCTIONS,
-			             "Unhandled command opcode %.2x\n",
+			debugC(kDebugScripts,
+			             "Unhandled command opcode %.2x",
 			             instr->opcode);
 		} else {
-			debug_printf(DEBUG_FUNCTIONS,
-			             "Unhandled test opcode %.2x - returning false\n",
+			debugC(kDebugScripts,
+			             "Unhandled test opcode %.2x - returning false",
 			             instr->opcode);
 			func_set_test_result(func_state, false);
 		}
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 73c5f4b077..d14bc60308 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -92,13 +92,12 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 	uint16 a, b;
 
 	opcode = _fb.readByte();
-	debug_printf(DEBUG_IMAGE_DRAW,
-	             "  %.4x [%.2x]: ", _fb.pos() - 1, opcode);
+	debugCN(kDebugGraphics, "  %.4x [%.2x]: ", _fb.pos() - 1, opcode);
 
 	switch (opcode) {
 	case IMAGE_OP_SCENE_END:
 	case IMAGE_OP_EOF:
-		debug_printf(DEBUG_IMAGE_DRAW, "end\n");
+		debugC(kDebugGraphics, "end");
 		return true;
 
 	case IMAGE_OP_PEN_COLOR_A:
@@ -109,7 +108,7 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 	case IMAGE_OP_PEN_COLOR_F:
 	case IMAGE_OP_PEN_COLOR_G:
 	case IMAGE_OP_PEN_COLOR_H:
-		debug_printf(DEBUG_IMAGE_DRAW, "set_pen_color(%.2x)\n", opcode);
+		debugC(kDebugGraphics, "set_pen_color(%.2x)", opcode);
 		ctx->_penColor = ds->getPenColor(opcode);
 		break;
 
@@ -121,8 +120,8 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		if (opcode & 0x1)
 			a += 255;
 
-		debug_printf(DEBUG_IMAGE_DRAW,
-		             "draw_line (%d, %d) - (%d, %d)\n", opcode,
+		debugC(kDebugGraphics,
+		             "draw_line (%d, %d) - (%d, %d)", opcode,
 		             ctx->_x, ctx->_y, a, b);
 		ds->drawLine(ctx->_x, ctx->_y, a, b, ctx->_penColor);
 
@@ -138,8 +137,8 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		if (opcode & 0x1)
 			a += 255;
 
-		debug_printf(DEBUG_IMAGE_DRAW,
-		             "draw_box (%d, %d) - (%d, %d)\n", opcode,
+		debugC(kDebugGraphics,
+		             "draw_box (%d, %d) - (%d, %d)", opcode,
 		             ctx->_x, ctx->_y, a, b);
 
 		ds->drawBox(ctx->_x, ctx->_y, a, b, ctx->_penColor);
@@ -154,7 +153,7 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		if (opcode & 0x1)
 			a += 255;
 
-		debug_printf(DEBUG_IMAGE_DRAW, "move_to(%d, %d)\n", a, b);
+		debugC(kDebugGraphics, "move_to(%d, %d)", a, b);
 		ctx->_x = a;
 		ctx->_y = b;
 		break;
@@ -167,8 +166,8 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 	case IMAGE_OP_SHAPE_CIRCLE_LARGE:
 	case IMAGE_OP_SHAPE_A:
 	case IMAGE_OP_SHAPE_SPRAY:
-		debug_printf(DEBUG_IMAGE_DRAW,
-		             "set_shape_type(%.2x)\n", opcode - 0x40);
+		debugC(kDebugGraphics,
+		             "set_shape_type(%.2x)", opcode - 0x40);
 		ctx->shape = opcode;
 		break;
 
@@ -177,7 +176,7 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		 * FIXME - This appears to be a shape type. Only used by
 		 *         OO-Topos.
 		 */
-		debug_printf(DEBUG_IMAGE_DRAW, "shape_unknown()\n");
+		debugC(kDebugGraphics, "shape_unknown()");
 		ctx->shape = IMAGE_OP_SHAPE_PIXEL;
 		break;
 
@@ -189,8 +188,7 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		if (opcode & 0x1)
 			a += 255;
 
-		debug_printf(DEBUG_IMAGE_DRAW,
-		             "draw_shape(%d, %d), style=%.2x, fill=%.2x\n",
+		debugC(kDebugGraphics, "draw_shape(%d, %d), style=%.2x, fill=%.2x",
 		             a, b, ctx->shape, ctx->fill_color);
 
 		ds->drawShape(a, b, ctx->shape, ctx->fill_color);
@@ -205,7 +203,7 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		if (opcode & 0x1)
 			a += 255;
 
-		debug_printf(DEBUG_IMAGE_DRAW, "paint(%d, %d)\n", a, b);
+		debugC(kDebugGraphics, "paint(%d, %d)", a, b);
 		if (!(draw_flags & IMAGEF_NO_FLOODFILL))
 			ds->floodFill(a, b, ctx->fill_color,
 			            ds->getPixelColor(a, b));
@@ -213,14 +211,14 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 
 	case IMAGE_OP_FILL_COLOR:
 		a = imageGetOperand();
-		debug_printf(DEBUG_IMAGE_DRAW, "set_fill_color(%.2x)\n", a);
+		debugC(kDebugGraphics, "set_fill_color(%.2x)", a);
 		ctx->fill_color = ds->getFillColor(a);
 		break;
 
 	case IMAGE_OP_SET_TEXT_POS:
 		a = imageGetOperand();
 		b = imageGetOperand();
-		debug_printf(DEBUG_IMAGE_DRAW, "set_text_pos(%d, %d)\n", a, b);
+		debugC(kDebugGraphics, "set_text_pos(%d, %d)", a, b);
 
 		ctx->text_x = a;
 		ctx->text_y = b;
@@ -228,7 +226,7 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 
 	case IMAGE_OP_DRAW_CHAR:
 		a = imageGetOperand();
-		debug_printf(DEBUG_IMAGE_DRAW, "draw_char(%c)\n",
+		debugC(kDebugGraphics, "draw_char(%c)",
 		             a >= 0x20 && a < 0x7f ? a : '?');
 
 		ds->drawBox(ctx->text_x, ctx->text_y,
@@ -241,14 +239,14 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		 * FIXME - Oo-Topos uses this at the beginning of some room
 		 *         images.
 		 */
-		debug_printf(DEBUG_IMAGE_DRAW, "unknown()\n");
+		debugC(kDebugGraphics, "unknown()");
 		break;
 
 	case 0xb5:
 	case 0x82:
 	case 0x50:
 		/* FIXME - unknown, no arguments */
-		debug_printf(DEBUG_IMAGE_DRAW, "unknown\n");
+		debugC(kDebugGraphics, "unknown");
 		break;
 
 	case 0x73:
@@ -256,7 +254,7 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 	case 0xd0:
 		/* FIXME - unknown, one argument */
 		a = imageGetOperand();
-		debug_printf(DEBUG_IMAGE_DRAW, "unknown %.2x: (%.2x) '%c'\n",
+		debugC(kDebugGraphics, "unknown %.2x: (%.2x) '%c'",
 		             opcode, a,
 		             a >= 0x20 && a < 0x7f ? a : '?');
 		break;
@@ -266,8 +264,7 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		a = imageGetOperand();
 		b = imageGetOperand();
 
-		debug_printf(DEBUG_IMAGE_DRAW,
-		             "unknown(%.2x, %.2x)\n", a, b);
+		debugC(kDebugGraphics, "unknown(%.2x, %.2x)", a, b);
 		ds->drawPixel(a, b, 0x00ff00ff);
 		break;
 	}
diff --git a/engines/glk/comprehend/util.cpp b/engines/glk/comprehend/util.cpp
index 62abe26163..5378798e5d 100644
--- a/engines/glk/comprehend/util.cpp
+++ b/engines/glk/comprehend/util.cpp
@@ -57,19 +57,5 @@ char *xstrndup(const char *str, size_t len) {
 	return p;
 }
 
-void debug_printf(unsigned flags, const char *fmt, ...) {
-#ifdef TODO
-	va_list args;
-
-	if (debug_flags & flags) {
-		va_start(args, fmt);
-		Common::String msg = Common::String::vformat(fmt, args);
-		va_end(args);
-
-		debug(1, "%s", msg.c_str());
-	}
-	#endif
-}
-
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/util.h b/engines/glk/comprehend/util.h
index f979d17937..8e8224ffff 100644
--- a/engines/glk/comprehend/util.h
+++ b/engines/glk/comprehend/util.h
@@ -42,8 +42,6 @@ void fatal_strerror(int err, const char *fmt, ...);
 void *xmalloc(size_t size);
 char *xstrndup(const char *str, size_t size);
 
-void debug_printf(unsigned flags, const char *fmt, ...);
-
 } // namespace Comprehend
 } // namespace Glk
 


Commit: 17454429e443e5f0b37d39e094af6408d7636653
    https://github.com/scummvm/scummvm/commit/17454429e443e5f0b37d39e094af6408d7636653
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Move floodfill disable to a debugger command

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/debugger.cpp
    engines/glk/comprehend/debugger.h


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index f5581d1527..4ad03d6381 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -38,93 +38,9 @@ namespace Comprehend {
 
 Comprehend *g_comprehend;
 
-#ifdef TODO
-int main(int argc, char **argv) {
-	option long_opts[] = {
-	    {"debug", no_argument, 0, 'd'},
-	    {"dump", required_argument, 0, 'D'},
-	    {"no-play", no_argument, 0, 'p'},
-	    {"no-graphics", no_argument, 0, 'g'},
-	    {"no-floodfill", no_argument, 0, 'f'},
-	    {"graphics-width", required_argument, 0, 'w'},
-	    {"graphics-height", required_argument, 0, 'h'},
-	    {"help", no_argument, 0, '?'},
-	    {NULL, 0, 0, 0},
-	};
-	const char *short_opts = "dD:pgfw:h:?";
-	ComprehendGame *game;
-	const char *game_name, *game_dir;
-	unsigned dump_flags = 0;
-	int i, c, opt_index;
-	unsigned graphics_width = G_RENDER_WIDTH,
-	         graphics_height = G_RENDER_HEIGHT;
-	bool play_game = true, graphics_enabled = true;
-
-	while (1) {
-		c = getopt_long(argc, argv, short_opts, long_opts, &opt_index);
-		if (c == -1)
-			break;
-
-		switch (c) {
-		case 'd':
-			// FIXME
-			debug_enable(DEBUG_FUNCTIONS);
-			break;
-
-		case 'D':
-			for (i = 0; i < ARRAY_SIZE(dump_options); i++)
-				if (strcmp(optarg, dump_options[i].option) == 0)
-					break;
-			if (i == ARRAY_SIZE(dump_options)) {
-				printf("Invalid dump option '%s'\n", optarg);
-				usage(argv[0]);
-			}
-
-			dump_flags |= dump_options[i].flag;
-			break;
-
-		case 'p':
-			play_game = false;
-			break;
-
-		case 'g':
-			graphics_enabled = false;
-			break;
-
-		case 'f':
-			image_set_draw_flags(IMAGEF_NO_FLOODFILL);
-			break;
-
-		case 'w':
-			graphics_width = strtoul(optarg, NULL, 0);
-			break;
-
-		case 'h':
-			graphics_height = strtoul(optarg, NULL, 0);
-			break;
-
-		case '?':
-			usage(argv[0]);
-			break;
-
-		default:
-			printf("Invalid option\n");
-			usage(argv[0]);
-			break;
-		}
-	}
-
-	if (optind >= argc || argc - optind != 2)
-		usage(argv[0]);
-
-	game_name = argv[optind++];
-	game_dir = argv[optind++];
-}
-#endif
-
 Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) :
 		GlkAPI(syst, gameDesc), _saveSlot(-1), _game(nullptr),
-		_graphicsEnabled(true) {
+		_graphicsEnabled(true), _drawFlags(0) {
 	g_comprehend = this;
 }
 
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 9e80fe9fa0..4b1c4a5856 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -59,6 +59,7 @@ public:
 	TextBufferWindow *_bottomWindow;
 	ComprehendGame *_game;
 	bool _graphicsEnabled;
+	uint _drawFlags;
 
 private:
 	/**
diff --git a/engines/glk/comprehend/debugger.cpp b/engines/glk/comprehend/debugger.cpp
index 63d3e9f8d8..69deba5166 100644
--- a/engines/glk/comprehend/debugger.cpp
+++ b/engines/glk/comprehend/debugger.cpp
@@ -31,6 +31,7 @@ Debugger *g_debugger;
 Debugger::Debugger() : Glk::Debugger() {
 	g_debugger = this;
 	registerCmd("dump", WRAP_METHOD(Debugger, cmdDump));
+	registerCmd("floodfills", WRAP_METHOD(Debugger, cmdFloodfills));
 }
 
 Debugger::~Debugger() {
@@ -56,5 +57,17 @@ bool Debugger::cmdDump(int argc, const char **argv) {
 	return true;
 }
 
+bool Debugger::cmdFloodfills(int argc, const char **argv) {
+	if (argc == 2 && !strcmp(argv[1], "off")) {
+		g_comprehend->_drawFlags |= IMAGEF_NO_FLOODFILL;
+		debugPrintf("Floodfills are off\n");
+	} else {
+		g_comprehend->_drawFlags &= ~IMAGEF_NO_FLOODFILL;
+		debugPrintf("Floodfills are on\n");
+	}
+
+	return true;
+}
+
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/debugger.h b/engines/glk/comprehend/debugger.h
index d42a953d78..0c1113b7e2 100644
--- a/engines/glk/comprehend/debugger.h
+++ b/engines/glk/comprehend/debugger.h
@@ -36,6 +36,11 @@ private:
 	 */
 	bool cmdDump(int argc, const char **argv);
 
+	/**
+	 * Sets whether floodfills are done when rendering images
+	 */
+	bool cmdFloodfills(int argc, const char **argv);
+
 protected:
 	void print(const char *fmt, ...) override;
 


Commit: 13b4698c832b60726edc973e4db2673ff1b86a3a
    https://github.com/scummvm/scummvm/commit/13b4698c832b60726edc973e4db2673ff1b86a3a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Skeleton for savegames within ScummVM

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_tr.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 4ad03d6381..32efb8b8c7 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -128,5 +128,19 @@ void Comprehend::readLine(char *buffer, size_t maxLen) {
 	buffer[ev.val1] = 0;
 }
 
+Common::Error Comprehend::readSaveData(Common::SeekableReadStream *rs) {
+	// TODO
+
+	_game->_updateFlags = UPDATE_ALL;
+	return Common::kNoError;
+}
+
+Common::Error Comprehend::writeGameData(Common::WriteStream *ws) {
+	// TODO
+
+	return Common::kNoError;
+}
+
+
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 4b1c4a5856..b8a2142132 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -103,17 +103,13 @@ public:
 	/**
 	 * Load a savegame from the passed Quetzal file chunk stream
 	 */
-	Common::Error readSaveData(Common::SeekableReadStream *rs) override {
-		return Common::kReadingFailed;
-	}
+	Common::Error readSaveData(Common::SeekableReadStream *rs) override;
 
 	/**
 	 * Save the game. The passed write stream represents access to the UMem chunk
 	 * in the Quetzal save file that will be created
 	 */
-	Common::Error writeGameData(Common::WriteStream *ws) override {
-		return Common::kWritingFailed;
-	}
+	Common::Error writeGameData(Common::WriteStream *ws) override;
 
 	/**
 	 * Print string to the buffer window
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 242f5fc019..bbeb84a4a6 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -30,6 +30,7 @@
 #include "glk/comprehend/strings.h"
 #include "glk/comprehend/util.h"
 #include "common/debug-channels.h"
+#include "common/translation.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -42,7 +43,6 @@ struct Sentence {
 ComprehendGame::ComprehendGame() : _gameName(nullptr),
                                    _shortName(nullptr),
                                    _gameDataFile(nullptr),
-                                   _savegameFileFormat(nullptr),
                                    _colorTable(0),
                                    _gameStrings(nullptr) {
 }
@@ -163,7 +163,6 @@ Item *get_item(ComprehendGame *game, uint16 index) {
 }
 
 void game_save(ComprehendGame *game) {
-	char filename[32];
 	int c;
 
 	console_println(game, game->_strings.strings[STRING_SAVE_GAME]);
@@ -178,12 +177,10 @@ void game_save(ComprehendGame *game) {
 		return;
 	}
 
-	snprintf(filename, sizeof(filename), game->_savegameFileFormat, c - '0');
-	comprehend_save_game(game, filename);
+	g_comprehend->saveGameState(c - '0', _("Savegame"));
 }
 
 void game_restore(ComprehendGame *game) {
-	char filename[32];
 	int c;
 
 	console_println(game, game->_strings.strings[STRING_RESTORE_GAME]);
@@ -198,10 +195,7 @@ void game_restore(ComprehendGame *game) {
 		return;
 	}
 
-	snprintf(filename, sizeof(filename), game->_savegameFileFormat, c - '0');
-	comprehend_restore_game(game, filename);
-
-	game->_updateFlags = UPDATE_ALL;
+	(void)g_comprehend->loadGameState(c - '0');
 }
 
 void game_restart(ComprehendGame *game) {
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 30d906ccf7..5ac930c186 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -43,7 +43,6 @@ public:
 	Common::Array<StringFile> _stringFiles;
 	Common::Array<const char *> _locationGraphicFiles;
 	Common::Array<const char *> _itemGraphicFiles;
-	const char *_savegameFileFormat;
 	unsigned _colorTable;
 
 	struct GameStrings *_gameStrings;
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index da416aa32d..bfe544c53a 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -50,7 +50,6 @@ CrimsonCrownGame::CrimsonCrownGame() : ComprehendGame() {
 	_itemGraphicFiles.push_back("OA.MS1");
 	_itemGraphicFiles.push_back("OB.MS1");
 
-	_savegameFileFormat = "G%d.MS0";
 	_gameStrings = &cc1_strings;
 }
 
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index 343c5549f2..2e8c49b1c4 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -55,7 +55,6 @@ OOToposGame::OOToposGame() : ComprehendGame() {
 	_itemGraphicFiles.push_back("OC");
 	_itemGraphicFiles.push_back("OD");
 
-	_savegameFileFormat = "G%d";
 	_colorTable = 1;
 }
 
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index b014d9dec6..d0d2b8567c 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -60,7 +60,6 @@ TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
 	_itemGraphicFiles.push_back("OB.MS1");
 	_itemGraphicFiles.push_back("OC.MS1");
 
-	_savegameFileFormat = "G%d.MS0";
 	_gameStrings = &tr_strings;
 }
 


Commit: e8c47aa747341ad6883edd5848908188fc5e6b0c
    https://github.com/scummvm/scummvm/commit/e8c47aa747341ad6883edd5848908188fc5e6b0c
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Implementing savegames

Changed paths:
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h


diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index bbeb84a4a6..bf97c75f34 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -21,16 +21,16 @@
  */
 
 #include "glk/comprehend/game.h"
+#include "common/debug-channels.h"
+#include "common/translation.h"
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/debugger.h"
 #include "glk/comprehend/dictionary.h"
-#include "glk/comprehend/game_data.h"
 #include "glk/comprehend/draw_surface.h"
+#include "glk/comprehend/game_data.h"
 #include "glk/comprehend/opcode_map.h"
 #include "glk/comprehend/strings.h"
 #include "glk/comprehend/util.h"
-#include "common/debug-channels.h"
-#include "common/translation.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -50,6 +50,44 @@ ComprehendGame::ComprehendGame() : _gameName(nullptr),
 ComprehendGame::~ComprehendGame() {
 }
 
+void ComprehendGame::synchronizeSave(Common::Serializer &s) {
+	uint dir, i;
+	size_t nr_rooms, nr_items;
+
+	s.syncAsUint16LE(_currentRoom);
+
+	// Variables
+	for (i = 0; i < ARRAY_SIZE(_variables); i++)
+		s.syncAsUint16LE(_variables[i]);
+
+	// Flags
+	for (i = 0; i < ARRAY_SIZE(_flags); i++)
+		s.syncAsByte(_flags[i]);
+
+	// Rooms
+	nr_rooms = _nr_rooms;
+	s.syncAsByte(_nr_rooms);
+	assert(nr_rooms == _nr_rooms);
+
+	for (i = 0; i < _nr_rooms; ++i) {
+		s.syncAsUint16LE(_rooms[i].string_desc);
+		for (dir = 0; dir < NR_DIRECTIONS; dir++)
+			s.syncAsByte(_rooms[i].direction[dir]);
+
+		s.syncAsByte(_rooms[i].flags);
+		s.syncAsByte(_rooms[i].graphic);
+	}
+
+	// Objects
+	nr_items = _header.nr_items;
+	s.syncAsByte(_header.nr_items);
+
+	for (i = 0; i < nr_items; ++i)
+		_items[i].synchronize(s);
+}
+
+/*-------------------------------------------------------*/
+
 static void console_init(void) {
 	//	ioctl(STDOUT_FILENO, TIOCGWINSZ, &console_winsize);
 }
@@ -207,7 +245,7 @@ void game_restart(ComprehendGame *game) {
 }
 
 static WordIndex *is_word_pair(ComprehendGame *game,
-                                       Word *word1, Word *word2) {
+                               Word *word1, Word *word2) {
 	WordMap *map;
 	uint i;
 
@@ -226,7 +264,7 @@ static WordIndex *is_word_pair(ComprehendGame *game,
 }
 
 static Item *get_item_by_noun(ComprehendGame *game,
-                                     Word *noun) {
+                              Word *noun) {
 	uint i;
 
 	if (!noun || !(noun->_type & WORD_TYPE_NOUN_MASK))
@@ -323,7 +361,7 @@ static void update(ComprehendGame *game) {
 	/* Check if the room is special (dark, too bright, etc) */
 	room_desc_string = room->string_desc;
 	room_type = game->room_is_special(game->_currentRoom,
-		&room_desc_string);
+	                                  &room_desc_string);
 
 	if (game->_updateFlags & UPDATE_ROOM_DESC)
 		console_println(game, string_lookup(game, room_desc_string));
@@ -341,7 +379,7 @@ static void move_to(ComprehendGame *game, uint8 room) {
 
 	game->_currentRoom = room;
 	game->_updateFlags = (UPDATE_GRAPHICS | UPDATE_ROOM_DESC |
-	                            UPDATE_ITEM_LIST);
+	                      UPDATE_ITEM_LIST);
 }
 
 static void func_set_test_result(FunctionState *func_state, bool value) {
@@ -397,7 +435,7 @@ void move_object(ComprehendGame *game, Item *item, int new_room) {
 		 * redraw, not the whole room.
 		 */
 		game->_updateFlags |= (UPDATE_GRAPHICS_ITEMS |
-		                             UPDATE_ITEM_LIST);
+		                       UPDATE_ITEM_LIST);
 	}
 
 	item->room = new_room;
@@ -941,12 +979,12 @@ static void eval_instruction(ComprehendGame *game,
 	default:
 		if (instr->opcode & 0x80) {
 			debugC(kDebugScripts,
-			             "Unhandled command opcode %.2x",
-			             instr->opcode);
+			       "Unhandled command opcode %.2x",
+			       instr->opcode);
 		} else {
 			debugC(kDebugScripts,
-			             "Unhandled test opcode %.2x - returning false",
-			             instr->opcode);
+			       "Unhandled test opcode %.2x - returning false",
+			       instr->opcode);
 			func_set_test_result(func_state, false);
 		}
 		break;
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 5ac930c186..f10cca9b7b 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -23,9 +23,10 @@
 #ifndef GLK_ComprehendGame_H
 #define GLK_ComprehendGame_H
 
-#include "common/array.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/opcode_map.h"
+#include "common/array.h"
+#include "common/serializer.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -64,6 +65,8 @@ public:
 		return ROOM_IS_NORMAL;
 	}
 	virtual void handle_special_opcode(uint8 operand) {}
+
+	void synchronizeSave(Common::Serializer &s);
 };
 
 void console_println(ComprehendGame *game, const char *text);
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index dabef81ce6..28e413076d 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -23,9 +23,9 @@
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/dictionary.h"
+#include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/file_buf.h"
 #include "glk/comprehend/game.h"
-#include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/strings.h"
 #include "glk/comprehend/util.h"
 
@@ -66,6 +66,15 @@ void Item::clear() {
 	graphic = 0;
 }
 
+void Item::synchronize(Common::Serializer &s) {
+	s.syncAsUint16LE(string_desc);
+	s.syncAsUint16LE(long_string);
+	s.syncAsByte(room);
+	s.syncAsByte(flags);
+	s.syncAsByte(word);
+	s.syncAsByte(graphic);
+}
+
 /*-------------------------------------------------------*/
 
 void Word::clear() {
@@ -1027,183 +1036,9 @@ void comprehend_load_game(ComprehendGame *game) {
 			DrawSurface::setColorTable(game->_colorTable);
 	}
 
-	/* FIXME - This can be merged, don't need to keep start room around */
+	// FIXME: This can be merged, don't need to keep start room around
 	game->_currentRoom = game->_startRoom;
 }
 
-#ifdef TODO
-static void patch_string_desc(uint16 *desc) {
-	/*
-	* String descriptors in the save file sometimes are encoded as a
-	* table/index value like the instruction opcodes used, and other
-	* times the are encoded as an absolute index. We fix them up to
-	* all be the former type.
-	*/
-	if (!(*desc & 0x8000) && *desc >= 0x100) {
-		*desc -= 0x100;
-		*desc |= 0x8100;
-	}
-}
-#endif
-
-void comprehend_save_game(ComprehendGame *game, const char *filename) {
-#ifdef TODO
-	FILE *fd;
-	uint8 bitmask;
-	int dir, bit, flag_index, i;
-	size_t nr_rooms, nr_items;
-
-	fd = fopen(filename, "w");
-	if (!fd) {
-		printf("Error: Failed to open save file '%s': %s\n",
-		       filename, strerror(errno));
-		return;
-	}
-
-	nr_rooms = game->nr_rooms;
-	nr_items = game->header.nr_items;
-
-	file_buf_put_u8(fd, 0);
-	file_buf_put_u8(fd, game->current_room);
-	file_buf_put_u8(fd, 0);
-
-	/* Variables */
-	for (i = 0; i < ARRAY_SIZE(game->variable); i++)
-		file_buf_put_le16(fd, game->variable[i]);
-
-	/* Flags */
-	for (flag_index = 0, i = 0; i < ARRAY_SIZE(game->flags) / 8; i++) {
-		bitmask = 0;
-		for (bit = 7; bit >= 0; bit--) {
-			bitmask |= (!!game->flags[flag_index]) << bit;
-			flag_index++;
-		}
-
-		file_buf_put_u8(fd, bitmask);
-	}
-
-	/*
-	* Re-Comprehend doesn't need this since the number of items is
-	* determined by the currently loaded game, but the original games
-	* won't load the file properly without it.
-	*/
-	file_buf_put_skip(fd, 0x12c - ftell(fd));
-	file_buf_put_u8(fd, nr_items);
-
-	if (game->comprehend_version == 1)
-		file_buf_put_skip(fd, 0x230 - ftell(fd));
-	else
-		file_buf_put_skip(fd, 0x130 - ftell(fd));
-
-	/* Rooms */
-	file_buf_put_array_le16(fd, 1, game->rooms,
-	                        string_desc, nr_rooms);
-	for (dir = 0; dir < NR_DIRECTIONS; dir++)
-		file_buf_put_array_u8(fd, 1, game->rooms,
-		                      direction[dir], nr_rooms);
-	file_buf_put_array_u8(fd, 1, game->rooms, flags, nr_rooms);
-	file_buf_put_array_u8(fd, 1, game->rooms, graphic, nr_rooms);
-
-	/*
-	* Objects
-	*
-	* Layout differs depending on Comprehend version. Version 2 also
-	* has long string descriptions for each object.
-	*/
-	file_buf_put_array_le16(fd, 0, game->item, string_desc, nr_items);
-	if (game->comprehend_version == 1) {
-		file_buf_put_array_u8(fd, 0, game->item, room, nr_items);
-		file_buf_put_array_u8(fd, 0, game->item, flags, nr_items);
-		file_buf_put_array_u8(fd, 0, game->item, word, nr_items);
-		file_buf_put_array_u8(fd, 0, game->item, graphic, nr_items);
-	} else {
-		file_buf_put_array_le16(fd, 0, game->item, long_string, nr_items);
-		file_buf_put_array_u8(fd, 0, game->item, word, nr_items);
-		file_buf_put_array_u8(fd, 0, game->item, room, nr_items);
-		file_buf_put_array_u8(fd, 0, game->item, flags, nr_items);
-		file_buf_put_array_u8(fd, 0, game->item, graphic, nr_items);
-	}
-
-	fclose(fd);
-#else
-	error("Save");
-#endif
-}
-
-void comprehend_restore_game(ComprehendGame *game, const char *filename) {
-#ifdef TODO
-	FileBuffer fb;
-	size_t nr_rooms, nr_items;
-	uint err, dir, i;
-
-	err = file_buf_map_may_fail(filename, &fb);
-	if (err) {
-		printf("Error: Failed to open save file '%s': %s\n",
-		       filename, strerror(-err));
-		return;
-	}
-
-	nr_rooms = game->nr_rooms;
-	nr_items = game->header.nr_items;
-
-	/* Restore starting room */
-	file_buf_set_pos(&fb, 1);
-	game->current_room = fb->readByte();
-
-	/* Restore flags and variables */
-	file_buf_set_pos(&fb, 3);
-	parse_variables(game, &fb);
-	parse_flags(game, &fb);
-
-	/* FIXME - unknown restore data, skip over it */
-	if (game->comprehend_version == 1)
-		file_buf_set_pos(&fb, 0x230);
-	else
-		file_buf_set_pos(&fb, 0x130);
-
-	/* Restore rooms */
-	file_buf_get_array_le16(&fb, 1, game->rooms,
-	                        string_desc, nr_rooms);
-	for (dir = 0; dir < NR_DIRECTIONS; dir++)
-		file_buf_get_array_u8(&fb, 1, game->rooms,
-		                      direction[dir], nr_rooms);
-	file_buf_get_array_u8(&fb, 1, game->rooms, flags, nr_rooms);
-	file_buf_get_array_u8(&fb, 1, game->rooms, graphic, nr_rooms);
-
-	/*
-	* Restore objects
-	*
-	* Layout differs depending on Comprehend version. Version 2 also
-	* has long string descriptions for each object.
-	*/
-	file_buf_get_array_le16(&fb, 0, game->item, string_desc, nr_items);
-	if (game->comprehend_version == 1) {
-		file_buf_get_array_u8(&fb, 0, game->item, room, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->item, flags, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->item, word, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->item, graphic, nr_items);
-	} else {
-		file_buf_get_array_le16(&fb, 0, game->item, long_string, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->item, word, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->item, room, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->item, flags, nr_items);
-		file_buf_get_array_u8(&fb, 0, game->item, graphic, nr_items);
-	}
-
-	/*
-	* FIXME - The save file has some string descriptors masked with 0x8000.
-	*         Not sure what this means, so just mask it out for now.
-	*/
-	for (i = 1; i <= nr_rooms; i++)
-		patch_string_desc(&game->rooms[i].string_desc);
-	for (i = 0; i < nr_items; i++)
-		patch_string_desc(&game->item[i].string_desc);
-
-	file_buf_unmap(&fb);
-#else
-	error("load");
-#endif
-}
-
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index f8a6e6f0fe..c4a6e94d19 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -24,6 +24,7 @@
 #define GLK_ComprehendGame_DATA_H
 
 #include "glk/comprehend/image_data.h"
+#include "common/serializer.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -84,6 +85,8 @@ struct Item {
 	}
 
 	void clear();
+
+	void synchronize(Common::Serializer &s);
 };
 
 struct Word {


Commit: 0a2478984f0c32ebba0a263f49f4c12b4145444f
    https://github.com/scummvm/scummvm/commit/0a2478984f0c32ebba0a263f49f4c12b4145444f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:10-07:00

Commit Message:
GLK: COMPREHEND: Change _replaceWords to be an Array

Changed paths:
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index 362031efc6..8286551ecf 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -365,8 +365,8 @@ void DebuggerDumper::dumpReplaceWords() {
 	uint i;
 
 	print("Replacement words (%u entries)\n",
-	      (uint)_game->_nr_replace_words);
-	for (i = 0; i < _game->_nr_replace_words; i++)
+	      _game->_replaceWords.size());
+	for (i = 0; i < _game->_replaceWords.size(); i++)
 		print("  [%.2x] %s\n", i + 1, _game->_replaceWords[i]);
 }
 
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index bf97c75f34..98eb644b61 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -125,7 +125,7 @@ void console_println(ComprehendGame *game, const char *text) {
 
 		case '@':
 			/* Replace word */
-			if (game->_currentReplaceWord >= game->_nr_replace_words) {
+			if (game->_currentReplaceWord >= game->_replaceWords.size()) {
 				snprintf(bad_word, sizeof(bad_word),
 				         "[BAD_REPLACE_WORD(%.2x)]",
 				         game->_currentReplaceWord);
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 28e413076d..f1344a40ee 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -179,7 +179,6 @@ void GameInfo::clearInfo() {
 	_nr_word_maps = 0;
 	_nr_actions = 0;
 	_nr_functions = 0;
-	_nr_replace_words = 0;
 	_currentReplaceWord = 0;
 	_updateFlags = 0;
 	_strings.clear();
@@ -200,7 +199,10 @@ void GameInfo::clearInfo() {
 
 	Common::fill(&_flags[0], &_flags[MAX_FLAGS], false);
 	Common::fill(&_variables[0], &_variables[MAX_VARIABLES], 0);
-	Common::fill(&_replaceWords[0], &_replaceWords[256], (char *)nullptr);
+
+	for (uint idx = 0; idx < _replaceWords.size(); ++idx)
+		free(_replaceWords[idx]);
+	_replaceWords.clear();
 }
 
 static void parse_header_le16(FileBuffer *fb, uint16 *val) {
@@ -843,12 +845,11 @@ static void parse_replace_words(ComprehendGame *game,
 		if (len == 0)
 			break;
 
-		game->_replaceWords[i] = xstrndup((const char *)fb->dataPtr(), len);
+		game->_replaceWords.push_back(xstrndup((const char *)fb->dataPtr(), len));
 		fb->skip(len + (eof ? 0 : 1));
 		if (eof)
 			break;
 	}
-	game->_nr_replace_words = i;
 }
 
 /*
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index c4a6e94d19..f75a65fdaf 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -251,15 +251,16 @@ struct GameInfo {
 	bool _flags[MAX_FLAGS];
 	uint16 _variables[MAX_VARIABLES];
 
-	char *_replaceWords[256];
-	size_t _nr_replace_words;
-
+	Common::Array<char *> _replaceWords;
 	uint8 _currentReplaceWord;
-	unsigned _updateFlags;
+	uint _updateFlags;
 
 	GameInfo() {
 		clearInfo();
 	}
+	~GameInfo() {
+		clearInfo();
+	}
 
 	void clearInfo();
 };


Commit: 6447f64709d5785263e4b14dfca3c962c3b06417
    https://github.com/scummvm/scummvm/commit/6447f64709d5785263e4b14dfca3c962c3b06417
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Merged string lookups into Game class

Changed paths:
  R engines/glk/comprehend/strings.cpp
  R engines/glk/comprehend/strings.h
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/module.mk


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index 8286551ecf..2457f85f95 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -23,7 +23,6 @@
 #include "glk/comprehend/debugger_dumper.h"
 #include "glk/comprehend/dictionary.h"
 #include "glk/comprehend/game.h"
-#include "glk/comprehend/strings.h"
 #include "glk/comprehend/util.h"
 
 namespace Glk {
@@ -120,7 +119,7 @@ Common::String DebuggerDumper::dumpInstruction(ComprehendGame *game,
 	opcode_map = game->_opcodeMap;
 	opcode = opcode_map[instr->opcode];
 
-	line += "  [%.2x] ", instr->opcode;
+	line += Common::String::format("  [%.2x] ", instr->opcode);
 	if (_opcodes.contains(opcode))
 		line += _opcodes[opcode];
 	else
@@ -129,7 +128,7 @@ Common::String DebuggerDumper::dumpInstruction(ComprehendGame *game,
 	if (instr->nr_operands) {
 		line += "(";
 		for (i = 0; i < instr->nr_operands; i++)
-			line += "%.2x%s", instr->operand[i],
+			line += Common::String::format("%.2x%s", instr->operand[i]),
 			      i == instr->nr_operands - 1 ? ")" : ", ";
 	}
 
@@ -147,11 +146,11 @@ Common::String DebuggerDumper::dumpInstruction(ComprehendGame *game,
 			str_table = instr->operand[2];
 		}
 
-		line += " %s", instr_lookup_string(game, str_index, str_table);
+		line += Common::String::format(" %s", game->instrStringLookup(str_index, str_table).c_str());
 		break;
 
 	case OPCODE_SET_STRING_REPLACEMENT:
-		line += " %s", game->_replaceWords[instr->operand[0] - 1];
+		line += Common::String::format(" %s", game->_replaceWords[instr->operand[0] - 1]);
 		break;
 	}
 
@@ -298,7 +297,7 @@ void DebuggerDumper::dumpRooms() {
 
 		print("  [%.2x] flags=%.2x, graphic=%.2x\n",
 		      i, room->flags, room->graphic);
-		print("    %s\n", string_lookup(_game, room->string_desc));
+		print("    %s\n", _game->stringLookup(room->string_desc).c_str());
 		print("    n: %.2x  s: %.2x  e: %.2x  w: %.2x\n",
 		      room->direction[DIRECTION_NORTH],
 		      room->direction[DIRECTION_SOUTH],
@@ -322,10 +321,10 @@ void DebuggerDumper::dumpItems() {
 		item = &_game->_items[i];
 
 		print("  [%.2x] %s\n", i + 1,
-		      item->string_desc ? string_lookup(_game, item->string_desc) : "");
+		      item->string_desc ? _game->stringLookup(item->string_desc).c_str() : "");
 		if (_game->_comprehendVersion == 2)
 			print("    long desc: %s\n",
-			      string_lookup(_game, item->long_string));
+			      _game->stringLookup(item->long_string).c_str());
 
 		print("    words: ");
 		for (j = 0; j < _game->_nr_words; j++)
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 98eb644b61..8eca383515 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -29,7 +29,6 @@
 #include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/opcode_map.h"
-#include "glk/comprehend/strings.h"
 #include "glk/comprehend/util.h"
 
 namespace Glk {
@@ -86,6 +85,51 @@ void ComprehendGame::synchronizeSave(Common::Serializer &s) {
 		_items[i].synchronize(s);
 }
 
+Common::String ComprehendGame::stringLookup(uint16 index) {
+	uint16 string;
+	uint8 table;
+
+	/*
+	 * There are two tables of strings. The first is stored in the main
+	 * game data file, and the second is stored in multiple string files.
+	 *
+	 * In instructions string indexes are split into a table and index
+	 * value. In other places such as the save files strings from the
+	 * main table are occasionally just a straight 16-bit index. We
+	 * convert all string indexes to the former case so that we can handle
+	 * them the same everywhere.
+	 */
+	table = (index >> 8) & 0xff;
+	string = index & 0xff;
+
+	switch (table) {
+	case 0x81:
+	case 0x01:
+		string += 0x100;
+		/* Fall-through */
+	case 0x00:
+	case 0x80:
+		if (string < _strings.nr_strings)
+			return _strings.strings[string];
+		break;
+
+	case 0x83:
+		string += 0x100;
+		/* Fall-through */
+	case 0x02:
+	case 0x82:
+		if (string < _strings2.nr_strings)
+			return _strings2.strings[string];
+		break;
+	}
+
+	return Common::String::format("BAD_STRING(%.4x)", index);
+}
+
+Common::String ComprehendGame::instrStringLookup(uint8 index, uint8 table) {
+	return stringLookup(table << 8 | index);
+}
+
 /*-------------------------------------------------------*/
 
 static void console_init(void) {
@@ -237,7 +281,7 @@ void game_restore(ComprehendGame *game) {
 }
 
 void game_restart(ComprehendGame *game) {
-	console_println(game, string_lookup(game, game->_gameStrings->game_restart));
+	console_println(game, game->stringLookup(game->_gameStrings->game_restart).c_str());
 	console_get_key();
 
 	comprehend_load_game(game);
@@ -340,14 +384,14 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 	}
 
 	if (count > 0) {
-		console_println(game, string_lookup(game, STRING_YOU_SEE));
+		console_println(game, game->stringLookup(STRING_YOU_SEE).c_str());
 
 		for (i = 0; i < game->_header.nr_items; i++) {
 			item = &game->_items[i];
 
 			if (item->room == game->_currentRoom &&
 			    item->string_desc != 0)
-				console_println(game, string_lookup(game, item->string_desc));
+				console_println(game, game->stringLookup(item->string_desc).c_str());
 		}
 	}
 }
@@ -364,7 +408,7 @@ static void update(ComprehendGame *game) {
 	                                  &room_desc_string);
 
 	if (game->_updateFlags & UPDATE_ROOM_DESC)
-		console_println(game, string_lookup(game, room_desc_string));
+		console_println(game, game->stringLookup(room_desc_string).c_str());
 
 	if ((game->_updateFlags & UPDATE_ITEM_LIST) &&
 	    room_type == ROOM_IS_NORMAL)
@@ -528,9 +572,8 @@ static void eval_instruction(ComprehendGame *game,
 		break;
 
 	case OPCODE_PRINT:
-		console_println(game, instr_lookup_string(game,
-		                                          instr->operand[0],
-		                                          instr->operand[1]));
+		console_println(game, game->instrStringLookup(
+			instr->operand[0], instr->operand[1]).c_str());
 		break;
 
 	case OPCODE_TEST_NOT_ROOM_FLAG:
@@ -576,14 +619,14 @@ static void eval_instruction(ComprehendGame *game,
 		if (room->direction[verb->_index - 1])
 			move_to(game, room->direction[verb->_index - 1]);
 		else
-			console_println(game, string_lookup(game, STRING_CANT_GO));
+			console_println(game, game->stringLookup(STRING_CANT_GO).c_str());
 		break;
 
 	case OPCODE_MOVE_DIRECTION:
 		if (room->direction[instr->operand[0] - 1])
 			move_to(game, room->direction[instr->operand[0] - 1]);
 		else
-			console_println(game, string_lookup(game, STRING_CANT_GO));
+			console_println(game, game->stringLookup(STRING_CANT_GO).c_str());
 		break;
 
 	case OPCODE_ELSE:
@@ -626,7 +669,7 @@ static void eval_instruction(ComprehendGame *game,
 		 * FIXME - unsure what the single operand is for.
 		 */
 		item = get_item_by_noun(game, noun);
-		printf("%s\n", string_lookup(game, item->long_string));
+		printf("%s\n", game->stringLookup(item->long_string).c_str());
 		break;
 
 	case OPCODE_CURRENT_OBJECT_IN_ROOM:
@@ -771,32 +814,32 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_INVENTORY:
 		count = num_objects_in_room(game, ROOM_INVENTORY);
 		if (count == 0) {
-			console_println(game, string_lookup(game, STRING_INVENTORY_EMPTY));
+			console_println(game, game->stringLookup(STRING_INVENTORY_EMPTY).c_str());
 			break;
 		}
 
-		console_println(game, string_lookup(game, STRING_INVENTORY));
+		console_println(game, game->stringLookup(STRING_INVENTORY).c_str());
 		for (i = 0; i < game->_header.nr_items; i++) {
 			item = &game->_items[i];
 			if (item->room == ROOM_INVENTORY)
 				printf("%s\n",
-				       string_lookup(game, item->string_desc));
+				       game->stringLookup(item->string_desc).c_str());
 		}
 		break;
 
 	case OPCODE_INVENTORY_ROOM:
 		count = num_objects_in_room(game, instr->operand[0]);
 		if (count == 0) {
-			console_println(game, string_lookup(game, instr->operand[1] + 1));
+			console_println(game, game->stringLookup(instr->operand[1] + 1).c_str());
 			break;
 		}
 
-		console_println(game, string_lookup(game, instr->operand[1]));
+		console_println(game, game->stringLookup(instr->operand[1]).c_str());
 		for (i = 0; i < game->_header.nr_items; i++) {
 			item = &game->_items[i];
 			if (item->room == instr->operand[0])
 				printf("%s\n",
-				       string_lookup(game, item->string_desc));
+				       game->stringLookup(item->string_desc).c_str());
 		}
 		break;
 
@@ -1074,7 +1117,7 @@ static bool handle_sentence(ComprehendGame *game,
 	}
 
 	/* No matching action */
-	console_println(game, string_lookup(game, STRING_DONT_UNDERSTAND));
+	console_println(game, game->stringLookup(STRING_DONT_UNDERSTAND).c_str());
 	return false;
 }
 
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index f10cca9b7b..90d1a29032 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -67,6 +67,9 @@ public:
 	virtual void handle_special_opcode(uint8 operand) {}
 
 	void synchronizeSave(Common::Serializer &s);
+
+	Common::String stringLookup(uint16 index);
+	Common::String instrStringLookup(uint8 index, uint8 table);
 };
 
 void console_println(ComprehendGame *game, const char *text);
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index f1344a40ee..6e9869b37e 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -26,7 +26,6 @@
 #include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/file_buf.h"
 #include "glk/comprehend/game.h"
-#include "glk/comprehend/strings.h"
 #include "glk/comprehend/util.h"
 
 namespace Glk {
diff --git a/engines/glk/comprehend/strings.cpp b/engines/glk/comprehend/strings.cpp
deleted file mode 100644
index 4b6ddb7f99..0000000000
--- a/engines/glk/comprehend/strings.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/* 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 "glk/comprehend/comprehend.h"
-#include "glk/comprehend/game.h"
-#include "glk/comprehend/game_data.h"
-#include "glk/comprehend/strings.h"
-
-namespace Glk {
-namespace Comprehend {
-
-static char bad_string[128];
-
-const char *string_lookup(ComprehendGame *game, uint16 index)
-{
-	uint16 string;
-	uint8 table;
-
-	/*
-	 * There are two tables of strings. The first is stored in the main
-	 * game data file, and the second is stored in multiple string files.
-	 *
-	 * In instructions string indexes are split into a table and index
-	 * value. In other places such as the save files strings from the
-	 * main table are occasionally just a straight 16-bit index. We
-	 * convert all string indexes to the former case so that we can handle
-	 * them the same everywhere.
-	 */
-	table = (index >> 8) & 0xff;
-	string = index & 0xff;
-
-	switch (table) {
-	case 0x81:
-	case 0x01:
-		string += 0x100;
-		/* Fall-through */
-	case 0x00:
-	case 0x80:
-		if (string < game->_strings.nr_strings)
-			return game->_strings.strings[string];
-		break;
-
-	case 0x83:
-		string += 0x100;
-		/* Fall-through */
-	case 0x02:
-	case 0x82:
-		if (string < game->_strings2.nr_strings)
-			return game->_strings2.strings[string];
-		break;
-	}
-
-	snprintf(bad_string, sizeof(bad_string), "BAD_STRING(%.4x)", index);
-	return bad_string;
-}
-
-const char *instr_lookup_string(ComprehendGame *game, uint8 index,
-				uint8 table)
-{
-	return string_lookup(game, table << 8 | index);
-}
-
-} // namespace Comprehend
-} // namespace Glk
diff --git a/engines/glk/comprehend/strings.h b/engines/glk/comprehend/strings.h
deleted file mode 100644
index 4d5a40db11..0000000000
--- a/engines/glk/comprehend/strings.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* 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.
- *
- */
-
-#ifndef GLK_COMPREHEND_STRINGS_H
-#define GLK_COMPREHEND_STRINGS_H
-
-namespace Glk {
-namespace Comprehend {
-
-class ComprehendGame;
-
-const char *string_lookup(ComprehendGame *game, uint16 index);
-const char *instr_lookup_string(ComprehendGame *game, uint8 index,
-				uint8 table);
-
-} // namespace Comprehend
-} // namespace Glk
-
-#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index aab0ec1e32..692892d709 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -181,7 +181,6 @@ MODULE_OBJS := \
 	comprehend/game_tr.o \
 	comprehend/image_data.o \
 	comprehend/opcode_map.o \
-	comprehend/strings.o \
 	comprehend/util.o \
 	frotz/bitmap_font.o \
 	frotz/config.o \


Commit: 744580a3a0a9f3cb48e536a3edb7d989eb634655
    https://github.com/scummvm/scummvm/commit/744580a3a0a9f3cb48e536a3edb7d989eb634655
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Change fatal_error to use error

Changed paths:
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/util.cpp
    engines/glk/comprehend/util.h


diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 8eca383515..1b2f0ef4c6 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -229,17 +229,17 @@ void console_println(ComprehendGame *game, const char *text) {
 static Room *get_room(ComprehendGame *game, uint16 index) {
 	/* Room zero is reserved for the players inventory */
 	if (index == 0)
-		fatal_error("Room index 0 (player inventory) is invalid");
+		error("Room index 0 (player inventory) is invalid");
 
 	if (index - 1 >= (int)game->_nr_rooms)
-		fatal_error("Room index %d is invalid", index);
+		error("Room index %d is invalid", index);
 
 	return &game->_rooms[index];
 }
 
 Item *get_item(ComprehendGame *game, uint16 index) {
 	if (index >= game->_header.nr_items)
-		fatal_error("Bad item %d\n", index);
+		error("Bad item %d\n", index);
 
 	return &game->_items[index];
 }
@@ -419,7 +419,7 @@ static void update(ComprehendGame *game) {
 
 static void move_to(ComprehendGame *game, uint8 room) {
 	if (room - 1 >= (int)game->_nr_rooms)
-		fatal_error("Attempted to move to invalid room %.2x\n", room);
+		error("Attempted to move to invalid room %.2x\n", room);
 
 	game->_currentRoom = room;
 	game->_updateFlags = (UPDATE_GRAPHICS | UPDATE_ROOM_DESC |
@@ -613,7 +613,7 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_MOVE:
 		/* Move in the direction dictated by the current verb */
 		if (verb->_index - 1 >= NR_DIRECTIONS)
-			fatal_error("Bad verb %d:%d in move",
+			error("Bad verb %d:%d in move",
 			            verb->_index, verb->_type);
 
 		if (room->direction[verb->_index - 1])
@@ -846,7 +846,7 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_MOVE_CURRENT_OBJECT_TO_ROOM:
 		item = get_item_by_noun(game, noun);
 		if (!item)
-			fatal_error("Bad current object\n");
+			error("Bad current object\n");
 
 		move_object(game, item, instr->operand[0]);
 		break;
@@ -859,7 +859,7 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_DROP_CURRENT_OBJECT:
 		item = get_item_by_noun(game, noun);
 		if (!item)
-			fatal_error("Attempt to take object failed\n");
+			error("Attempt to take object failed\n");
 
 		move_object(game, item, game->_currentRoom);
 		break;
@@ -867,7 +867,7 @@ static void eval_instruction(ComprehendGame *game,
 	case OPCODE_TAKE_CURRENT_OBJECT:
 		item = get_item_by_noun(game, noun);
 		if (!item)
-			fatal_error("Attempt to take object failed\n");
+			error("Attempt to take object failed\n");
 
 		move_object(game, item, ROOM_INVENTORY);
 		break;
@@ -927,7 +927,7 @@ static void eval_instruction(ComprehendGame *game,
 			room->string_desc = instr->operand[1] + 0x200;
 			break;
 		default:
-			fatal_error("Bad string desc %.2x:%.2x\n",
+			error("Bad string desc %.2x:%.2x\n",
 			            instr->operand[1], instr->operand[2]);
 			break;
 		}
@@ -952,7 +952,7 @@ static void eval_instruction(ComprehendGame *game,
 		if (instr->operand[1] == 0x81)
 			index += 256;
 		if (index >= game->_nr_functions)
-			fatal_error("Bad function %.4x >= %.4x\n",
+			error("Bad function %.4x >= %.4x\n",
 			            index, (uint)game->_nr_functions);
 
 		debugC(kDebugScripts, "Calling subfunction %.4x", index);
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 6e9869b37e..90b93c66a0 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -243,7 +243,7 @@ static void parse_function(FileBuffer *fb, Function *func) {
 
 	p = (const uint8 *)memchr(fb->dataPtr(), 0x00, fb->size() - fb->pos());
 	if (!p)
-		fatal_error("bad function @ %.4x", fb->pos());
+		error("bad function @ %.4x", fb->pos());
 
 	while (1) {
 		instruction = &func->instructions[func->nr_instructions];
@@ -254,7 +254,7 @@ static void parse_function(FileBuffer *fb, Function *func) {
 
 		func->nr_instructions++;
 		if (func->nr_instructions >= ARRAY_SIZE(func->instructions))
-			fatal_error("Function has too many instructions");
+			error("Function has too many instructions");
 	}
 }
 
@@ -879,7 +879,7 @@ static void parse_header(ComprehendGame *game, FileBuffer *fb) {
 		break;
 
 	default:
-		fatal_error("Unknown game_data magic %.4x\n", header->magic);
+		error("Unknown game_data magic %.4x\n", header->magic);
 		break;
 	}
 
diff --git a/engines/glk/comprehend/util.cpp b/engines/glk/comprehend/util.cpp
index 5378798e5d..9b600c15df 100644
--- a/engines/glk/comprehend/util.cpp
+++ b/engines/glk/comprehend/util.cpp
@@ -28,20 +28,12 @@
 namespace Glk {
 namespace Comprehend {
 
-void __fatal_error(const char *func, unsigned line, const char *fmt, ...) {
-	error("TODO");
-}
-
-void fatal_strerror(int err, const char *fmt, ...) {
-	error("TODO");
-}
-
 void *xmalloc(size_t size) {
 	void *p;
 
 	p = malloc(size);
 	if (!p)
-		fatal_error("Out of memory");
+		error("Out of memory");
 
 	memset(p, 0, size);
 	return p;
@@ -53,7 +45,7 @@ char *xstrndup(const char *str, size_t len) {
 	Common::String s(str, len);
 	p = scumm_strdup(s.c_str());
 	if (!p)
-		fatal_error("Out of memory");
+		error("Out of memory");
 	return p;
 }
 
diff --git a/engines/glk/comprehend/util.h b/engines/glk/comprehend/util.h
index 8e8224ffff..573fb4aa7b 100644
--- a/engines/glk/comprehend/util.h
+++ b/engines/glk/comprehend/util.h
@@ -35,10 +35,6 @@ namespace Comprehend {
 
 #define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
 
-#define fatal_error error
-
-void __fatal_error(const char *func, unsigned line, const char *fmt, ...);
-void fatal_strerror(int err, const char *fmt, ...);
 void *xmalloc(size_t size);
 char *xstrndup(const char *str, size_t size);
 


Commit: 093825f759795d7567c41f66eb05f4b2a8ba8aa7
    https://github.com/scummvm/scummvm/commit/093825f759795d7567c41f66eb05f4b2a8ba8aa7
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Changed StringTable to be a Common StringArray

Changed paths:
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/debugger_dumper.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_tr.cpp


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index 2457f85f95..e3b92f4547 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -341,23 +341,23 @@ void DebuggerDumper::dumpItems() {
 	}
 }
 
-void DebuggerDumper::dumpStringTable(StringTable *table) {
+void DebuggerDumper::dumpStringTable(Common::StringArray &table) {
 	uint i;
 
-	for (i = 0; i < table->nr_strings; i++)
-		print("[%.4x] %s\n", i, table->strings[i]);
+	for (i = 0; i < table.size(); i++)
+		print("[%.4x] %s\n", i, table[i].c_str());
 }
 
 void DebuggerDumper::dumpGameDataStrings() {
 	print("Main string table (%u entries)\n",
-	      (uint)_game->_strings.nr_strings);
-	dumpStringTable(&_game->_strings);
+	      _game->_strings.size());
+	dumpStringTable(_game->_strings);
 }
 
 void DebuggerDumper::dumpExtraStrings() {
 	print("Extra strings (%u entries)\n",
-	      (uint)_game->_strings2.nr_strings);
-	dumpStringTable(&_game->_strings2);
+	      _game->_strings2.size());
+	dumpStringTable(_game->_strings2);
 }
 
 void DebuggerDumper::dumpReplaceWords() {
diff --git a/engines/glk/comprehend/debugger_dumper.h b/engines/glk/comprehend/debugger_dumper.h
index add248e94d..895f8a4c1c 100644
--- a/engines/glk/comprehend/debugger_dumper.h
+++ b/engines/glk/comprehend/debugger_dumper.h
@@ -24,6 +24,7 @@
 #define GLK_COMPREHEND_DEBUGGER_DUMPER_H
 
 #include "common/hashmap.h"
+#include "common/str-array.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -31,7 +32,6 @@ namespace Comprehend {
 class ComprehendGame;
 struct FunctionState;
 struct Instruction;
-struct StringTable;
 
 class DebuggerDumper {
 private:
@@ -46,7 +46,7 @@ private:
 	void dumpWordMap();
 	void dumpRooms();
 	void dumpItems();
-	void dumpStringTable(StringTable *table);
+	void dumpStringTable(Common::StringArray &table);
 	void dumpGameDataStrings();
 	void dumpExtraStrings();
 	void dumpReplaceWords();
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 1b2f0ef4c6..f65951dc06 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -109,8 +109,8 @@ Common::String ComprehendGame::stringLookup(uint16 index) {
 		/* Fall-through */
 	case 0x00:
 	case 0x80:
-		if (string < _strings.nr_strings)
-			return _strings.strings[string];
+		if (string < _strings.size())
+			return _strings[string];
 		break;
 
 	case 0x83:
@@ -118,8 +118,8 @@ Common::String ComprehendGame::stringLookup(uint16 index) {
 		/* Fall-through */
 	case 0x02:
 	case 0x82:
-		if (string < _strings2.nr_strings)
-			return _strings2.strings[string];
+		if (string < _strings2.size())
+			return _strings2[string];
 		break;
 	}
 
@@ -247,7 +247,7 @@ Item *get_item(ComprehendGame *game, uint16 index) {
 void game_save(ComprehendGame *game) {
 	int c;
 
-	console_println(game, game->_strings.strings[STRING_SAVE_GAME]);
+	console_println(game, game->_strings[STRING_SAVE_GAME].c_str());
 
 	c = console_get_key();
 	if (c < '1' || c > '3') {
@@ -265,7 +265,7 @@ void game_save(ComprehendGame *game) {
 void game_restore(ComprehendGame *game) {
 	int c;
 
-	console_println(game, game->_strings.strings[STRING_RESTORE_GAME]);
+	console_println(game, game->_strings[STRING_RESTORE_GAME].c_str());
 
 	c = console_get_key();
 	if (c < '1' || c > '3') {
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 90b93c66a0..459d1a6753 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -131,13 +131,6 @@ void Function::clear() {
 
 /*-------------------------------------------------------*/
 
-void StringTable::clear() {
-	nr_strings = 0;
-	Common::fill(&strings[0], &strings[0xffff], (char *)nullptr);
-}
-
-/*-------------------------------------------------------*/
-
 void GameHeader::clear() {
 	magic = 0;
 	room_desc_table = 0;
@@ -747,16 +740,16 @@ static char decode_string_elem(uint8 c, bool capital, bool special) {
 * specifier). If a character has the value 0x1f then the next character is
 * taken from the symbols table.
 */
-static char *parse_string(FileBuffer *fb) {
+static Common::String parseString(FileBuffer *fb) {
 	bool capital_next = false, special_next = false;
 	unsigned i, j, k = 0;
 	uint64 chunk;
 	uint8 elem, *encoded;
-	char *string, c;
+	char c;
 	size_t encoded_len;
+	Common::String string;
 
 	encoded_len = fb->strlen();
-	string = (char *)xmalloc(encoded_len * 2);
 
 	/* Get the encoded string */
 	encoded = (uint8 *)xmalloc(encoded_len + 5);
@@ -784,13 +777,13 @@ static char *parse_string(FileBuffer *fb) {
 				                       special_next);
 				special_next = false;
 				capital_next = false;
-				string[k++] = c;
+				string += c;
+				k++;
 			}
 		}
 	}
 
 done:
-	string[k] = '\0';
 	free(encoded);
 
 	return string;
@@ -800,7 +793,7 @@ static void parse_string_table(FileBuffer *fb, unsigned start_addr,
                                uint32 end_addr, StringTable *table) {
 	fb->seek(start_addr);
 	while (1) {
-		table->strings[table->nr_strings++] = parse_string(fb);
+		table->push_back(parseString(fb));
 		if (fb->pos() >= (int32)end_addr)
 			break;
 	}
@@ -996,9 +989,9 @@ static void load_extra_string_files(ComprehendGame *game) {
 			break;
 
 		// HACK - get string offsets correct
-		game->_strings2.nr_strings = 0x40 * i;
-		if (game->_strings2.nr_strings == 0)
-			game->_strings2.nr_strings++;
+		game->_strings2.resize(0x40 * i);
+		if (game->_strings2.empty())
+			game->_strings2.push_back("");
 
 		load_extra_string_file(game, &game->_stringFiles[i]);
 	}
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index f75a65fdaf..5eb4b66787 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -25,6 +25,7 @@
 
 #include "glk/comprehend/image_data.h"
 #include "common/serializer.h"
+#include "common/str-array.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -167,16 +168,7 @@ struct Function {
 	void clear();
 };
 
-struct StringTable {
-	char *strings[0xffff];
-	size_t nr_strings;
-
-	StringTable() {
-		clear();
-	}
-
-	void clear();
-};
+typedef Common::StringArray StringTable;
 
 struct GameHeader {
 	uint16 magic;
@@ -236,8 +228,8 @@ struct GameInfo {
 	struct WordMap _wordMaps[0xff];
 	size_t _nr_word_maps;
 
-	struct StringTable _strings;
-	struct StringTable _strings2;
+	StringTable _strings;
+	StringTable _strings2;
 
 	struct Action _actions[0xffff];
 	size_t _nr_actions;
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index d0d2b8567c..9e2a75fa8d 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -161,7 +161,7 @@ void TransylvaniaGame::before_game() {
 	char buffer[128];
 
 	// Welcome to Transylvania - sign your name
-	console_println(this, _strings.strings[0x20]);
+	console_println(this, _strings[0x20].c_str());
 	g_comprehend->readLine(buffer, sizeof(buffer));
 
 	/*
@@ -178,7 +178,7 @@ void TransylvaniaGame::before_game() {
 			 "%s", buffer);
 
 	// And your next of kin - This isn't stored by the game
-	console_println(this, _strings.strings[0x21]);
+	console_println(this, _strings[0x21].c_str());
 	g_comprehend->readLine(buffer, sizeof(buffer));
 }
 


Commit: 2671e9a07105b874c022f691f0a59163caa2ded8
    https://github.com/scummvm/scummvm/commit/2671e9a07105b874c022f691f0a59163caa2ded8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Shifting DrawSurface to be a single instance of the engine

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/draw_surface.cpp
    engines/glk/comprehend/draw_surface.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/image_data.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 32efb8b8c7..b74e71a266 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -39,12 +39,14 @@ namespace Comprehend {
 Comprehend *g_comprehend;
 
 Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) :
-		GlkAPI(syst, gameDesc), _saveSlot(-1), _game(nullptr),
+		GlkAPI(syst, gameDesc), _topWindow(nullptr), _bottomWindow(nullptr),
+		_drawSurface(nullptr), _game(nullptr),_saveSlot(-1), 
 		_graphicsEnabled(true), _drawFlags(0) {
 	g_comprehend = this;
 }
 
 Comprehend::~Comprehend() {
+	delete _drawSurface;
 	delete _game;
 
 	g_comprehend = nullptr;
@@ -75,8 +77,9 @@ void Comprehend::initialize() {
 	_topWindow->fillRect(0, Rect(0, 0, _topWindow->_w, _topWindow->_h));
 
 	// Initialize drawing
-	DrawSurface::setColorTable(0);
-	DrawSurface::_renderColor = 0;
+	_drawSurface = new DrawSurface();
+	_drawSurface->setColorTable(0);
+	_drawSurface->_renderColor = 0;
 }
 
 void Comprehend::deinitialize() {
@@ -114,6 +117,7 @@ void Comprehend::print(const char *fmt, ...) {
 void Comprehend::readLine(char *buffer, size_t maxLen) {
 	event_t ev;
 
+	_drawSurface->renderIfDirty();
 	glk_request_line_event(_bottomWindow, buffer, maxLen - 1, 0);
 
 	for (;;) {
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index b8a2142132..3f5e1fd8f3 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -41,6 +41,7 @@ namespace Comprehend {
 
 struct GameInfo;
 struct gameState;
+class DrawSurface;
 
 #define EXTRA_STRING_TABLE(x) (0x8200 | (x))
 
@@ -57,6 +58,7 @@ private:
 public:
 	GraphicsWindow *_topWindow;
 	TextBufferWindow *_bottomWindow;
+	DrawSurface *_drawSurface;
 	ComprehendGame *_game;
 	bool _graphicsEnabled;
 	uint _drawFlags;
diff --git a/engines/glk/comprehend/draw_surface.cpp b/engines/glk/comprehend/draw_surface.cpp
index f3cd999fa7..19fc1a6a65 100644
--- a/engines/glk/comprehend/draw_surface.cpp
+++ b/engines/glk/comprehend/draw_surface.cpp
@@ -176,10 +176,6 @@ const uint32 *DrawSurface::COLOR_TABLES[2] = {
     COLOR_TABLE_1,
 };
 
-const uint32 *DrawSurface::_colorTable = DEFAULT_COLOR_TABLE;
-
-uint32 DrawSurface::_renderColor;
-
 /*-------------------------------------------------------*/
 
 void DrawSurface::reset() {
@@ -194,6 +190,7 @@ void DrawSurface::setColorTable(uint index) {
 	}
 
 	_colorTable = COLOR_TABLES[index];
+	_dirty = true;
 }
 
 uint DrawSurface::getPenColor(uint8 opcode) const {
@@ -213,20 +210,30 @@ uint32 DrawSurface::getFillColor(uint8 index) {
 	return color;
 }
 
+void DrawSurface::setColor(uint32 color) {
+	_renderColor = color;
+}
+
 void DrawSurface::drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint32 color) {
-	Graphics::ManagedSurface::drawLine(x1, y1, x2, y2, color);
+	setColor(color);
+	Graphics::ManagedSurface::drawLine(x1, y1, x2, y2, _renderColor);
+	_dirty = true;
 }
 
 void DrawSurface::drawBox(uint16 x1, uint16 y1, uint16 x2, uint16 y2,
                           uint32 color) {
+	setColor(color);
 	Common::Rect r(x1, y1, x2, y2);
-	frameRect(r, color);
+	frameRect(r, _renderColor);
+	_dirty = true;
 }
 
 void DrawSurface::drawFilledBox(uint16 x1, uint16 y1,
                                 uint16 x2, uint16 y2, uint32 color) {
+	setColor(color);
 	Common::Rect r(x1, y1, x2, y2);
-	fillRect(r, color);
+	fillRect(r, _renderColor);
+	_dirty = true;
 }
 
 void DrawSurface::drawShape(int x, int y, int shape_type, uint32 fill_color) {
@@ -333,6 +340,8 @@ void DrawSurface::drawShape(int x, int y, int shape_type, uint32 fill_color) {
 		/* Unknown shape */
 		break;
 	}
+
+	_dirty = true;
 }
 
 void DrawSurface::floodFill(int x, int y, uint32 fill_color, uint32 old_color) {
@@ -352,9 +361,7 @@ void DrawSurface::floodFill(int x, int y, uint32 fill_color, uint32 old_color) {
 			break;
 
 	drawLine(x1, y, x2, y, fill_color);
-#ifdef TODO
-	SDL_RenderPresent(ctx.renderer[RENDERER_SCREEN]);
-#endif
+
 	/* Scanline above */
 	for (i = x1; i < x2; i++)
 		if (y > 0 && getPixelColor(i, y - 1) == old_color)
@@ -364,11 +371,15 @@ void DrawSurface::floodFill(int x, int y, uint32 fill_color, uint32 old_color) {
 	for (i = x1; i < x2; i++)
 		if (y < RENDER_Y_MAX && getPixelColor(i, y + 1) == old_color)
 			floodFill(i, y + 1, fill_color, old_color);
+
+	_dirty = true;
 }
 
 void DrawSurface::drawPixel(uint16 x, uint16 y, uint32 color) {
+	setColor(color);
 	uint32 *ptr = (uint32 *)getBasePtr(x, y);
-	*ptr = color;
+	*ptr = _renderColor;
+	_dirty = true;
 }
 
 uint32 DrawSurface::getPixelColor(uint16 x, uint16 y) {
@@ -377,29 +388,21 @@ uint32 DrawSurface::getPixelColor(uint16 x, uint16 y) {
 }
 
 void DrawSurface::clearScreen(uint32 color) {
-	fillRect(Common::Rect(0, 0, this->w, this->h), color);
-	render();
+	setColor(color);
+	fillRect(Common::Rect(0, 0, this->w, this->h), _renderColor);
+	_dirty = true;
 }
 
-void DrawSurface::render() {
-	GraphicsWindow *win = g_comprehend->_topWindow;
-	win->drawPicture(*this, (uint)-2, 0, 0, win->_w, win->_h);
-}
-
-/*-------------------------------------------------------*/
-
-#ifdef TODO
-static void set_color(unsigned color) {
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(ctx.renderer); i++)
-		SDL_SetRenderDrawColor(ctx.renderer[i],
-		                       (color >> 24) & 0xff,
-		                       (color >> 16) & 0xff,
-		                       (color >> 8) & 0xff,
-		                       (color >> 0) & 0xff);
+void DrawSurface::renderIfDirty() {
+	if (_dirty) {
+		GraphicsWindow *win = g_comprehend->_topWindow;
+		win->drawPicture(*this, (uint)-2, 0, 0, win->_w, win->_h);
+		_dirty = false;
+		// FIXME: Get rid of this hack and properly use the graphics window
+		g_system->copyRectToScreen(getPixels(), pitch, 0, 0, w, h);
+		g_system->updateScreen();
+	}
 }
-#endif
 
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/draw_surface.h b/engines/glk/comprehend/draw_surface.h
index 5e1c95ffc4..71316eba13 100644
--- a/engines/glk/comprehend/draw_surface.h
+++ b/engines/glk/comprehend/draw_surface.h
@@ -69,12 +69,14 @@ private:
 	static const uint32 DEFAULT_COLOR_TABLE[256];
 	static const uint32 COLOR_TABLE_1[256];
 	static const uint32 *COLOR_TABLES[2];
-	static const uint32 *_colorTable;
+	bool _dirty;
 
 public:
-	static uint32 _renderColor;
+	uint32 _renderColor;
+	const uint32 *_colorTable;
 public:
-	DrawSurface() {
+	DrawSurface() : _renderColor(0), _colorTable(DEFAULT_COLOR_TABLE),
+	                _dirty(false) {
 		reset();
 	}
 
@@ -83,9 +85,10 @@ public:
 	 */
 	void reset();
 
-	static void setColorTable(uint index);
+	void setColorTable(uint index);
 	uint getPenColor(uint8 opcode) const;
 	uint32 getFillColor(uint8 index);
+	void setColor(uint32 color);
 
 	void drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint32 color);
 	void drawBox(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint32 color);
@@ -97,9 +100,9 @@ public:
 	void clearScreen(uint32 color);
 
 	/**
-	 * Render the surface to the screen's picture window
+	 * Render the surface to the screen if it's changed
 	 */
-	void render();
+	void renderIfDirty();
 };
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 459d1a6753..b1e0194f83 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -1026,7 +1026,7 @@ void comprehend_load_game(ComprehendGame *game) {
 		game->_itemImages.load(game->_itemGraphicFiles);
 
 		if (game->_colorTable)
-			DrawSurface::setColorTable(game->_colorTable);
+			g_comprehend->_drawSurface->setColorTable(game->_colorTable);
 	}
 
 	// FIXME: This can be merged, don't need to keep start room around
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index d14bc60308..5dc6eaa32a 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -76,13 +76,11 @@ void ImageFileData::load(const char *filename) {
 
 void ImageFileData::draw(uint index, ImageContext *ctx) {
 	_fb.seek(_imageOffsets[index]);
-	DrawSurface ds;
 
 	for (bool done = false; !done;) {
-		done = doImageOp(&ds, ctx);
+		done = doImageOp(g_comprehend->_drawSurface, ctx);
 		if (!done && (draw_flags & IMAGEF_OP_WAIT_KEYPRESS)) {
 			getchar();
-			ds.render();
 		}
 	}
 }
@@ -317,18 +315,15 @@ void draw_image(ImageData *info, unsigned index) {
 }
 
 void draw_dark_room() {
-	DrawSurface ds;
-	ds.clearScreen(G_COLOR_BLACK);
+	g_comprehend->_drawSurface->clearScreen(G_COLOR_BLACK);
 }
 
 void draw_bright_room() {
-	DrawSurface ds;
-	ds.clearScreen(G_COLOR_WHITE);
+	g_comprehend->_drawSurface->clearScreen(G_COLOR_WHITE);
 }
 
 void draw_location_image(ImageData *info, unsigned index) {
-	DrawSurface ds;
-	ds.clearScreen(G_COLOR_WHITE);
+	g_comprehend->_drawSurface->clearScreen(G_COLOR_WHITE);
 	draw_image(info, index);
 }
 


Commit: 3c4bcc9790fcb3eb32d0c3dfac18873c98e212a4
    https://github.com/scummvm/scummvm/commit/3c4bcc9790fcb3eb32d0c3dfac18873c98e212a4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Hooking up engine save/load methods

Changed paths:
    engines/glk/comprehend/comprehend.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index b74e71a266..83e2ccb79e 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -133,14 +133,16 @@ void Comprehend::readLine(char *buffer, size_t maxLen) {
 }
 
 Common::Error Comprehend::readSaveData(Common::SeekableReadStream *rs) {
-	// TODO
+	Common::Serializer s(rs, nullptr);
+	_game->synchronizeSave(s);
 
 	_game->_updateFlags = UPDATE_ALL;
 	return Common::kNoError;
 }
 
 Common::Error Comprehend::writeGameData(Common::WriteStream *ws) {
-	// TODO
+	Common::Serializer s(nullptr, ws);
+	_game->synchronizeSave(s);
 
 	return Common::kNoError;
 }


Commit: b26044de81e7f4a635ed50fccbf4e55774ef8129
    https://github.com/scummvm/scummvm/commit/b26044de81e7f4a635ed50fccbf4e55774ef8129
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Changing _rooms to be a Common::Array

Changed paths:
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index e3b92f4547..b176368aed 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -290,9 +290,9 @@ void DebuggerDumper::dumpRooms() {
 	Room *room;
 	uint i;
 
-	/* Room zero acts as the players inventory */
-	print("Rooms (%u entries)\n", (uint)_game->_nr_rooms);
-	for (i = 1; i <= _game->_nr_rooms; i++) {
+	// Room zero acts as the players inventory
+	print("Rooms (%u entries)\n", (uint)_game->_rooms.size() - 1);
+	for (i = 1; i < _game->_rooms.size(); i++) {
 		room = &_game->_rooms[i];
 
 		print("  [%.2x] flags=%.2x, graphic=%.2x\n",
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index f65951dc06..1cc2658714 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -63,12 +63,12 @@ void ComprehendGame::synchronizeSave(Common::Serializer &s) {
 	for (i = 0; i < ARRAY_SIZE(_flags); i++)
 		s.syncAsByte(_flags[i]);
 
-	// Rooms
-	nr_rooms = _nr_rooms;
-	s.syncAsByte(_nr_rooms);
-	assert(nr_rooms == _nr_rooms);
+	// Rooms. Note that index 0 is the player's inventory
+	nr_rooms = _rooms.size();
+	s.syncAsByte(nr_rooms);
+	assert(nr_rooms == _rooms.size());
 
-	for (i = 0; i < _nr_rooms; ++i) {
+	for (i = 1; i < _rooms.size(); ++i) {
 		s.syncAsUint16LE(_rooms[i].string_desc);
 		for (dir = 0; dir < NR_DIRECTIONS; dir++)
 			s.syncAsByte(_rooms[i].direction[dir]);
@@ -231,7 +231,7 @@ static Room *get_room(ComprehendGame *game, uint16 index) {
 	if (index == 0)
 		error("Room index 0 (player inventory) is invalid");
 
-	if (index - 1 >= (int)game->_nr_rooms)
+	if (index >= (int)game->_rooms.size())
 		error("Room index %d is invalid", index);
 
 	return &game->_rooms[index];
@@ -418,7 +418,7 @@ static void update(ComprehendGame *game) {
 }
 
 static void move_to(ComprehendGame *game, uint8 room) {
-	if (room - 1 >= (int)game->_nr_rooms)
+	if (room >= (int)game->_rooms.size())
 		error("Attempted to move to invalid room %.2x\n", room);
 
 	game->_currentRoom = room;
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index b1e0194f83..5644c3b002 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -164,7 +164,6 @@ void GameInfo::clearInfo() {
 	_header.clear();
 	_comprehendVersion = 0;
 	_startRoom = 0;
-	_nr_rooms = 0;
 	_currentRoom = 0;
 	_words = nullptr;
 	_nr_words = 0;
@@ -178,8 +177,7 @@ void GameInfo::clearInfo() {
 	_roomImages.clear();
 	_itemImages.clear();
 
-	for (uint idx = 0; idx < 0x100; ++idx)
-		_rooms[idx].clear();
+	_rooms.clear();
 	for (uint idx = 0; idx < 0xff; ++idx)
 		_items[idx].clear();
 	for (uint idx = 0; idx < 0xff; ++idx)
@@ -669,7 +667,7 @@ static void parse_items(ComprehendGame *game, FileBuffer *fb) {
 }
 
 static void parse_rooms(ComprehendGame *game, FileBuffer *fb) {
-	size_t nr_rooms = game->_nr_rooms;
+	size_t nr_rooms = game->_rooms.size() - 1;
 	int i;
 
 	/* Room exit directions */
@@ -959,8 +957,8 @@ static void parse_header(ComprehendGame *game, FileBuffer *fb) {
 	parse_variables(game, fb);
 	parse_flags(game, fb);
 
-	game->_nr_rooms = header->room_direction_table[DIRECTION_SOUTH] -
-	                  header->room_direction_table[DIRECTION_NORTH];
+	game->_rooms.resize(header->room_direction_table[DIRECTION_SOUTH] -
+	                    header->room_direction_table[DIRECTION_NORTH] + 1);
 
 	game->_nr_words = (addr_dictionary_end -
 	                   header->addr_dictionary) /
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 5eb4b66787..014b9b4ce2 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -216,8 +216,7 @@ struct GameInfo {
 
 	uint8 _startRoom;
 
-	Room _rooms[0x100];
-	size_t _nr_rooms;
+	Common::Array<Room> _rooms;
 	uint8 _currentRoom;
 
 	struct Item _items[0xff];


Commit: 4d5146341ad2b032c2161c1bb7c8287db02dc018
    https://github.com/scummvm/scummvm/commit/4d5146341ad2b032c2161c1bb7c8287db02dc018
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Change _items to Common::Array

Changed paths:
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index b176368aed..64b9bc4f44 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -316,8 +316,8 @@ void DebuggerDumper::dumpItems() {
 	Item *item;
 	uint i, j;
 
-	print("Items (%u entries)\n", (uint)_game->_header.nr_items);
-	for (i = 0; i < _game->_header.nr_items; i++) {
+	print("Items (%u entries)\n", _game->_items.size());
+	for (i = 0; i < _game->_items.size(); i++) {
 		item = &_game->_items[i];
 
 		print("  [%.2x] %s\n", i + 1,
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 1cc2658714..97a2f2babe 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -78,10 +78,11 @@ void ComprehendGame::synchronizeSave(Common::Serializer &s) {
 	}
 
 	// Objects
-	nr_items = _header.nr_items;
-	s.syncAsByte(_header.nr_items);
+	nr_items = _items.size();
+	s.syncAsByte(nr_items);
+	assert(nr_items == _items.size());
 
-	for (i = 0; i < nr_items; ++i)
+	for (i = 0; i < _items.size(); ++i)
 		_items[i].synchronize(s);
 }
 
@@ -238,7 +239,7 @@ static Room *get_room(ComprehendGame *game, uint16 index) {
 }
 
 Item *get_item(ComprehendGame *game, uint16 index) {
-	if (index >= game->_header.nr_items)
+	if (index >= game->_items.size())
 		error("Bad item %d\n", index);
 
 	return &game->_items[index];
@@ -319,7 +320,7 @@ static Item *get_item_by_noun(ComprehendGame *game,
 	 *         (the box and the snarl-in-a-box). The player is unable
 	 *         to drop the latter because this will match the former.
 	 */
-	for (i = 0; i < game->_header.nr_items; i++)
+	for (i = 0; i < game->_items.size(); i++)
 		if (game->_items[i].word == noun->_index)
 			return &game->_items[i];
 
@@ -357,7 +358,7 @@ static void update_graphics(ComprehendGame *game) {
 
 		if ((game->_updateFlags & UPDATE_GRAPHICS) ||
 		    (game->_updateFlags & UPDATE_GRAPHICS_ITEMS)) {
-			for (i = 0; i < game->_header.nr_items; i++) {
+			for (i = 0; i < game->_items.size(); i++) {
 				item = &game->_items[i];
 
 				if (item->room == game->_currentRoom &&
@@ -375,7 +376,7 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 	size_t count = 0;
 	uint i;
 
-	for (i = 0; i < game->_header.nr_items; i++) {
+	for (i = 0; i < game->_items.size(); i++) {
 		item = &game->_items[i];
 
 		if (item->room == game->_currentRoom &&
@@ -386,7 +387,7 @@ static void describe_objects_in_current_room(ComprehendGame *game) {
 	if (count > 0) {
 		console_println(game, game->stringLookup(STRING_YOU_SEE).c_str());
 
-		for (i = 0; i < game->_header.nr_items; i++) {
+		for (i = 0; i < game->_items.size(); i++) {
 			item = &game->_items[i];
 
 			if (item->room == game->_currentRoom &&
@@ -447,7 +448,7 @@ static void func_set_test_result(FunctionState *func_state, bool value) {
 static size_t num_objects_in_room(ComprehendGame *game, int room) {
 	size_t count = 0, i;
 
-	for (i = 0; i < game->_header.nr_items; i++)
+	for (i = 0; i < game->_items.size(); i++)
 		if (game->_items[i].room == room)
 			count++;
 
@@ -677,7 +678,7 @@ static void eval_instruction(ComprehendGame *game,
 		test = false;
 
 		if (noun) {
-			for (i = 0; i < game->_header.nr_items; i++) {
+			for (i = 0; i < game->_items.size(); i++) {
 				Item *itemP = &game->_items[i];
 
 				if (itemP->word == noun->_index &&
@@ -819,7 +820,7 @@ static void eval_instruction(ComprehendGame *game,
 		}
 
 		console_println(game, game->stringLookup(STRING_INVENTORY).c_str());
-		for (i = 0; i < game->_header.nr_items; i++) {
+		for (i = 0; i < game->_items.size(); i++) {
 			item = &game->_items[i];
 			if (item->room == ROOM_INVENTORY)
 				printf("%s\n",
@@ -835,7 +836,7 @@ static void eval_instruction(ComprehendGame *game,
 		}
 
 		console_println(game, game->stringLookup(instr->operand[1]).c_str());
-		for (i = 0; i < game->_header.nr_items; i++) {
+		for (i = 0; i < game->_items.size(); i++) {
 			item = &game->_items[i];
 			if (item->room == instr->operand[0])
 				printf("%s\n",
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 5644c3b002..3a41ad66d0 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -178,8 +178,7 @@ void GameInfo::clearInfo() {
 	_itemImages.clear();
 
 	_rooms.clear();
-	for (uint idx = 0; idx < 0xff; ++idx)
-		_items[idx].clear();
+	_items.clear();
 	for (uint idx = 0; idx < 0xff; ++idx)
 		_wordMaps[idx].clear();
 	for (uint idx = 0; idx < 0xffff; ++idx)
@@ -637,6 +636,7 @@ static void parse_word_map(ComprehendGame *game, FileBuffer *fb) {
 
 static void parse_items(ComprehendGame *game, FileBuffer *fb) {
 	size_t nr_items = game->_header.nr_items;
+	game->_items.resize(nr_items);
 
 	/* Item descriptions */
 	fb->seek(game->_header.addr_item_strings);
@@ -645,7 +645,7 @@ static void parse_items(ComprehendGame *game, FileBuffer *fb) {
 	if (game->_comprehendVersion == 2) {
 		/* Comprehend version 2 adds long string descriptions */
 		fb->seek(game->_header.addr_item_strings +
-		         (game->_header.nr_items * sizeof(uint16)));
+		         (game->_items.size() * sizeof(uint16)));
 		file_buf_get_array_le16(fb, 0, game->_items, long_string, nr_items);
 	}
 
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 014b9b4ce2..04cae7aae7 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -214,12 +214,11 @@ struct GameInfo {
 
 	unsigned _comprehendVersion;
 
-	uint8 _startRoom;
-
 	Common::Array<Room> _rooms;
 	uint8 _currentRoom;
+	uint8 _startRoom;
 
-	struct Item _items[0xff];
+	Common::Array<Item> _items;
 
 	Word *_words;
 	size_t _nr_words;


Commit: 6015d9c914e7416f1ed538114d9aaa49e8012217
    https://github.com/scummvm/scummvm/commit/6015d9c914e7416f1ed538114d9aaa49e8012217
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Change _wordMaps to Common::Array

Changed paths:
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index 64b9bc4f44..a4b5779d3b 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -266,8 +266,8 @@ void DebuggerDumper::dumpWordMap() {
 	WordMap *map;
 	uint i, j;
 
-	print("Word pairs (%u entries)\n", (uint)_game->_nr_word_maps);
-	for (i = 0; i < _game->_nr_word_maps; i++) {
+	print("Word pairs (%u entries)\n", _game->_wordMaps.size());
+	for (i = 0; i < _game->_wordMaps.size(); i++) {
 		map = &_game->_wordMaps[i];
 
 		for (j = 0; j < 3; j++) {
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 97a2f2babe..7f5dc65801 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -295,7 +295,7 @@ static WordIndex *is_word_pair(ComprehendGame *game,
 	uint i;
 
 	/* Check if this is a word pair */
-	for (i = 0; i < game->_nr_word_maps; i++) {
+	for (i = 0; i < game->_wordMaps.size(); i++) {
 		map = &game->_wordMaps[i];
 
 		if (map->word[0].index == word1->_index &&
@@ -305,7 +305,7 @@ static WordIndex *is_word_pair(ComprehendGame *game,
 			return &map->word[2];
 	}
 
-	return NULL;
+	return nullptr;
 }
 
 static Item *get_item_by_noun(ComprehendGame *game,
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 3a41ad66d0..2b5414337d 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -167,7 +167,6 @@ void GameInfo::clearInfo() {
 	_currentRoom = 0;
 	_words = nullptr;
 	_nr_words = 0;
-	_nr_word_maps = 0;
 	_nr_actions = 0;
 	_nr_functions = 0;
 	_currentReplaceWord = 0;
@@ -179,8 +178,7 @@ void GameInfo::clearInfo() {
 
 	_rooms.clear();
 	_items.clear();
-	for (uint idx = 0; idx < 0xff; ++idx)
-		_wordMaps[idx].clear();
+	_wordMaps.clear();
 	for (uint idx = 0; idx < 0xffff; ++idx)
 		_actions[idx].clear();
 	for (uint idx = 0; idx < 0xffff; ++idx)
@@ -588,11 +586,10 @@ static void parse_dictionary(ComprehendGame *game, FileBuffer *fb) {
 }
 
 static void parse_word_map(ComprehendGame *game, FileBuffer *fb) {
-	WordMap *map;
 	uint8 index, type;
 	uint i;
 
-	game->_nr_word_maps = 0;
+	game->_wordMaps.clear();
 	fb->seek(game->_header.addr_word_map);
 
 	/*
@@ -600,7 +597,7 @@ static void parse_word_map(ComprehendGame *game, FileBuffer *fb) {
 	* index/type values for a first and second word.
 	*/
 	while (1) {
-		map = &game->_wordMaps[game->_nr_word_maps];
+		WordMap map;
 
 		index = fb->readByte();
 		type = fb->readByte();
@@ -609,13 +606,13 @@ static void parse_word_map(ComprehendGame *game, FileBuffer *fb) {
 			break;
 		}
 
-		map->word[0].index = index;
-		map->word[0].type = type;
-		map->flags = fb->readByte();
-		map->word[1].index = fb->readByte();
-		map->word[1].type = fb->readByte();
+		map.word[0].index = index;
+		map.word[0].type = type;
+		map.flags = fb->readByte();
+		map.word[1].index = fb->readByte();
+		map.word[1].type = fb->readByte();
 
-		game->_nr_word_maps++;
+		game->_wordMaps.push_back(map);
 	}
 
 	/* Consume two more null bytes (type and index were also null) */
@@ -626,11 +623,11 @@ static void parse_word_map(ComprehendGame *game, FileBuffer *fb) {
 	* index/type. The first and second words from above map to the
 	* target word here. E.g. 'go north' -> 'north'.
 	*/
-	for (i = 0; i < game->_nr_word_maps; i++) {
-		map = &game->_wordMaps[i];
+	for (i = 0; i < game->_wordMaps.size(); i++) {
+		WordMap &map = game->_wordMaps[i];
 
-		map->word[2].index = fb->readByte();
-		map->word[2].type = fb->readByte();
+		map.word[2].index = fb->readByte();
+		map.word[2].type = fb->readByte();
 	}
 }
 
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 04cae7aae7..fa3f440781 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -223,8 +223,7 @@ struct GameInfo {
 	Word *_words;
 	size_t _nr_words;
 
-	struct WordMap _wordMaps[0xff];
-	size_t _nr_word_maps;
+	Common::Array<WordMap> _wordMaps;
 
 	StringTable _strings;
 	StringTable _strings2;


Commit: 0ed3473e35ba608f51fc9f3202964d031cbca191
    https://github.com/scummvm/scummvm/commit/0ed3473e35ba608f51fc9f3202964d031cbca191
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Change _actions to Common::Array

Changed paths:
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index a4b5779d3b..fcb5e81a75 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -180,8 +180,8 @@ void DebuggerDumper::dumpActionTable() {
 	Word *word;
 	uint i, j;
 
-	print("Action table (%u entries)\n", (uint)_game->_nr_actions);
-	for (i = 0; i < _game->_nr_actions; i++) {
+	print("Action table (%u entries)\n", _game->_actions.size());
+	for (i = 0; i < _game->_actions.size(); i++) {
 		action = &_game->_actions[i];
 
 		print("(");
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 7f5dc65801..1af2aace0f 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -1086,7 +1086,7 @@ static bool handle_sentence(ComprehendGame *game,
 		return false;
 
 	/* Find a matching action */
-	for (i = 0; i < game->_nr_actions; i++) {
+	for (i = 0; i < game->_actions.size(); i++) {
 		action = &game->_actions[i];
 
 		if (action->type == ACTION_VERB_OPT_NOUN &&
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 2b5414337d..819299f86b 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -167,7 +167,6 @@ void GameInfo::clearInfo() {
 	_currentRoom = 0;
 	_words = nullptr;
 	_nr_words = 0;
-	_nr_actions = 0;
 	_nr_functions = 0;
 	_currentReplaceWord = 0;
 	_updateFlags = 0;
@@ -179,8 +178,7 @@ void GameInfo::clearInfo() {
 	_rooms.clear();
 	_items.clear();
 	_wordMaps.clear();
-	for (uint idx = 0; idx < 0xffff; ++idx)
-		_actions[idx].clear();
+	_actions.clear();
 	for (uint idx = 0; idx < 0xffff; ++idx)
 		_functions[idx].clear();
 
@@ -261,9 +259,7 @@ static void parse_vm(ComprehendGame *game, FileBuffer *fb) {
 	}
 }
 
-static void parse_action_table_vvnn(ComprehendGame *game,
-                                    FileBuffer *fb, size_t *index) {
-	Action *action;
+static void parse_action_table_vvnn(ComprehendGame *game, FileBuffer *fb) {
 	uint8 verb, count;
 	int i, j;
 
@@ -285,29 +281,27 @@ static void parse_action_table_vvnn(ComprehendGame *game,
 		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
-			action = &game->_actions[*index];
-			action->type = ACTION_VERB_VERB_NOUN_NOUN;
+			Action action;
+			action.type = ACTION_VERB_VERB_NOUN_NOUN;
 
-			action->nr_words = 4;
-			action->word_type[0] = WORD_TYPE_VERB;
-			action->word_type[1] = WORD_TYPE_VERB;
-			action->word_type[2] = WORD_TYPE_NOUN_MASK;
-			action->word_type[3] = WORD_TYPE_NOUN_MASK;
+			action.nr_words = 4;
+			action.word_type[0] = WORD_TYPE_VERB;
+			action.word_type[1] = WORD_TYPE_VERB;
+			action.word_type[2] = WORD_TYPE_NOUN_MASK;
+			action.word_type[3] = WORD_TYPE_NOUN_MASK;
 
-			action->word[0] = verb;
+			action.word[0] = verb;
 
 			for (j = 0; j < 3; j++)
-				action->word[j + 1] = fb->readByte();
-			action->function = fb->readUint16LE();
+				action.word[j + 1] = fb->readByte();
+			action.function = fb->readUint16LE();
 
-			(*index)++;
+			game->_actions.push_back(action);
 		}
 	}
 }
 
-static void parse_action_table_vnjn(ComprehendGame *game,
-                                    FileBuffer *fb, size_t *index) {
-	Action *action;
+static void parse_action_table_vnjn(ComprehendGame *game, FileBuffer *fb) {
 	uint8 join, count;
 	int i;
 
@@ -329,30 +323,28 @@ static void parse_action_table_vnjn(ComprehendGame *game,
 		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
-			action = &game->_actions[*index];
-			action->type = ACTION_VERB_NOUN_JOIN_NOUN;
+			Action action;
+			action.type = ACTION_VERB_NOUN_JOIN_NOUN;
 
-			action->nr_words = 4;
-			action->word_type[0] = WORD_TYPE_VERB;
-			action->word_type[1] = WORD_TYPE_NOUN_MASK;
-			action->word_type[2] = WORD_TYPE_JOIN;
-			action->word_type[3] = WORD_TYPE_NOUN_MASK;
+			action.nr_words = 4;
+			action.word_type[0] = WORD_TYPE_VERB;
+			action.word_type[1] = WORD_TYPE_NOUN_MASK;
+			action.word_type[2] = WORD_TYPE_JOIN;
+			action.word_type[3] = WORD_TYPE_NOUN_MASK;
 
-			action->word[2] = join;
+			action.word[2] = join;
 
-			action->word[0] = fb->readByte();
-			action->word[1] = fb->readByte();
-			action->word[3] = fb->readByte();
-			action->function = fb->readUint16LE();
+			action.word[0] = fb->readByte();
+			action.word[1] = fb->readByte();
+			action.word[3] = fb->readByte();
+			action.function = fb->readUint16LE();
 
-			(*index)++;
+			game->_actions.push_back(action);
 		}
 	}
 }
 
-static void parse_action_table_vjn(ComprehendGame *game,
-                                   FileBuffer *fb, size_t *index) {
-	Action *action;
+static void parse_action_table_vjn(ComprehendGame *game, FileBuffer *fb) {
 	uint8 join, count;
 	int i;
 
@@ -373,27 +365,25 @@ static void parse_action_table_vjn(ComprehendGame *game,
 		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
-			action = &game->_actions[*index];
-			action->type = ACTION_VERB_JOIN_NOUN;
-			action->word[1] = join;
+			Action action;
+			action.type = ACTION_VERB_JOIN_NOUN;
+			action.word[1] = join;
 
-			action->nr_words = 3;
-			action->word_type[0] = WORD_TYPE_VERB;
-			action->word_type[1] = WORD_TYPE_JOIN;
-			action->word_type[2] = WORD_TYPE_NOUN_MASK;
+			action.nr_words = 3;
+			action.word_type[0] = WORD_TYPE_VERB;
+			action.word_type[1] = WORD_TYPE_JOIN;
+			action.word_type[2] = WORD_TYPE_NOUN_MASK;
 
-			action->word[0] = fb->readByte();
-			action->word[2] = fb->readByte();
-			action->function = fb->readUint16LE();
+			action.word[0] = fb->readByte();
+			action.word[2] = fb->readByte();
+			action.function = fb->readUint16LE();
 
-			(*index)++;
+			game->_actions.push_back(action);
 		}
 	}
 }
 
-static void parse_action_table_vdn(ComprehendGame *game,
-                                   FileBuffer *fb, size_t *index) {
-	Action *action;
+static void parse_action_table_vdn(ComprehendGame *game, FileBuffer *fb) {
 	uint8 verb, count;
 	int i;
 
@@ -414,27 +404,25 @@ static void parse_action_table_vdn(ComprehendGame *game,
 		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
-			action = &game->_actions[*index];
-			action->type = ACTION_VERB_JOIN_NOUN;
-			action->word[0] = verb;
+			Action action;
+			action.type = ACTION_VERB_JOIN_NOUN;
+			action.word[0] = verb;
 
-			action->nr_words = 3;
-			action->word_type[0] = WORD_TYPE_VERB;
-			action->word_type[1] = WORD_TYPE_VERB;
-			action->word_type[2] = WORD_TYPE_NOUN_MASK;
+			action.nr_words = 3;
+			action.word_type[0] = WORD_TYPE_VERB;
+			action.word_type[1] = WORD_TYPE_VERB;
+			action.word_type[2] = WORD_TYPE_NOUN_MASK;
 
-			action->word[1] = fb->readByte();
-			action->word[2] = fb->readByte();
-			action->function = fb->readUint16LE();
+			action.word[1] = fb->readByte();
+			action.word[2] = fb->readByte();
+			action.function = fb->readUint16LE();
 
-			(*index)++;
+			game->_actions.push_back(action);
 		}
 	}
 }
 
-static void parse_action_table_vnn(ComprehendGame *game,
-                                   FileBuffer *fb, size_t *index) {
-	Action *action;
+static void parse_action_table_vnn(ComprehendGame *game, FileBuffer *fb) {
 	uint8 verb, count;
 	int i;
 
@@ -456,27 +444,25 @@ static void parse_action_table_vnn(ComprehendGame *game,
 		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
-			action = &game->_actions[*index];
-			action->type = ACTION_VERB_NOUN_NOUN;
-			action->word[0] = verb;
+			Action action;
+			action.type = ACTION_VERB_NOUN_NOUN;
+			action.word[0] = verb;
 
-			action->nr_words = 3;
-			action->word_type[0] = WORD_TYPE_VERB;
-			action->word_type[1] = WORD_TYPE_NOUN_MASK;
-			action->word_type[2] = WORD_TYPE_NOUN_MASK;
+			action.nr_words = 3;
+			action.word_type[0] = WORD_TYPE_VERB;
+			action.word_type[1] = WORD_TYPE_NOUN_MASK;
+			action.word_type[2] = WORD_TYPE_NOUN_MASK;
 
-			action->word[1] = fb->readByte();
-			action->word[2] = fb->readByte();
-			action->function = fb->readUint16LE();
+			action.word[1] = fb->readByte();
+			action.word[2] = fb->readByte();
+			action.function = fb->readUint16LE();
 
-			(*index)++;
+			game->_actions.push_back(action);
 		}
 	}
 }
 
-static void parse_action_table_vn(ComprehendGame *game,
-                                  FileBuffer *fb, size_t *index) {
-	Action *action;
+static void parse_action_table_vn(ComprehendGame *game, FileBuffer *fb) {
 	uint8 verb, count;
 	int i;
 
@@ -497,25 +483,23 @@ static void parse_action_table_vn(ComprehendGame *game,
 		count = fb->readByte();
 
 		for (i = 0; i < count; i++) {
-			action = &game->_actions[*index];
-			action->type = ACTION_VERB_NOUN;
-			action->word[0] = verb;
+			Action action;
+			action.type = ACTION_VERB_NOUN;
+			action.word[0] = verb;
 
-			action->nr_words = 2;
-			action->word_type[0] = WORD_TYPE_VERB;
-			action->word_type[1] = WORD_TYPE_NOUN_MASK;
+			action.nr_words = 2;
+			action.word_type[0] = WORD_TYPE_VERB;
+			action.word_type[1] = WORD_TYPE_NOUN_MASK;
 
-			action->word[1] = fb->readByte();
-			action->function = fb->readUint16LE();
+			action.word[1] = fb->readByte();
+			action.function = fb->readUint16LE();
 
-			(*index)++;
+			game->_actions.push_back(action);
 		}
 	}
 }
 
-static void parse_action_table_v(ComprehendGame *game,
-                                 FileBuffer *fb, size_t *index) {
-	Action *action;
+static void parse_action_table_v(ComprehendGame *game, FileBuffer *fb) {
 	uint8 verb, nr_funcs;
 	uint16 func;
 	int i;
@@ -533,13 +517,13 @@ static void parse_action_table_v(ComprehendGame *game,
 		if (verb == 0)
 			break;
 
-		action = &game->_actions[*index];
-		action->type = ACTION_VERB_OPT_NOUN;
-		action->word[0] = verb;
+		Action action;
+		action.type = ACTION_VERB_OPT_NOUN;
+		action.word[0] = verb;
 
 		/* Can take an optional noun (nr_words here is maximum) */
-		action->nr_words = 1;
-		action->word_type[0] = WORD_TYPE_VERB;
+		action.nr_words = 1;
+		action.word_type[0] = WORD_TYPE_VERB;
 
 		/*
 		* Default actions can have more than one function, but only
@@ -549,29 +533,29 @@ static void parse_action_table_v(ComprehendGame *game,
 		for (i = 0; i < nr_funcs; i++) {
 			func = fb->readUint16LE();
 			if (i == 0)
-				action->function = func;
+				action.function = func;
 		}
 
-		(*index)++;
+		game->_actions.push_back(action);
 	}
 }
 
 static void parse_action_table(ComprehendGame *game,
                                FileBuffer *fb) {
-	game->_nr_actions = 0;
+	game->_actions.clear();
 
 	if (game->_comprehendVersion == 1) {
-		parse_action_table_vvnn(game, fb, &game->_nr_actions);
-		parse_action_table_vdn(game, fb, &game->_nr_actions);
+		parse_action_table_vvnn(game, fb);
+		parse_action_table_vdn(game, fb);
 	}
 	if (game->_comprehendVersion >= 2) {
-		parse_action_table_vnn(game, fb, &game->_nr_actions);
+		parse_action_table_vnn(game, fb);
 	}
 
-	parse_action_table_vnjn(game, fb, &game->_nr_actions);
-	parse_action_table_vjn(game, fb, &game->_nr_actions);
-	parse_action_table_vn(game, fb, &game->_nr_actions);
-	parse_action_table_v(game, fb, &game->_nr_actions);
+	parse_action_table_vnjn(game, fb);
+	parse_action_table_vjn(game, fb);
+	parse_action_table_vn(game, fb);
+	parse_action_table_v(game, fb);
 }
 
 static void parse_dictionary(ComprehendGame *game, FileBuffer *fb) {
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index fa3f440781..a3c737ed93 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -224,13 +224,11 @@ struct GameInfo {
 	size_t _nr_words;
 
 	Common::Array<WordMap> _wordMaps;
+	Common::Array<Action> _actions;
 
 	StringTable _strings;
 	StringTable _strings2;
 
-	struct Action _actions[0xffff];
-	size_t _nr_actions;
-
 	struct Function _functions[0xffff];
 	size_t _nr_functions;
 


Commit: f91628971d0ad2854b2d4d6b0b8306a13d31645b
    https://github.com/scummvm/scummvm/commit/f91628971d0ad2854b2d4d6b0b8306a13d31645b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Change _functions to Common::Array

Changed paths:
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index fcb5e81a75..f2485c1d89 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -162,8 +162,8 @@ void DebuggerDumper::dumpFunctions() {
 	Function *func;
 	uint i, j;
 
-	print("Functions (%u entries)\n", (uint)_game->_nr_functions);
-	for (i = 0; i < _game->_nr_functions; i++) {
+	print("Functions (%u entries)\n", _game->_functions.size());
+	for (i = 0; i < _game->_functions.size(); i++) {
 		func = &_game->_functions[i];
 
 		print("[%.4x] (%u instructions)\n", i, (uint)func->nr_instructions);
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 1af2aace0f..b76f4c42b7 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -952,9 +952,9 @@ static void eval_instruction(ComprehendGame *game,
 		index = instr->operand[0];
 		if (instr->operand[1] == 0x81)
 			index += 256;
-		if (index >= game->_nr_functions)
+		if (index >= game->_functions.size())
 			error("Bad function %.4x >= %.4x\n",
-			            index, (uint)game->_nr_functions);
+			      index, game->_functions.size());
 
 		debugC(kDebugScripts, "Calling subfunction %.4x", index);
 		eval_function(game, &game->_functions[index], verb, noun);
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 819299f86b..1be140269f 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -167,7 +167,6 @@ void GameInfo::clearInfo() {
 	_currentRoom = 0;
 	_words = nullptr;
 	_nr_words = 0;
-	_nr_functions = 0;
 	_currentReplaceWord = 0;
 	_updateFlags = 0;
 	_strings.clear();
@@ -179,8 +178,7 @@ void GameInfo::clearInfo() {
 	_items.clear();
 	_wordMaps.clear();
 	_actions.clear();
-	for (uint idx = 0; idx < 0xffff; ++idx)
-		_functions[idx].clear();
+	_functions.clear();
 
 	Common::fill(&_flags[0], &_flags[MAX_FLAGS], false);
 	Common::fill(&_variables[0], &_variables[MAX_VARIABLES], 0);
@@ -245,17 +243,16 @@ static void parse_function(FileBuffer *fb, Function *func) {
 }
 
 static void parse_vm(ComprehendGame *game, FileBuffer *fb) {
-	Function *func;
-
 	fb->seek(game->_header.addr_vm);
+
 	while (1) {
-		func = &game->_functions[game->_nr_functions];
+		Function func;
 
-		parse_function(fb, func);
-		if (func->nr_instructions == 0)
+		parse_function(fb, &func);
+		if (func.nr_instructions == 0)
 			break;
 
-		game->_nr_functions++;
+		game->_functions.push_back(func);
 	}
 }
 
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index a3c737ed93..c118f1c088 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -225,13 +225,11 @@ struct GameInfo {
 
 	Common::Array<WordMap> _wordMaps;
 	Common::Array<Action> _actions;
+	Common::Array<Function> _functions;
 
 	StringTable _strings;
 	StringTable _strings2;
 
-	struct Function _functions[0xffff];
-	size_t _nr_functions;
-
 	struct ImageData _roomImages;
 	struct ImageData _itemImages;
 


Commit: 08de10a9ec87af8472da77fe84c0a852c5815525
    https://github.com/scummvm/scummvm/commit/08de10a9ec87af8472da77fe84c0a852c5815525
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Change _replaceWords to a StringArray

Changed paths:
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_tr.cpp


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index f2485c1d89..a84a80e878 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -150,7 +150,7 @@ Common::String DebuggerDumper::dumpInstruction(ComprehendGame *game,
 		break;
 
 	case OPCODE_SET_STRING_REPLACEMENT:
-		line += Common::String::format(" %s", game->_replaceWords[instr->operand[0] - 1]);
+		line += Common::String::format(" %s", game->_replaceWords[instr->operand[0] - 1].c_str());
 		break;
 	}
 
@@ -366,7 +366,7 @@ void DebuggerDumper::dumpReplaceWords() {
 	print("Replacement words (%u entries)\n",
 	      _game->_replaceWords.size());
 	for (i = 0; i < _game->_replaceWords.size(); i++)
-		print("  [%.2x] %s\n", i + 1, _game->_replaceWords[i]);
+		print("  [%.2x] %s\n", i + 1, _game->_replaceWords[i].c_str());
 }
 
 void DebuggerDumper::dumpHeader() {
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index b76f4c42b7..9ce268ddd4 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -176,7 +176,7 @@ void console_println(ComprehendGame *game, const char *text) {
 				         game->_currentReplaceWord);
 				word = bad_word;
 			} else {
-				word = game->_replaceWords[game->_currentReplaceWord];
+				word = game->_replaceWords[game->_currentReplaceWord].c_str();
 			}
 			word_len = strlen(word);
 			p++;
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 1be140269f..f9690264d4 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -179,13 +179,10 @@ void GameInfo::clearInfo() {
 	_wordMaps.clear();
 	_actions.clear();
 	_functions.clear();
+	_replaceWords.clear();
 
 	Common::fill(&_flags[0], &_flags[MAX_FLAGS], false);
 	Common::fill(&_variables[0], &_variables[MAX_VARIABLES], 0);
-
-	for (uint idx = 0; idx < _replaceWords.size(); ++idx)
-		free(_replaceWords[idx]);
-	_replaceWords.clear();
 }
 
 static void parse_header_le16(FileBuffer *fb, uint16 *val) {
@@ -813,7 +810,7 @@ static void parse_replace_words(ComprehendGame *game,
 		if (len == 0)
 			break;
 
-		game->_replaceWords.push_back(xstrndup((const char *)fb->dataPtr(), len));
+		game->_replaceWords.push_back(Common::String((const char *)fb->dataPtr(), len));
 		fb->skip(len + (eof ? 0 : 1));
 		if (eof)
 			break;
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index c118f1c088..c79fc0df2f 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -226,6 +226,7 @@ struct GameInfo {
 	Common::Array<WordMap> _wordMaps;
 	Common::Array<Action> _actions;
 	Common::Array<Function> _functions;
+	Common::StringArray _replaceWords;
 
 	StringTable _strings;
 	StringTable _strings2;
@@ -236,7 +237,6 @@ struct GameInfo {
 	bool _flags[MAX_FLAGS];
 	uint16 _variables[MAX_VARIABLES];
 
-	Common::Array<char *> _replaceWords;
 	uint8 _currentReplaceWord;
 	uint _updateFlags;
 
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 9e2a75fa8d..d8ad0a6d72 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -164,18 +164,8 @@ void TransylvaniaGame::before_game() {
 	console_println(this, _strings[0x20].c_str());
 	g_comprehend->readLine(buffer, sizeof(buffer));
 
-	/*
-	 * Transylvania uses replace word 0 as the player's name, the game
-	 * data file stores a bunch of dummy characters, so the length is
-	 * limited (the original game will break if you put a name in that
-	 * is too long).
-	 */
-	if (!_replaceWords[0])
-		_replaceWords[0] = xstrndup(buffer, strlen(buffer));
-	else
-		snprintf(_replaceWords[0],
-			 strlen(_replaceWords[0]),
-			 "%s", buffer);
+	// The player's name is stored in word 0
+	_replaceWords[0] = Common::String(buffer);
 
 	// And your next of kin - This isn't stored by the game
 	console_println(this, _strings[0x21].c_str());


Commit: 0831f0d93c1021167caa50b0c2dabc9a312ddadc
    https://github.com/scummvm/scummvm/commit/0831f0d93c1021167caa50b0c2dabc9a312ddadc
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Remove deprecated utils file

Changed paths:
  R engines/glk/comprehend/util.cpp
  R engines/glk/comprehend/util.h
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/draw_surface.cpp
    engines/glk/comprehend/file_buf.cpp
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/image_data.cpp
    engines/glk/module.mk


diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index a84a80e878..2153f776ce 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -23,7 +23,6 @@
 #include "glk/comprehend/debugger_dumper.h"
 #include "glk/comprehend/dictionary.h"
 #include "glk/comprehend/game.h"
-#include "glk/comprehend/util.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -244,7 +243,7 @@ void DebuggerDumper::dumpDictionary() {
 	uint i;
 
 	/* Sort the dictionary by index */
-	dictionary = (Word *)xmalloc(sizeof(*words) * _game->_nr_words);
+	dictionary = (Word *)malloc(sizeof(*words) * _game->_nr_words);
 	memcpy(dictionary, _game->_words,
 	       sizeof(*words) * _game->_nr_words);
 	qsort(dictionary, _game->_nr_words, sizeof(*words),
diff --git a/engines/glk/comprehend/draw_surface.cpp b/engines/glk/comprehend/draw_surface.cpp
index 19fc1a6a65..f452470f1a 100644
--- a/engines/glk/comprehend/draw_surface.cpp
+++ b/engines/glk/comprehend/draw_surface.cpp
@@ -23,7 +23,6 @@
 #include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/image_data.h"
-#include "glk/comprehend/util.h"
 #include "glk/window_graphics.h"
 
 namespace Glk {
diff --git a/engines/glk/comprehend/file_buf.cpp b/engines/glk/comprehend/file_buf.cpp
index 426cbf4672..e20dc0fc9f 100644
--- a/engines/glk/comprehend/file_buf.cpp
+++ b/engines/glk/comprehend/file_buf.cpp
@@ -23,7 +23,6 @@
 #include "glk/comprehend/file_buf.h"
 #include "common/algorithm.h"
 #include "common/file.h"
-#include "glk/comprehend/util.h"
 
 namespace Glk {
 namespace Comprehend {
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 9ce268ddd4..2e5d32525d 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -29,7 +29,6 @@
 #include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/opcode_map.h"
-#include "glk/comprehend/util.h"
 
 namespace Glk {
 namespace Comprehend {
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index f9690264d4..ab9483c61f 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -26,7 +26,6 @@
 #include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/file_buf.h"
 #include "glk/comprehend/game.h"
-#include "glk/comprehend/util.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -556,7 +555,7 @@ static void parse_dictionary(ComprehendGame *game, FileBuffer *fb) {
 	uint i;
 
 	// FIXME - fixed size 0xff array?
-	game->_words = (Word *)xmalloc(game->_nr_words * sizeof(Word));
+	game->_words = (Word *)malloc(game->_nr_words * sizeof(Word));
 
 	fb->seek(game->_header.addr_dictionary);
 	for (i = 0; i < game->_nr_words; i++)
@@ -725,7 +724,7 @@ static Common::String parseString(FileBuffer *fb) {
 	encoded_len = fb->strlen();
 
 	/* Get the encoded string */
-	encoded = (uint8 *)xmalloc(encoded_len + 5);
+	encoded = (uint8 *)malloc(encoded_len + 5);
 	memset(encoded, 0, encoded_len);
 	fb->read(encoded, encoded_len);
 
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index c79fc0df2f..42eee01cf9 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -32,6 +32,7 @@ namespace Comprehend {
 
 #define MAX_FLAGS 64
 #define MAX_VARIABLES 128
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
 
 enum {
 	DIRECTION_NORTH,
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index d8ad0a6d72..220ddef4d7 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -23,7 +23,6 @@
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/game_tr.h"
-#include "glk/comprehend/util.h"
 
 namespace Glk {
 namespace Comprehend {
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 5dc6eaa32a..a06ac936c8 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -26,7 +26,6 @@
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/image_data.h"
 #include "glk/comprehend/draw_surface.h"
-#include "glk/comprehend/util.h"
 
 namespace Glk {
 namespace Comprehend {
diff --git a/engines/glk/comprehend/util.cpp b/engines/glk/comprehend/util.cpp
deleted file mode 100644
index 9b600c15df..0000000000
--- a/engines/glk/comprehend/util.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-/* 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 "glk/comprehend/util.h"
-#include "common/debug.h"
-#include "common/str.h"
-#include "common/textconsole.h"
-
-namespace Glk {
-namespace Comprehend {
-
-void *xmalloc(size_t size) {
-	void *p;
-
-	p = malloc(size);
-	if (!p)
-		error("Out of memory");
-
-	memset(p, 0, size);
-	return p;
-}
-
-char *xstrndup(const char *str, size_t len) {
-	char *p;
-
-	Common::String s(str, len);
-	p = scumm_strdup(s.c_str());
-	if (!p)
-		error("Out of memory");
-	return p;
-}
-
-} // namespace Comprehend
-} // namespace Glk
diff --git a/engines/glk/comprehend/util.h b/engines/glk/comprehend/util.h
deleted file mode 100644
index 573fb4aa7b..0000000000
--- a/engines/glk/comprehend/util.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* 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.
- *
- */
-
-#ifndef GLK_COMPREHEND_UTIL_H
-#define GLK_COMPREHEND_UTIL_H
-
-#include "common/scummsys.h"
-
-namespace Glk {
-namespace Comprehend {
-
-#define DEBUG_IMAGE_DRAW	(1 << 0)
-#define DEBUG_GAME_STATE	(1 << 1)
-#define DEBUG_FUNCTIONS		(1 << 2)
-#define DEBUG_ALL		(~0U)
-
-#define ARRAY_SIZE(a)	(sizeof(a) / sizeof(a[0]))
-
-void *xmalloc(size_t size);
-char *xstrndup(const char *str, size_t size);
-
-} // namespace Comprehend
-} // namespace Glk
-
-#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 692892d709..4f173fc742 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -181,7 +181,6 @@ MODULE_OBJS := \
 	comprehend/game_tr.o \
 	comprehend/image_data.o \
 	comprehend/opcode_map.o \
-	comprehend/util.o \
 	frotz/bitmap_font.o \
 	frotz/config.o \
 	frotz/detection.o \


Commit: 604b8f91ca16432ad860dfb830e5a8e22adbe407
    https://github.com/scummvm/scummvm/commit/604b8f91ca16432ad860dfb830e5a8e22adbe407
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Fix gcc warnings

Changed paths:
    engines/glk/comprehend/debugger.h
    engines/glk/comprehend/debugger_dumper.cpp
    engines/glk/comprehend/debugger_dumper.h
    engines/glk/comprehend/draw_surface.cpp
    engines/glk/comprehend/image_data.cpp


diff --git a/engines/glk/comprehend/debugger.h b/engines/glk/comprehend/debugger.h
index 0c1113b7e2..ec6fcf8e13 100644
--- a/engines/glk/comprehend/debugger.h
+++ b/engines/glk/comprehend/debugger.h
@@ -46,7 +46,7 @@ protected:
 
 public:
 	Debugger();
-	~Debugger();
+	virtual ~Debugger();
 };
 
 extern Debugger *g_debugger;
diff --git a/engines/glk/comprehend/debugger_dumper.cpp b/engines/glk/comprehend/debugger_dumper.cpp
index 2153f776ce..fdb56ee2c4 100644
--- a/engines/glk/comprehend/debugger_dumper.cpp
+++ b/engines/glk/comprehend/debugger_dumper.cpp
@@ -127,8 +127,9 @@ Common::String DebuggerDumper::dumpInstruction(ComprehendGame *game,
 	if (instr->nr_operands) {
 		line += "(";
 		for (i = 0; i < instr->nr_operands; i++)
-			line += Common::String::format("%.2x%s", instr->operand[i]),
-			      i == instr->nr_operands - 1 ? ")" : ", ";
+			line += Common::String::format("%.2x%s",
+				instr->operand[i],
+			    i == (instr->nr_operands - 1) ? ")" : ", ");
 	}
 
 	switch (opcode) {
diff --git a/engines/glk/comprehend/debugger_dumper.h b/engines/glk/comprehend/debugger_dumper.h
index 895f8a4c1c..89eda38936 100644
--- a/engines/glk/comprehend/debugger_dumper.h
+++ b/engines/glk/comprehend/debugger_dumper.h
@@ -61,9 +61,10 @@ protected:
 
 public:
 	DebuggerDumper();
+	virtual ~DebuggerDumper() {}
 
 	Common::String dumpInstruction(ComprehendGame *game,
-		FunctionState *func_state, Instruction *instr);
+	                               FunctionState *func_state, Instruction *instr);
 
 	bool dumpGameData(ComprehendGame *game, const Common::String &type);
 };
diff --git a/engines/glk/comprehend/draw_surface.cpp b/engines/glk/comprehend/draw_surface.cpp
index f452470f1a..cdc4a01860 100644
--- a/engines/glk/comprehend/draw_surface.cpp
+++ b/engines/glk/comprehend/draw_surface.cpp
@@ -34,8 +34,6 @@ namespace Comprehend {
 #define RENDERER_SCREEN 0
 #define RENDERER_PIXEL_DATA 1
 
-static bool graphics_enabled;
-
 const uint32 DrawSurface::PEN_COLORS[8] = {
     G_COLOR_BLACK,
     RGB(0x00, 0x66, 0x00),
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index a06ac936c8..3f9b8fd8e2 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -117,9 +117,8 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		if (opcode & 0x1)
 			a += 255;
 
-		debugC(kDebugGraphics,
-		             "draw_line (%d, %d) - (%d, %d)", opcode,
-		             ctx->_x, ctx->_y, a, b);
+		debugC(kDebugGraphics, "draw_line (%d, %d) - (%d, %d)",
+			ctx->_x, ctx->_y, a, b);
 		ds->drawLine(ctx->_x, ctx->_y, a, b, ctx->_penColor);
 
 		ctx->_x = a;
@@ -134,9 +133,8 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		if (opcode & 0x1)
 			a += 255;
 
-		debugC(kDebugGraphics,
-		             "draw_box (%d, %d) - (%d, %d)", opcode,
-		             ctx->_x, ctx->_y, a, b);
+		debugC(kDebugGraphics, "draw_box (%d, %d) - (%d, %d)",
+			ctx->_x, ctx->_y, a, b);
 
 		ds->drawBox(ctx->_x, ctx->_y, a, b, ctx->_penColor);
 		break;


Commit: 9609ef72ccb4bb91417e6a32aeb3a4892c4ebce0
    https://github.com/scummvm/scummvm/commit/9609ef72ccb4bb91417e6a32aeb3a4892c4ebce0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Implement engine readChar method

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/image_data.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 83e2ccb79e..a009403082 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -38,10 +38,9 @@ namespace Comprehend {
 
 Comprehend *g_comprehend;
 
-Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) :
-		GlkAPI(syst, gameDesc), _topWindow(nullptr), _bottomWindow(nullptr),
-		_drawSurface(nullptr), _game(nullptr),_saveSlot(-1), 
-		_graphicsEnabled(true), _drawFlags(0) {
+Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc), _topWindow(nullptr), _bottomWindow(nullptr),
+                                                                            _drawSurface(nullptr), _game(nullptr), _saveSlot(-1),
+                                                                            _graphicsEnabled(true), _drawFlags(0) {
 	g_comprehend = this;
 }
 
@@ -132,6 +131,24 @@ void Comprehend::readLine(char *buffer, size_t maxLen) {
 	buffer[ev.val1] = 0;
 }
 
+int Comprehend::readChar() {
+	_drawSurface->renderIfDirty();
+
+	glk_request_char_event(_bottomWindow);
+
+	event_t ev;
+	while (ev.type != evtype_CharInput) {
+		glk_select(&ev);
+
+		if (ev.type == evtype_Quit) {
+			glk_cancel_char_event(_bottomWindow);
+			return -1;
+		}
+	}
+
+	return ev.val1;
+}
+
 Common::Error Comprehend::readSaveData(Common::SeekableReadStream *rs) {
 	Common::Serializer s(rs, nullptr);
 	_game->synchronizeSave(s);
@@ -147,6 +164,5 @@ Common::Error Comprehend::writeGameData(Common::WriteStream *ws) {
 	return Common::kNoError;
 }
 
-
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 3f5e1fd8f3..c1362f8897 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -34,8 +34,6 @@ namespace Comprehend {
 
 #undef printf
 #define printf debugN
-#undef getchar
-#define getchar() (0)
 
 #define PATH_MAX 256
 
@@ -122,6 +120,11 @@ public:
 	 * Read an input line
 	 */
 	void readLine(char *buffer, size_t maxLen);
+
+	/**
+	 * Read in a character
+	 */
+	int readChar();
 };
 
 extern Comprehend *g_comprehend;
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 2e5d32525d..a2972a4a4c 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -139,11 +139,11 @@ static void console_init(void) {
 int console_get_key(void) {
 	int c, dummy;
 
-	dummy = c = getchar();
+	dummy = c = g_comprehend->readChar();
 
 	/* Clear input buffer */
 	while (dummy != '\n' && dummy != EOF)
-		dummy = getchar();
+		dummy = g_comprehend->readChar();
 
 	return c;
 }
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/image_data.cpp
index 3f9b8fd8e2..8dc7c2d08a 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/image_data.cpp
@@ -79,7 +79,8 @@ void ImageFileData::draw(uint index, ImageContext *ctx) {
 	for (bool done = false; !done;) {
 		done = doImageOp(g_comprehend->_drawSurface, ctx);
 		if (!done && (draw_flags & IMAGEF_OP_WAIT_KEYPRESS)) {
-			getchar();
+			if (g_comprehend->readChar() == -1)
+				return;
 		}
 	}
 }


Commit: 967c6a277efe8df36a4833c96fcaa04e66351cb0
    https://github.com/scummvm/scummvm/commit/967c6a277efe8df36a4833c96fcaa04e66351cb0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Remove use of printf macro

Changed paths:
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game_data.cpp


diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index c1362f8897..83b5a343f2 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -32,9 +32,6 @@
 namespace Glk {
 namespace Comprehend {
 
-#undef printf
-#define printf debugN
-
 #define PATH_MAX 256
 
 struct GameInfo;
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index a2972a4a4c..2a5e2f0037 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -154,7 +154,7 @@ void console_println(ComprehendGame *game, const char *text) {
 	int word_len = 0;
 
 	if (!text) {
-		printf("\n");
+		g_comprehend->print("\n");
 		return;
 	}
 
@@ -163,7 +163,7 @@ void console_println(ComprehendGame *game, const char *text) {
 		case '\n':
 			word = NULL;
 			word_len = 0;
-			printf("\n");
+			g_comprehend->print("\n");
 			p++;
 			break;
 
@@ -206,7 +206,7 @@ void console_println(ComprehendGame *game, const char *text) {
 		/* Print this word */
 		if (line_length + word_len > console_winsize.ws_col) {
 			/* Too long - insert a line break */
-			printf("\n");
+			g_comprehend->print("\n");
 			line_length = 0;
 		}
 #endif
@@ -523,7 +523,7 @@ static void eval_instruction(ComprehendGame *game,
 		do_command = func_state->test_result;
 
 		if (func_state->or_count != 0)
-			printf("Warning: or_count == %d\n",
+			g_comprehend->print("Warning: or_count == %d\n",
 			       func_state->or_count);
 		func_state->or_count = 0;
 
@@ -669,7 +669,7 @@ static void eval_instruction(ComprehendGame *game,
 		 * FIXME - unsure what the single operand is for.
 		 */
 		item = get_item_by_noun(game, noun);
-		printf("%s\n", game->stringLookup(item->long_string).c_str());
+		g_comprehend->print("%s\n", game->stringLookup(item->long_string).c_str());
 		break;
 
 	case OPCODE_CURRENT_OBJECT_IN_ROOM:
@@ -822,7 +822,7 @@ static void eval_instruction(ComprehendGame *game,
 		for (i = 0; i < game->_items.size(); i++) {
 			item = &game->_items[i];
 			if (item->room == ROOM_INVENTORY)
-				printf("%s\n",
+				g_comprehend->print("%s\n",
 				       game->stringLookup(item->string_desc).c_str());
 		}
 		break;
@@ -838,7 +838,7 @@ static void eval_instruction(ComprehendGame *game,
 		for (i = 0; i < game->_items.size(); i++) {
 			item = &game->_items[i];
 			if (item->room == instr->operand[0])
-				printf("%s\n",
+				g_comprehend->print("%s\n",
 				       game->stringLookup(item->string_desc).c_str());
 		}
 		break;
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index ab9483c61f..d6dbb96572 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -699,8 +699,8 @@ static char decode_string_elem(uint8 c, bool capital, bool special) {
 		}
 	}
 
-	/* Unknown character */
-	printf("Unknown char %d, caps=%d, special=%d\n", c, capital, special);
+	// Unknown character
+	g_comprehend->print("Unknown char %d, caps=%d, special=%d\n", c, capital, special);
 	return '*';
 }
 


Commit: d59873704ca780244645cf190469d112bccbf2d8
    https://github.com/scummvm/scummvm/commit/d59873704ca780244645cf190469d112bccbf2d8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Converting picture drawing to an Archive abstraction

Changed paths:
  A engines/glk/comprehend/pics.cpp
  A engines/glk/comprehend/pics.h
  R engines/glk/comprehend/image_data.cpp
  R engines/glk/comprehend/image_data.h
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/debugger.cpp
    engines/glk/comprehend/draw_surface.cpp
    engines/glk/comprehend/draw_surface.h
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_oo.h
    engines/glk/comprehend/game_tm.h
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/game_tr.h
    engines/glk/module.mk


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index a009403082..3ea7ea2f88 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -31,6 +31,7 @@
 #include "glk/comprehend/game_oo.h"
 #include "glk/comprehend/game_tm.h"
 #include "glk/comprehend/game_tr.h"
+#include "glk/comprehend/pics.h"
 #include "glk/quetzal.h"
 
 namespace Glk {
@@ -39,8 +40,8 @@ namespace Comprehend {
 Comprehend *g_comprehend;
 
 Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc), _topWindow(nullptr), _bottomWindow(nullptr),
-                                                                            _drawSurface(nullptr), _game(nullptr), _saveSlot(-1),
-                                                                            _graphicsEnabled(true), _drawFlags(0) {
+		_drawSurface(nullptr), _game(nullptr), _pics(nullptr), _saveSlot(-1),
+		_graphicsEnabled(true), _drawFlags(0) {
 	g_comprehend = this;
 }
 
@@ -75,10 +76,11 @@ void Comprehend::initialize() {
 	glk_set_window(_bottomWindow);
 	_topWindow->fillRect(0, Rect(0, 0, _topWindow->_w, _topWindow->_h));
 
-	// Initialize drawing
+	// Initialize drawing surface, and the archive that abstracts
+	// the room and item graphics as as individual files
 	_drawSurface = new DrawSurface();
-	_drawSurface->setColorTable(0);
-	_drawSurface->_renderColor = 0;
+	_pics = new Pics();
+	SearchMan.add("Pics", _pics, 99, false);
 }
 
 void Comprehend::deinitialize() {
@@ -116,7 +118,6 @@ void Comprehend::print(const char *fmt, ...) {
 void Comprehend::readLine(char *buffer, size_t maxLen) {
 	event_t ev;
 
-	_drawSurface->renderIfDirty();
 	glk_request_line_event(_bottomWindow, buffer, maxLen - 1, 0);
 
 	for (;;) {
@@ -132,8 +133,6 @@ void Comprehend::readLine(char *buffer, size_t maxLen) {
 }
 
 int Comprehend::readChar() {
-	_drawSurface->renderIfDirty();
-
 	glk_request_char_event(_bottomWindow);
 
 	event_t ev;
@@ -164,5 +163,17 @@ Common::Error Comprehend::writeGameData(Common::WriteStream *ws) {
 	return Common::kNoError;
 }
 
+void Comprehend::drawLocationPicture(int pictureNum, bool clearBg) {
+	glk_image_draw(_topWindow, pictureNum + (clearBg ? LOCATIONS_OFFSET : LOCATIONS_NO_BG_OFFSET), 0, 0);
+}
+
+void Comprehend::drawItemPicture(int pictureNum) {
+	glk_image_draw(_topWindow, pictureNum + ITEMS_OFFSET, 0, 0);
+}
+
+void Comprehend::clearScreen(bool isBright) {	
+	glk_image_draw(_topWindow, isBright ? BRIGHT_ROOM : DARK_ROOM, 0, 0);
+}
+
 } // namespace Comprehend
 } // namespace Glk
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 83b5a343f2..9327280e68 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -37,6 +37,7 @@ namespace Comprehend {
 struct GameInfo;
 struct gameState;
 class DrawSurface;
+class Pics;
 
 #define EXTRA_STRING_TABLE(x) (0x8200 | (x))
 
@@ -55,6 +56,7 @@ public:
 	TextBufferWindow *_bottomWindow;
 	DrawSurface *_drawSurface;
 	ComprehendGame *_game;
+	Pics *_pics;
 	bool _graphicsEnabled;
 	uint _drawFlags;
 
@@ -122,6 +124,21 @@ public:
 	 * Read in a character
 	 */
 	int readChar();
+
+	/**
+	 * Draw a location image
+	 */
+	void drawLocationPicture(int pictureNum, bool clearBg = true);
+
+	/**
+	 * Draw an item image
+	 */
+	void drawItemPicture(int pictureNum);
+
+	/**
+	 * Clear the picture area
+	 */
+	void clearScreen(bool isBright);
 };
 
 extern Comprehend *g_comprehend;
diff --git a/engines/glk/comprehend/debugger.cpp b/engines/glk/comprehend/debugger.cpp
index 69deba5166..bbd9b0555e 100644
--- a/engines/glk/comprehend/debugger.cpp
+++ b/engines/glk/comprehend/debugger.cpp
@@ -22,6 +22,7 @@
 
 #include "glk/comprehend/debugger.h"
 #include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/pics.h"
 
 namespace Glk {
 namespace Comprehend {
diff --git a/engines/glk/comprehend/draw_surface.cpp b/engines/glk/comprehend/draw_surface.cpp
index cdc4a01860..eb9cb99616 100644
--- a/engines/glk/comprehend/draw_surface.cpp
+++ b/engines/glk/comprehend/draw_surface.cpp
@@ -22,7 +22,7 @@
 
 #include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/comprehend.h"
-#include "glk/comprehend/image_data.h"
+#include "glk/comprehend/pics.h"
 #include "glk/window_graphics.h"
 
 namespace Glk {
@@ -187,7 +187,6 @@ void DrawSurface::setColorTable(uint index) {
 	}
 
 	_colorTable = COLOR_TABLES[index];
-	_dirty = true;
 }
 
 uint DrawSurface::getPenColor(uint8 opcode) const {
@@ -214,7 +213,6 @@ void DrawSurface::setColor(uint32 color) {
 void DrawSurface::drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2, uint32 color) {
 	setColor(color);
 	Graphics::ManagedSurface::drawLine(x1, y1, x2, y2, _renderColor);
-	_dirty = true;
 }
 
 void DrawSurface::drawBox(uint16 x1, uint16 y1, uint16 x2, uint16 y2,
@@ -222,7 +220,6 @@ void DrawSurface::drawBox(uint16 x1, uint16 y1, uint16 x2, uint16 y2,
 	setColor(color);
 	Common::Rect r(x1, y1, x2, y2);
 	frameRect(r, _renderColor);
-	_dirty = true;
 }
 
 void DrawSurface::drawFilledBox(uint16 x1, uint16 y1,
@@ -230,7 +227,6 @@ void DrawSurface::drawFilledBox(uint16 x1, uint16 y1,
 	setColor(color);
 	Common::Rect r(x1, y1, x2, y2);
 	fillRect(r, _renderColor);
-	_dirty = true;
 }
 
 void DrawSurface::drawShape(int x, int y, int shape_type, uint32 fill_color) {
@@ -337,8 +333,6 @@ void DrawSurface::drawShape(int x, int y, int shape_type, uint32 fill_color) {
 		/* Unknown shape */
 		break;
 	}
-
-	_dirty = true;
 }
 
 void DrawSurface::floodFill(int x, int y, uint32 fill_color, uint32 old_color) {
@@ -368,15 +362,12 @@ void DrawSurface::floodFill(int x, int y, uint32 fill_color, uint32 old_color) {
 	for (i = x1; i < x2; i++)
 		if (y < RENDER_Y_MAX && getPixelColor(i, y + 1) == old_color)
 			floodFill(i, y + 1, fill_color, old_color);
-
-	_dirty = true;
 }
 
 void DrawSurface::drawPixel(uint16 x, uint16 y, uint32 color) {
 	setColor(color);
 	uint32 *ptr = (uint32 *)getBasePtr(x, y);
 	*ptr = _renderColor;
-	_dirty = true;
 }
 
 uint32 DrawSurface::getPixelColor(uint16 x, uint16 y) {
@@ -387,18 +378,6 @@ uint32 DrawSurface::getPixelColor(uint16 x, uint16 y) {
 void DrawSurface::clearScreen(uint32 color) {
 	setColor(color);
 	fillRect(Common::Rect(0, 0, this->w, this->h), _renderColor);
-	_dirty = true;
-}
-
-void DrawSurface::renderIfDirty() {
-	if (_dirty) {
-		GraphicsWindow *win = g_comprehend->_topWindow;
-		win->drawPicture(*this, (uint)-2, 0, 0, win->_w, win->_h);
-		_dirty = false;
-		// FIXME: Get rid of this hack and properly use the graphics window
-		g_system->copyRectToScreen(getPixels(), pitch, 0, 0, w, h);
-		g_system->updateScreen();
-	}
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/draw_surface.h b/engines/glk/comprehend/draw_surface.h
index 71316eba13..c0de482353 100644
--- a/engines/glk/comprehend/draw_surface.h
+++ b/engines/glk/comprehend/draw_surface.h
@@ -69,14 +69,12 @@ private:
 	static const uint32 DEFAULT_COLOR_TABLE[256];
 	static const uint32 COLOR_TABLE_1[256];
 	static const uint32 *COLOR_TABLES[2];
-	bool _dirty;
 
 public:
 	uint32 _renderColor;
 	const uint32 *_colorTable;
 public:
-	DrawSurface() : _renderColor(0), _colorTable(DEFAULT_COLOR_TABLE),
-	                _dirty(false) {
+	DrawSurface() : _renderColor(0), _colorTable(DEFAULT_COLOR_TABLE) {
 		reset();
 	}
 
@@ -98,11 +96,6 @@ public:
 	void drawPixel(uint16 x, uint16 y, uint32 color);
 	uint32 getPixelColor(uint16 x, uint16 y);
 	void clearScreen(uint32 color);
-
-	/**
-	 * Render the surface to the screen if it's changed
-	 */
-	void renderIfDirty();
 };
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index 2a5e2f0037..b758a5b5e6 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -340,19 +340,18 @@ static void update_graphics(ComprehendGame *game) {
 	switch (type) {
 	case ROOM_IS_DARK:
 		if (game->_updateFlags & UPDATE_GRAPHICS)
-			draw_dark_room();
+			g_comprehend->clearScreen(false);
 		break;
 
 	case ROOM_IS_TOO_BRIGHT:
 		if (game->_updateFlags & UPDATE_GRAPHICS)
-			draw_bright_room();
+			g_comprehend->clearScreen(false);
 		break;
 
 	default:
 		if (game->_updateFlags & UPDATE_GRAPHICS) {
 			room = get_room(game, game->_currentRoom);
-			draw_location_image(&game->_roomImages,
-			                    room->graphic - 1);
+			g_comprehend->drawLocationPicture(room->graphic - 1);
 		}
 
 		if ((game->_updateFlags & UPDATE_GRAPHICS) ||
@@ -362,8 +361,7 @@ static void update_graphics(ComprehendGame *game) {
 
 				if (item->room == game->_currentRoom &&
 				    item->graphic != 0)
-					draw_image(&game->_itemImages,
-					           item->graphic - 1);
+					g_comprehend->drawItemPicture(item->graphic - 1);
 			}
 		}
 		break;
@@ -1002,12 +1000,11 @@ static void eval_instruction(ComprehendGame *game,
 		break;
 
 	case OPCODE_DRAW_ROOM:
-		draw_location_image(&game->_roomImages,
-		                    instr->operand[0] - 1);
+		g_comprehend->drawLocationPicture(instr->operand[0] - 1);
 		break;
 
 	case OPCODE_DRAW_OBJECT:
-		draw_image(&game->_itemImages, instr->operand[0] - 1);
+		g_comprehend->drawItemPicture(instr->operand[0] - 1);
 		break;
 
 	case OPCODE_WAIT_KEY:
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index 90d1a29032..f9a959bfa0 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef GLK_ComprehendGame_H
-#define GLK_ComprehendGame_H
+#ifndef GLK_COMPREHEND_GAME_H
+#define GLK_COMPREHEND_GAME_H
 
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/opcode_map.h"
@@ -42,8 +42,8 @@ public:
 
 	const char *_gameDataFile;
 	Common::Array<StringFile> _stringFiles;
-	Common::Array<const char *> _locationGraphicFiles;
-	Common::Array<const char *> _itemGraphicFiles;
+	Common::StringArray _locationGraphicFiles;
+	Common::StringArray _itemGraphicFiles;
 	unsigned _colorTable;
 
 	struct GameStrings *_gameStrings;
diff --git a/engines/glk/comprehend/game_cc.h b/engines/glk/comprehend/game_cc.h
index a60d9f2317..7ca5bd10b2 100644
--- a/engines/glk/comprehend/game_cc.h
+++ b/engines/glk/comprehend/game_cc.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef GLK_ComprehendGame_CC_H
-#define GLK_ComprehendGame_CC_H
+#ifndef GLK_COMPREHEND_GAME_CC_H
+#define GLK_COMPREHEND_GAME_CC_H
 
 #include "glk/comprehend/game.h"
 
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index d6dbb96572..add5462f83 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -26,6 +26,7 @@
 #include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/file_buf.h"
 #include "glk/comprehend/game.h"
+#include "glk/comprehend/pics.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -170,8 +171,6 @@ void GameInfo::clearInfo() {
 	_updateFlags = 0;
 	_strings.clear();
 	_strings2.clear();
-	_roomImages.clear();
-	_itemImages.clear();
 
 	_rooms.clear();
 	_items.clear();
@@ -993,9 +992,9 @@ void comprehend_load_game(ComprehendGame *game) {
 	load_game_data(game);
 
 	if (g_comprehend->_graphicsEnabled) {
-		// Set up image files
-		game->_roomImages.load(game->_locationGraphicFiles);
-		game->_itemImages.load(game->_itemGraphicFiles);
+		// Set up the picture archive
+		g_comprehend->_pics->load(game->_locationGraphicFiles,
+			game->_itemGraphicFiles);
 
 		if (game->_colorTable)
 			g_comprehend->_drawSurface->setColorTable(game->_colorTable);
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 42eee01cf9..557c16e015 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -20,10 +20,10 @@
  *
  */
 
-#ifndef GLK_ComprehendGame_DATA_H
-#define GLK_ComprehendGame_DATA_H
+#ifndef GLK_COMPREHEND_GAME_DATA_H
+#define GLK_COMPREHEND_GAME_DATA_H
 
-#include "glk/comprehend/image_data.h"
+#include "glk/comprehend/file_buf.h"
 #include "common/serializer.h"
 #include "common/str-array.h"
 
@@ -34,6 +34,8 @@ namespace Comprehend {
 #define MAX_VARIABLES 128
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
 
+class ComprehendGame;
+
 enum {
 	DIRECTION_NORTH,
 	DIRECTION_SOUTH,
@@ -232,9 +234,6 @@ struct GameInfo {
 	StringTable _strings;
 	StringTable _strings2;
 
-	struct ImageData _roomImages;
-	struct ImageData _itemImages;
-
 	bool _flags[MAX_FLAGS];
 	uint16 _variables[MAX_VARIABLES];
 
diff --git a/engines/glk/comprehend/game_oo.h b/engines/glk/comprehend/game_oo.h
index 469a85e384..bfac91ec9b 100644
--- a/engines/glk/comprehend/game_oo.h
+++ b/engines/glk/comprehend/game_oo.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef GLK_ComprehendGame_OO_H
-#define GLK_ComprehendGame_OO_H
+#ifndef GLK_COMPREHEND_GAME_OO_H
+#define GLK_COMPREHEND_GAME_OO_H
 
 #include "glk/comprehend/game.h"
 
diff --git a/engines/glk/comprehend/game_tm.h b/engines/glk/comprehend/game_tm.h
index 86c9cf20bb..0e1fc33038 100644
--- a/engines/glk/comprehend/game_tm.h
+++ b/engines/glk/comprehend/game_tm.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef GLK_ComprehendGame_TM_H
-#define GLK_ComprehendGame_TM_H
+#ifndef GLK_COMPREHEND_GAME_TM_H
+#define GLK_COMPREHEND_GAME_TM_H
 
 #include "glk/comprehend/game.h"
 
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 220ddef4d7..0cd7a8bd78 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -149,7 +149,7 @@ void TransylvaniaGame::handle_special_opcode(uint8 operand)
 		 * Show the Zin screen in reponse to doing 'sing some enchanted
 		 * evening' in his cabin.
 		 */
-		draw_location_image(&_roomImages, 41);
+		g_comprehend->drawLocationPicture(41);
 		console_get_key();
 		_updateFlags |= UPDATE_GRAPHICS;
 		break;
diff --git a/engines/glk/comprehend/game_tr.h b/engines/glk/comprehend/game_tr.h
index c9d4fdddb7..ef20981efb 100644
--- a/engines/glk/comprehend/game_tr.h
+++ b/engines/glk/comprehend/game_tr.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef GLK_ComprehendGame_TR_H
-#define GLK_ComprehendGame_TR_H
+#ifndef GLK_COMPREHEND_GAME_TR_H
+#define GLK_COMPREHEND_GAME_TR_H
 
 #include "glk/comprehend/game.h"
 
diff --git a/engines/glk/comprehend/image_data.h b/engines/glk/comprehend/image_data.h
deleted file mode 100644
index 3ea4f2e92b..0000000000
--- a/engines/glk/comprehend/image_data.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/* 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.
- *
- */
-
-#ifndef GLK_COMPREHEND_IMAGE_DATA_H
-#define GLK_COMPREHEND_IMAGE_DATA_H
-
-#include "glk/comprehend/file_buf.h"
-#include "glk/comprehend/draw_surface.h"
-#include "common/scummsys.h"
-
-namespace Glk {
-namespace Comprehend {
-
-class ComprehendGame;
-struct FileBuffer;
-struct ImageContext;
-
-struct ImageFileData {
-private:
-	Common::Array<uint16> _imageOffsets;
-	FileBuffer _fb;
-
-private:
-	bool doImageOp(DrawSurface *ds, ImageContext *ctx);
-	uint16 imageGetOperand();
-
-	public:
-	void load(const char *filename);
-
-	void draw(uint index, ImageContext *ctx);
-};
-
-struct ImageData {
-private:
-	Common::Array<ImageFileData> _files;
-
-public:
-	ImageData();
-	void clear();
-
-	uint size() const { return _files.size(); }
-	ImageFileData &operator[](uint index) { return _files[index]; }
-
-	void load(const Common::Array<const char *> &filenames);
-};
-
-#define IMAGEF_OP_WAIT_KEYPRESS		(1 << 0)
-#define IMAGEF_NO_FLOODFILL		(1 << 1)
-
-#define IMAGE_OP_SCENE_END		0x00
-
-#define IMAGE_OP_SET_TEXT_POS		0x10
-
-#define IMAGE_OP_PEN_COLOR_A		0x20
-#define IMAGE_OP_PEN_COLOR_B		0x21
-#define IMAGE_OP_PEN_COLOR_C		0x22
-#define IMAGE_OP_PEN_COLOR_D		0x23
-#define IMAGE_OP_PEN_COLOR_E		0x24
-#define IMAGE_OP_PEN_COLOR_F		0x25
-#define IMAGE_OP_PEN_COLOR_G		0x26
-#define IMAGE_OP_PEN_COLOR_H		0x27
-
-#define IMAGE_OP_DRAW_CHAR		0x30
-
-#define IMAGE_OP_SHAPE_PIXEL		0x40
-#define IMAGE_OP_SHAPE_BOX		0x41
-#define IMAGE_OP_SHAPE_CIRCLE_TINY	0x42
-#define IMAGE_OP_SHAPE_CIRCLE_SMALL	0x43
-#define IMAGE_OP_SHAPE_CIRCLE_MED	0x44
-#define IMAGE_OP_SHAPE_CIRCLE_LARGE	0x45
-#define IMAGE_OP_SHAPE_A		0x46
-#define IMAGE_OP_SHAPE_SPRAY		0x47
-
-#define IMAGE_OP_EOF			0x55
-
-#define IMAGE_OP_FILL_COLOR		0x60
-
-#define IMAGE_OP_MOVE_TO		0x80
-#define IMAGE_OP_MOVE_TO_FAR		0x81
-
-#define IMAGE_OP_DRAW_BOX		0x90
-#define IMAGE_OP_DRAW_BOX_FAR		0x91
-
-#define IMAGE_OP_DRAW_LINE		0xa0
-#define IMAGE_OP_DRAW_LINE_FAR		0xa1
-
-#define IMAGE_OP_DRAW_SHAPE		0xc0
-#define IMAGE_OP_DRAW_SHAPE_FAR		0xc1
-
-#define IMAGE_OP_PAINT			0xe0
-#define IMAGE_OP_PAINT_FAR		0xe1
-
-void image_set_draw_flags(unsigned flags);
-
-void draw_dark_room(void);
-void draw_bright_room(void);
-void draw_image(ImageData *info, unsigned index);
-void draw_location_image(ImageData *info, unsigned index);
-
-} // namespace Comprehend
-} // namespace Glk
-
-#endif
diff --git a/engines/glk/comprehend/image_data.cpp b/engines/glk/comprehend/pics.cpp
similarity index 51%
rename from engines/glk/comprehend/image_data.cpp
rename to engines/glk/comprehend/pics.cpp
index 8dc7c2d08a..0b7ff1e5d7 100644
--- a/engines/glk/comprehend/image_data.cpp
+++ b/engines/glk/comprehend/pics.cpp
@@ -24,7 +24,7 @@
 #include "glk/comprehend/file_buf.h"
 #include "glk/comprehend/game.h"
 #include "glk/comprehend/game_data.h"
-#include "glk/comprehend/image_data.h"
+#include "glk/comprehend/pics.h"
 #include "glk/comprehend/draw_surface.h"
 
 namespace Glk {
@@ -32,65 +32,53 @@ namespace Comprehend {
 
 #define IMAGES_PER_FILE	16
 
-struct ImageContext {
-	unsigned	_x;
-	unsigned	_y;
-	unsigned	_penColor;
-	unsigned	fill_color;
-	unsigned	shape;
-
-	unsigned	text_x;
-	unsigned	text_y;
-};
-
-static unsigned draw_flags;
-
 /*-------------------------------------------------------*/
 
-void ImageFileData::load(const char *filename) {
+Pics::ImageFile::ImageFile(const Common::String &filename) {
+	Common::File f;
 	uint16 version;
 	int i;
 
-	_fb = FileBuffer(filename);
+	if (!f.open(filename))
+		error("Could not open file - %s", filename.c_str());
 
 	/*
 	 * In earlier versions of Comprehend the first word is 0x1000 and
 	 * the image offsets start four bytes in. In newer versions the
 	 * image offsets start at the beginning of the image file.
 	 */
-	version = _fb.readUint16LE();
+	version = f.readUint16LE();
 	if (version == 0x1000)
-		_fb.seek(4);
+		f.seek(4);
 	else
-		_fb.seek(0);
+		f.seek(0);
 
 	// Get the image offsets in the file
 	_imageOffsets.resize(IMAGES_PER_FILE);
 	for (i = 0; i < IMAGES_PER_FILE; i++) {
-		_imageOffsets[i] = _fb.readUint16LE();
+		_imageOffsets[i] = f.readUint16LE();
 		if (version == 0x1000)
 			_imageOffsets[i] += 4;
 	}
 }
 
-void ImageFileData::draw(uint index, ImageContext *ctx) {
-	_fb.seek(_imageOffsets[index]);
+void Pics::ImageFile::draw(uint index, ImageContext *ctx) {
+	if (!ctx->_file.open(_filename))
+		error("Opening image file");
+
+	ctx->_file.seek(_imageOffsets[index]);
 
 	for (bool done = false; !done;) {
-		done = doImageOp(g_comprehend->_drawSurface, ctx);
-		if (!done && (draw_flags & IMAGEF_OP_WAIT_KEYPRESS)) {
-			if (g_comprehend->readChar() == -1)
-				return;
-		}
+		done = doImageOp(ctx);
 	}
 }
 
-bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
+bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) {
 	uint8 opcode;
 	uint16 a, b;
 
-	opcode = _fb.readByte();
-	debugCN(kDebugGraphics, "  %.4x [%.2x]: ", _fb.pos() - 1, opcode);
+	opcode = ctx->_file.readByte();
+	debugCN(kDebugGraphics, "  %.4x [%.2x]: ", ctx->_file.pos() - 1, opcode);
 
 	switch (opcode) {
 	case IMAGE_OP_SCENE_END:
@@ -107,20 +95,20 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 	case IMAGE_OP_PEN_COLOR_G:
 	case IMAGE_OP_PEN_COLOR_H:
 		debugC(kDebugGraphics, "set_pen_color(%.2x)", opcode);
-		ctx->_penColor = ds->getPenColor(opcode);
+		ctx->_penColor = ctx->_drawSurface->getPenColor(opcode);
 		break;
 
 	case IMAGE_OP_DRAW_LINE:
 	case IMAGE_OP_DRAW_LINE_FAR:
-		a = imageGetOperand();
-		b = imageGetOperand();
+		a = imageGetOperand(ctx);
+		b = imageGetOperand(ctx);
 
 		if (opcode & 0x1)
 			a += 255;
 
 		debugC(kDebugGraphics, "draw_line (%d, %d) - (%d, %d)",
 			ctx->_x, ctx->_y, a, b);
-		ds->drawLine(ctx->_x, ctx->_y, a, b, ctx->_penColor);
+		ctx->_drawSurface->drawLine(ctx->_x, ctx->_y, a, b, ctx->_penColor);
 
 		ctx->_x = a;
 		ctx->_y = b;
@@ -128,8 +116,8 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 
 	case IMAGE_OP_DRAW_BOX:
 	case IMAGE_OP_DRAW_BOX_FAR:
-		a = imageGetOperand();
-		b = imageGetOperand();
+		a = imageGetOperand(ctx);
+		b = imageGetOperand(ctx);
 
 		if (opcode & 0x1)
 			a += 255;
@@ -137,14 +125,14 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 		debugC(kDebugGraphics, "draw_box (%d, %d) - (%d, %d)",
 			ctx->_x, ctx->_y, a, b);
 
-		ds->drawBox(ctx->_x, ctx->_y, a, b, ctx->_penColor);
+		ctx->_drawSurface->drawBox(ctx->_x, ctx->_y, a, b, ctx->_penColor);
 		break;
 
 	case IMAGE_OP_MOVE_TO:
 	case IMAGE_OP_MOVE_TO_FAR:
 		/* Move to */
-		a = imageGetOperand();
-		b = imageGetOperand();
+		a = imageGetOperand(ctx);
+		b = imageGetOperand(ctx);
 
 		if (opcode & 0x1)
 			a += 255;
@@ -164,70 +152,70 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 	case IMAGE_OP_SHAPE_SPRAY:
 		debugC(kDebugGraphics,
 		             "set_shape_type(%.2x)", opcode - 0x40);
-		ctx->shape = opcode;
+		ctx->_shape = opcode;
 		break;
 
 	case 0x48:
 		/*
-		 * FIXME - This appears to be a shape type. Only used by
+		 * FIXME - This appears to be a _shape type. Only used by
 		 *         OO-Topos.
 		 */
 		debugC(kDebugGraphics, "shape_unknown()");
-		ctx->shape = IMAGE_OP_SHAPE_PIXEL;
+		ctx->_shape = IMAGE_OP_SHAPE_PIXEL;
 		break;
 
 	case IMAGE_OP_DRAW_SHAPE:
 	case IMAGE_OP_DRAW_SHAPE_FAR:
-		a = imageGetOperand();
-		b = imageGetOperand();
+		a = imageGetOperand(ctx);
+		b = imageGetOperand(ctx);
 
 		if (opcode & 0x1)
 			a += 255;
 
 		debugC(kDebugGraphics, "draw_shape(%d, %d), style=%.2x, fill=%.2x",
-		             a, b, ctx->shape, ctx->fill_color);
+		             a, b, ctx->_shape, ctx->_fillColor);
 
-		ds->drawShape(a, b, ctx->shape, ctx->fill_color);
+		ctx->_drawSurface->drawShape(a, b, ctx->_shape, ctx->_fillColor);
 		break;
 
 	case IMAGE_OP_PAINT:
 	case IMAGE_OP_PAINT_FAR:
 		/* Paint */
-		a = imageGetOperand();
-		b = imageGetOperand();
+		a = imageGetOperand(ctx);
+		b = imageGetOperand(ctx);
 
 		if (opcode & 0x1)
 			a += 255;
 
 		debugC(kDebugGraphics, "paint(%d, %d)", a, b);
-		if (!(draw_flags & IMAGEF_NO_FLOODFILL))
-			ds->floodFill(a, b, ctx->fill_color,
-			            ds->getPixelColor(a, b));
+		if (!(ctx->_drawFlags & IMAGEF_NO_FLOODFILL))
+			ctx->_drawSurface->floodFill(a, b, ctx->_fillColor,
+			            ctx->_drawSurface->getPixelColor(a, b));
 		break;
 
 	case IMAGE_OP_FILL_COLOR:
-		a = imageGetOperand();
+		a = imageGetOperand(ctx);
 		debugC(kDebugGraphics, "set_fill_color(%.2x)", a);
-		ctx->fill_color = ds->getFillColor(a);
+		ctx->_fillColor = ctx->_drawSurface->getFillColor(a);
 		break;
 
 	case IMAGE_OP_SET_TEXT_POS:
-		a = imageGetOperand();
-		b = imageGetOperand();
+		a = imageGetOperand(ctx);
+		b = imageGetOperand(ctx);
 		debugC(kDebugGraphics, "set_text_pos(%d, %d)", a, b);
 
-		ctx->text_x = a;
-		ctx->text_y = b;
+		ctx->_textX = a;
+		ctx->_textY = b;
 		break;
 
 	case IMAGE_OP_DRAW_CHAR:
-		a = imageGetOperand();
+		a = imageGetOperand(ctx);
 		debugC(kDebugGraphics, "draw_char(%c)",
 		             a >= 0x20 && a < 0x7f ? a : '?');
 
-		ds->drawBox(ctx->text_x, ctx->text_y,
-		           ctx->text_x + 6, ctx->text_y + 7, ctx->fill_color);
-		ctx->text_x += 8;
+		ctx->_drawSurface->drawBox(ctx->_textX, ctx->_textY,
+		           ctx->_textX + 6, ctx->_textY + 7, ctx->_fillColor);
+		ctx->_textX += 8;
 		break;
 
 	case 0xf3:
@@ -249,7 +237,7 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 	case 0xb0:
 	case 0xd0:
 		/* FIXME - unknown, one argument */
-		a = imageGetOperand();
+		a = imageGetOperand(ctx);
 		debugC(kDebugGraphics, "unknown %.2x: (%.2x) '%c'",
 		             opcode, a,
 		             a >= 0x20 && a < 0x7f ? a : '?');
@@ -257,72 +245,109 @@ bool ImageFileData::doImageOp(DrawSurface *ds, ImageContext *ctx) {
 
 	default:
 		/* FIXME - Unknown, two arguments */
-		a = imageGetOperand();
-		b = imageGetOperand();
+		a = imageGetOperand(ctx);
+		b = imageGetOperand(ctx);
 
 		debugC(kDebugGraphics, "unknown(%.2x, %.2x)", a, b);
-		ds->drawPixel(a, b, 0x00ff00ff);
+		ctx->_drawSurface->drawPixel(a, b, 0x00ff00ff);
 		break;
 	}
 
 	return false;
 }
 
-uint16 ImageFileData::imageGetOperand() {
-	return _fb.readByte();
+uint16 Pics::ImageFile::imageGetOperand(ImageContext *ctx) {
+	return ctx->_file.readByte();
 }
 
 /*-------------------------------------------------------*/
 
-ImageData::ImageData() {
+void Pics::clear() {
+	_rooms.clear();
+	_items.clear();
 }
 
+void Pics::load(const Common::StringArray &roomFiles,
+                const Common::StringArray &itemFiles) {
+	clear();
 
-void ImageData::clear() {
-	_files.clear();
+	for (uint idx = 0; idx < roomFiles.size(); ++idx)
+		_rooms.push_back(ImageFile(roomFiles[idx]));
+	for (uint idx = 0; idx < itemFiles.size(); ++idx)
+		_items.push_back(ImageFile(itemFiles[idx]));
 }
 
-void ImageData::load(const Common::Array<const char *> &filenames) {
-	// Set up files array
-	clear();
-	_files.resize(filenames.size());
+int Pics::getPictureNumber(const Common::String &filename) const {
+	// Ensure prefix and suffix
+	if (!filename.hasPrefixIgnoreCase("pic") ||
+	    !filename.hasSuffixIgnoreCase(".png"))
+		return -1;
 
-	// Iterate through loading each file
-	for (uint idx = 0; idx < filenames.size(); ++idx)
-		_files[idx].load(filenames[idx]);
+	// Get the number part
+	Common::String num(filename.c_str() + 3, filename.size() - 7);
+	if (num.empty() || !Common::isDigit(num[0]))
+		return -1;
+
+	return atoi(num.c_str());
 }
 
-/*-------------------------------------------------------*/
+bool Pics::hasFile(const Common::String &name) const {
+	int num = getPictureNumber(name);
+	if (num == -1)
+		return false;
+
+	if (num == DARK_ROOM || num == BRIGHT_ROOM)
+		return true;
+	if (num >= ITEMS_OFFSET && num < (int)(ITEMS_OFFSET + _items.size() * IMAGES_PER_FILE))
+		return true;
+	if (num < ITEMS_OFFSET && (num % 100) < (int)(_rooms.size() * IMAGES_PER_FILE))
+		return true;
 
-void image_set_draw_flags(unsigned flags) {
-	draw_flags |= flags;
+	return false;
 }
 
-void draw_image(ImageData *info, unsigned index) {
-	ImageContext ctx = {
-		0, 0, G_COLOR_BLACK, G_COLOR_BLACK, IMAGE_OP_SHAPE_CIRCLE_LARGE, 0, 0
-	};
+int Pics::listMembers(Common::ArchiveMemberList &list) const {
+	return list.size();
+}
 
-	if (index >= (info->size() * IMAGES_PER_FILE)) {
-		warning("Bad image index %.8x (max=%.8x)\n", index,
-		       (uint)info->size());
-		return;
-	}
+const Common::ArchiveMemberPtr Pics::getMember(const Common::String &name) const {
+	if (!hasFile(name))
+		return Common::ArchiveMemberPtr();
 
-	(*info)[index / IMAGES_PER_FILE].draw(index % IMAGES_PER_FILE, &ctx);
+	return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
 }
 
-void draw_dark_room() {
-	g_comprehend->_drawSurface->clearScreen(G_COLOR_BLACK);
-}
+Common::SeekableReadStream *Pics::createReadStreamForMember(const Common::String &name) const {
+	// Get the picture number
+	int num = getPictureNumber(name);
+	if (num == -1 || !hasFile(name))
+		return nullptr;
 
-void draw_bright_room() {
-	g_comprehend->_drawSurface->clearScreen(G_COLOR_WHITE);
+	// TODO
+	error("TODO: createReadStream");
 }
 
-void draw_location_image(ImageData *info, unsigned index) {
-	g_comprehend->_drawSurface->clearScreen(G_COLOR_WHITE);
-	draw_image(info, index);
+void Pics::drawPicture(int pictureNum) {
+	ImageContext ctx(g_comprehend->_drawSurface, g_comprehend->_drawFlags);
+
+	if (pictureNum == DARK_ROOM) {
+		ctx._drawSurface->clearScreen(G_COLOR_BLACK);
+
+	} else if (pictureNum == BRIGHT_ROOM) {
+		ctx._drawSurface->clearScreen(G_COLOR_WHITE);
+
+	} else if (pictureNum >= ITEMS_OFFSET) {
+		_items[pictureNum / IMAGES_PER_FILE].draw(
+		    pictureNum % IMAGES_PER_FILE, &ctx);
+
+	} else {
+		if (pictureNum < LOCATIONS_NO_BG_OFFSET)
+			ctx._drawSurface->clearScreen(G_COLOR_WHITE);
+
+		pictureNum %= 100;
+		_rooms[pictureNum / IMAGES_PER_FILE].draw(
+			pictureNum % IMAGES_PER_FILE, &ctx);
+	}
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/pics.h b/engines/glk/comprehend/pics.h
new file mode 100644
index 0000000000..8e4fc57806
--- /dev/null
+++ b/engines/glk/comprehend/pics.h
@@ -0,0 +1,176 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_PICS_H
+#define GLK_COMPREHEND_PICS_H
+
+#include "glk/comprehend/draw_surface.h"
+#include "common/archive.h"
+
+namespace Glk {
+namespace Comprehend {
+
+#define IMAGE_OP_SCENE_END 0x00
+
+#define IMAGE_OP_SET_TEXT_POS 0x10
+
+#define IMAGE_OP_PEN_COLOR_A 0x20
+#define IMAGE_OP_PEN_COLOR_B 0x21
+#define IMAGE_OP_PEN_COLOR_C 0x22
+#define IMAGE_OP_PEN_COLOR_D 0x23
+#define IMAGE_OP_PEN_COLOR_E 0x24
+#define IMAGE_OP_PEN_COLOR_F 0x25
+#define IMAGE_OP_PEN_COLOR_G 0x26
+#define IMAGE_OP_PEN_COLOR_H 0x27
+
+#define IMAGE_OP_DRAW_CHAR 0x30
+
+#define IMAGE_OP_SHAPE_PIXEL 0x40
+#define IMAGE_OP_SHAPE_BOX 0x41
+#define IMAGE_OP_SHAPE_CIRCLE_TINY 0x42
+#define IMAGE_OP_SHAPE_CIRCLE_SMALL 0x43
+#define IMAGE_OP_SHAPE_CIRCLE_MED 0x44
+#define IMAGE_OP_SHAPE_CIRCLE_LARGE 0x45
+#define IMAGE_OP_SHAPE_A 0x46
+#define IMAGE_OP_SHAPE_SPRAY 0x47
+
+#define IMAGE_OP_EOF 0x55
+
+#define IMAGE_OP_FILL_COLOR 0x60
+
+#define IMAGE_OP_MOVE_TO 0x80
+#define IMAGE_OP_MOVE_TO_FAR 0x81
+
+#define IMAGE_OP_DRAW_BOX 0x90
+#define IMAGE_OP_DRAW_BOX_FAR 0x91
+
+#define IMAGE_OP_DRAW_LINE 0xa0
+#define IMAGE_OP_DRAW_LINE_FAR 0xa1
+
+#define IMAGE_OP_DRAW_SHAPE 0xc0
+#define IMAGE_OP_DRAW_SHAPE_FAR 0xc1
+
+#define IMAGE_OP_PAINT 0xe0
+#define IMAGE_OP_PAINT_FAR 0xe1
+
+#define IMAGEF_NO_FLOODFILL (1 << 1)
+
+enum {
+	LOCATIONS_OFFSET = 0,
+	LOCATIONS_NO_BG_OFFSET = 100,
+	ITEMS_OFFSET = 200,
+	DARK_ROOM = 1000,
+	BRIGHT_ROOM = 1001
+};
+
+class Pics : public Common::Archive {
+	struct ImageContext {
+		Common::File _file;
+		DrawSurface *_drawSurface;
+		uint _drawFlags;
+
+		uint16 _x;
+		uint16 _y;
+		uint32 _penColor;
+		uint32 _fillColor;
+		uint32 _shape;
+
+		uint16 _textX;
+		uint16 _textY;
+
+		ImageContext(DrawSurface *drawSurface, uint flags) :
+			_drawSurface(drawSurface), _drawFlags(0), _x(0), _y(0),
+			_penColor(G_COLOR_BLACK), _fillColor(G_COLOR_BLACK),
+			_shape(IMAGE_OP_SHAPE_CIRCLE_LARGE), _textX(0), _textY(0) {
+		}
+
+	};
+
+	struct ImageFile {
+	private:
+		Common::Array<uint16> _imageOffsets;
+		Common::String _filename;
+
+	private:
+		bool doImageOp(ImageContext *ctx);
+		uint16 imageGetOperand(ImageContext *ctx);
+
+	public:
+		ImageFile() {}
+		ImageFile(const Common::String &filename);
+
+		void draw(uint index, ImageContext *ctx);
+	};
+
+private:
+	Common::Array<ImageFile> _rooms;
+	Common::Array<ImageFile> _items;
+
+private:
+	/**
+	 * Returns the image number if the passed filename is a picture
+	 */
+	int getPictureNumber(const Common::String &filename) const;
+
+	/**
+	 * Draw the specified picture
+	 */
+	void drawPicture(int pictureNum);
+
+public:
+	void clear();
+
+	void load(const Common::StringArray &roomFiles,
+		const Common::StringArray &itemFiles);
+
+	/**
+	 * Check if a member with the given name is present in the Archive.
+	 * Patterns are not allowed, as this is meant to be a quick File::exists()
+	 * replacement.
+	 */
+	bool hasFile(const Common::String &name) const override;
+
+	/**
+	 * Add all members of the Archive to list.
+	 * Must only append to list, and not remove elements from it.
+	 *
+	 * @return the number of names added to list
+	 */
+	int listMembers(Common::ArchiveMemberList &list) const override;
+
+	/**
+	 * Returns a ArchiveMember representation of the given file.
+	 */
+	const Common::ArchiveMemberPtr getMember(const Common::String &name) const override;
+
+	/**
+	 * Create a stream bound to a member with the specified name in the
+	 * archive. If no member with this name exists, 0 is returned.
+	 * @return the newly created input stream
+	 */
+	Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const override;
+};
+
+} // namespace Comprehend
+} // namespace Glk
+
+#endif
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index 4f173fc742..aa5c0aba34 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -179,8 +179,8 @@ MODULE_OBJS := \
 	comprehend/game_oo.o \
 	comprehend/game_tm.o \
 	comprehend/game_tr.o \
-	comprehend/image_data.o \
 	comprehend/opcode_map.o \
+	comprehend/pics.o \
 	frotz/bitmap_font.o \
 	frotz/config.o \
 	frotz/detection.o \


Commit: f7e40621ce24feda8c44cf47348e1ad7ca2ad5dc
    https://github.com/scummvm/scummvm/commit/f7e40621ce24feda8c44cf47348e1ad7ca2ad5dc
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Finish implementing PIcs archive

Changed paths:
    engines/glk/comprehend/pics.cpp
    engines/glk/comprehend/pics.h
    engines/glk/raw_decoder.cpp


diff --git a/engines/glk/comprehend/pics.cpp b/engines/glk/comprehend/pics.cpp
index 0b7ff1e5d7..16299e3010 100644
--- a/engines/glk/comprehend/pics.cpp
+++ b/engines/glk/comprehend/pics.cpp
@@ -26,6 +26,7 @@
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/pics.h"
 #include "glk/comprehend/draw_surface.h"
+#include "common/memstream.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -39,6 +40,7 @@ Pics::ImageFile::ImageFile(const Common::String &filename) {
 	uint16 version;
 	int i;
 
+	_filename = filename;
 	if (!f.open(filename))
 		error("Could not open file - %s", filename.c_str());
 
@@ -62,7 +64,7 @@ Pics::ImageFile::ImageFile(const Common::String &filename) {
 	}
 }
 
-void Pics::ImageFile::draw(uint index, ImageContext *ctx) {
+void Pics::ImageFile::draw(uint index, ImageContext *ctx) const {
 	if (!ctx->_file.open(_filename))
 		error("Opening image file");
 
@@ -73,7 +75,7 @@ void Pics::ImageFile::draw(uint index, ImageContext *ctx) {
 	}
 }
 
-bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) {
+bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) const {
 	uint8 opcode;
 	uint16 a, b;
 
@@ -256,7 +258,7 @@ bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) {
 	return false;
 }
 
-uint16 Pics::ImageFile::imageGetOperand(ImageContext *ctx) {
+uint16 Pics::ImageFile::imageGetOperand(ImageContext *ctx) const {
 	return ctx->_file.readByte();
 }
 
@@ -280,7 +282,7 @@ void Pics::load(const Common::StringArray &roomFiles,
 int Pics::getPictureNumber(const Common::String &filename) const {
 	// Ensure prefix and suffix
 	if (!filename.hasPrefixIgnoreCase("pic") ||
-	    !filename.hasSuffixIgnoreCase(".png"))
+	    !filename.hasSuffixIgnoreCase(".raw"))
 		return -1;
 
 	// Get the number part
@@ -323,11 +325,22 @@ Common::SeekableReadStream *Pics::createReadStreamForMember(const Common::String
 	if (num == -1 || !hasFile(name))
 		return nullptr;
 
-	// TODO
-	error("TODO: createReadStream");
+	// Draw the image
+	drawPicture(num);
+
+	// Create a stream with the data for the surface
+	Common::MemoryReadWriteStream *stream =
+	    new Common::MemoryReadWriteStream(DisposeAfterUse::YES);
+	const DrawSurface &ds = *g_comprehend->_drawSurface;
+	stream->writeUint16LE(ds.w);
+	stream->writeUint16LE(ds.h);
+	stream->writeUint16LE(0);		// Palette size
+	stream->write(ds.getPixels(), ds.w * ds.h * 4);
+
+	return stream;
 }
 
-void Pics::drawPicture(int pictureNum) {
+void Pics::drawPicture(int pictureNum) const {
 	ImageContext ctx(g_comprehend->_drawSurface, g_comprehend->_drawFlags);
 
 	if (pictureNum == DARK_ROOM) {
diff --git a/engines/glk/comprehend/pics.h b/engines/glk/comprehend/pics.h
index 8e4fc57806..99c931016b 100644
--- a/engines/glk/comprehend/pics.h
+++ b/engines/glk/comprehend/pics.h
@@ -111,14 +111,14 @@ class Pics : public Common::Archive {
 		Common::String _filename;
 
 	private:
-		bool doImageOp(ImageContext *ctx);
-		uint16 imageGetOperand(ImageContext *ctx);
+		bool doImageOp(ImageContext *ctx) const;
+		uint16 imageGetOperand(ImageContext *ctx) const;
 
 	public:
 		ImageFile() {}
 		ImageFile(const Common::String &filename);
 
-		void draw(uint index, ImageContext *ctx);
+		void draw(uint index, ImageContext *ctx) const;
 	};
 
 private:
@@ -134,7 +134,7 @@ private:
 	/**
 	 * Draw the specified picture
 	 */
-	void drawPicture(int pictureNum);
+	void drawPicture(int pictureNum) const;
 
 public:
 	void clear();
diff --git a/engines/glk/raw_decoder.cpp b/engines/glk/raw_decoder.cpp
index cf3700371b..d2643307e6 100644
--- a/engines/glk/raw_decoder.cpp
+++ b/engines/glk/raw_decoder.cpp
@@ -47,28 +47,37 @@ bool RawDecoder::loadStream(Common::SeekableReadStream &stream) {
 	uint width = stream.readUint16LE();
 	uint height = stream.readUint16LE();
 	_paletteColorCount = stream.readUint16LE();
-	assert(_paletteColorCount > 0);
+	assert(_paletteColorCount == 0 || _paletteColorCount <= 0x100);
 
-	// Read in the palette
-	_palette = new byte[_paletteColorCount * 3];
-	stream.read(_palette, _paletteColorCount * 3);
+	if (_paletteColorCount != 0) {
+		// Read in the palette
+		_palette = new byte[_paletteColorCount * 3];
+		stream.read(_palette, _paletteColorCount * 3);
 
-	// Get the transparent color
-	byte transColor = stream.readByte();
-	if (transColor < _paletteColorCount)
-		_transColor = transColor;
+		// Get the transparent color
+		byte transColor = stream.readByte();
+		if (transColor < _paletteColorCount)
+			_transColor = transColor;
+	} else {
+		_transColor = 0;
+	}
 
-	// Set up the surface and read it in
-	_surface.create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+	// Set up the surface
+	_surface.create(width, height, (_paletteColorCount == 0) ?
+	    Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0) :
+		Graphics::PixelFormat::createFormatCLUT8());
 
-	assert((stream.size() - stream.pos()) == (int)(width * height));
+	assert((stream.size() - stream.pos()) ==
+		(int)(width * height * _surface.format.bytesPerPixel));
 	byte *pixels = (byte *)_surface.getPixels();
-	stream.read(pixels, width * height);
+	stream.read(pixels, width * height * _surface.format.bytesPerPixel);
 
-	for (uint idx = 0; idx < width * height; ++idx, ++pixels) {
-		assert(*pixels != 0xff);
-		if (*pixels >= _paletteColorCount)
-			*pixels = _paletteColorCount - 1;
+	if (_palette) {
+		for (uint idx = 0; idx < width * height; ++idx, ++pixels) {
+			assert(*pixels != 0xff);
+			if (*pixels >= _paletteColorCount)
+				*pixels = _paletteColorCount - 1;
+		}
 	}
 
 	return true;


Commit: ead0a1bdd47063a076426e8ba1f541121585ed02
    https://github.com/scummvm/scummvm/commit/ead0a1bdd47063a076426e8ba1f541121585ed02
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:11-07:00

Commit Message:
GLK: COMPREHEND: Proper freeing of Pics on exit

Changed paths:
    engines/glk/comprehend/comprehend.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 3ea7ea2f88..646863fb4b 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -48,6 +48,7 @@ Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkA
 Comprehend::~Comprehend() {
 	delete _drawSurface;
 	delete _game;
+	SearchMan.remove("Pics");	// This also deletes it
 
 	g_comprehend = nullptr;
 }
@@ -80,7 +81,7 @@ void Comprehend::initialize() {
 	// the room and item graphics as as individual files
 	_drawSurface = new DrawSurface();
 	_pics = new Pics();
-	SearchMan.add("Pics", _pics, 99, false);
+	SearchMan.add("Pics", _pics, 99, true);
 }
 
 void Comprehend::deinitialize() {


Commit: 088bb3caf452be9503379fd3d8a51698b1d2bcad
    https://github.com/scummvm/scummvm/commit/088bb3caf452be9503379fd3d8a51698b1d2bcad
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:12-07:00

Commit Message:
GLK: COMPREHEND: Draw images doubled-sized to properly fill screen

Changed paths:
    engines/glk/comprehend/comprehend.cpp


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 646863fb4b..9ee1830e9b 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -165,15 +165,16 @@ Common::Error Comprehend::writeGameData(Common::WriteStream *ws) {
 }
 
 void Comprehend::drawLocationPicture(int pictureNum, bool clearBg) {
-	glk_image_draw(_topWindow, pictureNum + (clearBg ? LOCATIONS_OFFSET : LOCATIONS_NO_BG_OFFSET), 0, 0);
+	glk_image_draw_scaled(_topWindow, pictureNum + (clearBg ? LOCATIONS_OFFSET : LOCATIONS_NO_BG_OFFSET),
+		0, 0, 640, 480);
 }
 
 void Comprehend::drawItemPicture(int pictureNum) {
-	glk_image_draw(_topWindow, pictureNum + ITEMS_OFFSET, 0, 0);
+	glk_image_draw_scaled(_topWindow, pictureNum + ITEMS_OFFSET, 0, 0, 640, 480);
 }
 
 void Comprehend::clearScreen(bool isBright) {	
-	glk_image_draw(_topWindow, isBright ? BRIGHT_ROOM : DARK_ROOM, 0, 0);
+	glk_image_draw_scaled(_topWindow, isBright ? BRIGHT_ROOM : DARK_ROOM, 0, 0, 640, 480);
 }
 
 } // namespace Comprehend


Commit: 9a8d5e51d29bbbfb174ccaf47b91223280a78551
    https://github.com/scummvm/scummvm/commit/9a8d5e51d29bbbfb174ccaf47b91223280a78551
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:12-07:00

Commit Message:
GLK: COMPREHEND: Fix drawing of items on-screen

Changed paths:
    engines/glk/comprehend/pics.cpp


diff --git a/engines/glk/comprehend/pics.cpp b/engines/glk/comprehend/pics.cpp
index 16299e3010..09a1203822 100644
--- a/engines/glk/comprehend/pics.cpp
+++ b/engines/glk/comprehend/pics.cpp
@@ -350,6 +350,7 @@ void Pics::drawPicture(int pictureNum) const {
 		ctx._drawSurface->clearScreen(G_COLOR_WHITE);
 
 	} else if (pictureNum >= ITEMS_OFFSET) {
+		pictureNum -= ITEMS_OFFSET;
 		_items[pictureNum / IMAGES_PER_FILE].draw(
 		    pictureNum % IMAGES_PER_FILE, &ctx);
 


Commit: 21eb8249785f51c3f712acd3b9467df3e6ea38da
    https://github.com/scummvm/scummvm/commit/21eb8249785f51c3f712acd3b9467df3e6ea38da
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:12-07:00

Commit Message:
GLK: COMPREHEND: Fix parsing string table

Changed paths:
    engines/glk/comprehend/game_data.cpp


diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index add5462f83..7ad7e9b895 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -713,7 +713,7 @@ static char decode_string_elem(uint8 c, bool capital, bool special) {
 */
 static Common::String parseString(FileBuffer *fb) {
 	bool capital_next = false, special_next = false;
-	unsigned i, j, k = 0;
+	unsigned i, j;
 	uint64 chunk;
 	uint8 elem, *encoded;
 	char c;
@@ -724,7 +724,7 @@ static Common::String parseString(FileBuffer *fb) {
 
 	/* Get the encoded string */
 	encoded = (uint8 *)malloc(encoded_len + 5);
-	memset(encoded, 0, encoded_len);
+	Common::fill(encoded, encoded + encoded_len + 5, 0);
 	fb->read(encoded, encoded_len);
 
 	/* Skip over the zero byte */
@@ -749,7 +749,6 @@ static Common::String parseString(FileBuffer *fb) {
 				special_next = false;
 				capital_next = false;
 				string += c;
-				k++;
 			}
 		}
 	}


Commit: c6346f2db033e9cae2001cd0e958c01872bf3afe
    https://github.com/scummvm/scummvm/commit/c6346f2db033e9cae2001cd0e958c01872bf3afe
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:12-07:00

Commit Message:
GLK: COMPREHEND: Better placement of location images

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/draw_surface.h


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 9ee1830e9b..22e0eda472 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -21,8 +21,6 @@
  */
 
 #include "glk/comprehend/comprehend.h"
-#include "common/config-manager.h"
-#include "common/translation.h"
 #include "glk/comprehend/debugger.h"
 #include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/game.h"
@@ -33,10 +31,17 @@
 #include "glk/comprehend/game_tr.h"
 #include "glk/comprehend/pics.h"
 #include "glk/quetzal.h"
+#include "common/config-manager.h"
+#include "common/translation.h"
+#include "engines/util.h"
 
 namespace Glk {
 namespace Comprehend {
 
+// Even with no ScummVM scaling, internally we do a 2x scaling to
+// render on a 640x480 window, to allow for better looking text
+#define SCALE_FACTOR 2
+
 Comprehend *g_comprehend;
 
 Comprehend::Comprehend(OSystem *syst, const GlkGameDescription &gameDesc) : GlkAPI(syst, gameDesc), _topWindow(nullptr), _bottomWindow(nullptr),
@@ -53,6 +58,11 @@ Comprehend::~Comprehend() {
 	g_comprehend = nullptr;
 }
 
+void Comprehend::initGraphicsMode() {
+	Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
+	initGraphics(640, 400, &pixelFormat);
+}
+
 void Comprehend::runGame() {
 	initialize();
 
@@ -64,6 +74,7 @@ void Comprehend::runGame() {
 
 	deinitialize();
 }
+
 void Comprehend::initialize() {
 	// Set up the GLK windows
 	g_conf->_wMarginX = 0;
@@ -72,7 +83,7 @@ void Comprehend::initialize() {
 	_bottomWindow = (TextBufferWindow *)glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
 	_topWindow = (GraphicsWindow *)glk_window_open(_bottomWindow,
 	                                               winmethod_Above | winmethod_Fixed,
-	                                               400, wintype_Graphics, 2);
+	                                               160 * SCALE_FACTOR, wintype_Graphics, 2);
 
 	glk_set_window(_bottomWindow);
 	_topWindow->fillRect(0, Rect(0, 0, _topWindow->_w, _topWindow->_h));
@@ -166,15 +177,17 @@ Common::Error Comprehend::writeGameData(Common::WriteStream *ws) {
 
 void Comprehend::drawLocationPicture(int pictureNum, bool clearBg) {
 	glk_image_draw_scaled(_topWindow, pictureNum + (clearBg ? LOCATIONS_OFFSET : LOCATIONS_NO_BG_OFFSET),
-		0, 0, 640, 480);
+		20 * SCALE_FACTOR, 0, G_RENDER_WIDTH * SCALE_FACTOR, G_RENDER_HEIGHT * SCALE_FACTOR);
 }
 
 void Comprehend::drawItemPicture(int pictureNum) {
-	glk_image_draw_scaled(_topWindow, pictureNum + ITEMS_OFFSET, 0, 0, 640, 480);
+	glk_image_draw_scaled(_topWindow, pictureNum + ITEMS_OFFSET,
+		20 * SCALE_FACTOR, 0, G_RENDER_WIDTH * SCALE_FACTOR, G_RENDER_HEIGHT * SCALE_FACTOR);
 }
 
 void Comprehend::clearScreen(bool isBright) {	
-	glk_image_draw_scaled(_topWindow, isBright ? BRIGHT_ROOM : DARK_ROOM, 0, 0, 640, 480);
+	glk_image_draw_scaled(_topWindow, isBright ? BRIGHT_ROOM : DARK_ROOM,
+		20 * SCALE_FACTOR, 0, G_RENDER_WIDTH * SCALE_FACTOR, G_RENDER_HEIGHT * SCALE_FACTOR);
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index 9327280e68..a70ab80b33 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -94,6 +94,11 @@ public:
 	 */
 	InterpreterType getInterpreterType() const override { return INTERPRETER_SCOTT; }
 
+	/**
+	 * Initialize the graphics
+	 */
+	void initGraphicsMode() override;
+
 	/**
 	 * Execute the game
 	 */
diff --git a/engines/glk/comprehend/draw_surface.h b/engines/glk/comprehend/draw_surface.h
index c0de482353..2ed332b063 100644
--- a/engines/glk/comprehend/draw_surface.h
+++ b/engines/glk/comprehend/draw_surface.h
@@ -29,39 +29,39 @@
 namespace Glk {
 namespace Comprehend {
 
-#define G_RENDER_WIDTH	320
-#define G_RENDER_HEIGHT	240
+#define G_RENDER_WIDTH	280
+#define G_RENDER_HEIGHT	200
 
 #define RGB(r, g, b)		(uint32)(((r) << 24) | ((g) << 16) | ((b) << 8) | 0xff)
 
-#define G_COLOR_BLACK		0x000000ff
-#define G_COLOR_WHITE		0xffffffff
-#define G_COLOR_CYAN		0x3366ffff
-#define G_COLOR_YELLOW		0xffff00ff
-#define G_COLOR_RED		0xff0000ff
+#define G_COLOR_BLACK  0x000000ff
+#define G_COLOR_WHITE  0xffffffff
+#define G_COLOR_CYAN   0x3366ffff
+#define G_COLOR_YELLOW 0xffff00ff
+#define G_COLOR_RED    0xff0000ff
 
-#define G_COLOR_GRAY0		0x202020ff
-#define G_COLOR_GRAY1		0x404040ff
-#define G_COLOR_GRAY2		0x808080ff
-#define G_COLOR_GRAY3		0xc0c0c0ff
+#define G_COLOR_GRAY0  0x202020ff
+#define G_COLOR_GRAY1  0x404040ff
+#define G_COLOR_GRAY2  0x808080ff
+#define G_COLOR_GRAY3  0xc0c0c0ff
 
-#define G_COLOR_LIGHT_ORANGE	0xff9966ff
-#define G_COLOR_ORANGE		0xff9900ff
-#define G_COLOR_DARK_PURPLE	0x666699ff
-#define G_COLOR_DARK_BLUE	0x000099ff
+#define G_COLOR_LIGHT_ORANGE  0xff9966ff
+#define G_COLOR_ORANGE        0xff9900ff
+#define G_COLOR_DARK_PURPLE   0x666699ff
+#define G_COLOR_DARK_BLUE     0x000099ff
 
-#define G_COLOR_DARK_RED	0xcc0033ff
-#define G_COLOR_DITHERED_PINK	0xff6699ff
+#define G_COLOR_DARK_RED      0xcc0033ff
+#define G_COLOR_DITHERED_PINK 0xff6699ff
 
-#define G_COLOR_DARK_GREEN1	0x009966ff
-#define G_COLOR_DARK_GREEN2	0x003300ff
+#define G_COLOR_DARK_GREEN1   0x009966ff
+#define G_COLOR_DARK_GREEN2   0x003300ff
 
-#define G_COLOR_AQUA		0x33ccccff
+#define G_COLOR_AQUA          0x33ccccff
 
-#define G_COLOR_GREEN		0x33cc00ff
+#define G_COLOR_GREEN         0x33cc00ff
 
-#define G_COLOR_BROWN1		0x7a5200ff
-#define G_COLOR_BROWN2		0x663300ff
+#define G_COLOR_BROWN1        0x7a5200ff
+#define G_COLOR_BROWN2        0x663300ff
 
 class DrawSurface : public Graphics::ManagedSurface {
 private:


Commit: a06ed9ef2fdfbeb3a1d471f691f9974277881de9
    https://github.com/scummvm/scummvm/commit/a06ed9ef2fdfbeb3a1d471f691f9974277881de9
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:12-07:00

Commit Message:
GLK: COMPREHEND: Added loading of Transylvania title

Changed paths:
    engines/glk/comprehend/comprehend.cpp
    engines/glk/comprehend/comprehend.h
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_tr.cpp
    engines/glk/comprehend/pics.cpp
    engines/glk/comprehend/pics.h


diff --git a/engines/glk/comprehend/comprehend.cpp b/engines/glk/comprehend/comprehend.cpp
index 22e0eda472..a661568ef8 100644
--- a/engines/glk/comprehend/comprehend.cpp
+++ b/engines/glk/comprehend/comprehend.cpp
@@ -175,19 +175,21 @@ Common::Error Comprehend::writeGameData(Common::WriteStream *ws) {
 	return Common::kNoError;
 }
 
+void Comprehend::drawPicture(uint pictureNum) {
+	glk_image_draw_scaled(_topWindow, pictureNum,
+	                      20 * SCALE_FACTOR, 0, G_RENDER_WIDTH * SCALE_FACTOR, G_RENDER_HEIGHT * SCALE_FACTOR);
+}
+
 void Comprehend::drawLocationPicture(int pictureNum, bool clearBg) {
-	glk_image_draw_scaled(_topWindow, pictureNum + (clearBg ? LOCATIONS_OFFSET : LOCATIONS_NO_BG_OFFSET),
-		20 * SCALE_FACTOR, 0, G_RENDER_WIDTH * SCALE_FACTOR, G_RENDER_HEIGHT * SCALE_FACTOR);
+	drawPicture(pictureNum + (clearBg ? LOCATIONS_OFFSET : LOCATIONS_NO_BG_OFFSET));
 }
 
 void Comprehend::drawItemPicture(int pictureNum) {
-	glk_image_draw_scaled(_topWindow, pictureNum + ITEMS_OFFSET,
-		20 * SCALE_FACTOR, 0, G_RENDER_WIDTH * SCALE_FACTOR, G_RENDER_HEIGHT * SCALE_FACTOR);
+	drawPicture(pictureNum + ITEMS_OFFSET);
 }
 
 void Comprehend::clearScreen(bool isBright) {	
-	glk_image_draw_scaled(_topWindow, isBright ? BRIGHT_ROOM : DARK_ROOM,
-		20 * SCALE_FACTOR, 0, G_RENDER_WIDTH * SCALE_FACTOR, G_RENDER_HEIGHT * SCALE_FACTOR);
+	drawPicture(isBright ? BRIGHT_ROOM : DARK_ROOM);
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/comprehend.h b/engines/glk/comprehend/comprehend.h
index a70ab80b33..25bc6549ba 100644
--- a/engines/glk/comprehend/comprehend.h
+++ b/engines/glk/comprehend/comprehend.h
@@ -24,10 +24,10 @@
 #define GLK_COMPREHEND_COMPREHEND_H
 
 #include "common/scummsys.h"
+#include "glk/comprehend/game.h"
 #include "glk/glk_api.h"
 #include "glk/window_graphics.h"
 #include "glk/window_text_buffer.h"
-#include "glk/comprehend/game.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -50,7 +50,7 @@ struct GameStrings {
  */
 class Comprehend : public GlkAPI {
 private:
-	int _saveSlot;		 ///< Save slot when loading savegame from launcher
+	int _saveSlot; ///< Save slot when loading savegame from launcher
 public:
 	GraphicsWindow *_topWindow;
 	TextBufferWindow *_bottomWindow;
@@ -130,6 +130,11 @@ public:
 	 */
 	int readChar();
 
+	/**
+	 * Draw a picture
+	 */
+	void drawPicture(uint pictureNum);
+
 	/**
 	 * Draw a location image
 	 */
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index f9a959bfa0..c6f7c0e668 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -44,6 +44,7 @@ public:
 	Common::Array<StringFile> _stringFiles;
 	Common::StringArray _locationGraphicFiles;
 	Common::StringArray _itemGraphicFiles;
+	Common::String _titleGraphicFile;
 	unsigned _colorTable;
 
 	struct GameStrings *_gameStrings;
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 7ad7e9b895..45cbab53c0 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -993,7 +993,7 @@ void comprehend_load_game(ComprehendGame *game) {
 	if (g_comprehend->_graphicsEnabled) {
 		// Set up the picture archive
 		g_comprehend->_pics->load(game->_locationGraphicFiles,
-			game->_itemGraphicFiles);
+			game->_itemGraphicFiles, game->_titleGraphicFile);
 
 		if (game->_colorTable)
 			g_comprehend->_drawSurface->setColorTable(game->_colorTable);
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 0cd7a8bd78..c63e7c7b9c 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -23,6 +23,7 @@
 #include "glk/comprehend/comprehend.h"
 #include "glk/comprehend/game_data.h"
 #include "glk/comprehend/game_tr.h"
+#include "glk/comprehend/pics.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -59,6 +60,7 @@ TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
 	_itemGraphicFiles.push_back("OB.MS1");
 	_itemGraphicFiles.push_back("OC.MS1");
 
+	_titleGraphicFile = "trtitle.ms1";
 	_gameStrings = &tr_strings;
 }
 
@@ -159,6 +161,9 @@ void TransylvaniaGame::handle_special_opcode(uint8 operand)
 void TransylvaniaGame::before_game() {
 	char buffer[128];
 
+	// Draw the title
+	g_comprehend->drawPicture(TITLE_IMAGE);
+
 	// Welcome to Transylvania - sign your name
 	console_println(this, _strings[0x20].c_str());
 	g_comprehend->readLine(buffer, sizeof(buffer));
diff --git a/engines/glk/comprehend/pics.cpp b/engines/glk/comprehend/pics.cpp
index 09a1203822..3105c6b000 100644
--- a/engines/glk/comprehend/pics.cpp
+++ b/engines/glk/comprehend/pics.cpp
@@ -20,18 +20,18 @@
  *
  */
 
+#include "glk/comprehend/pics.h"
+#include "common/memstream.h"
 #include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/file_buf.h"
 #include "glk/comprehend/game.h"
 #include "glk/comprehend/game_data.h"
-#include "glk/comprehend/pics.h"
-#include "glk/comprehend/draw_surface.h"
-#include "common/memstream.h"
 
 namespace Glk {
 namespace Comprehend {
 
-#define IMAGES_PER_FILE	16
+#define IMAGES_PER_FILE 16
 
 /*-------------------------------------------------------*/
 
@@ -50,6 +50,12 @@ Pics::ImageFile::ImageFile(const Common::String &filename) {
 	 * image offsets start at the beginning of the image file.
 	 */
 	version = f.readUint16LE();
+	if (version == 0x6300 /* Single image file */) {
+		_imageOffsets.resize(1);
+		_imageOffsets[0] = 4;
+		return;
+	}
+
 	if (version == 0x1000)
 		f.seek(4);
 	else
@@ -109,7 +115,7 @@ bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) const {
 			a += 255;
 
 		debugC(kDebugGraphics, "draw_line (%d, %d) - (%d, %d)",
-			ctx->_x, ctx->_y, a, b);
+		       ctx->_x, ctx->_y, a, b);
 		ctx->_drawSurface->drawLine(ctx->_x, ctx->_y, a, b, ctx->_penColor);
 
 		ctx->_x = a;
@@ -125,7 +131,7 @@ bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) const {
 			a += 255;
 
 		debugC(kDebugGraphics, "draw_box (%d, %d) - (%d, %d)",
-			ctx->_x, ctx->_y, a, b);
+		       ctx->_x, ctx->_y, a, b);
 
 		ctx->_drawSurface->drawBox(ctx->_x, ctx->_y, a, b, ctx->_penColor);
 		break;
@@ -153,7 +159,7 @@ bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) const {
 	case IMAGE_OP_SHAPE_A:
 	case IMAGE_OP_SHAPE_SPRAY:
 		debugC(kDebugGraphics,
-		             "set_shape_type(%.2x)", opcode - 0x40);
+		       "set_shape_type(%.2x)", opcode - 0x40);
 		ctx->_shape = opcode;
 		break;
 
@@ -175,7 +181,7 @@ bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) const {
 			a += 255;
 
 		debugC(kDebugGraphics, "draw_shape(%d, %d), style=%.2x, fill=%.2x",
-		             a, b, ctx->_shape, ctx->_fillColor);
+		       a, b, ctx->_shape, ctx->_fillColor);
 
 		ctx->_drawSurface->drawShape(a, b, ctx->_shape, ctx->_fillColor);
 		break;
@@ -192,7 +198,7 @@ bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) const {
 		debugC(kDebugGraphics, "paint(%d, %d)", a, b);
 		if (!(ctx->_drawFlags & IMAGEF_NO_FLOODFILL))
 			ctx->_drawSurface->floodFill(a, b, ctx->_fillColor,
-			            ctx->_drawSurface->getPixelColor(a, b));
+			                             ctx->_drawSurface->getPixelColor(a, b));
 		break;
 
 	case IMAGE_OP_FILL_COLOR:
@@ -213,10 +219,10 @@ bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) const {
 	case IMAGE_OP_DRAW_CHAR:
 		a = imageGetOperand(ctx);
 		debugC(kDebugGraphics, "draw_char(%c)",
-		             a >= 0x20 && a < 0x7f ? a : '?');
+		       a >= 0x20 && a < 0x7f ? a : '?');
 
 		ctx->_drawSurface->drawBox(ctx->_textX, ctx->_textY,
-		           ctx->_textX + 6, ctx->_textY + 7, ctx->_fillColor);
+		                           ctx->_textX + 6, ctx->_textY + 7, ctx->_fillColor);
 		ctx->_textX += 8;
 		break;
 
@@ -241,8 +247,8 @@ bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) const {
 		/* FIXME - unknown, one argument */
 		a = imageGetOperand(ctx);
 		debugC(kDebugGraphics, "unknown %.2x: (%.2x) '%c'",
-		             opcode, a,
-		             a >= 0x20 && a < 0x7f ? a : '?');
+		       opcode, a,
+		       a >= 0x20 && a < 0x7f ? a : '?');
 		break;
 
 	default:
@@ -270,13 +276,17 @@ void Pics::clear() {
 }
 
 void Pics::load(const Common::StringArray &roomFiles,
-                const Common::StringArray &itemFiles) {
+                const Common::StringArray &itemFiles,
+                const Common::String &titleFile) {
 	clear();
 
 	for (uint idx = 0; idx < roomFiles.size(); ++idx)
 		_rooms.push_back(ImageFile(roomFiles[idx]));
 	for (uint idx = 0; idx < itemFiles.size(); ++idx)
 		_items.push_back(ImageFile(itemFiles[idx]));
+
+	if (!titleFile.empty())
+		_title = ImageFile(titleFile);
 }
 
 int Pics::getPictureNumber(const Common::String &filename) const {
@@ -298,7 +308,7 @@ bool Pics::hasFile(const Common::String &name) const {
 	if (num == -1)
 		return false;
 
-	if (num == DARK_ROOM || num == BRIGHT_ROOM)
+	if (num == DARK_ROOM || num == BRIGHT_ROOM || num == TITLE_IMAGE)
 		return true;
 	if (num >= ITEMS_OFFSET && num < (int)(ITEMS_OFFSET + _items.size() * IMAGES_PER_FILE))
 		return true;
@@ -334,7 +344,7 @@ Common::SeekableReadStream *Pics::createReadStreamForMember(const Common::String
 	const DrawSurface &ds = *g_comprehend->_drawSurface;
 	stream->writeUint16LE(ds.w);
 	stream->writeUint16LE(ds.h);
-	stream->writeUint16LE(0);		// Palette size
+	stream->writeUint16LE(0); // Palette size
 	stream->write(ds.getPixels(), ds.w * ds.h * 4);
 
 	return stream;
@@ -349,6 +359,9 @@ void Pics::drawPicture(int pictureNum) const {
 	} else if (pictureNum == BRIGHT_ROOM) {
 		ctx._drawSurface->clearScreen(G_COLOR_WHITE);
 
+	} else if (pictureNum == TITLE_IMAGE) {
+		_title.draw(0, &ctx);
+
 	} else if (pictureNum >= ITEMS_OFFSET) {
 		pictureNum -= ITEMS_OFFSET;
 		_items[pictureNum / IMAGES_PER_FILE].draw(
@@ -360,7 +373,7 @@ void Pics::drawPicture(int pictureNum) const {
 
 		pictureNum %= 100;
 		_rooms[pictureNum / IMAGES_PER_FILE].draw(
-			pictureNum % IMAGES_PER_FILE, &ctx);
+		    pictureNum % IMAGES_PER_FILE, &ctx);
 	}
 }
 
diff --git a/engines/glk/comprehend/pics.h b/engines/glk/comprehend/pics.h
index 99c931016b..9856584fec 100644
--- a/engines/glk/comprehend/pics.h
+++ b/engines/glk/comprehend/pics.h
@@ -25,6 +25,8 @@
 
 #include "glk/comprehend/draw_surface.h"
 #include "common/archive.h"
+#include "common/file.h"
+#include "common/str-array.h"
 
 namespace Glk {
 namespace Comprehend {
@@ -79,7 +81,8 @@ enum {
 	LOCATIONS_NO_BG_OFFSET = 100,
 	ITEMS_OFFSET = 200,
 	DARK_ROOM = 1000,
-	BRIGHT_ROOM = 1001
+	BRIGHT_ROOM = 1001,
+	TITLE_IMAGE = 9999
 };
 
 class Pics : public Common::Archive {
@@ -124,6 +127,7 @@ class Pics : public Common::Archive {
 private:
 	Common::Array<ImageFile> _rooms;
 	Common::Array<ImageFile> _items;
+	ImageFile _title;
 
 private:
 	/**
@@ -140,7 +144,8 @@ public:
 	void clear();
 
 	void load(const Common::StringArray &roomFiles,
-		const Common::StringArray &itemFiles);
+		const Common::StringArray &itemFiles,
+		const Common::String &titleFile);
 
 	/**
 	 * Check if a member with the given name is present in the Archive.


Commit: 508a65a02ede77b50c20e7d43b305a7bcf345e5e
    https://github.com/scummvm/scummvm/commit/508a65a02ede77b50c20e7d43b305a7bcf345e5e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:12-07:00

Commit Message:
GLK: COMPREHEND: Renaming constant arrays to be uppercase

Changed paths:
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_tr.cpp


diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index bfe544c53a..d937920f10 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -26,7 +26,7 @@
 namespace Glk {
 namespace Comprehend {
 
-static GameStrings cc1_strings = {0x9};
+static GameStrings CC1_STRINGS = {0x9};
 
 #ifdef TODO
 static game_ops cc2_ops = {
@@ -50,7 +50,7 @@ CrimsonCrownGame::CrimsonCrownGame() : ComprehendGame() {
 	_itemGraphicFiles.push_back("OA.MS1");
 	_itemGraphicFiles.push_back("OB.MS1");
 
-	_gameStrings = &cc1_strings;
+	_gameStrings = &CC1_STRINGS;
 }
 
 #ifdef TODO
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 45cbab53c0..67728bdff1 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -31,8 +31,8 @@
 namespace Glk {
 namespace Comprehend {
 
-static char charset[] = "..abcdefghijklmnopqrstuvwxyz .";
-static char special_charset[] = "[]\n!\"#$%&'(),-/0123456789:;?<>";
+static const char CHARSET[] = "..abcdefghijklmnopqrstuvwxyz .";
+static const char SPECIAL_CHARSET[] = "[]\n!\"#$%&'(),-/0123456789:;?<>";
 
 static uint16 magic_offset;
 
@@ -677,11 +677,11 @@ static uint64 string_get_chunk(uint8 *string) {
 
 static char decode_string_elem(uint8 c, bool capital, bool special) {
 	if (special) {
-		if (c < sizeof(special_charset) - 1)
-			return special_charset[c];
+		if (c < sizeof(SPECIAL_CHARSET) - 1)
+			return SPECIAL_CHARSET[c];
 	} else {
-		if (c < sizeof(charset) - 1) {
-			c = charset[c];
+		if (c < sizeof(CHARSET) - 1) {
+			c = CHARSET[c];
 			if (capital) {
 				/*
 				* A capital space means that the character
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index c63e7c7b9c..58c44ce9da 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -36,7 +36,7 @@ const TransylvaniaMonster TransylvaniaGame::VAMPIRE = {
 	0x26, 5, (1 << 7), 0, 5
 };
 
-static GameStrings tr_strings = {
+static GameStrings TR_STRINGS = {
     EXTRA_STRING_TABLE(0x8a)
 };
 
@@ -61,7 +61,7 @@ TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
 	_itemGraphicFiles.push_back("OC.MS1");
 
 	_titleGraphicFile = "trtitle.ms1";
-	_gameStrings = &tr_strings;
+	_gameStrings = &TR_STRINGS;
 }
 
 void TransylvaniaGame::update_monster(const TransylvaniaMonster *monster_info) {


Commit: 243adfe901726ad83ef158c70d8ca6c22dfe8791
    https://github.com/scummvm/scummvm/commit/243adfe901726ad83ef158c70d8ca6c22dfe8791
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:12-07:00

Commit Message:
GLK: COMPREHEND: Implemented game font

Changed paths:
  A engines/glk/comprehend/charset.cpp
  A engines/glk/comprehend/charset.h
    engines/glk/comprehend/pics.cpp
    engines/glk/comprehend/pics.h
    engines/glk/module.mk
    engines/glk/picture.cpp


diff --git a/engines/glk/comprehend/charset.cpp b/engines/glk/comprehend/charset.cpp
new file mode 100644
index 0000000000..0302973823
--- /dev/null
+++ b/engines/glk/comprehend/charset.cpp
@@ -0,0 +1,62 @@
+/* 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 "glk/comprehend/charset.h"
+#include "common/file.h"
+#include "graphics/surface.h"
+
+namespace Glk {
+namespace Comprehend {
+
+CharSet::CharSet() : Graphics::Font() {
+	Common::File f;
+	if (!f.open("charset.gda"))
+		error("Could not open char set");
+
+	uint version = f.readUint16LE();
+	if (version != 0x1100)
+		error("Unknown char set version");
+
+	f.seek(4);
+	for (int idx = 0; idx < 128 - 32; ++idx)
+		f.read(&_data[idx][0], 8);
+
+	f.close();
+}
+
+void CharSet::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
+	assert(dst->format.bytesPerPixel == 4);
+	assert(chr >= 32 && chr < 128);
+
+	for (uint yp = 0; yp < 8; ++yp) {
+		uint32 *lineP = (uint32 *)dst->getBasePtr(x, y + yp);
+		byte bits = _data[chr - 32][yp];
+
+		for (uint xp = 0; xp < 8; ++xp, ++lineP, bits >>= 1) {
+			if (bits & 1)
+				*lineP = color;
+		}
+	}
+}
+
+} // namespace Comprehend
+} // namespace Glk
diff --git a/engines/glk/comprehend/charset.h b/engines/glk/comprehend/charset.h
new file mode 100644
index 0000000000..98585ed9f6
--- /dev/null
+++ b/engines/glk/comprehend/charset.h
@@ -0,0 +1,83 @@
+/* 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.
+ *
+ */
+
+#ifndef GLK_COMPREHEND_CHARSET_H
+#define GLK_COMPREHEND_CHARSET_H
+
+#include "graphics/font.h"
+
+namespace Glk {
+namespace Comprehend {
+
+class CharSet : public Graphics::Font {
+private:
+	byte _data[128 - 32][8];
+
+public:
+	CharSet();
+
+	/**
+	 */
+	int getFontHeight() const override {
+		return 8;
+	}
+
+	/**
+	 * Query the maximum width of the font.
+	 */
+	int getMaxCharWidth() const override {
+		return 8;
+	}
+
+	/**
+	 * Query the width of a specific character.
+	 */
+	int getCharWidth(uint32 chr) const override {
+		return 8;
+	}
+
+	/**
+	 * Query the kerning offset between two characters.
+	 */
+	int getKerningOffset(uint32 left, uint32 right) const override {
+		return 0;
+	}
+
+	/**
+	 * Calculate the bounding box of a character. It is assumed that
+	 * the character shall be drawn at position (0, 0).
+	 */
+	Common::Rect getBoundingBox(uint32 chr) const override {
+		assert(chr < 127);
+		return Common::Rect(0, 0, 8, 8);
+	}
+
+	/**
+	 * Draw a character at a specific point on a surface.
+	 */
+	void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
+};
+
+} // End of namespace Comprehend
+} // End of namespace Glk
+
+#endif
diff --git a/engines/glk/comprehend/pics.cpp b/engines/glk/comprehend/pics.cpp
index 3105c6b000..fcb77eccba 100644
--- a/engines/glk/comprehend/pics.cpp
+++ b/engines/glk/comprehend/pics.cpp
@@ -23,6 +23,7 @@
 #include "glk/comprehend/pics.h"
 #include "common/memstream.h"
 #include "glk/comprehend/comprehend.h"
+#include "glk/comprehend/charset.h"
 #include "glk/comprehend/draw_surface.h"
 #include "glk/comprehend/file_buf.h"
 #include "glk/comprehend/game.h"
@@ -218,12 +219,14 @@ bool Pics::ImageFile::doImageOp(Pics::ImageContext *ctx) const {
 
 	case IMAGE_OP_DRAW_CHAR:
 		a = imageGetOperand(ctx);
-		debugC(kDebugGraphics, "draw_char(%c)",
-		       a >= 0x20 && a < 0x7f ? a : '?');
-
-		ctx->_drawSurface->drawBox(ctx->_textX, ctx->_textY,
-		                           ctx->_textX + 6, ctx->_textY + 7, ctx->_fillColor);
-		ctx->_textX += 8;
+		if (a < 0x20 || a >= 0x7f) {
+			warning("Invalid character - %c", a);
+			a = '?';
+		}
+
+		debugC(kDebugGraphics, "draw_char(%c)", a);
+		ctx->_font->drawChar(ctx->_drawSurface, a, ctx->_textX, ctx->_textY, ctx->_penColor);
+		ctx->_textX += ctx->_font->getCharWidth(a);
 		break;
 
 	case 0xf3:
@@ -270,6 +273,15 @@ uint16 Pics::ImageFile::imageGetOperand(ImageContext *ctx) const {
 
 /*-------------------------------------------------------*/
 
+Pics::Pics() : _font(nullptr) {
+	if (Common::File::exists("charset.gda"))
+		_font = new CharSet();
+}
+
+Pics::~Pics() {
+	delete _font;
+}
+
 void Pics::clear() {
 	_rooms.clear();
 	_items.clear();
@@ -351,7 +363,7 @@ Common::SeekableReadStream *Pics::createReadStreamForMember(const Common::String
 }
 
 void Pics::drawPicture(int pictureNum) const {
-	ImageContext ctx(g_comprehend->_drawSurface, g_comprehend->_drawFlags);
+	ImageContext ctx(g_comprehend->_drawSurface, _font, g_comprehend->_drawFlags);
 
 	if (pictureNum == DARK_ROOM) {
 		ctx._drawSurface->clearScreen(G_COLOR_BLACK);
diff --git a/engines/glk/comprehend/pics.h b/engines/glk/comprehend/pics.h
index 9856584fec..9140b959b3 100644
--- a/engines/glk/comprehend/pics.h
+++ b/engines/glk/comprehend/pics.h
@@ -89,6 +89,7 @@ class Pics : public Common::Archive {
 	struct ImageContext {
 		Common::File _file;
 		DrawSurface *_drawSurface;
+		Graphics::Font *_font;
 		uint _drawFlags;
 
 		uint16 _x;
@@ -100,9 +101,9 @@ class Pics : public Common::Archive {
 		uint16 _textX;
 		uint16 _textY;
 
-		ImageContext(DrawSurface *drawSurface, uint flags) :
-			_drawSurface(drawSurface), _drawFlags(0), _x(0), _y(0),
-			_penColor(G_COLOR_BLACK), _fillColor(G_COLOR_BLACK),
+		ImageContext(DrawSurface *drawSurface, Graphics::Font *font, uint flags) :
+			_drawSurface(drawSurface), _font(font), _drawFlags(0),
+			_x(0), _y(0), _penColor(G_COLOR_BLACK), _fillColor(G_COLOR_BLACK),
 			_shape(IMAGE_OP_SHAPE_CIRCLE_LARGE), _textX(0), _textY(0) {
 		}
 
@@ -128,6 +129,7 @@ private:
 	Common::Array<ImageFile> _rooms;
 	Common::Array<ImageFile> _items;
 	ImageFile _title;
+	Graphics::Font *_font;
 
 private:
 	/**
@@ -141,6 +143,9 @@ private:
 	void drawPicture(int pictureNum) const;
 
 public:
+	Pics();
+	~Pics();
+
 	void clear();
 
 	void load(const Common::StringArray &roomFiles,
diff --git a/engines/glk/module.mk b/engines/glk/module.mk
index aa5c0aba34..dafed0a320 100644
--- a/engines/glk/module.mk
+++ b/engines/glk/module.mk
@@ -166,6 +166,7 @@ MODULE_OBJS := \
 	archetype/sys_object.o \
 	archetype/timestamp.o \
 	archetype/token.o \
+	comprehend/charset.o \
 	comprehend/comprehend.o \
 	comprehend/debugger.o \
 	comprehend/debugger_dumper.o \
diff --git a/engines/glk/picture.cpp b/engines/glk/picture.cpp
index 5cb44c8857..4c3f8454ed 100644
--- a/engines/glk/picture.cpp
+++ b/engines/glk/picture.cpp
@@ -214,7 +214,7 @@ Picture *Pictures::scale(Picture *src, size_t sx, size_t sy) {
 	dst = new Picture(sx, sy, src->format);
 	dst->_id = src->_id;
 	dst->_scaled = true;
-	dst->transBlitFrom(*src, src->getBounds(), dst->getBounds(), (uint)-1);
+	dst->transBlitFrom(*src, src->getBounds(), dst->getBounds(), (uint)0x8888);
 
 	storeScaled(dst);
 	return dst;


Commit: 88c1d4ecf1df5d9472fb234f2e542551d55d5ced
    https://github.com/scummvm/scummvm/commit/88c1d4ecf1df5d9472fb234f2e542551d55d5ced
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:12-07:00

Commit Message:
GLK: COMPREHEND: Cleanup of Crimson Crown code, remove deprecated data

Changed paths:
    engines/glk/comprehend/game.cpp
    engines/glk/comprehend/game.h
    engines/glk/comprehend/game_cc.cpp
    engines/glk/comprehend/game_cc.h
    engines/glk/comprehend/game_data.cpp
    engines/glk/comprehend/game_data.h
    engines/glk/comprehend/game_oo.cpp
    engines/glk/comprehend/game_tm.cpp
    engines/glk/comprehend/game_tr.cpp


diff --git a/engines/glk/comprehend/game.cpp b/engines/glk/comprehend/game.cpp
index b758a5b5e6..06b04fb4a9 100644
--- a/engines/glk/comprehend/game.cpp
+++ b/engines/glk/comprehend/game.cpp
@@ -38,9 +38,7 @@ struct Sentence {
 	size_t nr_words;
 };
 
-ComprehendGame::ComprehendGame() : _gameName(nullptr),
-                                   _shortName(nullptr),
-                                   _gameDataFile(nullptr),
+ComprehendGame::ComprehendGame() : _gameDataFile(nullptr),
                                    _colorTable(0),
                                    _gameStrings(nullptr) {
 }
diff --git a/engines/glk/comprehend/game.h b/engines/glk/comprehend/game.h
index c6f7c0e668..8e82a44dd0 100644
--- a/engines/glk/comprehend/game.h
+++ b/engines/glk/comprehend/game.h
@@ -37,10 +37,7 @@ namespace Comprehend {
 
 class ComprehendGame : public GameInfo, public OpcodeMap {
 public:
-	const char *_gameName;
-	const char *_shortName;
-
-	const char *_gameDataFile;
+	Common::String _gameDataFile;
 	Common::Array<StringFile> _stringFiles;
 	Common::StringArray _locationGraphicFiles;
 	Common::StringArray _itemGraphicFiles;
diff --git a/engines/glk/comprehend/game_cc.cpp b/engines/glk/comprehend/game_cc.cpp
index d937920f10..401cf420db 100644
--- a/engines/glk/comprehend/game_cc.cpp
+++ b/engines/glk/comprehend/game_cc.cpp
@@ -28,55 +28,36 @@ namespace Comprehend {
 
 static GameStrings CC1_STRINGS = {0x9};
 
-#ifdef TODO
-static game_ops cc2_ops = {
-    nullptr,
-    cc2_before_prompt,
-    nullptr,
-    nullptr,
-    nullptr,
-    cc2_handle_special_opcode};
-#endif
-
 CrimsonCrownGame::CrimsonCrownGame() : ComprehendGame() {
-	_gameName = "Crimson Crown";
-	_shortName = "cc1";
-	_gameDataFile = "cc1.gda";
-
-	_stringFiles.push_back(StringFile("ma.ms1", 0x89));
-	_locationGraphicFiles.push_back("RA.MS1");
-	_locationGraphicFiles.push_back("RB.MS1");
-	_locationGraphicFiles.push_back("RC.MS1");
-	_itemGraphicFiles.push_back("OA.MS1");
-	_itemGraphicFiles.push_back("OB.MS1");
-
-	_gameStrings = &CC1_STRINGS;
+	setupDisk(1);
 }
 
-#ifdef TODO
-ComprehendGame game_crimson_crown_2 = {
-    "Crimson Crown (Part 2/2)",
-    "cc2",
-    "CC2.GDA",
-    {{"MA.MS2", 0x89}},
-    {"RA.MS2", "RB.MS2"},
-    {"OA.MS2", "OB.MS2"},
-    "G%d.MS0",
-    0,
-    nullptr,
-    &cc2_ops,
-    nullptr};
-#endif
-
-static void cc_clear_companion_flags(ComprehendGame *game) {
-	/* Clear the Sabrina/Erik action flags */
-	game->_flags[0xa] = 0;
-	game->_flags[0xb] = 0;
+void CrimsonCrownGame::setupDisk(uint diskNum) {
+	assert(diskNum == 1 || diskNum == 2);
+
+	_gameDataFile = Common::String::format("cc%u.gda", diskNum);
+	_stringFiles.push_back(StringFile(Common::String::format("ma.ms%u", diskNum), 0x89));
+	_locationGraphicFiles.push_back(Common::String::format("ra.ms%u", diskNum));
+	_locationGraphicFiles.push_back(Common::String::format("rb.ms%u", diskNum));
+	if (diskNum == 1)
+		_locationGraphicFiles.push_back("RC.ms1");
+	_itemGraphicFiles.push_back(Common::String::format("oa.ms%u", diskNum));
+	_itemGraphicFiles.push_back(Common::String::format("ob.ms%u", diskNum));
+
+	if (diskNum == 1)
+		_gameStrings = &CC1_STRINGS;
+	else
+		_gameStrings = nullptr;
 }
 
-static bool cc_common_handle_special_opcode(ComprehendGame *game,
-                                            uint8 operand) {
+void CrimsonCrownGame::handle_special_opcode(uint8 operand) {
 	switch (operand) {
+	case 0x01:
+		// Enter the Vampire's throne room
+		assert(_diskNum == 1);
+		eval_function(this, &_functions[0xe], nullptr, nullptr);
+		break;
+
 	case 0x03:
 		/*
 		 * Game over - failure.
@@ -84,69 +65,37 @@ static bool cc_common_handle_special_opcode(ComprehendGame *game,
 		 * FIXME - If playing the second disk this should restart
 		 *         from the beginning of the first disk.
 		 */
-		game_restart(game);
+		game_restart(this);
 		break;
 
-	case 0x06:
-		game_save(game);
-		break;
-
-	case 0x07:
-		/*
-		 * FIXME - This will only correctly restore games that were
-		 *         saved for the disk currently being played.
-		 */
-		game_restore(game);
-		return true;
-	}
-
-	return false;
-}
-
-void CrimsonCrownGame::handle_special_opcode(uint8 operand) {
-	if (cc_common_handle_special_opcode(this, operand))
-		return;
-
-	switch (operand) {
 	case 0x05:
-		/*
-		 * Completed first part (disk 1) of the game.
-		 *
-		 * FIXME - This should automatically load disk 2.
-		 */
-		error("[Completed disk 1 - to continue run Re-Comprehend with the 'cc2' game]");
+		if (_diskNum == 1) {
+			// Finished disk 1
+			error("[Completed disk 1 - handle switch to disk 2]");
+		} else {
+			// Won the game.
+			// FIXME: The merchant ship should arrives, etc.
+			game_restart(this);
+		}
 		break;
-	}
-}
 
-static void cc2_handle_special_opcode(ComprehendGame *game,
-                                      uint8 operand) {
-	if (cc_common_handle_special_opcode(game, operand))
-		return;
+	case 0x06:
+		game_save(this);
+		break;
 
-	switch (operand) {
-	case 0x01:
-		/* Enter the Vampire's throne room */
-		eval_function(game, &game->_functions[0xe], NULL, NULL);
+	case 0x07:
+		game_restore(this);
 		break;
 
-	case 0x05:
-		/*
-		 * Won the game.
-		 *
-		 * FIXME - The merchant ship should arrives, etc.
-		 */
-		game_restart(game);
+	default:
 		break;
 	}
 }
 
-static void cc2_before_prompt(ComprehendGame *game) {
-	cc_clear_companion_flags(game);
-}
-
 void CrimsonCrownGame::before_prompt() {
-	cc_clear_companion_flags(this);
+	// Clear the Sabrina/Erik action flags
+	_flags[0xa] = 0;
+	_flags[0xb] = 0;
 }
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game_cc.h b/engines/glk/comprehend/game_cc.h
index 7ca5bd10b2..d69eab2b66 100644
--- a/engines/glk/comprehend/game_cc.h
+++ b/engines/glk/comprehend/game_cc.h
@@ -29,12 +29,17 @@ namespace Glk {
 namespace Comprehend {
 
 class CrimsonCrownGame : public ComprehendGame {
+private:
+	uint _diskNum;
+
 public:
 	CrimsonCrownGame();
 	~CrimsonCrownGame() override {}
 
 	void before_prompt() override;
 	void handle_special_opcode(uint8 operand) override;
+
+	void setupDisk(uint diskNum);
 };
 
 } // namespace Comprehend
diff --git a/engines/glk/comprehend/game_data.cpp b/engines/glk/comprehend/game_data.cpp
index 67728bdff1..4dbe472e0c 100644
--- a/engines/glk/comprehend/game_data.cpp
+++ b/engines/glk/comprehend/game_data.cpp
@@ -954,10 +954,7 @@ static void load_extra_string_file(ComprehendGame *game,
 static void load_extra_string_files(ComprehendGame *game) {
 	uint i;
 
-	for (i = 0; i < ARRAY_SIZE(game->_stringFiles); i++) {
-		if (!game->_stringFiles[i].filename)
-			break;
-
+	for (i = 0; i < game->_stringFiles.size(); i++) {
 		// HACK - get string offsets correct
 		game->_strings2.resize(0x40 * i);
 		if (game->_strings2.empty())
diff --git a/engines/glk/comprehend/game_data.h b/engines/glk/comprehend/game_data.h
index 557c16e015..420888e1fd 100644
--- a/engines/glk/comprehend/game_data.h
+++ b/engines/glk/comprehend/game_data.h
@@ -251,12 +251,12 @@ struct GameInfo {
 };
 
 struct StringFile {
-	const char *filename;
+	Common::String filename;
 	uint32 base_offset;
 	uint32 end_offset;
 
 	StringFile() : filename(nullptr), base_offset(0), end_offset(0) {}
-	StringFile(const char *fname, uint32 baseOfs, uint32 endO = 0) : filename(fname), base_offset(baseOfs), end_offset(endO) {
+	StringFile(const Common::String &fname, uint32 baseOfs, uint32 endO = 0) : filename(fname), base_offset(baseOfs), end_offset(endO) {
 	}
 };
 
diff --git a/engines/glk/comprehend/game_oo.cpp b/engines/glk/comprehend/game_oo.cpp
index 2e8c49b1c4..bba0a7fc89 100644
--- a/engines/glk/comprehend/game_oo.cpp
+++ b/engines/glk/comprehend/game_oo.cpp
@@ -35,8 +35,6 @@ namespace Comprehend {
 #define OO_FLAG_FLASHLIGHT_ON 0x27
 
 OOToposGame::OOToposGame() : ComprehendGame() {
-	_gameName = "Oo-Topos";
-	_shortName = "oo";
 	_gameDataFile = "g0";
 
 	// Extra strings are (annoyingly) stored in the game binary
diff --git a/engines/glk/comprehend/game_tm.cpp b/engines/glk/comprehend/game_tm.cpp
index 6ba9ff960a..7fefaf06ea 100644
--- a/engines/glk/comprehend/game_tm.cpp
+++ b/engines/glk/comprehend/game_tm.cpp
@@ -29,8 +29,6 @@ namespace Comprehend {
 /* FIXME - This is broken */
 
 TalismanGame::TalismanGame() : ComprehendGame() {
-	_gameName = "Talisman, Challenging the Sands of Time (broken)";
-	_shortName = "tm";
 	_gameDataFile = "G0";
 
 	_locationGraphicFiles.push_back("RA");
diff --git a/engines/glk/comprehend/game_tr.cpp b/engines/glk/comprehend/game_tr.cpp
index 58c44ce9da..ea2209198a 100644
--- a/engines/glk/comprehend/game_tr.cpp
+++ b/engines/glk/comprehend/game_tr.cpp
@@ -42,8 +42,6 @@ static GameStrings TR_STRINGS = {
 
 
 TransylvaniaGame::TransylvaniaGame() : ComprehendGame() {
-	_gameName = "Transylvania";
-	_shortName = "tr";
 	_gameDataFile = "tr.gda";
 
 	_stringFiles.push_back(StringFile("MA.MS1", 0x88));


Commit: 3aacc800a964583641fa25b764f0052bdd199ca9
    https://github.com/scummvm/scummvm/commit/3aacc800a964583641fa25b764f0052bdd199ca9
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2020-06-02T18:22:12-07:00

Commit Message:
GLK: COMPREHEND: Flesh out and fixes for detection code

Changed paths:
    engines/glk/comprehend/detection.cpp
    engines/glk/comprehend/detection_tables.h


diff --git a/engines/glk/comprehend/detection.cpp b/engines/glk/comprehend/detection.cpp
index 8624a3b7b9..5621f581f1 100644
--- a/engines/glk/comprehend/detection.cpp
+++ b/engines/glk/comprehend/detection.cpp
@@ -31,12 +31,12 @@ namespace Glk {
 namespace Comprehend {
 
 void ComprehendMetaEngine::getSupportedGames(PlainGameList &games) {
-	for (const PlainGameDescriptor *pd = ComprehendGame_LIST; pd->gameId; ++pd)
+	for (const PlainGameDescriptor *pd = COMPREHEND_GAME_LIST; pd->gameId; ++pd)
 		games.push_back(*pd);
 }
 
 GameDescriptor ComprehendMetaEngine::findGame(const char *gameId) {
-	for (const PlainGameDescriptor *pd = ComprehendGame_LIST; pd->gameId; ++pd) {
+	for (const PlainGameDescriptor *pd = COMPREHEND_GAME_LIST; pd->gameId; ++pd) {
 		if (!strcmp(gameId, pd->gameId))
 			return *pd;
 	}
@@ -51,9 +51,14 @@ bool ComprehendMetaEngine::detectGames(const Common::FSList &fslist, DetectedGam
 		if (file->isDirectory())
 			continue;
 
+		// Check if file occurs in the list
 		Common::String filename = file->getName();
-		bool hasExt = filename.hasSuffixIgnoreCase(".gda");
-		if (!hasExt)
+		bool isPossible = false;
+		const ComprehendDetectionEntry *p = COMPREHEND_GAMES;
+		for (; p->_gameId && !isPossible; ++p)
+			isPossible = filename.equalsIgnoreCase(p->_filename);
+
+		if (!isPossible)
 			continue;
 
 		// Get the file's MD5
@@ -64,7 +69,7 @@ bool ComprehendMetaEngine::detectGames(const Common::FSList &fslist, DetectedGam
 		gameFile.close();
 
 		// Iterate through the known games
-		const ComprehendDetectionEntry *p = ComprehendGameS;
+		p = COMPREHEND_GAMES;
 		for (; p->_gameId; ++p) {
 			if (filename.equalsIgnoreCase(p->_filename)) {
 				// Check for an md5 match
@@ -81,7 +86,7 @@ bool ComprehendMetaEngine::detectGames(const Common::FSList &fslist, DetectedGam
 }
 
 void ComprehendMetaEngine::detectClashes(Common::StringMap &map) {
-	for (const PlainGameDescriptor *pd = ComprehendGame_LIST; pd->gameId; ++pd) {
+	for (const PlainGameDescriptor *pd = COMPREHEND_GAME_LIST; pd->gameId; ++pd) {
 		if (map.contains(pd->gameId))
 			error("Duplicate game Id found - %s", pd->gameId);
 		map[pd->gameId] = "";
diff --git a/engines/glk/comprehend/detection_tables.h b/engines/glk/comprehend/detection_tables.h
index 5b744f86b2..0e26bbd7de 100644
--- a/engines/glk/comprehend/detection_tables.h
+++ b/engines/glk/comprehend/detection_tables.h
@@ -27,12 +27,14 @@
 namespace Glk {
 namespace Comprehend {
 
-const PlainGameDescriptor ComprehendGame_LIST[] = {
+const PlainGameDescriptor COMPREHEND_GAME_LIST[] = {
     {"crimsoncrown", "Crimson Crown"},
     {"ootopis", "OO-Topos"},
+#ifndef RELEASE_BUILD
+    {"talisman", "Talisman: Challenging the Sands of Time"},
+#endif
     {"transylvania", "Transylvania"},
-    {"talisman", "Talisman"},
-	{nullptr, nullptr}
+    {nullptr, nullptr}
 };
 
 struct ComprehendDetectionEntry {
@@ -41,12 +43,16 @@ struct ComprehendDetectionEntry {
 	const char *const _md5;
 };
 
-const ComprehendDetectionEntry ComprehendGameS[] = {
-    // DOS games
+const ComprehendDetectionEntry COMPREHEND_GAMES[] = {
     {"crimsoncrown", "cc1.gda", "f2abf019675ac5c9bcfd81032bc7787b"},
+    {"ootopis", "g0", "56460c1ee669c253607534155d7e9db4"},
+#ifndef RELEASE_BUILD
+	{"talisman", "g0", "35770d4815e610b5252e3fcd9f11def3"},
+#endif
     {"transylvania", "tr.gda", "22e08633eea02ceee49b909dfd982d22"},
 
-    {nullptr, nullptr, nullptr}};
+	{nullptr, nullptr, nullptr}
+};
 
 } // End of namespace Comprehend
 } // End of namespace Glk




More information about the Scummvm-git-logs mailing list