[Scummvm-cvs-logs] scummvm master -> 1ef27b3e5b0b2ef955af87c8ac6ff0458299e7bc

sev- sev at scummvm.org
Sun Jan 31 22:37:46 CET 2016


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

Summary:
8a595e7771 AGI: graphics rewrite + cleanup
ccfd870c81 AGI: adjust mouse pos using render start Y
df845be116 AGI: added/changed font warnings
1a5bef2302 AGI: remove initGraphics comment
1987b4b4e5 AGI: remove commented out code in console.cpp
a560f7ad01 AGI: improve checkPosition() code, remove while(0)
5f43f07947 AGI: font.h / change comment to use unix slashes
41620c95cc AGI: remove commented out code from CmdSetSimple()
0f15ec2ce8 AGI: use Common::RenderMode instead of its own
0c2de08155 AGI: new font class created
614884ed39 AGI: support for user-supplied font-file
72161adf1c AGI: overwrite save restore dialog font character
855059ca05 AGI: font loader support for Atari ST font
e8791ac979 AGI: add hack to make numpad cursor keys work
bd59851300 AGI: fix amiga mouse cursor comment
243c861264 AGI: fix F7-F10 keys
125cec693f AGI: do not allow load/save while in inner loop
72f0d012c6 AGI: fix keyboard input code for keycodes
98730cb962 AGI: Fix some word parsing issues
cb3b5d5e31 AGI: fix agi256 view decompression
26cb39beee AGI: Ego motion type change on newroom only agi3
428df3e6cb AGI: copying between var + ego screen obj fixed
4afda5bbea AGI: motion type check in objectstop was AGI3 only
83495eab28 AGI: change key -> direction handling
6baadff8d3 AGI: font cleanup
8115145e4b AGI: hardcoded value replaced with VM_VAR_SECONDS
143fb9458f AGI: added/improved font debug output
121415ef1f AGI: rename VGA font to PC BIOS font
1548f2cebf AGI: revert "motion type check in objectstop AGI3"
82b958f274 AGI: VM Var code cleanup
4bc01ab7d5 AGI: getflag/setflag/etc. cleanup
9acbe6f3f4 AGI: adjust getFlag(), setVar() and getVar()
fd9c46831d AGI: remove timer hack, implement in game timer
a9b25b53d7 AGI: properly implement volume control + sync
f2fb921f84 AGI: vol system setting gets sent to scripts
1ef27b3e5b Merge pull request #654 from m-kiewitz/master


Commit: 8a595e7771aa89d06876e13d7ab6751e26da8982
    https://github.com/scummvm/scummvm/commit/8a595e7771aa89d06876e13d7ab6751e26da8982
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T13:22:22+01:00

Commit Message:
AGI: graphics rewrite + cleanup

- graphics code fully rewritten
- Apple IIgs font support
- Amiga Topaz support
- Word parser rewritten
- menu code rewritten
- removed forced 2 second delay on all room changes
  replaced with heuristic to detect situations, where it's required
- lots of naming cleanup
- new console commands show_map, screenobj, vmvars and vmflags
- all sorts of hacks/workarounds removed
- added SCI wait mouse cursor
- added Apple IIgs mouse cursor
- added Atari ST mouse cursor
- added Amiga/Apple IIgs transition
- added Atari ST transition
- user can select another render mode and
  use Apple IIgs palette + transition for PC versions
- inventory screen rewritten
- SetSimple command now properly implemented
- PreAGI Mickey: Sierra logo now shown
- saved games: now saving controller key mapping
  also saving automatic save data (SetSimple command)
- fixed invalid memory access when saving games (31 bytes were saved
  using Common::String c_ptr()

Special Thanks to:
- fuzzie for helping out with the Apple IIgs font + valgrind
- eriktorbjorn for helping out with valgrind
- LordHoto for figuring out the code, that caused invalid memory
  access in the original code, when saving a game
- sev for help out with reversing the Amiga transition

currently missing:
- mouse support for menu
- mouse support for system dialogs
- predictive dialog support

Changed paths:
  A engines/agi/inv.h
  A engines/agi/mouse_cursor.h
  A engines/agi/palette.h
  A engines/agi/systemui.cpp
  A engines/agi/systemui.h
  A engines/agi/text.h
  A engines/agi/words.h
    engines/agi/agi.cpp
    engines/agi/agi.h
    engines/agi/checks.cpp
    engines/agi/console.cpp
    engines/agi/console.h
    engines/agi/cycle.cpp
    engines/agi/detection.cpp
    engines/agi/font.h
    engines/agi/global.cpp
    engines/agi/graphics.cpp
    engines/agi/graphics.h
    engines/agi/inv.cpp
    engines/agi/keyboard.cpp
    engines/agi/keyboard.h
    engines/agi/loader_v1.cpp
    engines/agi/loader_v2.cpp
    engines/agi/loader_v3.cpp
    engines/agi/logic.cpp
    engines/agi/menu.cpp
    engines/agi/menu.h
    engines/agi/module.mk
    engines/agi/motion.cpp
    engines/agi/objects.cpp
    engines/agi/op_cmd.cpp
    engines/agi/op_dbg.cpp
    engines/agi/op_test.cpp
    engines/agi/opcodes.cpp
    engines/agi/picture.cpp
    engines/agi/picture.h
    engines/agi/preagi.cpp
    engines/agi/preagi_mickey.cpp
    engines/agi/preagi_troll.cpp
    engines/agi/preagi_winnie.cpp
    engines/agi/saveload.cpp
    engines/agi/sound_pcjr.cpp
    engines/agi/sound_sarien.cpp
    engines/agi/sprite.cpp
    engines/agi/sprite.h
    engines/agi/text.cpp
    engines/agi/view.cpp
    engines/agi/view.h
    engines/agi/words.cpp



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index e907d38..19e0595 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -21,7 +21,6 @@
  */
 
 #include "common/md5.h"
-#include "common/events.h"
 #include "common/file.h"
 #include "common/memstream.h"
 #include "common/savefile.h"
@@ -42,9 +41,13 @@
 
 #include "agi/agi.h"
 #include "agi/graphics.h"
+#include "agi/inv.h"
 #include "agi/sprite.h"
+#include "agi/text.h"
 #include "agi/keyboard.h"
 #include "agi/menu.h"
+#include "agi/systemui.h"
+#include "agi/words.h"
 
 #include "gui/predictivedialog.h"
 
@@ -54,241 +57,6 @@ void AgiEngine::allowSynthetic(bool allow) {
 	_allowSynthetic = allow;
 }
 
-void AgiEngine::processEvents() {
-	Common::Event event;
-	int key = 0;
-
-	while (_eventMan->pollEvent(event)) {
-		switch (event.type) {
-		case Common::EVENT_PREDICTIVE_DIALOG: {
-			GUI::PredictiveDialog _predictiveDialog;
-			_predictiveDialog.runModal();
-			strcpy(_predictiveResult, _predictiveDialog.getResult());
-			if (strcmp(_predictiveResult, "")) {
-				if (_game.inputMode == INPUT_NORMAL) {
-					strcpy((char *)_game.inputBuffer, _predictiveResult);
-					handleKeys(KEY_ENTER);
-				} else if (_game.inputMode == INPUT_GETSTRING) {
-					strcpy(_game.strings[_stringdata.str], _predictiveResult);
-					newInputMode(INPUT_NORMAL);
-					_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
-							_stringdata.y, ' ', _game.colorFg, _game.colorBg);
-				} else if (_game.inputMode == INPUT_NONE) {
-					for (int n = 0; _predictiveResult[n]; n++)
-						keyEnqueue(_predictiveResult[n]);
-				}
-			}
-			/*
-			if (predictiveDialog()) {
-				if (_game.inputMode == INPUT_NORMAL) {
-					strcpy((char *)_game.inputBuffer, _predictiveResult);
-					handleKeys(KEY_ENTER);
-				} else if (_game.inputMode == INPUT_GETSTRING) {
-					strcpy(_game.strings[_stringdata.str], _predictiveResult);
-					newInputMode(INPUT_NORMAL);
-					_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
-							_stringdata.y, ' ', _game.colorFg, _game.colorBg);
-				} else if (_game.inputMode == INPUT_NONE) {
-					for (int n = 0; _predictiveResult[n]; n++)
-						keyEnqueue(_predictiveResult[n]);
-				}
-			}
-			*/
-			}
-			break;
-		case Common::EVENT_LBUTTONDOWN:
-			if (_game.mouseEnabled) {
-				key = BUTTON_LEFT;
-				_mouse.button = kAgiMouseButtonLeft;
-				keyEnqueue(key);
-				_mouse.x = event.mouse.x;
-				_mouse.y = event.mouse.y;
-			}
-			break;
-		case Common::EVENT_RBUTTONDOWN:
-			if (_game.mouseEnabled) {
-				key = BUTTON_RIGHT;
-				_mouse.button = kAgiMouseButtonRight;
-				keyEnqueue(key);
-				_mouse.x = event.mouse.x;
-				_mouse.y = event.mouse.y;
-			}
-			break;
-		case Common::EVENT_WHEELUP:
-			if (_game.mouseEnabled) {
-				key = WHEEL_UP;
-				keyEnqueue(key);
-			}
-			break;
-		case Common::EVENT_WHEELDOWN:
-			if (_game.mouseEnabled) {
-				key = WHEEL_DOWN;
-				keyEnqueue(key);
-			}
-			break;
-		case Common::EVENT_MOUSEMOVE:
-			if (_game.mouseEnabled) {
-				_mouse.x = event.mouse.x;
-				_mouse.y = event.mouse.y;
-
-				if (!_game.mouseFence.isEmpty()) {
-					if (_mouse.x < _game.mouseFence.left)
-						_mouse.x = _game.mouseFence.left;
-					if (_mouse.x > _game.mouseFence.right)
-						_mouse.x = _game.mouseFence.right;
-					if (_mouse.y < _game.mouseFence.top)
-						_mouse.y = _game.mouseFence.top;
-					if (_mouse.y > _game.mouseFence.bottom)
-						_mouse.y = _game.mouseFence.bottom;
-
-					g_system->warpMouse(_mouse.x, _mouse.y);
-				}
-			}
-
-			break;
-		case Common::EVENT_LBUTTONUP:
-		case Common::EVENT_RBUTTONUP:
-			if (_game.mouseEnabled) {
-				_mouse.button = kAgiMouseButtonUp;
-				_mouse.x = event.mouse.x;
-				_mouse.y = event.mouse.y;
-			}
-			break;
-		case Common::EVENT_KEYDOWN:
-			if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) {
-				_console->attach();
-				break;
-			}
-
-			switch (key = event.kbd.keycode) {
-			case Common::KEYCODE_LEFT:
-			case Common::KEYCODE_KP4:
-				if (_allowSynthetic || !event.synthetic)
-					key = KEY_LEFT;
-				break;
-			case Common::KEYCODE_RIGHT:
-			case Common::KEYCODE_KP6:
-				if (_allowSynthetic || !event.synthetic)
-					key = KEY_RIGHT;
-				break;
-			case Common::KEYCODE_UP:
-			case Common::KEYCODE_KP8:
-				if (_allowSynthetic || !event.synthetic)
-					key = KEY_UP;
-				break;
-			case Common::KEYCODE_DOWN:
-			case Common::KEYCODE_KP2:
-				if (_allowSynthetic || !event.synthetic)
-					key = KEY_DOWN;
-				break;
-			case Common::KEYCODE_PAGEUP:
-			case Common::KEYCODE_KP9:
-				if (_allowSynthetic || !event.synthetic)
-					key = KEY_UP_RIGHT;
-				break;
-			case Common::KEYCODE_PAGEDOWN:
-			case Common::KEYCODE_KP3:
-				if (_allowSynthetic || !event.synthetic)
-					key = KEY_DOWN_RIGHT;
-				break;
-			case Common::KEYCODE_HOME:
-			case Common::KEYCODE_KP7:
-				if (_allowSynthetic || !event.synthetic)
-					key = KEY_UP_LEFT;
-				break;
-			case Common::KEYCODE_END:
-			case Common::KEYCODE_KP1:
-				if (_allowSynthetic || !event.synthetic)
-					key = KEY_DOWN_LEFT;
-				break;
-			case Common::KEYCODE_KP5:
-				key = KEY_STATIONARY;
-				break;
-			case Common::KEYCODE_PLUS:
-				key = '+';
-				break;
-			case Common::KEYCODE_MINUS:
-				key = '-';
-				break;
-			case Common::KEYCODE_TAB:
-				key = 0x0009;
-				break;
-			case Common::KEYCODE_F1:
-				key = 0x3b00;
-				break;
-			case Common::KEYCODE_F2:
-				key = 0x3c00;
-				break;
-			case Common::KEYCODE_F3:
-				key = 0x3d00;
-				break;
-			case Common::KEYCODE_F4:
-				key = 0x3e00;
-				break;
-			case Common::KEYCODE_F5:
-				key = 0x3f00;
-				break;
-			case Common::KEYCODE_F6:
-				key = 0x4000;
-				break;
-			case Common::KEYCODE_F7:
-				key = 0x4100;
-				break;
-			case Common::KEYCODE_F8:
-				key = 0x4200;
-				break;
-			case Common::KEYCODE_F9:
-				key = 0x4300;
-				break;
-			case Common::KEYCODE_F10:
-				key = 0x4400;
-				break;
-			case Common::KEYCODE_F11:
-				key = KEY_STATUSLN;
-				break;
-			case Common::KEYCODE_F12:
-				key = KEY_PRIORITY;
-				break;
-			case Common::KEYCODE_ESCAPE:
-				key = 0x1b;
-				break;
-			case Common::KEYCODE_RETURN:
-			case Common::KEYCODE_KP_ENTER:
-				key = KEY_ENTER;
-				break;
-			case Common::KEYCODE_BACKSPACE:
-				key = KEY_BACKSPACE;
-				break;
-			default:
-				// Not a special key, so get the ASCII code for it
-				key = event.kbd.ascii;
-
-				if (Common::isAlpha(key)) {
-					// Key is A-Z.
-					// Map Ctrl-A to 1, Ctrl-B to 2, etc.
-					if (event.kbd.flags & Common::KBD_CTRL) {
-						key = toupper(key) - 'A' + 1;
-					} else if (event.kbd.flags & Common::KBD_ALT) {
-						// Map Alt-A, Alt-B etc. to special scancode values according to an internal scancode table.
-						key = scancodeTable[toupper(key) - 'A'] << 8;
-					}
-				}
-				break;
-			}
-			if (key)
-				keyEnqueue(key);
-			break;
-
-		case Common::EVENT_KEYUP:
-			if (_egoHoldKey)
-				_game.viewTable[0].direction = 0;
-
-		default:
-			break;
-		}
-	}
-}
-
 void AgiEngine::pollTimer() {
 	_lastTick += 50;
 
@@ -305,24 +73,14 @@ void AgiEngine::pollTimer() {
 void AgiEngine::pause(uint32 msec) {
 	uint32 endTime = _system->getMillis() + msec;
 
-	_gfx->setCursor(_renderMode == Common::kRenderAmiga, true);
+	_gfx->setMouseCursor(true); // Busy mouse cursor
 
 	while (_system->getMillis() < endTime) {
 		processEvents();
 		_system->updateScreen();
 		_system->delayMillis(10);
 	}
-	_gfx->setCursor(_renderMode == Common::kRenderAmiga);
-}
-
-void AgiEngine::initPriTable() {
-	int i, p, y = 0;
-
-	for (p = 1; p < 15; p++) {
-		for (i = 0; i < 12; i++) {
-			_game.priTable[y++] = p < 4 ? 4 : p;
-		}
-	}
+	_gfx->setMouseCursor(); // regular mouse cursor
 }
 
 int AgiEngine::agiInit() {
@@ -341,7 +99,7 @@ int AgiEngine::agiInit() {
 		_game.vars[i] = 0;
 
 	// clear all resources and events
-	for (i = 0; i < MAX_DIRS; i++) {
+	for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
 		memset(&_game.views[i], 0, sizeof(struct AgiView));
 		memset(&_game.pictures[i], 0, sizeof(struct AgiPicture));
 		memset(&_game.logics[i], 0, sizeof(struct AgiLogic));
@@ -353,15 +111,17 @@ int AgiEngine::agiInit() {
 	}
 
 	// clear view table
-	for (i = 0; i < MAX_VIEWTABLE; i++)
-		memset(&_game.viewTable[i], 0, sizeof(struct VtEntry));
+	for (i = 0; i < SCREENOBJECTS_MAX; i++)
+		memset(&_game.screenObjTable[i], 0, sizeof(struct ScreenObjEntry));
+
+	memset(&_game.addToPicView, 0, sizeof(struct ScreenObjEntry));
 
-	initWords();
+	_words->clearEgoWords();
 
 	if (!_menu)
-		_menu = new Menu(this, _gfx, _picture);
+		_menu = new GfxMenu(this, _gfx, _picture, _text);
 
-	initPriTable();
+	_gfx->initPriorityTable();
 
 	// Clear the string buffer on startup, but not when the game restarts, as
 	// some scripts expect that the game strings remain unaffected after a
@@ -394,10 +154,6 @@ int AgiEngine::agiInit() {
 	if (getFeatures() & GF_AGDS)
 		_game.gameFlags |= ID_AGDS;
 
-	// Make the 256 color AGI screen the default AGI screen when AGI256 or AGI256-2 is used
-	if (getFeatures() & (GF_AGI256 | GF_AGI256_2))
-		_game.sbuf = _game.sbuf256c;
-
 	if (_game.gameFlags & ID_AMIGA)
 		debug(1, "Amiga padded game detected.");
 
@@ -413,12 +169,9 @@ int AgiEngine::agiInit() {
 	if (ec == errOK)
 		ec = _loader->loadWords(WORDS);
 
-	// FIXME: load IIgs instruments and samples
-	// load_instruments("kq.sys16");
-
 	// Load logic 0 into memory
 	if (ec == errOK)
-		ec = _loader->loadResource(rLOGIC, 0);
+		ec = _loader->loadResource(RESOURCETYPE_LOGIC, 0);
 
 #ifdef __DS__
 	// Normally, the engine loads the predictive text dictionary when the predictive dialog
@@ -443,42 +196,42 @@ void AgiEngine::agiUnloadResources() {
 	int i;
 
 	// Make sure logic 0 is always loaded
-	for (i = 1; i < MAX_DIRS; i++) {
-		_loader->unloadResource(rLOGIC, i);
+	for (i = 1; i < MAX_DIRECTORY_ENTRIES; i++) {
+		_loader->unloadResource(RESOURCETYPE_LOGIC, i);
 	}
-	for (i = 0; i < MAX_DIRS; i++) {
-		_loader->unloadResource(rVIEW, i);
-		_loader->unloadResource(rPICTURE, i);
-		_loader->unloadResource(rSOUND, i);
+	for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
+		_loader->unloadResource(RESOURCETYPE_VIEW, i);
+		_loader->unloadResource(RESOURCETYPE_PICTURE, i);
+		_loader->unloadResource(RESOURCETYPE_SOUND, i);
 	}
 }
 
 int AgiEngine::agiDeinit() {
 	int ec;
 
-	cleanInput();		// remove all words from memory
+	_words->clearEgoWords();		// remove all words from memory
 	agiUnloadResources();	// unload resources in memory
-	_loader->unloadResource(rLOGIC, 0);
+	_loader->unloadResource(RESOURCETYPE_LOGIC, 0);
 	ec = _loader->deinit();
 	unloadObjects();
-	unloadWords();
+	_words->unloadDictionary();
 
 	clearImageStack();
 
 	return ec;
 }
 
-int AgiEngine::agiLoadResource(int r, int n) {
+int AgiEngine::agiLoadResource(int16 resourceType, int16 resourceNr) {
 	int i;
 
-	i = _loader->loadResource(r, n);
+	i = _loader->loadResource(resourceType, resourceNr);
 
 	// WORKAROUND: Patches broken picture 147 in a corrupted Amiga version of Gold Rush! (v2.05 1989-03-09).
 	// The picture can be seen in room 147 after dropping through the outhouse's hole in room 146.
-	if (i == errOK && getGameID() == GID_GOLDRUSH && r == rPICTURE && n == 147 && _game.dirPic[n].len == 1982) {
-		uint8 *pic = _game.pictures[n].rdata;
-		Common::MemoryReadStream picStream(pic, _game.dirPic[n].len);
-		Common::String md5str = Common::computeStreamMD5AsString(picStream, _game.dirPic[n].len);
+	if (i == errOK && getGameID() == GID_GOLDRUSH && resourceType == RESOURCETYPE_PICTURE && resourceNr == 147 && _game.dirPic[resourceNr].len == 1982) {
+		uint8 *pic = _game.pictures[resourceNr].rdata;
+		Common::MemoryReadStream picStream(pic, _game.dirPic[resourceNr].len);
+		Common::String md5str = Common::computeStreamMD5AsString(picStream, _game.dirPic[resourceNr].len);
 		if (md5str == "1c685eb048656cedcee4eb6eca2cecea") {
 			pic[0x042] = 0x4B; // 0x49 -> 0x4B
 			pic[0x043] = 0x66; // 0x26 -> 0x66
@@ -492,8 +245,8 @@ int AgiEngine::agiLoadResource(int r, int n) {
 	return i;
 }
 
-int AgiEngine::agiUnloadResource(int r, int n) {
-	return _loader->unloadResource(r, n);
+int AgiEngine::agiUnloadResource(int16 resourceType, int16 resourceNr) {
+	return _loader->unloadResource(resourceType, resourceNr);
 }
 
 struct GameSettings {
@@ -510,7 +263,8 @@ AgiBase::AgiBase(OSystem *syst, const AGIGameDescription *gameDesc) : Engine(sys
 	_rnd = new Common::RandomSource("agi");
 	_sound = 0;
 
-	_fontData = NULL;
+	_fontData = nullptr;
+	_fontDataAllocated = nullptr;
 
 	initFeatures();
 	initVersion();
@@ -520,30 +274,419 @@ AgiBase::~AgiBase() {
 	delete _rnd;
 
 	delete _sound;
+
+	if (_fontDataAllocated) {
+		free(_fontDataAllocated);
+	}
 }
 
 void AgiBase::initRenderMode() {
-	_renderMode = Common::kRenderEGA;
+	Common::Platform platform = Common::parsePlatform(ConfMan.get("platform"));
+	Common::RenderMode configRenderMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str());
+
+	// Default to EGA PC rendering
+	_renderMode = RENDERMODE_EGA;
+
+	switch (platform) {
+	case Common::kPlatformDOS:
+		switch (configRenderMode) {
+		case Common::kRenderCGA:
+			_renderMode = RENDERMODE_CGA;
+			break;
+		// Hercules is not supported atm
+		//case Common::kRenderHercA:
+		//case Common::kRenderHercG:
+		//	_renderMode = RENDERMODE_HERCULES;
+		//	break;
+		default:
+			break;
+		}
+		break;
+	case Common::kPlatformAmiga:
+		_renderMode = RENDERMODE_AMIGA;
+		break;
+	case Common::kPlatformApple2GS:
+		_renderMode = RENDERMODE_APPLE_II_GS;
+		break;
+	case Common::kPlatformAtariST:
+		_renderMode = RENDERMODE_ATARI_ST;
+		break;
+	default:
+		break;
+	}
 
-	if (ConfMan.hasKey("platform")) {
-		Common::Platform platform = Common::parsePlatform(ConfMan.get("platform"));
-		_renderMode = (platform == Common::kPlatformAmiga) ? Common::kRenderAmiga : Common::kRenderEGA;
+	// If render mode is explicitly set, force rendermode
+	switch (configRenderMode) {
+	case Common::kRenderAmiga:
+		_renderMode = RENDERMODE_AMIGA;
+		break;
+	case Common::kRenderApple2GS:
+		_renderMode = RENDERMODE_APPLE_II_GS;
+		break;
+	case Common::kRenderAtariST:
+		_renderMode = RENDERMODE_ATARI_ST;
+		break;
+	default:
+		break;
 	}
 
-	if (ConfMan.hasKey("render_mode")) {
-		Common::RenderMode tmpMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str());
-		if (tmpMode != Common::kRenderDefault)
-			_renderMode = tmpMode;
+	if (getFeatures() & (GF_AGI256 | GF_AGI256_2)) {
+		// If current game is AGI256, switch (force) to VGA render mode
+		_renderMode = RENDERMODE_VGA;
 	}
 }
 
+void AgiBase::initFont() {
+	// We are currently using the custom font for all fanmade games
+	if (getFeatures() & (GF_FANMADE | GF_AGDS)) {
+		// fanmade game, use custom font for now
+		_fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc.
+		return;
+	}
+
+	switch (_renderMode) {
+	case RENDERMODE_AMIGA:
+		loadFontAmigaPseudoTopaz();
+		//_fontData = fontData_Amiga; // use Amiga Topaz font
+		break;
+	case RENDERMODE_APPLE_II_GS:
+		// Special font, stored in file AGIFONT
+		loadFontAppleIIgs();
+		break;
+	case RENDERMODE_ATARI_ST:
+		// TODO: Atari ST uses another font
+		// Seems to be the standard Atari ST 8x8 system font
+
+	case RENDERMODE_CGA:
+	case RENDERMODE_EGA:
+	case RENDERMODE_VGA:
+		switch (getGameID()) {
+		case GID_MICKEY:
+			// load mickey mouse font from interpreter file
+			loadFontMickey();
+			break;
+		default:
+			break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	if (!_fontData) {
+		// no font asigned?
+		switch (getGameID()) {
+		case GID_MICKEY:
+		case GID_TROLL:
+		case GID_WINNIE:
+			// use IBM font for pre-AGI games as standard
+			_fontData = fontData_IBM;
+			break;
+		default:
+			// for everything else use Sierra PC font
+			_fontData = fontData_Sierra;
+			break;
+		}
+	}
+}
+
+// We load the Mickey Mouse font from MICKEY.EXE
+void AgiBase::loadFontMickey() {
+	Common::File interpreterFile;
+	int32 interpreterFileSize = 0;
+	byte *fontData = nullptr;
+
+	if (!interpreterFile.open("mickey.exe")) {
+		// Continue, if file not found
+		return;
+	}
+
+	interpreterFileSize = interpreterFile.size();
+	if (interpreterFileSize != 55136) {
+		// unexpected file size
+		interpreterFile.close();
+		warning("mickey.exe unexpected file size");
+		return;
+	}
+	interpreterFile.seek(32476); // offset of font data
+
+	// allocate space for font bitmap data
+	fontData = (uint8 *)calloc(256, 8);
+	_fontData = fontData;
+	_fontDataAllocated = fontData;
+ 
+	// read font data, is already in the format that we need (plain bitmap 8x8)
+	interpreterFile.read(fontData, 256 * 8);
+	interpreterFile.close();
+}
+
+// we create a bitmap out of the topaz data used in parallaction (which is normally found in staticres.cpp)
+// it's a recreation of the Amiga Topaz font but not really accurate
+void AgiBase::loadFontAmigaPseudoTopaz() {
+	const byte *topazStart = fontData_AmigaPseudoTopaz + 32;
+	const byte *topazHeader = topazStart + 78;
+	const byte *topazData = nullptr;
+	const byte *topazLocations = nullptr;
+	byte *fontData = nullptr;
+	uint16 topazHeight = 0;
+	uint16 topazWidth = 0;
+	uint16 topazModulo = 0;
+	uint32 topazDataOffset = 0;
+	uint32 topazLocationOffset = 0;
+	byte   topazLowChar = 0;
+	byte   topazHighChar = 0;
+	uint16 topazTotalChars = 0;
+	uint16 topazBitLength = 0;
+	uint16 topazBitOffset = 0;
+	uint16 topazByteOffset = 0;
+
+	// allocate space for font bitmap data
+	fontData = (uint8 *)calloc(256, 8);
+	_fontData = fontData;
+	_fontDataAllocated = fontData;
+
+	topazHeight = READ_BE_UINT16(topazHeader + 0);
+	topazWidth = READ_BE_UINT16(topazHeader + 4);
+
+	// we expect 8x8
+	assert(topazHeight == 8);
+	assert(topazWidth == 8);
+
+	topazLowChar = topazHeader[12];
+	topazHighChar = topazHeader[13];
+	topazTotalChars = topazHighChar - topazLowChar + 1;
+	topazDataOffset = READ_BE_UINT32(topazHeader + 14);
+	topazModulo = READ_BE_UINT16(topazHeader + 18);
+	topazLocationOffset = READ_BE_UINT32(topazHeader + 20);
+
+	// Security checks
+	assert(topazLowChar == ' ');
+	assert(topazHighChar == 0xFF);
+
+	// copy first 32 characters over
+	memcpy(fontData, fontData_Sierra, FONT_DISPLAY_WIDTH * 32);
+	fontData += FONT_DISPLAY_WIDTH * 32;
+
+	// now actually convert from topaz data
+	topazData = topazStart + topazDataOffset;
+	topazLocations = topazStart + topazLocationOffset;
+
+	for (uint16 curChar = 0; curChar < topazTotalChars; curChar++) {
+		topazBitOffset = READ_BE_UINT16(topazLocations + (curChar * 4) + 0);
+		topazBitLength = READ_BE_UINT16(topazLocations + (curChar * 4) + 2);
+
+		if (topazBitLength == 8) {
+			assert((topazBitOffset & 7) == 0);
+
+			topazByteOffset = topazBitOffset >> 3;
+			for (uint16 curHeight = 0; curHeight < topazHeight; curHeight++) {
+				*fontData = topazData[topazByteOffset];
+				fontData++;
+				topazByteOffset += topazModulo;
+			}
+		} else {
+			memset(fontData, 0, 8);
+			fontData += 8;
+		}
+	}
+}
+
+void AgiBase::loadFontAppleIIgs() {
+	Common::File fontFile;
+	uint16 headerIIgs_OffsetMacHeader = 0;
+	uint16 headerIIgs_Version = 0;
+	uint16 macRecord_FirstChar = 0;
+	uint16 macRecord_LastChar = 0;
+	int16 macRecord_MaxKern = 0;
+	uint16 macRecord_RectHeight = 0;
+	uint16 macRecord_StrikeWidth = 0;
+	uint16 strikeDataLen = 0;
+	byte *strikeDataPtr = nullptr;
+	uint16 actualCharacterCount = 0;
+	uint16 totalCharacterCount = 0;
+	uint16 *locationTablePtr = nullptr;
+	uint16 *offsetWidthTablePtr = nullptr;
+
+	uint16 curCharNr = 0;
+	uint16 curRow = 0;
+	uint16 curLocation = 0;
+	uint16 curLocationBytes = 0;
+	uint16 curLocationBits = 0;
+	uint16 curCharOffsetWidth = 0;
+	uint16 curCharOffset = 0;
+	uint16 curCharWidth = 0;
+	uint16 curStrikeWidth = 0;
+
+	uint16 curPixelNr = 0;
+	uint16 curBitMask = 0;
+	int16 positionAdjust = 0;
+	byte curByte = 0;
+	byte fontByte = 0;
+
+	uint16 strikeRowOffset = 0;
+	uint16 strikeCurOffset = 0;
+
+	byte *fontData = nullptr;
+
+	if (!fontFile.open("agifont")) {
+		// Continue,
+		// This also happens when the user selected Apple IIgs as render for the palette for non-AppleIIgs games
+		warning("could not open agifont for Apple IIgs font");
+		return;
+	}
+
+	// Apple IIgs header
+	headerIIgs_OffsetMacHeader = fontFile.readUint16LE();
+	fontFile.skip(2); // font family
+	fontFile.skip(2); // font style
+	fontFile.skip(2); // point size
+	headerIIgs_Version = fontFile.readUint16LE();
+	fontFile.skip(2); // bounds type
+	// end of Apple IIgs header
+	// Macintosh font record
+	fontFile.skip(2); // font type
+	macRecord_FirstChar = fontFile.readUint16LE();
+	macRecord_LastChar = fontFile.readUint16LE();
+	fontFile.skip(2); // max width
+	macRecord_MaxKern = fontFile.readSint16LE();
+	fontFile.skip(2); // negative descent
+	fontFile.skip(2); // rect width
+	macRecord_RectHeight = fontFile.readUint16LE();
+	fontFile.skip(2); // low word ptr table
+	fontFile.skip(2); // font ascent
+	fontFile.skip(2); // font descent
+	fontFile.skip(2); // leading
+	macRecord_StrikeWidth = fontFile.readUint16LE();
+
+	// security-checks
+	if (headerIIgs_OffsetMacHeader != 6)
+		error("AppleIIgs-font: unexpected header");
+	if (headerIIgs_Version != 0x0101)
+		error("AppleIIgs-font: not a 1.1 font");
+	if ((macRecord_FirstChar != 0) || (macRecord_LastChar != 255))
+		error("AppleIIgs-font: unexpected characters");
+	if (macRecord_RectHeight != 8)
+		error("AppleIIgs-font: expected 8x8 font");
+
+	// Calculate table sizes
+	strikeDataLen = macRecord_StrikeWidth * macRecord_RectHeight * 2;
+	actualCharacterCount = (macRecord_LastChar - macRecord_FirstChar + 1);
+	totalCharacterCount = actualCharacterCount + 2; // replacement-char + extra character
+
+	// Allocate memory for tables
+	strikeDataPtr = (byte *)calloc(strikeDataLen, 1);
+	locationTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // 1 word per character
+	offsetWidthTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // ditto
+
+	// read tables
+	fontFile.read(strikeDataPtr, strikeDataLen);
+	for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+		locationTablePtr[curCharNr] = fontFile.readUint16LE();
+	}
+	for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+		offsetWidthTablePtr[curCharNr] = fontFile.readUint16LE();
+	}
+	fontFile.close();
+
+	// allocate space for font bitmap data
+	fontData = (uint8 *)calloc(256, 8);
+	_fontData = fontData;
+	_fontDataAllocated = fontData;
+
+	// extract font bitmap data
+	for (curCharNr = 0; curCharNr < actualCharacterCount; curCharNr++) {
+		curCharOffsetWidth = offsetWidthTablePtr[curCharNr];
+		curLocation = locationTablePtr[curCharNr];
+		if (curCharOffsetWidth == 0xFFFF) {
+			// character does not exist in font, use replacement character instead
+			curCharOffsetWidth = offsetWidthTablePtr[actualCharacterCount];
+			curLocation = locationTablePtr[actualCharacterCount];
+			curStrikeWidth = locationTablePtr[actualCharacterCount + 1] - curLocation;
+		} else {
+			curStrikeWidth = locationTablePtr[curCharNr + 1] - curLocation;
+		}
+
+		// Figure out bytes + bits location
+		curLocationBytes = curLocation >> 3;
+		curLocationBits = curLocation & 0x0007;
+		curCharWidth = curCharOffsetWidth & 0x00FF; // isolate width
+		curCharOffset = curCharOffsetWidth >> 8; // isolate offset
+
+		if (!curCharWidth) {
+			fontData += 8; // skip over this character
+			continue;
+		}
+
+		if (curCharWidth != 8) {
+			if (curCharNr != 0x3B)
+				error("AppleIIgs-font: expected 8x8 font");
+		}
+
+		// Get all rows of the current character
+		strikeRowOffset = 0;
+		for (curRow = 0; curRow < macRecord_RectHeight; curRow++) {
+			strikeCurOffset = strikeRowOffset + curLocationBytes;
+
+			// Copy over bits
+			fontByte = 0;
+			curByte = strikeDataPtr[strikeCurOffset];
+			curBitMask = 0x80 >> curLocationBits;
+
+			for (curPixelNr = 0; curPixelNr < curStrikeWidth; curPixelNr++) {
+				fontByte = fontByte << 1;
+				if (curByte & curBitMask) {
+					fontByte |= 0x01;
+				}
+				curBitMask = curBitMask >> 1;
+				if (!curBitMask) {
+					curByte = strikeDataPtr[strikeCurOffset + 1];
+					curBitMask = 0x80;
+				}
+			}
+
+			// adjust, so that it's aligned to the left (starting at 0x80 bit)
+			fontByte = fontByte << (8 - curStrikeWidth);
+
+			// now adjust according to offset + MaxKern
+			positionAdjust = macRecord_MaxKern + curCharOffset;
+
+			// adjust may be negative for space, or 8 for "empty" characters
+			if (positionAdjust > 8)
+				error("AppleIIgs-font: invalid character spacing");
+
+			if (positionAdjust < 0) {
+				// negative adjust strangely happens for empty characters like space
+				if (curStrikeWidth)
+					error("AppleIIgs-font: invalid character spacing");
+			}
+
+			if (positionAdjust > 0) {
+				// move the amount of pixels to the right
+				fontByte = fontByte >> positionAdjust;
+			}
+
+			*fontData = fontByte;
+			fontData++;
+
+			strikeRowOffset += macRecord_StrikeWidth * 2;
+		}
+	}
+
+	free(offsetWidthTablePtr);
+	free(locationTablePtr);
+	free(strikeDataPtr);
+
+	// overwrite character 0x1A with the standard Sierra arrow to the right character
+	// required for the original save/restore dialogs
+	memcpy(_fontDataAllocated + (0x1A * 8), fontData_ArrowRightCharacter, sizeof(fontData_ArrowRightCharacter));
+}
+
 AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBase(syst, gameDesc) {
 
 	// Setup mixer
 	syncSoundSettings();
 
-	parseFeatures();
-
 	DebugMan.addDebugChannel(kDebugLevelMain, "Main", "Generic debug level");
 	DebugMan.addDebugChannel(kDebugLevelResources, "Resources", "Resources debugging");
 	DebugMan.addDebugChannel(kDebugLevelSprites, "Sprites", "Sprites debugging");
@@ -561,20 +704,21 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
 	memset(&_mouse, 0, sizeof(struct Mouse));
 
 	_game.mouseEnabled = true;
+	_game.mouseHidden = false;
+	// don't check for Amiga, Amiga doesn't allow disabling mouse support. It's mandatory.
 	if (!ConfMan.getBool("mousesupport")) {
 		// we effectively disable the mouse for games, that explicitly do not want mouse support to be enabled
 		_game.mouseEnabled = false;
+		_game.mouseHidden = true;
 	}
 
-	// We are currently using the custom font for all fanmade games
-	if (!(getFeatures() & (GF_FANMADE | GF_AGDS))) {
-		_fontData = fontData_Sierra; // original Sierra font
-	} else {
-		_fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc.
-	}
+	_fontData = nullptr;
+	_fontDataAllocated = nullptr;
 
 	_game._vm = this;
 
+	_game.gfxMode = true;
+
 	_game.clockEnabled = false;
 	_game.state = STATE_INIT;
 
@@ -585,17 +729,13 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
 
 	_intobj = NULL;
 
-	_menu = NULL;
-	_menuSelected = false;
-
-	_lastSentence[0] = 0;
 	memset(&_stringdata, 0, sizeof(struct StringData));
 
 	_objects = NULL;
 
 	_restartGame = false;
 
-	_oldMode = INPUT_NONE;
+	_oldMode = INPUTMODE_NONE;
 
 	_firstSlot = 0;
 
@@ -609,16 +749,17 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
 	_lastTick = 0;
 
 	memset(_keyQueue, 0, sizeof(_keyQueue));
-	memset(_predictiveResult, 0, sizeof(_predictiveResult));
 
+	_text = NULL;
 	_sprites = NULL;
 	_picture = NULL;
 	_loader = NULL;
 	_console = NULL;
+	_menu = NULL;
+	_gfx = NULL;
+	_systemUI = NULL;
 
 	_egoHoldKey = false;
-
-
 }
 
 void AgiEngine::initialize() {
@@ -657,29 +798,28 @@ void AgiEngine::initialize() {
 	}
 
 	initRenderMode();
+	initFont();
 
-	_buttonStyle = AgiButtonStyle(_renderMode);
-	_defaultButtonStyle = AgiButtonStyle();
 	_console = new Console(this);
+	_words = new Words(this);
 	_gfx = new GfxMgr(this);
 	_sound = new SoundMgr(this, _mixer);
 	_picture = new PictureMgr(this, _gfx);
 	_sprites = new SpritesMgr(this, _gfx);
+	_text = new TextMgr(this, _words, _gfx);
+	_systemUI = new SystemUI(this, _gfx, _text);
+	_inventory = new InventoryMgr(this, _gfx, _text, _systemUI);
+
+	_text->init(_systemUI);
 
 	_gfx->initMachine();
 
 	_game.gameFlags = 0;
 
-	_game.colorFg = 15;
-	_game.colorBg = 0;
+	_text->charAttrib_Set(15, 0);
 
 	_game.name[0] = '\0';
 
-	_game.sbufOrig = (uint8 *)calloc(_WIDTH, _HEIGHT * 2); // Allocate space for two AGI screens vertically
-	_game.sbuf16c  = _game.sbufOrig + SBUF16_OFFSET; // Make sbuf16c point to the 16 color (+control line & priority info) AGI screen
-	_game.sbuf256c = _game.sbufOrig + SBUF256_OFFSET; // Make sbuf256c point to the 256 color AGI screen
-	_game.sbuf     = _game.sbuf16c; // Make sbuf point to the 16 color (+control line & priority info) AGI screen by default
-
 	_gfx->initVideo();
 
 	_lastSaveTime = 0;
@@ -698,6 +838,30 @@ void AgiEngine::initialize() {
 	debugC(2, kDebugLevelMain, "Init sound");
 }
 
+bool AgiEngine::promptIsEnabled() {
+	return _text->promptIsEnabled();
+}
+
+void AgiEngine::redrawScreen() {
+	_game.gfxMode = true; // enable graphics mode
+	_gfx->setPalette(true); // set graphics mode palette
+	_text->charAttrib_Set(_text->_textAttrib.foreground, _text->_textAttrib.background);
+	_gfx->clearDisplay(0);
+	_picture->showPic();
+	_text->statusDraw();
+	_text->promptRedraw();
+}
+
+// Adjust a given coordinate to the local game screen
+// Used on mouse cursor coordinates before passing them to scripts
+void AgiEngine::adjustPosToGameScreen(int16 &x, int16 &y) {
+	x = x / 2; // 320 -> 160
+	y = y - 8; // remove status bar line
+	if (y >= SCRIPT_HEIGHT) {
+		y = SCRIPT_HEIGHT + 1; // 1 beyond
+	}
+}
+
 AgiEngine::~AgiEngine() {
 	// If the engine hasn't been initialized yet via
 	// AgiEngine::initialize(), don't attempt to free any resources, as
@@ -710,22 +874,25 @@ AgiEngine::~AgiEngine() {
 	agiDeinit();
 	delete _loader;
 	_gfx->deinitVideo();
+	delete _inventory;
+	delete _systemUI;
+	delete _text;
 	delete _sprites;
 	delete _picture;
-	free(_game.sbufOrig);
 	_gfx->deinitMachine();
 	delete _gfx;
+	delete _words;
 	delete _console;
 }
 
 Common::Error AgiBase::init() {
 
 	// Initialize backend
-	initGraphics(320, 200, false);
+	//initGraphics(320, 200, false);
 
 	initialize();
 
-	_gfx->gfxSetPalette();
+	_gfx->setPalette(true);
 
 	return Common::kNoError;
 }
@@ -747,74 +914,68 @@ Common::Error AgiEngine::go() {
 	return Common::kNoError;
 }
 
-void AgiEngine::parseFeatures() {
-
-	/* FIXME: Seems this method doesn't really do anything. It might
-	   be a leftover that could be removed, except that some of its
-	   intended purpose may still need to be reimplemented.
-
-	[0:29] <Fingolfin> can you tell me what the point behind AgiEngine::parseFeatures() is?
-	[0:30] <_sev> when games are created with WAGI studio
-	[0:31] <_sev> it creates .wag site with game-specific features such as full game title, whether to use AGIMOUSE etc
-	[0:32] <Fingolfin> ... and the "features" config key is created by our detector based on the wag file, I guess?
-	[0:33] <_sev> yes
-	[0:33] <Fingolfin> it's just that I cant seem to find a place we do that
-	[0:33] <_sev> it is used for fallback
-	[0:34] <_sev> ah, perhaps it was not updated
-	[0:34] <Fingolfin> I only see us check the value, but never set it
-	[0:34] <Fingolfin> maybe I am grepping wrong, who knows :)
-	[0:44] <Fingolfin> _sev: so, unless I miss something, it seem that function does nothing right now
-	[0:45] <_sev> Fingolfin: it could be unfinished. It was part of GSoC 3 years ago
-	[0:45] <Fingolfin> well
-	[0:45] <_sev> I just don't remember
-	[0:45] <Fingolfin> but don't we just re-parse the wag when the game is loaded anyway?
-	[0:45] <_sev> but it documents the format
-	[0:45] <Fingolfin> the advanced meta engine would re-run the detector, wouldn't it?
-	[0:45] <_sev> yep
-	[0:47] <Fingolfin> so... shouldn't we at least add a comment to the function explaining what it does and that it's unfinished etc.? maybe add a TODO to the wiki?
-	[0:47] <Fingolfin> otherwise it might stay as it is for another 3 years :)
-	*/
-
-	if (!ConfMan.hasKey("features"))
-		return;
+// Scenes that need this:
+//
+// Manhunter 1:
+//  - intro text screen (DrawPic)
+//  - MAD "zooming in..." during intro and other scenes, for example room 124 (NewRoom)
+//     The NewRoom call is not done during the same cycle as the "zooming in..." print call.
+// Space Quest 1:
+//  - right at the start of the game (NewRoom)
+// Space Quest 2
+//  - right at the start of the game (NewRoom)
+//  - after exiting the very first room, a message pops up, that isn't readable without it (NewRoom)
+
+
+// Games, that must not be triggered:
+//
+// Fanmade Voodoo Girl:
+//  - waterfall (DrawPic, room 17)
+//  - inside shop (NewRoom, changes to same room every new button, room 4)
+
+void AgiEngine::nonBlockingText_IsShown() {
+	_game.nonBlockingTextShown = true;
+	_game.nonBlockingTextCyclesLeft = 2; // 1 additional script cycle is counted too
+}
+void AgiEngine::nonBlockingText_Forget() {
+	_game.nonBlockingTextShown = false;
+	_game.nonBlockingTextCyclesLeft = 0;
+}
+void AgiEngine::nonBlockingText_CycleDone() {
+	if (_game.nonBlockingTextCyclesLeft) {
+		_game.nonBlockingTextCyclesLeft--;
+
+		if (!_game.nonBlockingTextCyclesLeft) {
+			// cycle count expired, we assume that non-blocking text won't be a problem for room / pic change
+			_game.nonBlockingTextShown = false;
+		}
+	}
+}
 
-	char *features = strdup(ConfMan.get("features").c_str());
-	const char *feature[100];
-	int numFeatures = 0;
+void AgiEngine::loadingTrigger_NewRoom(int16 newRoomNr) {
+	if (_game.nonBlockingTextShown) {
+		_game.nonBlockingTextShown = false;
 
-	char *tok = strtok(features, " ");
-	if (tok) {
-		do {
-			feature[numFeatures++] = tok;
-		} while ((tok = strtok(NULL, " ")) != NULL);
-	} else {
-		feature[numFeatures++] = features;
-	}
-
-	const struct Flags {
-		const char *name;
-		uint32 flag;
-	} flags[] = {
-		{ "agimouse", GF_AGIMOUSE },
-		{ "agds", GF_AGDS },
-		{ "agi256", GF_AGI256 },
-		{ "agi256-2", GF_AGI256_2 },
-		{ "agipal", GF_AGIPAL },
-		{ 0, 0 }
-	};
-
-	for (int i = 0; i < numFeatures; i++) {
-		for (const Flags *flag = flags; flag->name; flag++) {
-			if (!scumm_stricmp(feature[i], flag->name)) {
-				debug(2, "Added feature: %s", flag->name);
-
-				setFeature(flag->flag);
-				break;
+		int16 curRoomNr = _game.vars[VM_VAR_CURRENT_ROOM];
+
+		if (newRoomNr != curRoomNr) {
+			if (!_game.automaticRestoreGame) {
+				// wait a bit, we detected non-blocking text
+				pause(2000); // 2 seconds
 			}
 		}
 	}
+}
+
+void AgiEngine::loadingTrigger_DrawPicture() {
+	if (_game.nonBlockingTextShown) {
+		_game.nonBlockingTextShown = false;
 
-	free(features);
+		if (!_game.automaticRestoreGame) {
+			// wait a bit, we detected non-blocking text
+			pause(2000); // 2 seconds
+		}
+	}
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 04e02dc..fd44afd 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -79,14 +79,18 @@ typedef signed int Err;
 #define OBJECTS		"object"
 #define WORDS		"words.tok"
 
-#define	MAX_DIRS	256
+#define MAX_DIRECTORY_ENTRIES 256
+#define	MAX_CONTROLLERS	256
 #define	MAX_VARS	256
 #define	MAX_FLAGS	(256 >> 3)
-#define MAX_VIEWTABLE	255	// KQ3 uses o255!
+#define SCREENOBJECTS_MAX	255	// KQ3 uses o255!
+#define SCREENOBJECTS_EGO_ENTRY 0 // first entry is ego
 #define MAX_WORDS	20
 #define	MAX_STRINGS	24		// MAX_STRINGS + 1 used for get.num
 #define MAX_STRINGLEN	40
-#define MAX_CONTROLLERS 39
+#define MAX_CONTROLLER_KEYMAPPINGS 39
+
+#define SAVEDGAME_DESCRIPTION_LEN 30
 
 #define	_EMPTY		0xfffff
 #define	EGO_OWNED	0xff
@@ -95,13 +99,6 @@ typedef signed int Err;
 #define	CRYPT_KEY_SIERRA	"Avis Durgan"
 #define CRYPT_KEY_AGDS		"Alex Simkin"
 
-#define	MSG_BOX_COLOR	0x0f	// White
-#define MSG_BOX_TEXT	0x00	// Black
-#define MSG_BOX_LINE	0x04	// Red
-#define BUTTON_BORDER	0x00	// Black
-#define STATUS_FG	0x00		// Black
-#define	STATUS_BG	0x0f		// White
-
 #define ADD_PIC 1
 #define ADD_VIEW 2
 
@@ -128,7 +125,7 @@ enum AgiGameID {
 	GID_GETOUTTASQ,	// Fanmade
 	GID_MICKEY,			// PreAGI
 	GID_WINNIE,			// PreAGI
-	GID_TROLL				// PreAGI
+	GID_TROLL			// PreAGI
 };
 
 enum AgiGameType {
@@ -143,6 +140,16 @@ enum AgiGameType {
 	 BooterDisk2 = 1
  };
 
+enum AgiRenderMode {
+	RENDERMODE_EGA = 0,
+	RENDERMODE_CGA = 1,
+	RENDERMODE_VGA = 2,
+	RENDERMODE_HERCULES = 3,
+	RENDERMODE_AMIGA = 4,
+	RENDERMODE_APPLE_II_GS = 5,
+	RENDERMODE_ATARI_ST = 6
+};
+
 //
 // GF_OLDAMIGAV20 means that the interpreter is an old Amiga AGI interpreter that
 // uses value 20 for the computer type (v20 i.e. vComputer) rather than the usual value 5.
@@ -206,15 +213,17 @@ enum kDebugLevels {
  * AGI resources.
  */
 enum {
-	rLOGIC = 1,
-	rSOUND,
-	rVIEW,
-	rPICTURE
+	RESOURCETYPE_LOGIC = 1,
+	RESOURCETYPE_SOUND,
+	RESOURCETYPE_VIEW,
+	RESOURCETYPE_PICTURE
 };
 
 enum {
-	RES_LOADED = 1,
-	RES_COMPRESSED = 0x40
+	RES_LOADED                 = 0x01,
+	RES_COMPRESSED             = 0x40,
+	RES_PICTURE_V3_NIBBLE_PARM = 0x80  // Flag that gets set for picture resources,
+	                                   // which use a nibble instead of a byte as F0+F2 parameters
 };
 
 enum {
@@ -244,44 +253,37 @@ enum AgiMouseButton {
 	kAgiMouseButtonMiddle // Middle mouse button
 };
 
-enum GameId {
-	GID_AGI = 1
-};
-
-#define WIN_TO_PIC_X(x) ((x) / 2)
-#define WIN_TO_PIC_Y(y) ((y) < 8 ? 999 : (y) >= (8 + _HEIGHT) ? 999 : (y) - 8)
-
 /**
  * AGI variables.
  */
 enum {
-	vCurRoom = 0,		// 0
-	vPrevRoom,
-	vBorderTouchEgo,
-	vScore,
-	vBorderCode,
-	vBorderTouchObj,	// 5
-	vEgoDir,
-	vMaxScore,
-	vFreePages,
-	vWordNotFound,
-	vTimeDelay,		// 10
-	vSeconds,
-	vMinutes,
-	vHours,
-	vDays,
-	vJoystickSensitivity,	// 15
-	vEgoViewResource,
-	vAgiErrCode,
-	vAgiErrCodeInfo,
-	vKey,
-	vComputer,		// 20
-	vWindowReset,
-	vSoundgen,
-	vVolume,
-	vMaxInputChars,
-	vSelItem,		// 25
-	vMonitor
+	VM_VAR_CURRENT_ROOM = 0,		// 0
+	VM_VAR_PREVIOUS_ROOM,			// 1
+	VM_VAR_BORDER_TOUCH_EGO,		// 2
+	VM_VAR_SCORE,					// 3
+	VM_VAR_BORDER_CODE,				// 4
+	VM_VAR_BORDER_TOUCH_OBJECT,		// 5
+	VM_VAR_EGO_DIRECTION,			// 6
+	VM_VAR_MAX_SCORE,				// 7
+	VM_VAR_FREE_PAGES,				// 8
+	VM_VAR_WORD_NOT_FOUND,			// 9
+	VM_VAR_TIME_DELAY,				// 10
+	VM_VAR_SECONDS,					// 11
+	VM_VAR_MINUTES,					// 12
+	VM_VAR_HOURS,					// 13
+	VM_VAR_DAYS,					// 14
+	VM_VAR_JOYSTICK_SENSITIVITY,	// 15
+	VM_VAR_EGO_VIEW_RESOURCE,		// 16
+	VM_VAR_AGI_ERROR_CODE,			// 17
+	VM_VAR_AGI_ERROR_INFO,			// 18
+	VM_VAR_KEY,						// 19
+	VM_VAR_COMPUTER,				// 20
+	VM_VAR_WINDOW_RESET,			// 21
+	VM_VAR_SOUNDGENERATOR,			// 22
+	VM_VAR_VOLUME,					// 23
+	VM_VAR_MAX_INPUT_CHARACTERS,	// 24
+	VM_VAR_SELECTED_INVENTORY_ITEM,	// 25
+	VM_VAR_MONITOR					// 26
 };
 
 /**
@@ -335,33 +337,28 @@ enum AgiSoundType {
  * AGI flags
  */
 enum {
-	fEgoWater = 0,	// 0
-	fEgoInvisible,
-	fEnteredCli,
-	fEgoTouchedP2,
-	fSaidAcceptedInput,
-	fNewRoomExec,	// 5
-	fRestartGame,
-	fScriptBlocked,
-	fJoySensitivity,
-	fSoundOn,
-	fDebuggerOn,		// 10
-	fLogicZeroFirsttime,
-	fRestoreJustRan,
-	fStatusSelectsItems,
-	fMenusWork,
-	fOutputMode,		// 15
-	fAutoRestart
-};
-
-enum AgiSlowliness {
-	kPauseRoom = 1500,
-	kPausePicture = 500
-};
-
-struct AgiController {
+	VM_FLAG_EGO_WATER = 0,	// 0
+	VM_FLAG_EGO_INVISIBLE,
+	VM_FLAG_ENTERED_CLI,
+	VM_FLAG_EGO_TOUCHED_P2,
+	VM_FLAG_SAID_ACCEPTED_INPUT,
+	VM_FLAG_NEW_ROOM_EXEC,	// 5
+	VM_FLAG_RESTART_GAME,
+	VM_FLAG_SCRIPT_BLOCKED,
+	VM_FLAG_JOY_SENSITIVITY,
+	VM_FLAG_SOUND_ON,
+	VM_FLAG_DEBUGGER_ON,		// 10
+	VM_FLAG_LOGIC_ZERO_FIRST_TIME,
+	VM_FLAG_RESTORE_JUST_RAN,
+	VM_FLAG_STATUS_SELECTS_ITEMS,
+	VM_FLAG_MENUS_WORK,
+	VM_FLAG_OUTPUT_MODE,		// 15
+	VM_FLAG_AUTO_RESTART
+};
+
+struct AgiControllerKeyMapping {
 	uint16 keycode;
-	uint8 controller;
+	byte   controllerSlot;
 };
 
 struct AgiObject {
@@ -369,11 +366,6 @@ struct AgiObject {
 	char *name;
 };
 
-struct AgiWord {
-	int id;
-	char *word;
-};
-
 struct AgiDir {
 	uint8 volume;
 	uint32 offset;
@@ -389,122 +381,9 @@ struct AgiDir {
 };
 
 struct AgiBlock {
-	int active;
-	int x1, y1;
-	int x2, y2;
-	uint8 *buffer;		// used for window background
-};
-
-/** AGI text color (Background and foreground color). */
-struct AgiTextColor {
-	/** Creates an AGI text color. Uses black text on white background by default. */
-	AgiTextColor(int fgColor = 0x00, int bgColor = 0x0F) : fg(fgColor), bg(bgColor) {}
-
-	/** Get an AGI text color with swapped foreground and background color. */
-	AgiTextColor swap() const { return AgiTextColor(bg, fg); }
-
-	int fg; ///< Foreground color (Used for text).
-	int bg; ///< Background color (Used for text's background).
-};
-
-/**
- * AGI button style (Amiga or PC).
- *
- * Supports positive and negative button types (Used with Amiga-style only):
- * Positive buttons do what the dialog was opened for.
- * Negative buttons cancel what the dialog was opened for.
- * Restart-dialog example: Restart-button is positive, Cancel-button negative.
- * Paused-dialog example: Continue-button is positive.
- */
-struct AgiButtonStyle {
-// Public constants etc
-public:
-	static const int
-		// Amiga colors (Indexes into the Amiga-ish palette)
-		amigaBlack  = 0x00, ///< Accurate,                   is          #000000 (24-bit RGB)
-		amigaWhite  = 0x0F, ///< Practically accurate,       is close to #FFFFFF (24-bit RGB)
-		amigaGreen  = 0x02, ///< Quite accurate,             should be   #008A00 (24-bit RGB)
-		amigaOrange = 0x0C, ///< Inaccurate, too much blue,  should be   #FF7500 (24-bit RGB)
-		amigaPurple = 0x0D, ///< Inaccurate, too much green, should be   #FF00FF (24-bit RGB)
-		amigaRed    = 0x04, ///< Quite accurate,             should be   #BD0000 (24-bit RGB)
-		amigaCyan   = 0x0B, ///< Inaccurate, too much red,   should be   #00FFDE (24-bit RGB)
-		// PC colors (Indexes into the EGA-palette)
-		pcBlack     = 0x00,
-		pcWhite     = 0x0F;
-
-// Public methods
-public:
-	/**
-	 * Get the color of the button with the given state and type using current style.
-	 *
-	 * @param hasFocus True if button has focus, false otherwise.
-	 * @param pressed True if button is being pressed, false otherwise.
-	 * @param positive True if button is positive, false if button is negative. Only matters for Amiga-style buttons.
-	 */
-	AgiTextColor getColor(bool hasFocus, bool pressed, bool positive = true) const;
-
-	/**
-	 * Get the color of a button with the given base color and state ignoring current style.
-	 * Swaps foreground and background color when the button has focus or is being pressed.
-	 *
-	 * @param hasFocus True if button has focus, false otherwise.
-	 * @param pressed True if button is being pressed, false otherwise.
-	 * @param baseFgColor Foreground color of the button when it has no focus and is not being pressed.
-	 * @param baseBgColor Background color of the button when it has no focus and is not being pressed.
-	 */
-	AgiTextColor getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const;
-
-	/**
-	 * Get the color of a button with the given base color and state ignoring current style.
-	 * Swaps foreground and background color when the button has focus or is being pressed.
-	 *
-	 * @param hasFocus True if button has focus, false otherwise.
-	 * @param pressed True if button is being pressed, false otherwise.
-	 * @param baseColor Color of the button when it has no focus and is not being pressed.
-	 */
-	AgiTextColor getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const;
-
-	/**
-	 * How many pixels to offset the shown text diagonally down and to the right.
-	 * Currently only used for pressed PC-style buttons.
-	 */
-	int getTextOffset(bool hasFocus, bool pressed) const;
-
-	/**
-	 * Show border around the button?
-	 * Currently border is only used for in focus or pressed Amiga-style buttons
-	 * when in inauthentic Amiga-style mode.
-	 */
-	bool getBorder(bool hasFocus, bool pressed) const;
-
-	/**
-	 * Set Amiga-button style.
-	 *
-	 * @param amigaStyle Set Amiga-button style if true, otherwise set PC-button style.
-	 * @param olderAgi If true then use older AGI style in Amiga-mode, otherwise use newer.
-	 * @param authenticAmiga If true then don't use a border around buttons in Amiga-mode, otherwise use.
-	 */
-	void setAmigaStyle(bool amigaStyle = true, bool olderAgi = false, bool authenticAmiga = false);
-
-	/**
-	 * Set PC-button style.
-	 * @param pcStyle Set PC-button style if true, otherwise set default Amiga-button style.
-	 */
-	void setPcStyle(bool pcStyle = true);
-
-// Public constructors
-public:
-	/**
-	 * Create a button style based on the given rendering mode.
-	 * @param renderMode If Common::kRenderAmiga then creates default Amiga-button style, otherwise PC-style.
-	 */
-	AgiButtonStyle(Common::RenderMode renderMode = Common::kRenderDefault);
-
-// Private member variables
-private:
-	bool _amigaStyle;     ///< Use Amiga-style buttons if true, otherwise use PC-style buttons.
-	bool _olderAgi;       ///< Use older AGI style in Amiga-style mode.
-	bool _authenticAmiga; ///< Don't use border around buttons in Amiga-style mode.
+	bool active;
+	int16 x1, y1;
+	int16 x2, y2;
 };
 
 struct ScriptPos {
@@ -512,18 +391,17 @@ struct ScriptPos {
 	int curIP;
 };
 
-enum {
-	EGO_VIEW_TABLE	= 0,
-	HORIZON			= 36,
-	_WIDTH			= 160,
-	_HEIGHT			= 168
+enum InputMode {
+	INPUTMODE_NONE		= 0x04,
+	INPUTMODE_NORMAL	= 0x01 // prompt active
 };
 
-enum InputMode {
-	INPUT_NORMAL	= 0x01,
-	INPUT_GETSTRING	= 0x02,
-	INPUT_MENU		= 0x03,
-	INPUT_NONE		= 0x04
+enum CycleInnerLoopType {
+	CYCLE_INNERLOOP_GETSTRING                    = 0,
+	CYCLE_INNERLOOP_GETNUMBER                    = 1,
+	CYCLE_INNERLOOP_INVENTORY                    = 2,
+	CYCLE_INNERLOOP_MENU                         = 3,
+	CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT = 4
 };
 
 enum State {
@@ -532,12 +410,7 @@ enum State {
 	STATE_RUNNING	= 0x02
 };
 
-enum {
-	SBUF16_OFFSET = 0,
-	SBUF256_OFFSET = ((_WIDTH) * (_HEIGHT)),
-	FROM_SBUF16_TO_SBUF256_OFFSET = ((SBUF256_OFFSET) - (SBUF16_OFFSET)),
-	FROM_SBUF256_TO_SBUF16_OFFSET = ((SBUF16_OFFSET) - (SBUF256_OFFSET))
-};
+typedef Common::Array<int16> SavedGameSlotIdArray;
 
 /**
  * AGI game structure.
@@ -563,94 +436,89 @@ struct AgiGame {
 	uint8 vars[MAX_VARS];   /**< 256 variables */
 
 	// internal variables
-	int horizon;			/**< horizon y coordinate */
-	int lineStatus;		/**< line number to put status on */
-	int lineUserInput;	/**< line to put user input on */
-	int lineMinPrint;		/**< num lines to print on */
-	int cursorPos;			/**< column where the input cursor is */
-	byte inputBuffer[40]; /**< buffer for user input */
-	byte echoBuffer[40];	/**< buffer for echo.line */
+	int16 horizon;			/**< horizon y coordinate */
+
 	int keypress;
 
+	bool  cycleInnerLoopActive;
+	int16 cycleInnerLoopType;
+
 	InputMode inputMode;			/**< keyboard input mode */
-	bool inputEnabled;		/**< keyboard input enabled */
+
+	uint16 specialMenuTriggerKey;	/**< key to trigger menu for platforms except PC */
+
 	int lognum;				/**< current logic number */
 	Common::Array<ScriptPos> execStack;
 
 	// internal flags
 	int playerControl;		/**< player is in control */
-	int statusLine;		/**< status line on/off */
 	int clockEnabled;		/**< clock is on/off */
 	int exitAllLogics;	/**< break cycle after new.room */
-	int pictureShown;		/**< show.pic has been issued */
+	bool pictureShown;		/**< show.pic has been issued */
 	int hasPrompt;			/**< input prompt has been printed */
 #define ID_AGDS		0x00000001
 #define ID_AMIGA	0x00000002
 	int gameFlags;			/**< agi options flags */
 
-	uint8 priTable[_HEIGHT];/**< priority table */
-
 	// windows
 	uint32 msgBoxTicks;	/**< timed message box tick counter */
 	AgiBlock block;
-	AgiBlock window;
-	int hasWindow;
 
 	// graphics & text
-	int gfxMode;
-	char cursorChar;
-	unsigned int colorFg;
-	unsigned int colorBg;
-
-	uint8 *sbufOrig;		/**< Pointer to the 160x336 AGI screen buffer that contains vertically two 160x168 screens (16 color and 256 color). */
-	uint8 *sbuf16c;			/**< 160x168 16 color (+control line & priority information) AGI screen buffer. Points at sbufOrig + SBUF16_OFFSET. */
-	uint8 *sbuf256c;		/**< 160x168 256 color AGI screen buffer (For AGI256 and AGI256-2 support). Points at sbufOrig + SBUF256_OFFSET. */
-	uint8 *sbuf;			/**< Currently chosen AGI screen buffer (sbuf256c if AGI256 or AGI256-2 is used, otherwise sbuf16c). */
-
-	// player command line
-	AgiWord egoWords[MAX_WORDS];
-	int numEgoWords;
+	bool gfxMode;
 
 	unsigned int numObjects;
 
-	bool controllerOccured[MAX_DIRS];  /**< keyboard keypress events */
-	AgiController controllers[MAX_CONTROLLERS];
+	bool controllerOccured[MAX_CONTROLLERS];  /**< keyboard keypress events */
+	AgiControllerKeyMapping controllerKeyMapping[MAX_CONTROLLER_KEYMAPPINGS];
 
 	char strings[MAX_STRINGS + 1][MAX_STRINGLEN]; /**< strings */
 
 	// directory entries for resources
-	AgiDir dirLogic[MAX_DIRS];
-	AgiDir dirPic[MAX_DIRS];
-	AgiDir dirView[MAX_DIRS];
-	AgiDir dirSound[MAX_DIRS];
+	AgiDir dirLogic[MAX_DIRECTORY_ENTRIES];
+	AgiDir dirPic[MAX_DIRECTORY_ENTRIES];
+	AgiDir dirView[MAX_DIRECTORY_ENTRIES];
+	AgiDir dirSound[MAX_DIRECTORY_ENTRIES];
 
 	// resources
-	AgiPicture pictures[MAX_DIRS];	/**< AGI picture resources */
-	AgiLogic logics[MAX_DIRS];		/**< AGI logic resources */
-	AgiView views[MAX_DIRS];		/**< AGI view resources */
-	AgiSound *sounds[MAX_DIRS];		/**< Pointers to AGI sound resources */
+	AgiPicture pictures[MAX_DIRECTORY_ENTRIES];	/**< AGI picture resources */
+	AgiLogic logics[MAX_DIRECTORY_ENTRIES];		/**< AGI logic resources */
+	AgiView views[MAX_DIRECTORY_ENTRIES];		/**< AGI view resources */
+	AgiSound *sounds[MAX_DIRECTORY_ENTRIES];	/**< Pointers to AGI sound resources */
 
 	AgiLogic *_curLogic;
 
-	// words
-	Common::Array<AgiWord *> words[26];
-
 	// view table
-	VtEntry viewTable[MAX_VIEWTABLE];
+	ScreenObjEntry screenObjTable[SCREENOBJECTS_MAX];
+
+	ScreenObjEntry addToPicView;
 
 	int32 ver;						/**< detected game version */
 
-	int simpleSave;					/**< select simple savegames */
+	bool automaticSave;             /**< set by CmdSetSimple() */
+	char automaticSaveDescription[SAVEDGAME_DESCRIPTION_LEN + 1];
 
 	Common::Rect mouseFence;		/**< rectangle set by fence.mouse command */
 	bool mouseEnabled;              /**< if mouse is supposed to be active */
+	bool mouseHidden;               /**< if mouse is currently hidden */
 
 	// IF condition handling
 	int testResult;
 
-
 	int max_logics;
 	int logic_list[256];
+
+	// used to detect situations, where the game shows some text and changes rooms right afterwards
+	// for example Space Quest 2 intro right at the start
+	// or Space Quest 2, when entering the vent also right at the start
+	// The developers assumed that loading the new room would take a bit.
+	// In ScummVM it's basically done in an instant, which means that
+	// the text would only get shown for a split second.
+	// We delay a bit as soon as such situations get detected.
+	bool nonBlockingTextShown;
+	int16 nonBlockingTextCyclesLeft;
+
+	bool automaticRestoreGame;
 };
 
 class AgiLoader {
@@ -662,8 +530,8 @@ public:
 	virtual int init() = 0;
 	virtual int deinit() = 0;
 	virtual int detectGame() = 0;
-	virtual int loadResource(int, int) = 0;
-	virtual int unloadResource(int, int) = 0;
+	virtual int loadResource(int16 resourceType, int16 resourceNr) = 0;
+	virtual int unloadResource(int16 resourceType, int16 resourceNr) = 0;
 	virtual int loadObjects(const char *) = 0;
 	virtual int loadWords(const char *) = 0;
 };
@@ -684,8 +552,8 @@ public:
 	virtual int init();
 	virtual int deinit();
 	virtual int detectGame();
-	virtual int loadResource(int, int);
-	virtual int unloadResource(int, int);
+	virtual int loadResource(int16 resourceType, int16 resourceNr);
+	virtual int unloadResource(int16 resourceType, int16 resourceNr);
 	virtual int loadObjects(const char *);
 	virtual int loadWords(const char *);
 };
@@ -706,8 +574,8 @@ public:
 	virtual int init();
 	virtual int deinit();
 	virtual int detectGame();
-	virtual int loadResource(int, int);
-	virtual int unloadResource(int, int);
+	virtual int loadResource(int16 resourceType, int16 resourceNr);
+	virtual int unloadResource(int16 resourceType, int16 resourceNr);
 	virtual int loadObjects(const char *);
 	virtual int loadWords(const char *);
 };
@@ -728,8 +596,8 @@ public:
 	virtual int init();
 	virtual int deinit();
 	virtual int detectGame();
-	virtual int loadResource(int, int);
-	virtual int unloadResource(int, int);
+	virtual int loadResource(int16 resourceType, int16 resourceNr);
+	virtual int unloadResource(int16 resourceType, int16 resourceNr);
 	virtual int loadObjects(const char *);
 	virtual int loadWords(const char *);
 };
@@ -737,7 +605,11 @@ public:
 
 class GfxMgr;
 class SpritesMgr;
-class Menu;
+class InventoryMgr;
+class TextMgr;
+class GfxMenu;
+class SystemUI;
+class Words;
 
 // Image stack support
 struct ImageStackElement {
@@ -780,15 +652,21 @@ protected:
 	virtual void initialize() = 0;
 
 	void initRenderMode();
+	void initFont();
+
+	void loadFontMickey();
+	void loadFontAmigaPseudoTopaz();
+	void loadFontAppleIIgs();
 
-	const uint8 *_fontData;
+	const uint8 *_fontData; // pointer to the currently used font
+	uint8 *_fontDataAllocated;
 
 public:
+	Words *_words;
+
 	GfxMgr *_gfx;
 
-	AgiButtonStyle _defaultButtonStyle;
-	AgiButtonStyle _buttonStyle;
-	Common::RenderMode _renderMode;
+	AgiRenderMode _renderMode;
 	volatile uint32 _clockCount;
 	AgiDebug _debug;
 	AgiGame _game;
@@ -800,6 +678,10 @@ public:
 
 	bool _noSaveLoadAllowed;
 
+	virtual bool promptIsEnabled() {
+		return false;
+	}
+
 	virtual void pollTimer() = 0;
 	virtual int getKeypress() = 0;
 	virtual bool isKeypress() = 0;
@@ -844,6 +726,17 @@ public:
 	bool canSaveGameStateCurrently();
 
 	const uint8 *getFontData() { return _fontData; };
+
+	void cycleInnerLoopActive(int16 loopType) {
+		_game.cycleInnerLoopActive = true;
+		_game.cycleInnerLoopType = loopType;
+	};
+	void cycleInnerLoopInactive() {
+		_game.cycleInnerLoopActive = false;
+	};
+	bool cycleInnerLoopIsActive() {
+		return _game.cycleInnerLoopActive;
+	}
 };
 
 typedef void (*AgiCommand)(AgiGame *state, uint8 *p);
@@ -861,8 +754,12 @@ public:
 	AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc);
 	virtual ~AgiEngine();
 
+	bool promptIsEnabled();
+
 	Common::Error loadGameState(int slot);
-	Common::Error saveGameState(int slot, const Common::String &desc);
+	Common::Error saveGameState(int slot, const Common::String &description);
+
+	void adjustPosToGameScreen(int16 &x, int16 &y);
 
 private:
 	uint32 _lastTick;
@@ -873,11 +770,9 @@ private:
 
 	bool _allowSynthetic;
 
-	int checkPriority(VtEntry *v);
-	int checkCollision(VtEntry *v);
-	int checkPosition(VtEntry *v);
-
-	void parseFeatures();
+	bool checkPriority(ScreenObjEntry *v);
+	bool checkCollision(ScreenObjEntry *v);
+	bool checkPosition(ScreenObjEntry *v);
 
 	int _firstSlot;
 
@@ -886,15 +781,16 @@ public:
 
 	StringData _stringdata;
 
-	Common::String getSavegameFilename(int num) const;
-	void getSavegameDescription(int num, char *buf, bool showEmpty = true);
-	int selectSlot();
-	int saveGame(const Common::String &fileName, const Common::String &saveName);
+	SavedGameSlotIdArray getSavegameSlotIds();
+	Common::String getSavegameFilename(int16 slotId) const;
+	bool getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint16 &saveTime, bool &saveIsValid);
+
+	int saveGame(const Common::String &fileName, const Common::String &descriptionString);
 	int loadGame(const Common::String &fileName, bool checkId = true);
-	int saveGameDialog();
-	int saveGameSimple();
-	int loadGameDialog();
-	int loadGameSimple();
+	bool saveGameDialog();
+	bool saveGameAutomatic();
+	bool loadGameDialog();
+	bool loadGameAutomatic();
 	int doSave(int slot, const Common::String &desc);
 	int doLoad(int slot, bool showMessages);
 	int scummVMSaveLoadDialog(bool isSave);
@@ -903,14 +799,13 @@ public:
 	InputMode _oldMode;
 	bool _restartGame;
 
-	Menu* _menu;
-	bool _menuSelected;
-
-	char _lastSentence[40];
-
 	SpritesMgr *_sprites;
+	TextMgr *_text;
+	InventoryMgr *_inventory;
 	PictureMgr *_picture;
 	AgiLoader *_loader;	// loader
+	GfxMenu *_menu;
+	SystemUI *_systemUI;
 
 	Common::Stack<ImageStackElement> _imageStack;
 
@@ -929,8 +824,8 @@ public:
 	int agiInit();
 	int agiDeinit();
 	int agiDetectGame();
-	int agiLoadResource(int, int);
-	int agiUnloadResource(int, int);
+	int agiLoadResource(int16 resourceType, int16 resourceNr);
+	int agiUnloadResource(int16 resourceType, int16 resourceNr);
 	void agiUnloadResources();
 
 	virtual void pollTimer();
@@ -938,35 +833,27 @@ public:
 	virtual bool isKeypress();
 	virtual void clearKeyQueue();
 
-	void initPriTable();
-
 	void newInputMode(InputMode mode);
 	void oldInputMode();
 
-	int getvar(int);
-	void setvar(int, int);
+	int getVar(int16 varNr);
+	void setVar(int16 varNr, int);
 	void decrypt(uint8 *mem, int len);
 	void releaseSprites();
 	int mainCycle(bool onlyCheckForEvents = false);
 	int viewPictures();
 	int runGame();
-	void inventory();
 	void updateTimer();
 	int getAppDir(char *appDir, unsigned int size);
 
 	int setupV2Game(int ver);
 	int setupV3Game(int ver);
 
-	void newRoom(int n);
+	void newRoom(int16 newRoomNr);
 	void resetControllers();
 	void interpretCycle();
 	int playGame();
 
-	void printItem(int n, int fg, int bg);
-	int findItem();
-	int showItems();
-	void selectItems(int n);
-
 	void allowSynthetic(bool);
 	void processEvents();
 	void checkQuickLoad();
@@ -977,9 +864,9 @@ public:
 	int loadObjects(const char *fname);
 	int loadObjects(Common::File &fp);
 	void unloadObjects();
-	const char *objectName(unsigned int);
-	int objectGetLocation(unsigned int);
-	void objectSetLocation(unsigned int, int);
+	const char *objectName(uint16 objectNr);
+	int objectGetLocation(uint16 objectNr);
+	void objectSetLocation(uint16 objectNr, int);
 private:
 	int decodeObjects(uint8 *mem, uint32 flen);
 	int readObjects(Common::File &fp, int flen);
@@ -987,8 +874,8 @@ private:
 
 	// Logic
 public:
-	int decodeLogic(int);
-	void unloadLogic(int);
+	int decodeLogic(int16 logicNr);
+	void unloadLogic(int16 logicNr);
 	int runLogic(int);
 	void debugConsole(int, int, const char *);
 	int testIfCode(int);
@@ -1010,93 +897,72 @@ public:
 	// View
 private:
 
-	void lSetCel(VtEntry *v, int n);
-	void lSetLoop(VtEntry *v, int n);
-	void updateView(VtEntry *v);
+	void lSetLoop(ScreenObjEntry *screenObj, int16 loopNr);
+	void updateView(ScreenObjEntry *screenObj);
 
 public:
+	void setView(ScreenObjEntry *screenObj, int16 viewNr);
+	void setLoop(ScreenObjEntry *screenObj, int16 loopNr);
+	void setCel(ScreenObjEntry *screenObj, int16 celNr);
 
-	void setCel(VtEntry *, int);
-	void clipViewCoordinates(VtEntry *v);
-	void setLoop(VtEntry *, int);
-	void setView(VtEntry *, int);
-	void startUpdate(VtEntry *);
-	void stopUpdate(VtEntry *);
-	void updateViewtable();
-	void unloadView(int);
-	int decodeView(int);
-	void addToPic(int, int, int, int, int, int, int);
-	void drawObj(int);
-	bool isEgoView(const VtEntry *v);
+	void clipViewCoordinates(ScreenObjEntry *screenObj);
+
+	void startUpdate(ScreenObjEntry *);
+	void stopUpdate(ScreenObjEntry *);
+	void updateScreenObjTable();
+	void unloadView(int16 viewNr);
+	int decodeView(byte *resourceData, uint16 resourceSize, int16 viewNr);
+
+private:
+	void unpackViewCelData(AgiViewCel *celData, byte *compressedData, uint16 compressedSize);
+	void unpackViewCelDataAGI256(AgiViewCel *celData, byte *compressedData, uint16 compressedSize);
 
-	// Words
 public:
-	int showWords();
-	int loadWords(const char *);
-	int loadWords_v1(Common::File &f);
-	void unloadWords();
-	int findWord(const char *word, int *flen);
-	void dictionaryWords(char *);
+	void addToPic(int, int, int, int, int, int, int);
+	void drawObj(int);
+	bool isEgoView(const ScreenObjEntry *screenObj);
 
 	// Motion
 private:
 	int checkStep(int delta, int step);
-	int checkBlock(int x, int y);
-	void changePos(VtEntry *v);
-	void motionWander(VtEntry *v);
-	void motionFollowEgo(VtEntry *v);
-	void motionMoveObj(VtEntry *v);
-	void checkMotion(VtEntry *v);
+	bool checkBlock(int16 x, int16 y);
+	void changePos(ScreenObjEntry *screenObj);
+	void motionWander(ScreenObjEntry *screenObj);
+	void motionFollowEgo(ScreenObjEntry *screenObj);
+	void motionMoveObj(ScreenObjEntry *screenObj);
+	void motionMoveObjStop(ScreenObjEntry *screenObj);
+	void checkMotion(ScreenObjEntry *screenObj);
 
 public:
 	void checkAllMotions();
-	void moveObj(VtEntry *);
-	void inDestination(VtEntry *);
-	void fixPosition(int);
+	void moveObj(ScreenObjEntry *screenObj);
+	void inDestination(ScreenObjEntry *screenObj);
+	void fixPosition(int16 screenObjNr);
+	void fixPosition(ScreenObjEntry *screenObj);
 	void updatePosition();
-	int getDirection(int x0, int y0, int x, int y, int s);
+	int getDirection(int16 objX, int16 objY, int16 destX, int16 destY, int16 stepSize);
 
 	bool _egoHoldKey;
 
 	// Keyboard
-	void initWords();
-	void cleanInput();
 	int doPollKeyboard();
 	void cleanKeyboard();
-	void handleKeys(int);
-	void handleGetstring(int);
-	int handleController(int);
-	void getString(int, int, int, int);
+
+	int16 getSpecialMenuControllerSlot();
+	bool handleController(uint16 key);
 	uint16 agiGetKeypress();
 	int waitKey();
 	int waitAnyKey();
 
-	// Text
-public:
-	int messageBox(const char *);
-	int selectionBox(const char *, const char **);
-	void closeWindow();
-	void drawWindow(int, int, int, int);
-	void printText(const char *, int, int, int, int, int, int, bool checkerboard = false);
-	void printTextConsole(const char *, int, int, int, int, int);
-	int print(const char *, int, int, int);
-	char *wordWrapString(const char *, int *);
-	char *agiSprintf(const char *);
-	void writeStatus();
-	void writePrompt();
-	void clearPrompt(bool useBlackBg = false);
-	void clearLines(int, int, int);
-	void flushLines(int, int);
+	void nonBlockingText_IsShown();
+	void nonBlockingText_Forget();
+	void nonBlockingText_CycleDone();
 
-private:
-	void printStatus(const char *message, ...) GCC_PRINTF(2, 3);
-	void printText2(int l, const char *msg, int foff, int xoff, int yoff, int len, int fg, int bg, bool checkerboard = false);
-	void blitTextbox(const char *p, int y, int x, int len);
-	void eraseTextbox();
-	bool matchWord();
+	void loadingTrigger_NewRoom(int16 newRoomNr);
+	void loadingTrigger_DrawPicture();
 
 public:
-	char _predictiveResult[40];
+	void redrawScreen();
 
 private:
 	AgiCommand _agiCommands[183];
diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp
index e61146e..8399c98 100644
--- a/engines/agi/checks.cpp
+++ b/engines/agi/checks.cpp
@@ -21,159 +21,156 @@
  */
 
 #include "agi/agi.h"
+#include "agi/graphics.h"
 
 namespace Agi {
 
-int AgiEngine::checkPosition(VtEntry *v) {
-	debugC(4, kDebugLevelSprites, "check position @ %d, %d", v->xPos, v->yPos);
+bool AgiEngine::checkPosition(ScreenObjEntry *screenObj) {
+	bool result = true; // position is fine
+	debugC(4, kDebugLevelSprites, "check position @ %d, %d", screenObj->xPos, screenObj->yPos);
 
-	if (v->xPos < 0 ||
-			v->xPos + v->xSize > _WIDTH ||
-			v->yPos - v->ySize + 1 < 0 ||
-			v->yPos >= _HEIGHT ||
-			((~v->flags & fIgnoreHorizon) && v->yPos <= _game.horizon)) {
-		debugC(4, kDebugLevelSprites, "check position failed: x=%d, y=%d, h=%d, w=%d",
-				v->xPos, v->yPos, v->xSize, v->ySize);
-		return 0;
-	}
+	do {
+		if (screenObj->xPos < 0) {
+			result = false;
+			break;
+		}
+		if (screenObj->xPos + screenObj->xSize > SCRIPT_WIDTH) {
+			result = false;
+			break;
+		}
+		if (screenObj->yPos - screenObj->ySize < -1) {
+			result = false;
+			break;
+		}
+		if (screenObj->yPos >= SCRIPT_HEIGHT) {
+			result = false;
+			break;
+		}
+		if (((!(screenObj->flags & fIgnoreHorizon)) && screenObj->yPos <= _game.horizon)) {
+			result = false;
+			break;
+		}
+	} while (0);
 
 	// MH1 needs this, but it breaks LSL1
-	if (getVersion() >= 0x3000) {
-		if (v->yPos < v->ySize)
-			return 0;
-	}
+// TODO: *NOT* in disassembly of AGI3 .149, why was this needed?
+//	if (getVersion() >= 0x3000) {
+//		if (screenObj->yPos < screenObj->ySize)
+//			result = false;
+//	}
 
-	return 1;
+	if (!result) {
+		debugC(4, kDebugLevelSprites, "check position failed: x=%d, y=%d, h=%d, w=%d",
+				screenObj->xPos, screenObj->yPos, screenObj->xSize, screenObj->ySize);
+	}
+	return result;
 }
 
 /**
  * Check if there's another object on the way
  */
-int AgiEngine::checkCollision(VtEntry *v) {
-	VtEntry *u;
+bool AgiEngine::checkCollision(ScreenObjEntry *screenObj) {
+	ScreenObjEntry *checkObj;
 
-	if (v->flags & fIgnoreObjects)
-		return 0;
+	if (screenObj->flags & fIgnoreObjects)
+		return false;
 
-	for (u = _game.viewTable; u < &_game.viewTable[MAX_VIEWTABLE]; u++) {
-		if ((u->flags & (fAnimated | fDrawn)) != (fAnimated | fDrawn))
+	for (checkObj = _game.screenObjTable; checkObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; checkObj++) {
+		if ((checkObj->flags & (fAnimated | fDrawn)) != (fAnimated | fDrawn))
 			continue;
 
-		if (u->flags & fIgnoreObjects)
+		if (checkObj->flags & fIgnoreObjects)
 			continue;
 
 		// Same object, check next
-		if (v->entry == u->entry)
+		if (screenObj->objectNr == checkObj->objectNr)
 			continue;
 
 		// No horizontal overlap, check next
-		if (v->xPos + v->xSize < u->xPos || v->xPos > u->xPos + u->xSize)
+		if (screenObj->xPos + screenObj->xSize < checkObj->xPos || screenObj->xPos > checkObj->xPos + checkObj->xSize)
 			continue;
 
 		// Same y, return error!
-		if (v->yPos == u->yPos) {
-			debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", v->entry);
-			return 1;
+		if (screenObj->yPos == checkObj->yPos) {
+			debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", screenObj->objectNr);
+			return true;
 		}
 
 		// Crossed the baseline, return error!
-		if ((v->yPos > u->yPos && v->yPos2 < u->yPos2) ||
-				(v->yPos < u->yPos && v->yPos2 > u->yPos2)) {
-			debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", v->entry);
-			return 1;
+		if ((screenObj->yPos > checkObj->yPos && screenObj->yPos_prev < checkObj->yPos_prev) ||
+				(screenObj->yPos < checkObj->yPos && screenObj->yPos_prev > checkObj->yPos_prev)) {
+			debugC(4, kDebugLevelSprites, "check returns 1 (object %d)", screenObj->objectNr);
+			return true;
 		}
 	}
-
-	return 0;
-
+	
+	return false;
 }
 
-int AgiEngine::checkPriority(VtEntry *v) {
-	int i, trigger, water, pass, pri;
-	uint8 *p0;
+bool AgiEngine::checkPriority(ScreenObjEntry *screenObj) {
+	bool touchedWater = false;
+	bool touchedTrigger = false;
+	bool touchedControl = true;
+	int16 curX;
+	int16 curY;
+	int16 celX;
+	byte screenPriority = 0;
 
-	if (~v->flags & fFixedPriority) {
+	if (!(screenObj->flags & fFixedPriority)) {
 		// Priority bands
-		v->priority = _game.priTable[v->yPos];
-	}
-
-	trigger = 0;
-	water = 0;
-	pass = 1;
-
-	if (v->priority == 0x0f) {
-		// Check ego
-		if (v->entry == 0) {
-			setflag(fEgoTouchedP2, trigger ? true : false);
-			setflag(fEgoWater, water ? true : false);
-		}
-
-		return pass;
-	}
-
-	water = 1;
-
-	// Check if any picture is loaded before checking for priority below.
-	// If no picture has been loaded, the priority buffer won't be initialized,
-	// thus the check below will always fail. This case causes an infinite loop
-	// in the fanmade game Nick's Quest (bug #3451122), as the game attempts to
-	// draw a sprite (view 4, floating Nick) before it loads any picture. This
-	// causes the checks below to always fail, and the engine keeps readjusting
-	// the sprite's position in fixPosition() forever, as there is no valid
-	// position to place it (the default visual and priority screen is set to
-	// zero, i.e. unconditional black). To remedy this situation, we always
-	// return true here if no picture has been loaded and no priority screen
-	// has been set up.
-	if (!_game._vm->_picture->isPictureLoaded()) {
-		warning("checkPriority: no picture loaded");
-		return pass;
+		screenObj->priority = _gfx->priorityFromY(screenObj->yPos);
 	}
 
-	p0 = &_game.sbuf16c[v->xPos + v->yPos * _WIDTH];
-
-	for (i = 0; i < v->xSize; i++, p0++) {
-		pri = *p0 >> 4;
+	if (screenObj->priority != 0x0f) {
 
-		if (pri == 0) {	// unconditional black. no go at all!
-			pass = 0;
-			break;
-		}
+		touchedWater = true;
 
-		if (pri == 3)	// water surface
-			continue;
+		curX = screenObj->xPos;
+		curY = screenObj->yPos;
 
-		water = 0;
+		for (celX = 0; celX < screenObj->xSize; celX++, curX++) {
+			screenPriority = _gfx->getPriority(curX, curY);
 
-		if (pri == 1) {	// conditional blue
-			if (v->flags & fIgnoreBlocks)
-				continue;
+			if (screenPriority == 0) {	// unconditional black. no go at all!
+				touchedControl = 0;
+				break;
+			}
 
-			debugC(4, kDebugLevelSprites, "Blocks observed!");
-			pass = 0;
-			break;
+			if (screenPriority != 3) {	// not water surface
+				touchedWater = false;
+
+				if (screenPriority == 1) {	// conditional blue
+					if (!(screenObj->flags & fIgnoreBlocks)) {
+						debugC(4, kDebugLevelSprites, "Blocks observed!");
+						touchedControl = false;
+						break;
+					}
+				} else if (screenPriority == 2) {
+					debugC(4, kDebugLevelSprites, "stepped on trigger");
+					if (!_debug.ignoretriggers)
+						touchedTrigger = true;
+				}
+			}
 		}
 
-		if (pri == 2) {	// trigger
-			debugC(4, kDebugLevelSprites, "stepped on trigger");
-			if (!_debug.ignoretriggers)
-				trigger = 1;
+		if (touchedControl) {
+			if (!touchedWater) {
+				if (screenObj->flags & fOnWater)
+					touchedControl = false;
+			} else {
+				if (screenObj->flags & fOnLand)
+					touchedControl = false;
+			}
 		}
 	}
 
-	if (pass) {
-		if (!water && v->flags & fOnWater)
-			pass = 0;
-		if (water && v->flags & fOnLand)
-			pass = 0;
-	}
-
 	// Check ego
-	if (v->entry == 0) {
-		setflag(fEgoTouchedP2, trigger ? true : false);
-		setflag(fEgoWater, water ? true : false);
+	if (screenObj->objectNr == 0) {
+		setflag(VM_FLAG_EGO_TOUCHED_P2, touchedTrigger ? true : false);
+		setflag(VM_FLAG_EGO_WATER, touchedWater ? true : false);
 	}
 
-	return pass;
+	return touchedControl;
 }
 
 /*
@@ -188,91 +185,106 @@ int AgiEngine::checkPriority(VtEntry *v) {
  * rules, otherwise the previous position will be kept.
  */
 void AgiEngine::updatePosition() {
-	VtEntry *v;
+	ScreenObjEntry *screenObj;
 	int x, y, oldX, oldY, border;
 
-	_game.vars[vBorderCode] = 0;
-	_game.vars[vBorderTouchEgo] = 0;
-	_game.vars[vBorderTouchObj] = 0;
+	_game.vars[VM_VAR_BORDER_CODE] = 0;
+	_game.vars[VM_VAR_BORDER_TOUCH_EGO] = 0;
+	_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = 0;
 
-	for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) {
-		if ((v->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) {
+	for (screenObj = _game.screenObjTable; screenObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
+		if ((screenObj->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) {
 			continue;
 		}
 
-		if (v->stepTimeCount != 0) {
-			if (--v->stepTimeCount != 0)
-				continue;
+		if (screenObj->stepTimeCount > 1) {
+			screenObj->stepTimeCount--;
+			continue;
 		}
 
-		v->stepTimeCount = v->stepTime;
+		screenObj->stepTimeCount = screenObj->stepTime;
 
-		x = oldX = v->xPos;
-		y = oldY = v->yPos;
+		x = oldX = screenObj->xPos;
+		y = oldY = screenObj->yPos;
 
 		// If object has moved, update its position
-		if (~v->flags & fUpdatePos) {
+		if (!(screenObj->flags & fUpdatePos)) {
 			int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
 			int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
-			x += v->stepSize * dx[v->direction];
-			y += v->stepSize * dy[v->direction];
+			x += screenObj->stepSize * dx[screenObj->direction];
+			y += screenObj->stepSize * dy[screenObj->direction];
 		}
 
 		// Now check if it touched the borders
 		border = 0;
 
 		// Check left/right borders
-		if (x < 0) {
-			x = 0;
-			border = 4;
-		} else if (x <= 0 && getVersion() == 0x3086) {	// KQ4
-			x = 0;	// See Sarien bug #590462
-			border = 4;
-		} else if (v->entry == 0 && x == 0 && v->flags & fAdjEgoXY) {
-			// Extra test to walk west clicking the mouse
-			x = 0;
-			border = 4;
-		} else if (x + v->xSize > _WIDTH) {
-			x = _WIDTH - v->xSize;
-			border = 2;
+		if (getVersion() == 0x3086) {
+			// KQ4 interpreter does a different comparison on x
+			// The interpreter before (2.917) and after that (3.098) don't do them that way
+			// This difference is required for at least Sarien bug #192
+			// KQ4: room 135, hen moves from the center of the screen to the left border,
+			// but it doesn't disappear.
+			if (x <= 0) {
+				x = 0;
+				border = 4;
+			}
+		} else {
+			// regular comparison
+			if (x < 0) {
+				x = 0;
+				border = 4;
+			}
+		}
+
+//		} else if (v->entry == 0 && x == 0 && v->flags & fAdjEgoXY) { // should not be required
+//			// Extra test to walk west clicking the mouse
+//			x = 0;
+//			border = 4;
+
+		if (!border) {
+			if (x + screenObj->xSize > SCRIPT_WIDTH) {
+				x = SCRIPT_WIDTH - screenObj->xSize;
+				border = 2;
+			}
 		}
 
 		// Check top/bottom borders.
-		if (y - v->ySize + 1 < 0) {
-			y = v->ySize - 1;
+		if (y - screenObj->ySize < -1) {
+			y = screenObj->ySize - 1;
 			border = 1;
-		} else if (y > _HEIGHT - 1) {
-			y = _HEIGHT - 1;
+		} else if (y > SCRIPT_HEIGHT - 1) {
+			y = SCRIPT_HEIGHT - 1;
 			border = 3;
-		} else if ((~v->flags & fIgnoreHorizon) && y <= _game.horizon) {
+		} else if ((!(screenObj->flags & fIgnoreHorizon)) && y <= _game.horizon) {
 			debugC(4, kDebugLevelSprites, "y = %d, horizon = %d", y, _game.horizon);
 			y = _game.horizon + 1;
 			border = 1;
 		}
 
 		// Test new position. rollback if test fails
-		v->xPos = x;
-		v->yPos = y;
-		if (checkCollision(v) || !checkPriority(v)) {
-			v->xPos = oldX;
-			v->yPos = oldY;
+		screenObj->xPos = x;
+		screenObj->yPos = y;
+		if (checkCollision(screenObj) || !checkPriority(screenObj)) {
+			screenObj->xPos = oldX;
+			screenObj->yPos = oldY;
 			border = 0;
-			fixPosition(v->entry);
+			fixPosition(screenObj->objectNr);
 		}
 
-		if (border != 0) {
-			if (isEgoView(v)) {
-				_game.vars[vBorderTouchEgo] = border;
+		if (border) {
+			if (isEgoView(screenObj)) {
+				_game.vars[VM_VAR_BORDER_TOUCH_EGO] = border;
 			} else {
-				_game.vars[vBorderCode] = v->entry;
-				_game.vars[vBorderTouchObj] = border;
+				_game.vars[VM_VAR_BORDER_CODE] = screenObj->objectNr;
+				_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = border;
 			}
-			if (v->motion == kMotionMoveObj) {
-				inDestination(v);
+			if (screenObj->motionType == kMotionMoveObj) { // ANGEPASST
+				motionMoveObjStop(screenObj);
 			}
 		}
 
-		v->flags &= ~fUpdatePos;
+		screenObj->flags &= ~fUpdatePos;
 	}
 }
 
@@ -285,42 +297,46 @@ void AgiEngine::updatePosition() {
  *
  * @param n view table entry number
  */
-void AgiEngine::fixPosition(int n) {
-	VtEntry *v = &_game.viewTable[n];
+void AgiEngine::fixPosition(int16 screenObjNr) {
+	ScreenObjEntry *screenObj = &_game.screenObjTable[screenObjNr];
+	fixPosition(screenObj);
+}
+
+void AgiEngine::fixPosition(ScreenObjEntry *screenObj) {
 	int count, dir, size;
 
-	debugC(4, kDebugLevelSprites, "adjusting view table entry #%d (%d,%d)", n, v->xPos, v->yPos);
+	debugC(4, kDebugLevelSprites, "adjusting view table entry #%d (%d,%d)", screenObj->objectNr, screenObj->xPos, screenObj->yPos);
 
 	// test horizon
-	if ((~v->flags & fIgnoreHorizon) && v->yPos <= _game.horizon)
-		v->yPos = _game.horizon + 1;
+	if ((!(screenObj->flags & fIgnoreHorizon)) && screenObj->yPos <= _game.horizon)
+		screenObj->yPos = _game.horizon + 1;
 
 	dir = 0;
 	count = size = 1;
 
-	while (!checkPosition(v) || checkCollision(v) || !checkPriority(v)) {
+	while (!checkPosition(screenObj) || checkCollision(screenObj) || !checkPriority(screenObj)) {
 		switch (dir) {
 		case 0:	// west
-			v->xPos--;
+			screenObj->xPos--;
 			if (--count)
 				continue;
 			dir = 1;
 			break;
 		case 1:	// south
-			v->yPos++;
+			screenObj->yPos++;
 			if (--count)
 				continue;
 			dir = 2;
 			size++;
 			break;
 		case 2:	// east
-			v->xPos++;
+			screenObj->xPos++;
 			if (--count)
 				continue;
 			dir = 3;
 			break;
 		case 3:	// north
-			v->yPos--;
+			screenObj->yPos--;
 			if (--count)
 				continue;
 			dir = 0;
@@ -331,7 +347,7 @@ void AgiEngine::fixPosition(int n) {
 		count = size;
 	}
 
-	debugC(4, kDebugLevelSprites, "view table entry #%d position adjusted to (%d,%d)", n, v->xPos, v->yPos);
+	debugC(4, kDebugLevelSprites, "view table entry #%d position adjusted to (%d,%d)", screenObj->objectNr, screenObj->xPos, screenObj->yPos);
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/console.cpp b/engines/agi/console.cpp
index 89838b3..d8ecb2a 100644
--- a/engines/agi/console.cpp
+++ b/engines/agi/console.cpp
@@ -22,6 +22,7 @@
 
 #include "agi/agi.h"
 #include "agi/opcodes.h"
+#include "agi/graphics.h"
 
 #include "agi/preagi.h"
 #include "agi/preagi_mickey.h"
@@ -49,6 +50,10 @@ Console::Console(AgiEngine *vm) : GUI::Debugger() {
 	registerCmd("setobj",     WRAP_METHOD(Console, Cmd_SetObj));
 	registerCmd("room",       WRAP_METHOD(Console, Cmd_Room));
 	registerCmd("bt",         WRAP_METHOD(Console, Cmd_BT));
+	registerCmd("show_map",   WRAP_METHOD(Console, Cmd_ShowMap));
+	registerCmd("screenobj",  WRAP_METHOD(Console, Cmd_ScreenObj));
+	registerCmd("vmvars",     WRAP_METHOD(Console, Cmd_VmVars));
+	registerCmd("vmflags",    WRAP_METHOD(Console, Cmd_VmFlags));
 }
 
 bool Console::Cmd_SetVar(int argc, const char **argv) {
@@ -58,7 +63,7 @@ bool Console::Cmd_SetVar(int argc, const char **argv) {
 	}
 	int p1 = (int)atoi(argv[1]);
 	int p2 = (int)atoi(argv[2]);
-	_vm->setvar(p1, p2);
+	_vm->setVar(p1, p2);
 
 	return true;
 }
@@ -158,13 +163,13 @@ bool Console::Cmd_Version(int argc, const char **argv) {
 	// We do this by scanning through all script texts
 	// This is the best we can do about it. There is no special location for the game version number.
 	// There are multiple variations, like "ver. X.XX", "ver X.XX" and even "verion X.XX".
-	for (scriptNr = 0; scriptNr < MAX_DIRS; scriptNr++) {
+	for (scriptNr = 0; scriptNr < MAX_DIRECTORY_ENTRIES; scriptNr++) {
 		if (game->dirLogic[scriptNr].offset != _EMPTY) {
 			// Script is supposed to exist?
 			scriptLoadedByUs = false;
 			if (!(game->dirLogic[scriptNr].flags & RES_LOADED)) {
 				// But not currently loaded? -> load it now
-				if (_vm->agiLoadResource(rLOGIC, scriptNr) != errOK) {
+				if (_vm->agiLoadResource(RESOURCETYPE_LOGIC, scriptNr) != errOK) {
 					// In case we can't load the source, skip it
 					continue;
 				}
@@ -263,7 +268,7 @@ bool Console::Cmd_Version(int argc, const char **argv) {
 			}
 
 			if (scriptLoadedByUs) {
-				_vm->agiUnloadResource(rLOGIC, scriptNr);
+				_vm->agiUnloadResource(RESOURCETYPE_LOGIC, scriptNr);
 			}
 		}
 	}
@@ -298,7 +303,7 @@ bool Console::Cmd_Vars(int argc, const char **argv) {
 
 	for (i = 0; i < 255;) {
 		for (j = 0; j < 5; j++, i++) {
-			debugPrintf("%03d:%3d ", i, _vm->getvar(i));
+			debugPrintf("%03d:%3d ", i, _vm->getVar(i));
 		}
 		debugPrintf("\n");
 	}
@@ -380,7 +385,7 @@ bool Console::Cmd_Room(int argc, const char **argv) {
 		_vm->newRoom(strtoul(argv[1], NULL, 0));
 	}
 
-	debugPrintf("Current room: %d\n", _vm->getvar(0));
+	debugPrintf("Current room: %d\n", _vm->getVar(0));
 
 	return true;
 }
@@ -412,6 +417,182 @@ bool Console::Cmd_BT(int argc, const char **argv) {
 	return true;
 }
 
+bool Console::Cmd_ShowMap(int argc, const char **argv) {
+	if (argc != 2) {
+		debugPrintf("Switches to one of the following screen maps\n");
+		debugPrintf("Usage: %s <screen map>\n", argv[0]);
+		debugPrintf("Screen maps:\n");
+		debugPrintf("- 0: visual map\n");
+		debugPrintf("- 1: priority map\n");
+		return true;
+	}
+
+	int map = atoi(argv[1]);
+
+	switch (map) {
+	case 0:
+	case 1:
+		_vm->_gfx->debugShowMap(map);
+		break;
+
+	default:
+		debugPrintf("Map %d is not available.\n", map);
+		return true;
+	}
+	return cmdExit(0, 0);
+}
+
+bool Console::Cmd_ScreenObj(int argc, const char **argv) {
+	if (argc != 2) {
+		debugPrintf("Shows information about a specific screen object\n");
+		debugPrintf("Usage: %s <screenobj number>\n", argv[0]);
+		return true;
+	}
+
+	int16 screenObjNr = atoi(argv[1]);
+
+	if ((screenObjNr >= 0) && (screenObjNr < SCREENOBJECTS_MAX)) {
+		ScreenObjEntry *screenObj = &_vm->_game.screenObjTable[screenObjNr];
+
+		debugPrintf("Screen Object ID %d\n", screenObj->objectNr);
+		debugPrintf("current view: %d, loop: %d, cel: %d\n", screenObj->currentViewNr, screenObj->currentLoopNr, screenObj->currentCelNr);
+		debugPrintf("flags: %x\n", screenObj->flags);
+		debugPrintf("\n");
+		debugPrintf("xPos: %d, yPos: %d, xSize: %d, ySize: %d\n", screenObj->xPos, screenObj->yPos, screenObj->xSize, screenObj->ySize);
+		debugPrintf("previous: xPos: %d, yPos: %d, xSize: %d, ySize: %d\n", screenObj->xPos_prev, screenObj->yPos_prev, screenObj->xSize_prev, screenObj->ySize_prev);
+		debugPrintf("direction: %d, priority: %d\n", screenObj->direction, screenObj->priority);
+		debugPrintf("stepTime: %d, timeCount: %d, size: %d\n", screenObj->stepTime, screenObj->stepTimeCount, screenObj->stepSize);
+		debugPrintf("cycleTime: %d, timeCount: %d\n", screenObj->cycleTime, screenObj->cycleTimeCount);
+
+		switch(screenObj->motionType) {
+		case kMotionNormal:
+			debugPrintf("motion: normal\n");
+			break;
+		case kMotionWander:
+			debugPrintf("motion: wander\n");
+			debugPrintf("wanderCount: %d\n", screenObj->wander_count);
+			break;
+		case kMotionFollowEgo:
+			debugPrintf("motion: follow ego\n");
+			debugPrintf("stepSize: %d, flag: %x, count: %d", screenObj->follow_stepSize, screenObj->follow_flag, screenObj->follow_count);
+			break;
+		case kMotionMoveObj:
+		case kMotionEgo:
+			if (screenObj->motionType == kMotionMoveObj) {
+				debugPrintf("motion: move obj\n");
+			} else {
+				debugPrintf("motion: ego\n");
+			}
+			debugPrintf("x: %d, y: %d, stepSize: %d, flag: %x\n", screenObj->move_x, screenObj->move_y, screenObj->move_stepSize, screenObj->move_flag);
+			break;
+		}
+	}
+#if 0
+	CycleType cycle;
+#endif 
+	return true;
+}
+
+bool Console::Cmd_VmVars(int argc, const char **argv) {
+	if (argc < 2) {
+		debugPrintf("Shows the content of a VM variable / sets it\n");
+		debugPrintf("Usage: %s <variable number> [<value>]\n", argv[0]);
+		return true;
+	}
+
+	int varNr = 0;
+	int newValue = 0;
+
+	if (!parseInteger(argv[1], varNr))
+		return true;
+
+	if ((varNr < 0) || (varNr > 255)) {
+		debugPrintf("invalid variable number\n");
+		return true;
+	}
+
+	if (argc < 3) {
+		// show contents
+		debugPrintf("variable %d == %d\n", varNr, _vm->getVar(varNr));
+	} else {
+		if (!parseInteger(argv[2], newValue))
+			return true;
+
+		_vm->setVar(varNr, newValue);
+
+		debugPrintf("value set.\n");
+	}
+	return true;
+}
+
+bool Console::Cmd_VmFlags(int argc, const char **argv) {
+	if (argc < 2) {
+		debugPrintf("Shows the content of a VM flag / sets it\n");
+		debugPrintf("Usage: %s <flag number> [<value>]\n", argv[0]);
+		return true;
+	}
+
+	int flagNr = 0;
+	int newFlagState = 0;
+
+	if (!parseInteger(argv[1], flagNr))
+		return true;
+
+	if ((flagNr < 0) || (flagNr > 255)) {
+		debugPrintf("invalid flag number\n");
+		return true;
+	}
+
+	if (argc < 3) {
+		// show contents
+		if (_vm->getflag(flagNr)) {
+			debugPrintf("flag %d == set\n", flagNr);
+		} else {
+			debugPrintf("flag %d == not set\n", flagNr);
+		}
+	} else {
+		if (!parseInteger(argv[2], newFlagState))
+			return true;
+
+		if ((newFlagState != 0) && (newFlagState != 1)) {
+			debugPrintf("new state must bei either 0 or 1\n");
+			return true;
+		}
+
+		if (!newFlagState) {
+			_vm->setflag(flagNr, 0);
+			debugPrintf("flag %d reset.\n", flagNr);
+		} else {
+			_vm->setflag(flagNr, 1);
+			debugPrintf("flag %d set.\n", flagNr);
+		}
+	}
+	return true;
+}
+
+bool Console::parseInteger(const char *argument, int &result) {
+	char *endPtr = 0;
+	int idxLen = strlen(argument);
+	const char *lastChar = argument + idxLen - (idxLen == 0 ? 0 : 1);
+
+	if ((strncmp(argument, "0x", 2) == 0) || (*lastChar == 'h')) {
+		// hexadecimal number
+		result = strtol(argument, &endPtr, 16);
+		if ((*endPtr != 0) && (*endPtr != 'h')) {
+			debugPrintf("Invalid hexadecimal number '%s'\n", argument);
+			return false;
+		}
+	} else {
+		// decimal number
+		result = strtol(argument, &endPtr, 10);
+		if (*endPtr != 0) {
+			debugPrintf("Invalid decimal number '%s'\n", argument);
+			return false;
+		}
+	}
+	return true;
+}
+
 MickeyConsole::MickeyConsole(MickeyEngine *mickey) : GUI::Debugger() {
 	_mickey = mickey;
 
diff --git a/engines/agi/console.h b/engines/agi/console.h
index c650e14..41dc9dd 100644
--- a/engines/agi/console.h
+++ b/engines/agi/console.h
@@ -62,6 +62,12 @@ private:
 	bool Cmd_Cont(int argc, const char **argv);
 	bool Cmd_Room(int argc, const char **argv);
 	bool Cmd_BT(int argc, const char **argv);
+	bool Cmd_ShowMap(int argc, const char **argv);
+	bool Cmd_ScreenObj(int argc, const char **argv);
+	bool Cmd_VmVars(int argc, const char **argv);
+	bool Cmd_VmFlags(int argc, const char **argv);
+
+	bool parseInteger(const char *argument, int &result);
 
 private:
 	AgiEngine *_vm;
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index 145b827..98f29ec 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -20,11 +20,16 @@
  *
  */
 
+#include "common/config-manager.h"
+
 #include "agi/agi.h"
 #include "agi/sprite.h"
 #include "agi/graphics.h"
+#include "agi/inv.h"
+#include "agi/text.h"
 #include "agi/keyboard.h"
 #include "agi/menu.h"
+#include "agi/systemui.h"
 
 namespace Agi {
 
@@ -33,124 +38,133 @@ namespace Agi {
  * This function is called when ego enters a new room.
  * @param n room number
  */
-void AgiEngine::newRoom(int n) {
-	VtEntry *v;
+void AgiEngine::newRoom(int16 newRoomNr) {
+	ScreenObjEntry *screenObj;
+	ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
 	int i;
 
-	// Simulate slowww computer.
-	// Many effects rely on it.
-	pause(kPauseRoom);
+	// Loading trigger
+	loadingTrigger_NewRoom(newRoomNr);
 
-	debugC(4, kDebugLevelMain, "*** room %d ***", n);
+	debugC(4, kDebugLevelMain, "*** room %d ***", newRoomNr);
 	_sound->stopSound();
 
 	i = 0;
-	for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) {
-		v->entry = i++;
-		v->flags &= ~(fAnimated | fDrawn);
-		v->flags |= fUpdate;
-		v->stepTime = 1;
-		v->stepTimeCount = 1;
-		v->cycleTime = 1;
-		v->cycleTimeCount = 1;
-		v->stepSize = 1;
+	for (screenObj = _game.screenObjTable; screenObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
+		screenObj->objectNr = i++;
+		screenObj->flags &= ~(fAnimated | fDrawn);
+		screenObj->flags |= fUpdate;
+		screenObj->stepTime = 1;
+		screenObj->stepTimeCount = 1;
+		screenObj->cycleTime = 1;
+		screenObj->cycleTimeCount = 1;
+		screenObj->stepSize = 1;
 	}
 	agiUnloadResources();
 
 	_game.playerControl = true;
 	_game.block.active = false;
 	_game.horizon = 36;
-	_game.vars[vPrevRoom] = _game.vars[vCurRoom];
-	_game.vars[vCurRoom] = n;
-	_game.vars[vBorderTouchObj] = 0;
-	_game.vars[vBorderCode] = 0;
-	_game.vars[vEgoViewResource] = _game.viewTable[0].currentView;
+	_game.vars[VM_VAR_PREVIOUS_ROOM] = _game.vars[VM_VAR_CURRENT_ROOM];
+	_game.vars[VM_VAR_CURRENT_ROOM] = newRoomNr;
+	_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = 0;
+	_game.vars[VM_VAR_BORDER_CODE] = 0;
+	_game.vars[VM_VAR_EGO_VIEW_RESOURCE] = screenObjEgo->currentViewNr;
 
-	agiLoadResource(rLOGIC, n);
+	agiLoadResource(RESOURCETYPE_LOGIC, newRoomNr);
 
 	// Reposition ego in the new room
-	switch (_game.vars[vBorderTouchEgo]) {
+	switch (_game.vars[VM_VAR_BORDER_TOUCH_EGO]) {
 	case 1:
-		_game.viewTable[0].yPos = _HEIGHT - 1;
+		screenObjEgo->yPos = SCRIPT_HEIGHT - 1;
 		break;
 	case 2:
-		_game.viewTable[0].xPos = 0;
+		screenObjEgo->xPos = 0;
 		break;
 	case 3:
-		_game.viewTable[0].yPos = HORIZON + 1;
+		screenObjEgo->yPos = _game.horizon + 1;
 		break;
 	case 4:
-		_game.viewTable[0].xPos = _WIDTH - _game.viewTable[0].xSize;
+		screenObjEgo->xPos = SCRIPT_WIDTH - screenObjEgo->xSize;
 		break;
 	}
 
 	if (getVersion() < 0x2000) {
-		warning("STUB: NewRoom(%d)", n);
+		warning("STUB: NewRoom(%d)", newRoomNr);
 
-		v->flags &= ~fDidntMove;
+		screenObjEgo->flags &= ~fDidntMove;
 		// animateObject(0);
-		agiLoadResource(rVIEW, _game.viewTable[0].currentView);
-		setView(&_game.viewTable[0], _game.viewTable[0].currentView);
+		agiLoadResource(RESOURCETYPE_VIEW, screenObjEgo->currentViewNr);
+		setView(screenObjEgo, screenObjEgo->currentViewNr);
 
 	} else {
-		_game.vars[vBorderTouchEgo] = 0;
-		setflag(fNewRoomExec, true);
+		if (screenObjEgo->motionType == kMotionEgo) {
+			screenObjEgo->motionType = kMotionNormal;
+			_game.vars[VM_VAR_EGO_DIRECTION] = 0;
+		}
+
+		_game.vars[VM_VAR_BORDER_TOUCH_EGO] = 0;
+		setflag(VM_FLAG_NEW_ROOM_EXEC, true);
 
 		_game.exitAllLogics = true;
 
-		writeStatus();
-		writePrompt();
+		_game._vm->_text->statusDraw();
+		_game._vm->_text->promptRedraw();
 	}
 }
 
 void AgiEngine::resetControllers() {
 	int i;
 
-	for (i = 0; i < MAX_DIRS; i++) {
+	for (i = 0; i < MAX_CONTROLLERS; i++) {
 		_game.controllerOccured[i] = false;
 	}
 }
 
 void AgiEngine::interpretCycle() {
+	ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
 	int oldSound, oldScore;
 
 	if (_game.playerControl)
-		_game.vars[vEgoDir] = _game.viewTable[0].direction;
+		_game.vars[VM_VAR_EGO_DIRECTION] = screenObjEgo->direction;
 	else
-		_game.viewTable[0].direction = _game.vars[vEgoDir];
+		screenObjEgo->direction = _game.vars[VM_VAR_EGO_DIRECTION];
 
 	checkAllMotions();
 
-	oldScore = _game.vars[vScore];
-	oldSound = getflag(fSoundOn);
+	oldScore = _game.vars[VM_VAR_SCORE];
+	oldSound = getflag(VM_FLAG_SOUND_ON);
 
 	_game.exitAllLogics = false;
 	while (runLogic(0) == 0 && !(shouldQuit() || _restartGame)) {
-		_game.vars[vWordNotFound] = 0;
-		_game.vars[vBorderTouchObj] = 0;
-		_game.vars[vBorderCode] = 0;
-		oldScore = _game.vars[vScore];
-		setflag(fEnteredCli, false);
+		_game.vars[VM_VAR_WORD_NOT_FOUND] = 0;
+		_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = 0;
+		_game.vars[VM_VAR_BORDER_CODE] = 0;
+		oldScore = _game.vars[VM_VAR_SCORE];
+		setflag(VM_FLAG_ENTERED_CLI, false);
 		_game.exitAllLogics = false;
+		nonBlockingText_CycleDone();
 		resetControllers();
 	}
+	nonBlockingText_CycleDone();
 	resetControllers();
 
-	_game.viewTable[0].direction = _game.vars[vEgoDir];
+	screenObjEgo->direction = _game.vars[VM_VAR_EGO_DIRECTION];
 
-	if (_game.vars[vScore] != oldScore || getflag(fSoundOn) != oldSound)
-		writeStatus();
+	if (_game.vars[VM_VAR_SCORE] != oldScore || getflag(VM_FLAG_SOUND_ON) != oldSound)
+		_game._vm->_text->statusDraw();
 
-	_game.vars[vBorderTouchObj] = 0;
-	_game.vars[vBorderCode] = 0;
-	setflag(fNewRoomExec, false);
-	setflag(fRestartGame, false);
-	setflag(fRestoreJustRan, false);
+	_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = 0;
+	_game.vars[VM_VAR_BORDER_CODE] = 0;
+	setflag(VM_FLAG_NEW_ROOM_EXEC, false);
+	setflag(VM_FLAG_RESTART_GAME, false);
+	setflag(VM_FLAG_RESTORE_JUST_RAN, false);
 
 	if (_game.gfxMode) {
-		updateViewtable();
-		_gfx->doUpdate();
+		updateScreenObjTable();
 	}
+	_gfx->updateScreen();
+	//_gfx->doUpdate();
 }
 
 /**
@@ -166,27 +180,27 @@ void AgiEngine::updateTimer() {
 	if (!_game.clockEnabled)
 		return;
 
-	setvar(vSeconds, getvar(vSeconds) + 1);
-	if (getvar(vSeconds) < 60)
+	setVar(VM_VAR_SECONDS, getVar(VM_VAR_SECONDS) + 1);
+	if (getVar(VM_VAR_SECONDS) < 60)
 		return;
 
-	setvar(vSeconds, 0);
-	setvar(vMinutes, getvar(vMinutes) + 1);
-	if (getvar(vMinutes) < 60)
+	setVar(VM_VAR_SECONDS, 0);
+	setVar(VM_VAR_MINUTES, getVar(VM_VAR_MINUTES) + 1);
+	if (getVar(VM_VAR_MINUTES) < 60)
 		return;
 
-	setvar(vMinutes, 0);
-	setvar(vHours, getvar(vHours) + 1);
-	if (getvar(vHours) < 24)
+	setVar(VM_VAR_MINUTES, 0);
+	setVar(VM_VAR_HOURS, getVar(VM_VAR_HOURS) + 1);
+	if (getVar(VM_VAR_HOURS) < 24)
 		return;
 
-	setvar(vHours, 0);
-	setvar(vDays, getvar(vDays) + 1);
+	setVar(VM_VAR_HOURS, 0);
+	setVar(VM_VAR_DAYS, getVar(VM_VAR_DAYS) + 1);
 }
 
 void AgiEngine::newInputMode(InputMode mode) {
-	if (mode == INPUT_MENU && !getflag(fMenusWork) && !(getFeatures() & GF_MENUS))
-		return;
+	//if (mode == INPUTMODE_MENU && !getflag(VM_FLAG_MENUS_WORK) && !(getFeatures() & GF_MENUS))
+	//	return;
 
 	_oldMode = _game.inputMode;
 	_game.inputMode = mode;
@@ -198,14 +212,19 @@ void AgiEngine::oldInputMode() {
 
 // If main_cycle returns false, don't process more events!
 int AgiEngine::mainCycle(bool onlyCheckForEvents) {
-	unsigned int key, kascii;
-	VtEntry *v = &_game.viewTable[0];
+	uint16 key;
+	byte   keyAscii;
+	ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
 
 	if (!onlyCheckForEvents) {
 		pollTimer();
 		updateTimer();
 	}
 
+	if (_menu->delayedExecuteActive()) {
+		_menu->execute();
+	}
+
 	key = doPollKeyboard();
 
 	// In AGI Mouse emulation mode we must update the mouse-related
@@ -217,98 +236,106 @@ int AgiEngine::mainCycle(bool onlyCheckForEvents) {
 		_game.vars[29] = _mouse.y;
 	//}
 
-	if (key == KEY_STATUSLN) {	// F11
-		_debug.statusline = !_debug.statusline;
-		writeStatus();
-		key = 0;
-	}
-
-	if (key == KEY_PRIORITY) {	// F12
-		_sprites->eraseBoth();
-		_debug.priority = !_debug.priority;
-		_picture->showPic();
-		_sprites->blitBoth();
-		_sprites->commitBoth();
-		key = 0;
+	switch (_game.inputMode) {
+	case INPUTMODE_NORMAL:
+	case INPUTMODE_NONE:
+		// Click-to-walk mouse interface
+		if (_game.playerControl && (screenObjEgo->flags & fAdjEgoXY)) {
+			int toX = screenObjEgo->move_x;
+			int toY = screenObjEgo->move_y;
+
+			// AGI Mouse games use ego's sprite's bottom left corner for mouse walking target.
+			// Amiga games use ego's sprite's bottom center for mouse walking target.
+			// Atari ST and Apple II GS seem to use the bottom left
+			if (getPlatform() == Common::kPlatformAmiga)
+				toX -= (screenObjEgo->xSize / 2); // Center ego's sprite horizontally
+
+			// Adjust ego's sprite's mouse walking target position (These parameters are
+			// controlled with the adj.ego.move.to.x.y-command). Note that these values rely
+			// on the horizontal centering of the ego's sprite at least on the Amiga platform.
+			toX += _game.adjMouseX;
+			toY += _game.adjMouseY;
+
+			screenObjEgo->direction = getDirection(screenObjEgo->xPos, screenObjEgo->yPos, toX, toY, screenObjEgo->stepSize);
+
+			if (screenObjEgo->direction == 0)
+				inDestination(screenObjEgo);
+		}
+		break;
+	default:
+		break;
 	}
 
-	// Click-to-walk mouse interface
-	if (_game.playerControl && (v->flags & fAdjEgoXY)) {
-		int toX = v->parm1;
-		int toY = v->parm2;
-
-		// AGI Mouse games use ego's sprite's bottom left corner for mouse walking target.
-		// Amiga games use ego's sprite's bottom center for mouse walking target.
-		// TODO: Check what Atari ST AGI and Apple IIGS AGI use for mouse walking target.
-		if (getPlatform() == Common::kPlatformAmiga)
-			toX -= (v->xSize / 2); // Center ego's sprite horizontally
-
-		// Adjust ego's sprite's mouse walking target position (These parameters are
-		// controlled with the adj.ego.move.to.x.y-command). Note that these values rely
-		// on the horizontal centering of the ego's sprite at least on the Amiga platform.
-		toX += _game.adjMouseX;
-		toY += _game.adjMouseY;
-
-		v->direction = getDirection(v->xPos, v->yPos, toX, toY, v->stepSize);
-
-		if (v->direction == 0)
-			inDestination(v);
+	keyAscii = key & 0xFF;
+	if (keyAscii) {
+		setVar(VM_VAR_KEY, keyAscii);
 	}
 
-	kascii = KEY_ASCII(key);
-
-	if (kascii)
-		setvar(vKey, kascii);
-
-	bool restartProcessKey;
-	do {
-		restartProcessKey = false;
-
+	if (!cycleInnerLoopIsActive()) {
+		// no inner loop active at the moment, regular processing
 		switch (_game.inputMode) {
-		case INPUT_NORMAL:
+		case INPUTMODE_NORMAL:
 			if (!handleController(key)) {
-				if (key == 0 || !_game.inputEnabled)
+				if (key == 0 || (!_text->promptIsEnabled()))
 					break;
-				handleKeys(key);
-
-				// if ESC pressed, activate menu before
-				// accept.input from the interpreter cycle
-				// sets the input mode to normal again
-				// (closes: #540856)
-				if (key == KEY_ESCAPE) {
-					key = 0;
-					restartProcessKey = true;
-				}
-
-				// commented out to close Sarien bug #438872
-				//if (key)
-				//	_game.keypress = key;
+
+				_text->promptCharPress(key);
 			}
 			break;
-		case INPUT_GETSTRING:
-			handleController(key);
-			handleGetstring(key);
-			setvar(vKey, 0);	// clear ENTER key
-			break;
-		case INPUT_MENU:
-			_menu->keyhandler(key);
-			_gfx->doUpdate();
-			return false;
-		case INPUT_NONE:
+		case INPUTMODE_NONE:
 			handleController(key);
 			if (key)
 				_game.keypress = key;
 			break;
+		default:
+			break;
 		}
-	} while (restartProcessKey);
 
-	if (!onlyCheckForEvents) {
-		_gfx->doUpdate();
+	} else {
+		// inner loop active
+		// call specific workers
+		setVar(VM_VAR_KEY, 0);	// clear keys, they must not be passed to the scripts
+		_game.keypress = 0;
+
+		switch (_game.cycleInnerLoopType) {
+		case CYCLE_INNERLOOP_GETSTRING: // loop called from TextMgr::stringEdit()
+		case CYCLE_INNERLOOP_GETNUMBER:
+			//handleController(key);
+			if (key) {
+				_text->stringCharPress(key);
+			}
+			break;
+
+		case CYCLE_INNERLOOP_INVENTORY: // loop called from InventoryMgr::show()
+			if (key) {
+				_inventory->charPress(key);
+			}
+			break;
+
+		case CYCLE_INNERLOOP_MENU:
+			if (key) {
+				_menu->charPress(key);
+			}
+			return false;
+
+		case CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT:
+			if (key) {
+				_systemUI->savedGameSlot_CharPress(key);
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
 
+	if (!onlyCheckForEvents) {
 		if (_game.msgBoxTicks > 0)
 			_game.msgBoxTicks--;
 	}
 
+	_gfx->updateScreen();
+
 	return true;
 }
 
@@ -319,19 +346,24 @@ int AgiEngine::playGame() {
 	debugC(2, kDebugLevelMain, "game version = 0x%x", getVersion());
 
 	_sound->stopSound();
-	_gfx->clearScreen(0);
 
-	_game.horizon = HORIZON;
+	// We need to do this accurately and reset the AGI priorityscreen to 4
+	// otherwise at least the fan game Nick's Quest will go into an endless
+	// loop, because the game draws views before it draws the first background picture.
+	// For further study see bug #3451122
+	_gfx->clear(0, 4);
+
+	_game.horizon = 36;
 	_game.playerControl = false;
 
-	setflag(fLogicZeroFirsttime, true);	// not in 2.917
-	setflag(fNewRoomExec, true);	// needed for MUMG and SQ2!
-	setflag(fSoundOn, true);	// enable sound
-	setvar(vTimeDelay, 2);	// "normal" speed
+	setflag(VM_FLAG_LOGIC_ZERO_FIRST_TIME, true);	// not in 2.917
+	setflag(VM_FLAG_NEW_ROOM_EXEC, true);	// needed for MUMG and SQ2!
+	setflag(VM_FLAG_SOUND_ON, true);	// enable sound
+	setVar(VM_VAR_TIME_DELAY, 2);	// "normal" speed
 
 	_game.gfxMode = true;
 	_game.clockEnabled = true;
-	_game.lineUserInput = 22;
+	_text->promptRow_Set(22);
 
 	// We run AGIMOUSE always as a side effect
 	//if (getFeatures() & GF_AGIMOUSE)
@@ -342,25 +374,34 @@ int AgiEngine::playGame() {
 
 	debug(0, "Running AGI script.\n");
 
-	setflag(fEnteredCli, false);
-	setflag(fSaidAcceptedInput, false);
-	_game.vars[vWordNotFound] = 0;
-	_game.vars[vKey] = 0;
+	setflag(VM_FLAG_ENTERED_CLI, false);
+	setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+	_game.vars[VM_VAR_WORD_NOT_FOUND] = 0;
+	_game.vars[VM_VAR_KEY] = 0;
 
 	debugC(2, kDebugLevelMain, "Entering main loop");
-	bool firstLoop = !getflag(fRestartGame); // Do not restore on game restart
+	bool firstLoop = !getflag(VM_FLAG_RESTART_GAME); // Do not restore on game restart
+
+	if (firstLoop) {
+		if (ConfMan.hasKey("save_slot")) {
+			// quick restore enabled
+			_game.automaticRestoreGame = true;
+		}
+	}
+
+	nonBlockingText_Forget();
 
 	do {
 
 		if (!mainCycle())
 			continue;
 
-		if (getvar(vTimeDelay) == 0 || (1 + _clockCount) % getvar(vTimeDelay) == 0) {
-			if (!_game.hasPrompt && _game.inputMode == INPUT_NORMAL) {
-				writePrompt();
+		if (getVar(VM_VAR_TIME_DELAY) == 0 || (1 + _clockCount) % getVar(VM_VAR_TIME_DELAY) == 0) {
+			if (!_game.hasPrompt && _game.inputMode == INPUTMODE_NORMAL) {
+				_text->promptRedraw();
 				_game.hasPrompt = 1;
-			} else if (_game.hasPrompt && _game.inputMode == INPUT_NONE) {
-				writePrompt();
+			} else if (_game.hasPrompt && _game.inputMode == INPUTMODE_NONE) {
+				_text->promptRedraw();
 				_game.hasPrompt = 0;
 			}
 
@@ -368,15 +409,15 @@ int AgiEngine::playGame() {
 
 			// Check if the user has asked to load a game from the command line
 			// or the launcher
-			if (firstLoop) {
+			if (_game.automaticRestoreGame) {
+				_game.automaticRestoreGame = false;
 				checkQuickLoad();
-				firstLoop = false;
 			}
 
-			setflag(fEnteredCli, false);
-			setflag(fSaidAcceptedInput, false);
-			_game.vars[vWordNotFound] = 0;
-			_game.vars[vKey] = 0;
+			setflag(VM_FLAG_ENTERED_CLI, false);
+			setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+			_game.vars[VM_VAR_WORD_NOT_FOUND] = 0;
+			_game.vars[VM_VAR_KEY] = 0;
 		}
 
 		if (shouldPerformAutoSave(_lastSaveTime)) {
@@ -393,6 +434,23 @@ int AgiEngine::playGame() {
 int AgiEngine::runGame() {
 	int ec = errOK;
 
+	// figure out the expected menu trigger for the current platform
+	// need to trigger the menu via mouse and via keyboard for platforms except PC
+	if (!(getFeatures() & GF_ESCPAUSE)) {
+		switch (getPlatform()) {
+		case Common::kPlatformAmiga:
+		case Common::kPlatformApple2GS:
+			_game.specialMenuTriggerKey = AGI_MENU_TRIGGER_APPLE2GS;
+			break;
+		case Common::kPlatformAtariST:
+			_game.specialMenuTriggerKey = AGI_MENU_TRIGGER_ATARIST;
+			break;
+		// Macintosh games seem to use ESC key just like PC versions do
+		default:
+			break;
+		}
+	}
+
 	// Execute the game
 	do {
 		debugC(2, kDebugLevelMain, "game loop");
@@ -402,61 +460,62 @@ int AgiEngine::runGame() {
 			break;
 
 		if (_restartGame) {
-			setflag(fRestartGame, true);
-			setvar(vTimeDelay, 2);	// "normal" speed
+			setflag(VM_FLAG_RESTART_GAME, true);
+			setVar(VM_VAR_TIME_DELAY, 2);	// "normal" speed
 			_restartGame = false;
 		}
 
 		// Set computer type (v20 i.e. vComputer) and sound type
 		switch (getPlatform()) {
 		case Common::kPlatformAtariST:
-			setvar(vComputer, kAgiComputerAtariST);
-			setvar(vSoundgen, kAgiSoundPC);
+			setVar(VM_VAR_COMPUTER, kAgiComputerAtariST);
+			setVar(VM_VAR_SOUNDGENERATOR, kAgiSoundPC);
 			break;
 		case Common::kPlatformAmiga:
 			if (getFeatures() & GF_OLDAMIGAV20)
-				setvar(vComputer, kAgiComputerAmigaOld);
+				setVar(VM_VAR_COMPUTER, kAgiComputerAmigaOld);
 			else
-				setvar(vComputer, kAgiComputerAmiga);
-			setvar(vSoundgen, kAgiSoundTandy);
+				setVar(VM_VAR_COMPUTER, kAgiComputerAmiga);
+			setVar(VM_VAR_SOUNDGENERATOR, kAgiSoundTandy);
 			break;
 		case Common::kPlatformApple2GS:
-			setvar(vComputer, kAgiComputerApple2GS);
+			setVar(VM_VAR_COMPUTER, kAgiComputerApple2GS);
 			if (getFeatures() & GF_2GSOLDSOUND)
-				setvar(vSoundgen, kAgiSound2GSOld);
+				setVar(VM_VAR_SOUNDGENERATOR, kAgiSound2GSOld);
 			else
-				setvar(vSoundgen, kAgiSoundTandy);
+				setVar(VM_VAR_SOUNDGENERATOR, kAgiSoundTandy);
 			break;
 		case Common::kPlatformDOS:
 		default:
-			setvar(vComputer, kAgiComputerPC);
-			setvar(vSoundgen, kAgiSoundPC);
+			setVar(VM_VAR_COMPUTER, kAgiComputerPC);
+			setVar(VM_VAR_SOUNDGENERATOR, kAgiSoundPC);
 			break;
 		}
 
 		// Set monitor type (v26 i.e. vMonitor)
 		switch (_renderMode) {
-		case Common::kRenderCGA:
-			setvar(vMonitor, kAgiMonitorCga);
+		case RENDERMODE_CGA:
+			setVar(VM_VAR_MONITOR, kAgiMonitorCga);
 			break;
-		case Common::kRenderHercG:
-		case Common::kRenderHercA:
-			setvar(vMonitor, kAgiMonitorHercules);
+		case RENDERMODE_HERCULES:
+			setVar(VM_VAR_MONITOR, kAgiMonitorHercules);
 			break;
 		// Don't know if Amiga AGI games use a different value than kAgiMonitorEga
 		// for vMonitor so I just use kAgiMonitorEga for them (As was done before too).
-		case Common::kRenderAmiga:
-		case Common::kRenderDefault:
-		case Common::kRenderEGA:
+		case RENDERMODE_AMIGA:
+		case RENDERMODE_APPLE_II_GS:
+		case RENDERMODE_ATARI_ST:
+		case RENDERMODE_EGA:
+		case RENDERMODE_VGA:
 		default:
-			setvar(vMonitor, kAgiMonitorEga);
+			setVar(VM_VAR_MONITOR, kAgiMonitorEga);
 			break;
 		}
 
-		setvar(vFreePages, 180); // Set amount of free memory to realistic value
-		setvar(vMaxInputChars, 38);
-		_game.inputMode = INPUT_NONE;
-		_game.inputEnabled = false;
+		setVar(VM_VAR_FREE_PAGES, 180); // Set amount of free memory to realistic value
+		setVar(VM_VAR_MAX_INPUT_CHARACTERS, 38);
+		_game.inputMode = INPUTMODE_NONE;
+		_text->promptDisable();
 		_game.hasPrompt = 0;
 
 		_game.state = STATE_RUNNING;
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 971b562..17358e0 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -257,7 +257,6 @@ SaveStateList AgiMetaEngine::listSaves(const char *target) const {
 	const uint32 AGIflag = MKTAG('A','G','I',':');
 	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
 	Common::StringArray filenames;
-	char saveDesc[31];
 	Common::String pattern = target;
 	pattern += ".###";
 
@@ -267,16 +266,35 @@ SaveStateList AgiMetaEngine::listSaves(const char *target) const {
 	SaveStateList saveList;
 	for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
 		// Obtain the last 3 digits of the filename, since they correspond to the save slot
-		int slotNum = atoi(file->c_str() + file->size() - 3);
+		int slotNr = atoi(file->c_str() + file->size() - 3);
 
-		if (slotNum >= 0 && slotNum <= 999) {
+		if (slotNr >= 0 && slotNr <= 999) {
 			Common::InSaveFile *in = saveFileMan->openForLoading(*file);
 			if (in) {
 				uint32 type = in->readUint32BE();
-				if (type == AGIflag)
-					in->read(saveDesc, 31);
-				saveList.push_back(SaveStateDescriptor(slotNum, saveDesc));
+				char description[31];
+
+				if (type == AGIflag) {
+					uint16 descriptionPos = 0;
+
+					in->read(description, 31);
+
+					// Security-check, if saveDescription has a terminating NUL
+					while (description[descriptionPos]) {
+						descriptionPos++;
+						if (descriptionPos >= sizeof(description))
+							break;
+					}
+					if (descriptionPos >= sizeof(description)) {
+						strcpy(description, "[broken saved game]");
+					}
+				} else {
+					strcpy(description, "[not an AGI saved game]");
+				}
+
 				delete in;
+
+				saveList.push_back(SaveStateDescriptor(slotNr, description));
 			}
 		}
 	}
@@ -291,9 +309,9 @@ void AgiMetaEngine::removeSaveState(const char *target, int slot) const {
 	g_system->getSavefileManager()->removeSavefile(fileName);
 }
 
-SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int slotNr) const {
 	const uint32 AGIflag = MKTAG('A','G','I',':');
-	Common::String fileName = Common::String::format("%s.%03d", target, slot);
+	Common::String fileName = Common::String::format("%s.%03d", target, slotNr);
 
 	Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
 
@@ -303,49 +321,73 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl
 			return SaveStateDescriptor();
 		}
 
-		char name[32];
-		in->read(name, 31);
+		char description[31];
+		uint16 descriptionPos = 0;
+
+		in->read(description, 31);
+
+		while (description[descriptionPos]) {
+			descriptionPos++;
+			if (descriptionPos >= sizeof(description))
+				break;
+		}
+		if (descriptionPos >= sizeof(description)) {
+			// broken description, ignore it
+			delete in;
+
+			SaveStateDescriptor descriptor(slotNr, "[broken saved game]");
+			return descriptor;
+		}
 
-		SaveStateDescriptor desc(slot, name);
+		SaveStateDescriptor descriptor(slotNr, description);
 
 		// Do not allow save slot 0 (used for auto-saving) to be deleted or
 		// overwritten.
-		desc.setDeletableFlag(slot != 0);
-		desc.setWriteProtectedFlag(slot == 0);
+		if (slotNr == 0) {
+			descriptor.setWriteProtectedFlag(true);
+			descriptor.setDeletableFlag(false);
+		} else {
+			descriptor.setWriteProtectedFlag(false);
+			descriptor.setDeletableFlag(true);
+		}
 
 		char saveVersion = in->readByte();
 		if (saveVersion >= 4) {
 			Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*in);
 
-			desc.setThumbnail(thumbnail);
+			descriptor.setThumbnail(thumbnail);
 
 			uint32 saveDate = in->readUint32BE();
 			uint16 saveTime = in->readUint16BE();
 			if (saveVersion >= 6) {
 				uint32 playTime = in->readUint32BE();
-				desc.setPlayTime(playTime * 1000);
+				descriptor.setPlayTime(playTime * 1000);
 			}
 
 			int day = (saveDate >> 24) & 0xFF;
 			int month = (saveDate >> 16) & 0xFF;
 			int year = saveDate & 0xFFFF;
 
-			desc.setSaveDate(year, month, day);
+			descriptor.setSaveDate(year, month, day);
 
 			int hour = (saveTime >> 8) & 0xFF;
 			int minutes = saveTime & 0xFF;
 
-			desc.setSaveTime(hour, minutes);
+			descriptor.setSaveTime(hour, minutes);
 		}
 
-
 		delete in;
 
-		return desc;
+		return descriptor;
+
 	} else {
 		SaveStateDescriptor emptySave;
 		// Do not allow save slot 0 (used for auto-saving) to be overwritten.
-		emptySave.setWriteProtectedFlag(slot == 0);
+		if (slotNr == 0) {
+			emptySave.setWriteProtectedFlag(true);
+		} else {
+			emptySave.setWriteProtectedFlag(false);
+		}
 		return emptySave;
 	}
 }
@@ -528,14 +570,17 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 namespace Agi {
 
 bool AgiBase::canLoadGameStateCurrently() {
-	return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed);
+	return (!(getGameType() == GType_PreAGI) && getflag(VM_FLAG_MENUS_WORK) && !_noSaveLoadAllowed);
 }
 
 bool AgiBase::canSaveGameStateCurrently() {
+	bool promptEnabled = false;
+
 	if (getGameID() == GID_BC) // Technically in Black Cauldron we may save anytime
 		return true;
 
-	return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed && _game.inputEnabled);
+	promptEnabled = promptIsEnabled();
+	return (!(getGameType() == GType_PreAGI) && getflag(VM_FLAG_MENUS_WORK) && !_noSaveLoadAllowed && promptEnabled);
 }
 
 int AgiEngine::agiDetectGame() {
diff --git a/engines/agi/font.h b/engines/agi/font.h
index 0e6b15f..6b6381c 100644
--- a/engines/agi/font.h
+++ b/engines/agi/font.h
@@ -25,6 +25,181 @@
 
 namespace Agi {
 
+// Arrow to the right character, used for original saved game dialogs
+// Needs to get patched into at least the Apple IIgs font, because the font didn't support
+// that character and original AGI on Apple IIgs used Apple II menus for saving/restoring.
+static const uint8 fontData_ArrowRightCharacter[8] = {
+	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
+};
+
+// topaz data, same as in engines\parallaction\staticres.cpp
+// seems to have been recreated and is not the original amiga font
+static const uint8 fontData_AmigaPseudoTopaz[2600] = {
+	0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79,
+	0x70, 0xff, 0x4e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+	0x00, 0x1a, 0x0f, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x45, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x74, 0x00, 0x08,
+	0x00, 0x40, 0x00, 0x08, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x00, 0x6e,
+	0x00, 0xbe, 0x00, 0x00, 0x06, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+	0x6c, 0x6c, 0x18, 0x00, 0x38, 0x18, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x18,
+	0x3c, 0x3c, 0x1c, 0x7e, 0x1c, 0x7e, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7c, 0x3c,
+	0x7c, 0x1e, 0x78, 0x7e, 0x7e, 0x3c, 0x66, 0x3c, 0x06, 0xc6, 0x60, 0xc6, 0xc6, 0x3c, 0x7c, 0x78,
+	0x7c, 0x3c, 0x7e, 0x66, 0x66, 0xc6, 0xc3, 0xc3, 0xfe, 0x3c, 0xc0, 0x3c, 0x10, 0x00, 0x18, 0x00,
+	0x60, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x60, 0x18, 0x0c, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x18, 0x70, 0x72, 0x0f, 0x00, 0x18,
+	0x00, 0x1c, 0x42, 0xc3, 0x18, 0x3c, 0x66, 0x7e, 0x1c, 0x00, 0x3e, 0x7e, 0x7e, 0x3c, 0x18, 0x78,
+	0x78, 0x18, 0x00, 0x3e, 0x00, 0x00, 0x30, 0x38, 0x00, 0x40, 0x40, 0xc0, 0x18, 0x3c, 0x3c, 0x7e,
+	0x06, 0x66, 0x18, 0x7e, 0x7e, 0x36, 0x0c, 0x0c, 0x18, 0x3c, 0xc6, 0x3c, 0x60, 0x76, 0x18, 0x00,
+	0x0c, 0x7e, 0x71, 0x66, 0x00, 0x66, 0x60, 0x0e, 0x7e, 0x66, 0x18, 0x6e, 0x3c, 0x00, 0x18, 0x7e,
+	0x06, 0x66, 0x18, 0x00, 0x7e, 0x34, 0x0c, 0x0c, 0x18, 0x0c, 0x60, 0x00, 0x18, 0x3c, 0x0c, 0x00,
+	0x0c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x7e, 0x00, 0x18, 0x3c, 0x00, 0x18, 0x6c, 0x6c,
+	0x3e, 0x66, 0x6c, 0x18, 0x18, 0x18, 0x66, 0x18, 0x00, 0x00, 0x00, 0x06, 0x66, 0x38, 0x66, 0x66,
+	0x3c, 0x60, 0x30, 0x06, 0x66, 0x66, 0x18, 0x18, 0x06, 0x00, 0x60, 0x66, 0xc6, 0x66, 0x66, 0x30,
+	0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x06, 0xcc, 0x60, 0xee, 0xe6, 0x66, 0x66, 0xcc, 0x66, 0x66,
+	0x18, 0x66, 0x66, 0xc6, 0x66, 0x66, 0x0c, 0x30, 0x60, 0x0c, 0x38, 0x00, 0x18, 0x00, 0x60, 0x00,
+	0x06, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x9c, 0x3c, 0x7e, 0x00, 0x0c, 0x36,
+	0x3c, 0x66, 0x18, 0x60, 0x66, 0x81, 0x24, 0x33, 0x06, 0x81, 0x00, 0x66, 0x18, 0x0c, 0x0c, 0x30,
+	0x00, 0x7a, 0x00, 0x00, 0x70, 0x44, 0xcc, 0xc6, 0xc6, 0x23, 0x00, 0x66, 0x18, 0x00, 0x1c, 0x00,
+	0x24, 0x60, 0x00, 0x1c, 0x18, 0x18, 0x00, 0x66, 0xcc, 0x00, 0x60, 0x3c, 0x30, 0xc6, 0x18, 0x00,
+	0x8e, 0x00, 0xc6, 0x66, 0x60, 0x38, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x0c, 0x00,
+	0x24, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x7e,
+	0x8e, 0x66, 0x18, 0x00, 0x18, 0x18, 0x00, 0x66, 0x00, 0x18, 0x00, 0x18, 0x00, 0xfe, 0x60, 0xac,
+	0x68, 0x30, 0x30, 0x0c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x78, 0x06, 0x06, 0x6c, 0x7c,
+	0x60, 0x06, 0x66, 0x66, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x06, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60,
+	0x60, 0x60, 0x66, 0x18, 0x06, 0xd8, 0x60, 0xfe, 0xf6, 0x66, 0x66, 0xcc, 0x66, 0x70, 0x18, 0x66,
+	0x66, 0xc6, 0x3c, 0x3c, 0x18, 0x30, 0x30, 0x0c, 0x6c, 0x00, 0x0c, 0x3c, 0x7c, 0x3c, 0x3e, 0x3c,
+	0x7c, 0x3e, 0x7c, 0x18, 0x0c, 0x66, 0x18, 0xec, 0x7c, 0x3c, 0x7c, 0x3e, 0x7c, 0x3c, 0x7c, 0x66,
+	0x66, 0xc6, 0xc6, 0x66, 0x7e, 0x18, 0x18, 0x18, 0x00, 0xf0, 0x66, 0x18, 0x3e, 0x30, 0x66, 0x3c,
+	0x18, 0x3c, 0x00, 0x9d, 0x44, 0x66, 0x00, 0xb9, 0x00, 0x3c, 0x7e, 0x18, 0x18, 0x60, 0x66, 0x7a,
+	0x18, 0x00, 0x30, 0x44, 0x66, 0x4c, 0x4c, 0x66, 0x18, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x60,
+	0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x60, 0xd8, 0x3c, 0x60, 0x66, 0xc6, 0xe6, 0x3c, 0x3c, 0x3c, 0x3c,
+	0x6c, 0x66, 0x6c, 0x66, 0x66, 0x66, 0x7e, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0x3c, 0x3c, 0x3c,
+	0x3c, 0x18, 0x3c, 0x7e, 0x3c, 0x3e, 0x6c, 0x00, 0x18, 0x3c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x66, 0x1e, 0x3c, 0x66, 0x00, 0x7e, 0x7e, 0x00, 0x18, 0x00, 0x6c, 0x3c, 0xd8, 0x76, 0x00,
+	0x30, 0x0c, 0xff, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x7e, 0x18, 0x0c, 0x1c, 0xcc, 0x06, 0x7c, 0x0c,
+	0x3c, 0x3e, 0x00, 0x00, 0x60, 0x00, 0x06, 0x0c, 0xd6, 0x7e, 0x7c, 0x60, 0x66, 0x78, 0x78, 0x6e,
+	0x7e, 0x18, 0x06, 0xf0, 0x60, 0xd6, 0xde, 0x66, 0x7c, 0xcc, 0x7c, 0x3c, 0x18, 0x66, 0x66, 0xd6,
+	0x18, 0x18, 0x30, 0x30, 0x18, 0x0c, 0xc6, 0x00, 0x00, 0x06, 0x66, 0x60, 0x66, 0x66, 0x30, 0x66,
+	0x66, 0x18, 0x0c, 0x6c, 0x18, 0xfe, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x30, 0x66, 0x66, 0xc6,
+	0x6c, 0x66, 0x0c, 0x70, 0x18, 0x0e, 0x00, 0xc3, 0x66, 0x18, 0x6c, 0x78, 0x3c, 0x18, 0x00, 0x66,
+	0x00, 0xb1, 0x3c, 0xcc, 0x00, 0xa5, 0x00, 0x00, 0x18, 0x30, 0x0c, 0x00, 0x66, 0x3a, 0x18, 0x00,
+	0x30, 0x38, 0x33, 0x58, 0x58, 0x2c, 0x30, 0x7e, 0x18, 0x66, 0x66, 0x66, 0x66, 0x78, 0x60, 0x66,
+	0x60, 0x4c, 0x60, 0x6e, 0xf0, 0x18, 0x60, 0x30, 0xe6, 0xf6, 0x66, 0x66, 0x66, 0x66, 0x38, 0x66,
+	0x70, 0x30, 0x66, 0x66, 0x4c, 0x4c, 0x6c, 0x06, 0x18, 0x06, 0x3c, 0x06, 0x06, 0x66, 0x66, 0x3c,
+	0x66, 0x0c, 0x66, 0x66, 0x78, 0x18, 0x18, 0x60, 0x7c, 0x66, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x66,
+	0x78, 0x60, 0x66, 0x66, 0x0c, 0x0c, 0x00, 0x18, 0x00, 0xfe, 0x06, 0x36, 0xdc, 0x00, 0x30, 0x0c,
+	0x3c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x76, 0x18, 0x18, 0x06, 0xfe, 0x06, 0x66, 0x18, 0x66, 0x06,
+	0x00, 0x00, 0x18, 0x7e, 0x18, 0x18, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60, 0x60, 0x66, 0x66, 0x18,
+	0x06, 0xd8, 0x60, 0xc6, 0xce, 0x66, 0x60, 0xcc, 0x6c, 0x0e, 0x18, 0x66, 0x3c, 0xfe, 0x3c, 0x18,
+	0x60, 0x30, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x60, 0x66, 0x7e, 0x30, 0x66, 0x66, 0x18,
+	0x0c, 0x78, 0x18, 0xd6, 0x66, 0x66, 0x66, 0x66, 0x60, 0x3c, 0x30, 0x66, 0x66, 0xd6, 0x38, 0x66,
+	0x18, 0x18, 0x18, 0x18, 0x00, 0x0f, 0x66, 0x18, 0x3e, 0x30, 0x42, 0x3c, 0x18, 0x3c, 0x00, 0x9d,
+	0x00, 0x66, 0x00, 0xb9, 0x00, 0x00, 0x18, 0x7c, 0x78, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x30, 0x00,
+	0x66, 0x32, 0x3e, 0xd9, 0x60, 0x66, 0x18, 0x7e, 0x40, 0x7e, 0x7e, 0x60, 0x78, 0x40, 0x78, 0x18,
+	0x78, 0x66, 0xd8, 0x18, 0x60, 0x0c, 0xf6, 0xde, 0x66, 0x66, 0x66, 0x66, 0x6c, 0x66, 0xe0, 0x0c,
+	0x66, 0x66, 0x18, 0x18, 0x66, 0x3e, 0x18, 0x3e, 0x60, 0x3e, 0x3e, 0x7e, 0x7e, 0x60, 0x7e, 0x18,
+	0x7e, 0x66, 0x6c, 0x18, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x18, 0x3c,
+	0x66, 0x66, 0x18, 0x18, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x6a, 0xce, 0x00, 0x18, 0x18, 0x66, 0x18,
+	0x18, 0x00, 0x18, 0x60, 0x66, 0x18, 0x30, 0x66, 0x0c, 0x66, 0x66, 0x18, 0x66, 0x0c, 0x18, 0x18,
+	0x06, 0x00, 0x60, 0x00, 0xc0, 0x66, 0x66, 0x30, 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x66, 0xcc,
+	0x60, 0xc6, 0xc6, 0x66, 0x60, 0xdc, 0x66, 0x66, 0x18, 0x66, 0x3c, 0xee, 0x66, 0x18, 0xc0, 0x30,
+	0x06, 0x0c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x60, 0x66, 0x60, 0x30, 0x3e, 0x66, 0x18, 0x0c, 0x6c,
+	0x18, 0xc6, 0x66, 0x66, 0x7c, 0x3e, 0x60, 0x06, 0x30, 0x66, 0x3c, 0xfe, 0x6c, 0x3c, 0x30, 0x18,
+	0x18, 0x18, 0x00, 0x3c, 0x66, 0x18, 0x0c, 0x30, 0x00, 0x18, 0x18, 0x06, 0x00, 0x81, 0x7e, 0x33,
+	0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x00, 0x7c, 0xcc, 0x66,
+	0x62, 0x33, 0x66, 0x66, 0x18, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0x66, 0x60, 0x32, 0x60, 0x3e,
+	0xcc, 0x18, 0x7e, 0x66, 0xde, 0xce, 0x66, 0x66, 0x66, 0x66, 0xc6, 0x66, 0x60, 0x66, 0x66, 0x66,
+	0x32, 0x32, 0x66, 0x66, 0x18, 0x66, 0x60, 0x66, 0x66, 0x60, 0x60, 0x60, 0x60, 0x30, 0x60, 0x3e,
+	0x66, 0x18, 0x18, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x18, 0x66, 0x18, 0x06, 0x66, 0x66,
+	0x30, 0x30, 0x00, 0x18, 0x00, 0x6c, 0x18, 0xcc, 0x7b, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x18, 0x00,
+	0x18, 0xc0, 0x3c, 0x18, 0x7e, 0x3c, 0x0c, 0x3c, 0x3c, 0x18, 0x3c, 0x38, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x18, 0x78, 0x66, 0x7c, 0x1e, 0x78, 0x7e, 0x60, 0x3e, 0x66, 0x3c, 0x3c, 0xc6, 0x7e, 0xc6,
+	0xc6, 0x3c, 0x60, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0xc6, 0xc3, 0x18, 0xfe, 0x3c, 0x03, 0x3c,
+	0x00, 0x00, 0x00, 0x3e, 0x7c, 0x3c, 0x3e, 0x3c, 0x30, 0x06, 0x66, 0x0c, 0x0c, 0x66, 0x0c, 0xc6,
+	0x66, 0x3c, 0x60, 0x06, 0x60, 0x7c, 0x1c, 0x3e, 0x18, 0x6c, 0xc6, 0x18, 0x7e, 0x0e, 0x18, 0x70,
+	0x00, 0xf0, 0x7e, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x3c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x81,
+	0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00, 0xcf, 0xc4, 0x67,
+	0x3c, 0x67, 0x3e, 0x66, 0x3c, 0x66, 0x66, 0x7f, 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x18, 0x30, 0x3c,
+	0x18, 0x3c, 0xce, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x7e, 0x3c, 0x3c, 0x3c, 0x7e, 0x7e,
+	0x6c, 0x3f, 0x1e, 0x3e, 0x3c, 0x3e, 0x3e, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x3c, 0x06, 0x18, 0x0c,
+	0x0c, 0x7c, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x0c, 0x7c, 0x3e, 0x3e, 0x7e, 0x7e,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x01, 0x00, 0x03,
+	0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x00, 0x30, 0x00,
+	0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03,
+	0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x18, 0x00,
+	0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x18, 0x00, 0x08, 0x00, 0x20,
+	0x00, 0x08, 0x00, 0x28, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x00, 0x40,
+	0x00, 0x08, 0x00, 0x48, 0x00, 0x08, 0x00, 0x50, 0x00, 0x08, 0x00, 0x58, 0x00, 0x08, 0x00, 0x60,
+	0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x00, 0x70, 0x00, 0x08, 0x00, 0x78, 0x00, 0x08, 0x00, 0x80,
+	0x00, 0x08, 0x00, 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0x98, 0x00, 0x08, 0x00, 0xa0,
+	0x00, 0x08, 0x00, 0xa8, 0x00, 0x08, 0x00, 0xb0, 0x00, 0x08, 0x00, 0xb8, 0x00, 0x08, 0x00, 0xc0,
+	0x00, 0x08, 0x00, 0xc8, 0x00, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x00, 0xd8, 0x00, 0x08, 0x00, 0xe0,
+	0x00, 0x08, 0x00, 0xe8, 0x00, 0x08, 0x00, 0xf0, 0x00, 0x08, 0x00, 0xf8, 0x00, 0x08, 0x01, 0x00,
+	0x00, 0x08, 0x01, 0x08, 0x00, 0x08, 0x01, 0x10, 0x00, 0x08, 0x01, 0x18, 0x00, 0x08, 0x01, 0x20,
+	0x00, 0x08, 0x01, 0x28, 0x00, 0x08, 0x01, 0x30, 0x00, 0x08, 0x01, 0x38, 0x00, 0x08, 0x01, 0x40,
+	0x00, 0x08, 0x01, 0x48, 0x00, 0x08, 0x01, 0x50, 0x00, 0x08, 0x01, 0x58, 0x00, 0x08, 0x01, 0x60,
+	0x00, 0x08, 0x01, 0x68, 0x00, 0x08, 0x01, 0x70, 0x00, 0x08, 0x01, 0x78, 0x00, 0x08, 0x01, 0x80,
+	0x00, 0x08, 0x01, 0x88, 0x00, 0x08, 0x01, 0x90, 0x00, 0x08, 0x01, 0x98, 0x00, 0x08, 0x01, 0xa0,
+	0x00, 0x08, 0x01, 0xa8, 0x00, 0x08, 0x01, 0xb0, 0x00, 0x08, 0x01, 0xb8, 0x00, 0x08, 0x01, 0xc0,
+	0x00, 0x08, 0x01, 0xc8, 0x00, 0x08, 0x01, 0xd0, 0x00, 0x08, 0x01, 0xd8, 0x00, 0x08, 0x01, 0xe0,
+	0x00, 0x08, 0x01, 0xe8, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xf8, 0x00, 0x08, 0x02, 0x00,
+	0x00, 0x08, 0x02, 0x08, 0x00, 0x08, 0x02, 0x10, 0x00, 0x08, 0x02, 0x18, 0x00, 0x08, 0x02, 0x20,
+	0x00, 0x08, 0x02, 0x28, 0x00, 0x08, 0x02, 0x30, 0x00, 0x08, 0x02, 0x38, 0x00, 0x08, 0x02, 0x40,
+	0x00, 0x08, 0x02, 0x48, 0x00, 0x08, 0x02, 0x50, 0x00, 0x08, 0x02, 0x58, 0x00, 0x08, 0x02, 0x60,
+	0x00, 0x08, 0x02, 0x68, 0x00, 0x08, 0x02, 0x70, 0x00, 0x08, 0x02, 0x78, 0x00, 0x08, 0x02, 0x80,
+	0x00, 0x08, 0x02, 0x88, 0x00, 0x08, 0x02, 0x90, 0x00, 0x08, 0x02, 0x98, 0x00, 0x08, 0x02, 0xa0,
+	0x00, 0x08, 0x02, 0xa8, 0x00, 0x08, 0x02, 0xb0, 0x00, 0x08, 0x02, 0xb8, 0x00, 0x08, 0x02, 0xc0,
+	0x00, 0x08, 0x02, 0xc8, 0x00, 0x08, 0x02, 0xd0, 0x00, 0x08, 0x02, 0xd8, 0x00, 0x08, 0x02, 0xe0,
+	0x00, 0x08, 0x02, 0xe8, 0x00, 0x08, 0x02, 0xf0, 0x00, 0x08, 0x02, 0xf8, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x08, 0x03, 0x08, 0x00, 0x08, 0x03, 0x10, 0x00, 0x08, 0x03, 0x18, 0x00, 0x08, 0x03, 0x20,
+	0x00, 0x08, 0x03, 0x28, 0x00, 0x08, 0x03, 0x30, 0x00, 0x08, 0x03, 0x38, 0x00, 0x08, 0x03, 0x40,
+	0x00, 0x08, 0x03, 0x48, 0x00, 0x08, 0x03, 0x50, 0x00, 0x08, 0x03, 0x58, 0x00, 0x08, 0x03, 0x60,
+	0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x03, 0x68, 0x00, 0x08, 0x03, 0x70, 0x00, 0x08, 0x03, 0x78,
+	0x00, 0x08, 0x03, 0x80, 0x00, 0x08, 0x03, 0x88, 0x00, 0x08, 0x03, 0x90, 0x00, 0x08, 0x03, 0x98,
+	0x00, 0x08, 0x03, 0xa0, 0x00, 0x08, 0x03, 0xa8, 0x00, 0x08, 0x03, 0xb0, 0x00, 0x08, 0x03, 0xb8,
+	0x00, 0x08, 0x03, 0xc0, 0x00, 0x08, 0x03, 0xc8, 0x00, 0x08, 0x03, 0xd0, 0x00, 0x08, 0x03, 0xd8,
+	0x00, 0x08, 0x03, 0xe0, 0x00, 0x08, 0x03, 0xe8, 0x00, 0x08, 0x03, 0xf0, 0x00, 0x08, 0x03, 0xf8,
+	0x00, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x08, 0x00, 0x08, 0x04, 0x10, 0x00, 0x08, 0x04, 0x18,
+	0x00, 0x08, 0x04, 0x20, 0x00, 0x08, 0x04, 0x28, 0x00, 0x08, 0x04, 0x30, 0x00, 0x08, 0x04, 0x38,
+	0x00, 0x08, 0x04, 0x40, 0x00, 0x08, 0x04, 0x48, 0x00, 0x08, 0x04, 0x50, 0x00, 0x08, 0x04, 0x58,
+	0x00, 0x08, 0x04, 0x60, 0x00, 0x08, 0x04, 0x68, 0x00, 0x08, 0x04, 0x70, 0x00, 0x08, 0x04, 0x78,
+	0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04, 0x88, 0x00, 0x08, 0x04, 0x90, 0x00, 0x08, 0x04, 0x98,
+	0x00, 0x08, 0x04, 0xa0, 0x00, 0x08, 0x04, 0xa8, 0x00, 0x08, 0x04, 0xb0, 0x00, 0x08, 0x04, 0xb8,
+	0x00, 0x08, 0x04, 0xc0, 0x00, 0x08, 0x04, 0xc8, 0x00, 0x08, 0x04, 0xd0, 0x00, 0x08, 0x04, 0xd8,
+	0x00, 0x08, 0x04, 0xe0, 0x00, 0x08, 0x04, 0xe8, 0x00, 0x08, 0x04, 0xf0, 0x00, 0x08, 0x04, 0xf8,
+	0x00, 0x08, 0x05, 0x00, 0x00, 0x08, 0x05, 0x08, 0x00, 0x08, 0x05, 0x10, 0x00, 0x08, 0x05, 0x18,
+	0x00, 0x08, 0x05, 0x20, 0x00, 0x08, 0x05, 0x28, 0x00, 0x08, 0x05, 0x30, 0x00, 0x08, 0x05, 0x38,
+	0x00, 0x08, 0x05, 0x40, 0x00, 0x08, 0x05, 0x48, 0x00, 0x08, 0x05, 0x50, 0x00, 0x08, 0x05, 0x58,
+	0x00, 0x08, 0x05, 0x60, 0x00, 0x08, 0x05, 0x68, 0x00, 0x08, 0x05, 0x70, 0x00, 0x08, 0x05, 0x78,
+	0x00, 0x08, 0x05, 0x80, 0x00, 0x08, 0x05, 0x88, 0x00, 0x08, 0x05, 0x90, 0x00, 0x08, 0x05, 0x98,
+	0x00, 0x08, 0x05, 0xa0, 0x00, 0x08, 0x05, 0xa8, 0x00, 0x08, 0x05, 0xb0, 0x00, 0x08, 0x05, 0xb8,
+	0x00, 0x08, 0x05, 0xc0, 0x00, 0x08, 0x05, 0xc8, 0x00, 0x08, 0x05, 0xd0, 0x00, 0x08, 0x05, 0xd8,
+	0x00, 0x08, 0x05, 0xe0, 0x00, 0x08, 0x05, 0xe8, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf2
+};
+
 // 8x8 font patterns
 static const uint8 fontData_Sierra[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -546,6 +721,7 @@ static const uint8 fontData_FanGames[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
 };
 
+#if 0
 static const uint8 fontData_Mickey[] = {
 	0x00, 0x36, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00,
 	0x00, 0x00, 0x3F, 0x20, 0x2F, 0x28, 0x28, 0x28,
@@ -804,6 +980,7 @@ static const uint8 fontData_Mickey[] = {
 	0x08, 0x18, 0x38, 0x78, 0x38, 0x18, 0x08, 0x00,
 	0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00,
 };
+#endif
 
 static const uint8 fontData_IBM[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index 7d55316..bf6356d 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -48,17 +48,17 @@ void AgiBase::flipflag(int n) {
 	*set ^= 1 << (n & 0x07);	// flip bit
 }
 
-void AgiEngine::setvar(int var, int val) {
-	_game.vars[var] = val;
+void AgiEngine::setVar(int16 varNr, int val) {
+	_game.vars[varNr] = val;
 
-	if (var == vVolume) {
+	if (varNr == VM_VAR_VOLUME) {
 		_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, val * 17);
 		_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, val * 17);
 	}
 }
 
-int AgiEngine::getvar(int var) {
-	return _game.vars[var];
+int AgiEngine::getVar(int16 varNr) {
+	return _game.vars[varNr];
 }
 
 void AgiEngine::decrypt(uint8 *mem, int len) {
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index b46e6f7..e9ae129 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -23,773 +23,739 @@
 #include "common/config-manager.h"
 #include "common/file.h"
 #include "common/textconsole.h"
+#include "engines/util.h"
 
 #include "graphics/cursorman.h"
 #include "graphics/palette.h"
 
 #include "agi/agi.h"
 #include "agi/graphics.h"
+#include "agi/mouse_cursor.h"
+#include "agi/palette.h"
+#include "agi/picture.h"
+#include "agi/text.h"
 
 namespace Agi {
 
-#define DEV_X0(x) ((x) << 1)
-#define DEV_X1(x) (((x) << 1) + 1)
-#define DEV_Y(x) (x)
+#include "agi/font.h"
 
-#ifndef MAX_INT
-#  define MAX_INT (int)((unsigned)~0 >> 1)
-#endif
+GfxMgr::GfxMgr(AgiBase *vm) : _vm(vm) {
+	_agipalFileNum = 0;
 
-#include "agi/font.h"
+	memset(&_paletteGfxMode, 0, sizeof(_paletteGfxMode));
+	memset(&_paletteTextMode, 0, sizeof(_paletteTextMode));
 
-/**
- * 16 color RGB palette.
- * This array contains the 6-bit RGB values of the EGA palette exported
- * to the console drivers.
- */
-static const uint8 egaPalette[16 * 3] = {
-	0x00, 0x00, 0x00,
-	0x00, 0x00, 0x2a,
-	0x00, 0x2a, 0x00,
-	0x00, 0x2a, 0x2a,
-	0x2a, 0x00, 0x00,
-	0x2a, 0x00, 0x2a,
-	0x2a, 0x15, 0x00,
-	0x2a, 0x2a, 0x2a,
-	0x15, 0x15, 0x15,
-	0x15, 0x15, 0x3f,
-	0x15, 0x3f, 0x15,
-	0x15, 0x3f, 0x3f,
-	0x3f, 0x15, 0x15,
-	0x3f, 0x15, 0x3f,
-	0x3f, 0x3f, 0x15,
-	0x3f, 0x3f, 0x3f
-};
+	memset(&_mouseCursor, 0, sizeof(_mouseCursor));
+	memset(&_mouseCursorBusy, 0, sizeof(_mouseCursorBusy));
 
-/**
- * Atari ST AGI palette.
- * Used by all of the tested Atari ST AGI games
- * from Donald Duck's Playground (1986) to Manhunter II (1989).
- * 16 RGB colors. 3 bits per color component.
- */
-#if 0
-static const uint8 atariStAgiPalette[16 * 3] = {
-	0x0, 0x0, 0x0,
-	0x0, 0x0, 0x7,
-	0x0, 0x4, 0x0,
-	0x0, 0x5, 0x4,
-	0x5, 0x0, 0x0,
-	0x5, 0x3, 0x6,
-	0x4, 0x3, 0x0,
-	0x5, 0x5, 0x5,
-	0x3, 0x3, 0x2,
-	0x0, 0x5, 0x7,
-	0x0, 0x6, 0x0,
-	0x0, 0x7, 0x6,
-	0x7, 0x2, 0x3,
-	0x7, 0x4, 0x7,
-	0x7, 0x7, 0x4,
-	0x7, 0x7, 0x7
-};
-#endif
+	initPriorityTable();
 
-/**
- * Second generation Apple IIGS AGI palette.
- * A 16-color, 12-bit RGB palette.
- *
- * Used by at least the following Apple IIGS AGI versions:
- * 1.003 (Leisure Suit Larry I  v1.0E, intro says 1987)
- * 1.005 (AGI Demo 2            1987-06-30?)
- * 1.006 (King's Quest I        v1.0S 1988-02-23)
- * 1.007 (Police Quest I        v2.0B 1988-04-21 8:00am)
- * 1.013 (King's Quest II       v2.0A 1988-06-16 (CE))
- * 1.013 (Mixed-Up Mother Goose v2.0A 1988-05-31 10:00am)
- * 1.014 (King's Quest III      v2.0A 1988-08-28 (CE))
- * 1.014 (Space Quest II        v2.0A, LOGIC.141 says 1988)
- * 2.004 (Manhunter I           v2.0E 1988-10-05 (CE))
- * 2.006 (King's Quest IV       v1.0K 1988-11-22 (CE))
- * 3.001 (Black Cauldron        v1.0O 1989-02-24 (CE))
- * 3.003 (Gold Rush!            v1.0M 1989-02-28 (CE))
- */
-#if 0
-// FIXME: Identical to amigaAgiPaletteV2
-static const uint8 appleIIgsAgiPaletteV2[16 * 3] = {
-	0x0, 0x0, 0x0,
-	0x0, 0x0, 0xF,
-	0x0, 0x8, 0x0,
-	0x0, 0xD, 0xB,
-	0xC, 0x0, 0x0,
-	0xB, 0x7, 0xD,
-	0x8, 0x5, 0x0,
-	0xB, 0xB, 0xB,
-	0x7, 0x7, 0x7,
-	0x0, 0xB, 0xF,
-	0x0, 0xE, 0x0,
-	0x0, 0xF, 0xD,
-	0xF, 0x9, 0x8,
-	0xD, 0x9, 0xF, // Only this differs from the 1st generation palette
-	0xE, 0xE, 0x0,
-	0xF, 0xF, 0xF
-};
-#endif
+	_renderStartOffsetY = 0;
+}
 
 /**
- * First generation Amiga & Apple IIGS AGI palette.
- * A 16-color, 12-bit RGB palette.
- *
- * Used by at least the following Amiga AGI versions:
- * 2.082 (King's Quest I   v1.0U 1986)
- * 2.082 (Space Quest I    v1.2  1986)
- * 2.090 (King's Quest III v1.01 1986-11-08)
- * 2.107 (King's Quest II  v2.0J 1987-01-29)
- * x.yyy (Black Cauldron   v2.00 1987-06-14)
- * x.yyy (Larry I          v1.05 1987-06-26)
+ * Initialize graphics device.
  *
- * Also used by at least the following Apple IIGS AGI versions:
- * 1.002 (Space Quest I, intro says v2.2 1987)
+ * @see deinit_video()
  */
-static const uint8 amigaAgiPaletteV1[16 * 3] = {
-	0x0, 0x0, 0x0,
-	0x0, 0x0, 0xF,
-	0x0, 0x8, 0x0,
-	0x0, 0xD, 0xB,
-	0xC, 0x0, 0x0,
-	0xB, 0x7, 0xD,
-	0x8, 0x5, 0x0,
-	0xB, 0xB, 0xB,
-	0x7, 0x7, 0x7,
-	0x0, 0xB, 0xF,
-	0x0, 0xE, 0x0,
-	0x0, 0xF, 0xD,
-	0xF, 0x9, 0x8,
-	0xF, 0x7, 0x0,
-	0xE, 0xE, 0x0,
-	0xF, 0xF, 0xF
-};
+int GfxMgr::initVideo() {
+	// Set up palettes
+	initPalette(_paletteTextMode, PALETTE_EGA);
+
+	switch (_vm->_renderMode) {
+	case RENDERMODE_EGA:
+		initPalette(_paletteGfxMode, PALETTE_EGA);
+		break;
+	case RENDERMODE_CGA:
+		initPalette(_paletteGfxMode, PALETTE_CGA, 4, 8);
+		break;
+	case RENDERMODE_VGA:
+		initPalette(_paletteGfxMode, PALETTE_VGA, 256, 8);
+		break;
+	case RENDERMODE_AMIGA:
+		if (!ConfMan.getBool("altamigapalette")) {
+			// Set the correct Amiga palette depending on AGI interpreter version
+			if (_vm->getVersion() < 0x2936)
+				initPalette(_paletteGfxMode, PALETTE_AMIGA_V1, 16, 4);
+			else if (_vm->getVersion() == 0x2936)
+				initPalette(_paletteGfxMode, PALETTE_AMIGA_V2, 16, 4);
+			else if (_vm->getVersion() > 0x2936)
+				initPalette(_paletteGfxMode, PALETTE_AMIGA_V3, 16, 4);
+		} else {
+			// Set the old common alternative Amiga palette
+			initPalette(_paletteGfxMode, PALETTE_AMIGA_ALT);
+		}
+		break;
+	case RENDERMODE_APPLE_II_GS:
+		initPalette(_paletteGfxMode, PALETTE_APPLE_II_GS, 16, 4);
+		break;
+	case RENDERMODE_ATARI_ST:
+		initPalette(_paletteGfxMode, PALETTE_ATARI_ST, 16, 3);
+		break;
+	default:
+		error("initVideo: unsupported render mode");
+		break;
+	}
 
-/**
- * Second generation Amiga AGI palette.
- * A 16-color, 12-bit RGB palette.
- *
- * Used by at least the following Amiga AGI versions:
- * 2.202 (Space Quest II v2.0F. Intro says 1988. ScummVM 0.10.0 detects as 1986-12-09)
- */
-static const uint8 amigaAgiPaletteV2[16 * 3] = {
-	0x0, 0x0, 0x0,
-	0x0, 0x0, 0xF,
-	0x0, 0x8, 0x0,
-	0x0, 0xD, 0xB,
-	0xC, 0x0, 0x0,
-	0xB, 0x7, 0xD,
-	0x8, 0x5, 0x0,
-	0xB, 0xB, 0xB,
-	0x7, 0x7, 0x7,
-	0x0, 0xB, 0xF,
-	0x0, 0xE, 0x0,
-	0x0, 0xF, 0xD,
-	0xF, 0x9, 0x8,
-	0xD, 0x0, 0xF,
-	0xE, 0xE, 0x0,
-	0xF, 0xF, 0xF
-};
+	// set up mouse cursors
+	switch (_vm->_renderMode) {
+	case RENDERMODE_EGA:
+	case RENDERMODE_CGA:
+	case RENDERMODE_VGA:
+		initMouseCursor(&_mouseCursor, MOUSECURSOR_SCI, 11, 16, 1, 1);
+		initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
+		break;
+	case RENDERMODE_AMIGA:
+		initMouseCursor(&_mouseCursor, MOUSECURSOR_AMIGA, 8, 11, 1, 1);
+		initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_AMIGA_BUSY, 13, 16, 7, 8);
+		break;
+	case RENDERMODE_APPLE_II_GS:
+		// had no special busy mouse cursor
+		initMouseCursor(&_mouseCursor, MOUSECURSOR_APPLE_II_GS, 9, 11, 1, 1);
+		initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
+		break;
+	case RENDERMODE_ATARI_ST:
+		initMouseCursor(&_mouseCursor, MOUSECURSOR_ATARI_ST, 11, 16, 1, 1);
+		initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
+		break;
+	default:
+		error("initVideo: unsupported render mode");
+		break;
+	}
 
-/**
- * Third generation Amiga AGI palette.
- * A 16-color, 12-bit RGB palette.
- *
- * Used by at least the following Amiga AGI versions:
- * 2.310 (Police Quest I   v2.0B 1989-02-22)
- * 2.316 (Gold Rush!       v2.05 1989-03-09)
- * x.yyy (Manhunter I      v1.06 1989-03-18)
- * 2.333 (Manhunter II     v3.06 1989-08-17)
- * 2.333 (King's Quest III v2.15 1989-11-15)
- */
-static const uint8 amigaAgiPaletteV3[16 * 3] = {
-	0x0, 0x0, 0x0,
-	0x0, 0x0, 0xB,
-	0x0, 0xB, 0x0,
-	0x0, 0xB, 0xB,
-	0xB, 0x0, 0x0,
-	0xB, 0x0, 0xB,
-	0xC, 0x7, 0x0,
-	0xB, 0xB, 0xB,
-	0x7, 0x7, 0x7,
-	0x0, 0x0, 0xF,
-	0x0, 0xF, 0x0,
-	0x0, 0xF, 0xF,
-	0xF, 0x0, 0x0,
-	0xF, 0x0, 0xF,
-	0xF, 0xF, 0x0,
-	0xF, 0xF, 0xF
-};
+	_pixels = SCRIPT_WIDTH * SCRIPT_HEIGHT;
+	_visualScreen = (byte *)calloc(_pixels, 1);
+	_priorityScreen = (byte *)calloc(_pixels, 1);
+	_activeScreen = _visualScreen;
+	//_activeScreen = _priorityScreen;
 
-/**
- * 16 color amiga-ish palette.
- */
-static const uint8 altAmigaPalette[16 * 3] = {
-	0x00, 0x00, 0x00,
-	0x00, 0x00, 0x3f,
-	0x00, 0x2A, 0x00,
-	0x00, 0x2A, 0x2A,
-	0x33, 0x00, 0x00,
-	0x2f, 0x1c, 0x37,
-	0x23, 0x14, 0x00,
-	0x2f, 0x2f, 0x2f,
-	0x15, 0x15, 0x15,
-	0x00, 0x2f, 0x3f,
-	0x00, 0x33, 0x15,
-	0x15, 0x3F, 0x3F,
-	0x3f, 0x27, 0x23,
-	0x3f, 0x15, 0x3f,
-	0x3b, 0x3b, 0x00,
-	0x3F, 0x3F, 0x3F
-};
+	_displayPixels = DISPLAY_WIDTH * DISPLAY_HEIGHT;
+	_displayScreen = (byte *)calloc(_displayPixels, 1);
+
+	initGraphics(DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_WIDTH > 320);
+
+	setPalette(true); // set gfx-mode palette
+
+	// set up mouse cursor palette
+	CursorMan.replaceCursorPalette(MOUSECURSOR_PALETTE, 1, ARRAYSIZE(MOUSECURSOR_PALETTE) / 3);
+	setMouseCursor();
+
+	return errOK;
+}
 
 /**
- * 256 color palette used with AGI256 and AGI256-2 games.
- * Uses full 8 bits per color component.
+ * Deinitialize graphics device.
+ *
+ * @see init_video()
  */
-static const uint8 vgaPalette[256 * 3] = {
-	0x00, 0x00, 0x00,
-	0x00, 0x00, 0xA8,
-	0x00, 0xA8, 0x00,
-	0x00, 0xA8, 0xA8,
-	0xA8, 0x00, 0x00,
-	0xA8, 0x00, 0xA8,
-	0xA8, 0x54, 0x00,
-	0xA8, 0xA8, 0xA8,
-	0x54, 0x54, 0x54,
-	0x54, 0x54, 0xFC,
-	0x54, 0xFC, 0x54,
-	0x54, 0xFC, 0xFC,
-	0xFC, 0x54, 0x54,
-	0xFC, 0x54, 0xFC,
-	0xFC, 0xFC, 0x54,
-	0xFC, 0xFC, 0xFC,
-	0x00, 0x00, 0x00,
-	0x14, 0x14, 0x14,
-	0x20, 0x20, 0x20,
-	0x2C, 0x2C, 0x2C,
-	0x38, 0x38, 0x38,
-	0x44, 0x44, 0x44,
-	0x50, 0x50, 0x50,
-	0x60, 0x60, 0x60,
-	0x70, 0x70, 0x70,
-	0x80, 0x80, 0x80,
-	0x90, 0x90, 0x90,
-	0xA0, 0xA0, 0xA0,
-	0xB4, 0xB4, 0xB4,
-	0xC8, 0xC8, 0xC8,
-	0xE0, 0xE0, 0xE0,
-	0xFC, 0xFC, 0xFC,
-	0x00, 0x00, 0xFC,
-	0x40, 0x00, 0xFC,
-	0x7C, 0x00, 0xFC,
-	0xBC, 0x00, 0xFC,
-	0xFC, 0x00, 0xFC,
-	0xFC, 0x00, 0xBC,
-	0xFC, 0x00, 0x7C,
-	0xFC, 0x00, 0x40,
-	0xFC, 0x00, 0x00,
-	0xFC, 0x40, 0x00,
-	0xFC, 0x7C, 0x00,
-	0xFC, 0xBC, 0x00,
-	0xFC, 0xFC, 0x00,
-	0xBC, 0xFC, 0x00,
-	0x7C, 0xFC, 0x00,
-	0x40, 0xFC, 0x00,
-	0x00, 0xFC, 0x00,
-	0x00, 0xFC, 0x40,
-	0x00, 0xFC, 0x7C,
-	0x00, 0xFC, 0xBC,
-	0x00, 0xFC, 0xFC,
-	0x00, 0xBC, 0xFC,
-	0x00, 0x7C, 0xFC,
-	0x00, 0x40, 0xFC,
-	0x7C, 0x7C, 0xFC,
-	0x9C, 0x7C, 0xFC,
-	0xBC, 0x7C, 0xFC,
-	0xDC, 0x7C, 0xFC,
-	0xFC, 0x7C, 0xFC,
-	0xFC, 0x7C, 0xDC,
-	0xFC, 0x7C, 0xBC,
-	0xFC, 0x7C, 0x9C,
-	0xFC, 0x7C, 0x7C,
-	0xFC, 0x9C, 0x7C,
-	0xFC, 0xBC, 0x7C,
-	0xFC, 0xDC, 0x7C,
-	0xFC, 0xFC, 0x7C,
-	0xDC, 0xFC, 0x7C,
-	0xBC, 0xFC, 0x7C,
-	0x9C, 0xFC, 0x7C,
-	0x7C, 0xFC, 0x7C,
-	0x7C, 0xFC, 0x9C,
-	0x7C, 0xFC, 0xBC,
-	0x7C, 0xFC, 0xDC,
-	0x7C, 0xFC, 0xFC,
-	0x7C, 0xDC, 0xFC,
-	0x7C, 0xBC, 0xFC,
-	0x7C, 0x9C, 0xFC,
-	0xB4, 0xB4, 0xFC,
-	0xC4, 0xB4, 0xFC,
-	0xD8, 0xB4, 0xFC,
-	0xE8, 0xB4, 0xFC,
-	0xFC, 0xB4, 0xFC,
-	0xFC, 0xB4, 0xE8,
-	0xFC, 0xB4, 0xD8,
-	0xFC, 0xB4, 0xC4,
-	0xFC, 0xB4, 0xB4,
-	0xFC, 0xC4, 0xB4,
-	0xFC, 0xD8, 0xB4,
-	0xFC, 0xE8, 0xB4,
-	0xFC, 0xFC, 0xB4,
-	0xE8, 0xFC, 0xB4,
-	0xD8, 0xFC, 0xB4,
-	0xC4, 0xFC, 0xB4,
-	0xB4, 0xFC, 0xB4,
-	0xB4, 0xFC, 0xC4,
-	0xB4, 0xFC, 0xD8,
-	0xB4, 0xFC, 0xE8,
-	0xB4, 0xFC, 0xFC,
-	0xB4, 0xE8, 0xFC,
-	0xB4, 0xD8, 0xFC,
-	0xB4, 0xC4, 0xFC,
-	0x00, 0x00, 0x70,
-	0x1C, 0x00, 0x70,
-	0x38, 0x00, 0x70,
-	0x54, 0x00, 0x70,
-	0x70, 0x00, 0x70,
-	0x70, 0x00, 0x54,
-	0x70, 0x00, 0x38,
-	0x70, 0x00, 0x1C,
-	0x70, 0x00, 0x00,
-	0x70, 0x1C, 0x00,
-	0x70, 0x38, 0x00,
-	0x70, 0x54, 0x00,
-	0x70, 0x70, 0x00,
-	0x54, 0x70, 0x00,
-	0x38, 0x70, 0x00,
-	0x1C, 0x70, 0x00,
-	0x00, 0x70, 0x00,
-	0x00, 0x70, 0x1C,
-	0x00, 0x70, 0x38,
-	0x00, 0x70, 0x54,
-	0x00, 0x70, 0x70,
-	0x00, 0x54, 0x70,
-	0x00, 0x38, 0x70,
-	0x00, 0x1C, 0x70,
-	0x38, 0x38, 0x70,
-	0x44, 0x38, 0x70,
-	0x54, 0x38, 0x70,
-	0x60, 0x38, 0x70,
-	0x70, 0x38, 0x70,
-	0x70, 0x38, 0x60,
-	0x70, 0x38, 0x54,
-	0x70, 0x38, 0x44,
-	0x70, 0x38, 0x38,
-	0x70, 0x44, 0x38,
-	0x70, 0x54, 0x38,
-	0x70, 0x60, 0x38,
-	0x70, 0x70, 0x38,
-	0x60, 0x70, 0x38,
-	0x54, 0x70, 0x38,
-	0x44, 0x70, 0x38,
-	0x38, 0x70, 0x38,
-	0x38, 0x70, 0x44,
-	0x38, 0x70, 0x54,
-	0x38, 0x70, 0x60,
-	0x38, 0x70, 0x70,
-	0x38, 0x60, 0x70,
-	0x38, 0x54, 0x70,
-	0x38, 0x44, 0x70,
-	0x50, 0x50, 0x70,
-	0x58, 0x50, 0x70,
-	0x60, 0x50, 0x70,
-	0x68, 0x50, 0x70,
-	0x70, 0x50, 0x70,
-	0x70, 0x50, 0x68,
-	0x70, 0x50, 0x60,
-	0x70, 0x50, 0x58,
-	0x70, 0x50, 0x50,
-	0x70, 0x58, 0x50,
-	0x70, 0x60, 0x50,
-	0x70, 0x68, 0x50,
-	0x70, 0x70, 0x50,
-	0x68, 0x70, 0x50,
-	0x60, 0x70, 0x50,
-	0x58, 0x70, 0x50,
-	0x50, 0x70, 0x50,
-	0x50, 0x70, 0x58,
-	0x50, 0x70, 0x60,
-	0x50, 0x70, 0x68,
-	0x50, 0x70, 0x70,
-	0x50, 0x68, 0x70,
-	0x50, 0x60, 0x70,
-	0x50, 0x58, 0x70,
-	0x00, 0x00, 0x40,
-	0x10, 0x00, 0x40,
-	0x20, 0x00, 0x40,
-	0x30, 0x00, 0x40,
-	0x40, 0x00, 0x40,
-	0x40, 0x00, 0x30,
-	0x40, 0x00, 0x20,
-	0x40, 0x00, 0x10,
-	0x40, 0x00, 0x00,
-	0x40, 0x10, 0x00,
-	0x40, 0x20, 0x00,
-	0x40, 0x30, 0x00,
-	0x40, 0x40, 0x00,
-	0x30, 0x40, 0x00,
-	0x20, 0x40, 0x00,
-	0x10, 0x40, 0x00,
-	0x00, 0x40, 0x00,
-	0x00, 0x40, 0x10,
-	0x00, 0x40, 0x20,
-	0x00, 0x40, 0x30,
-	0x00, 0x40, 0x40,
-	0x00, 0x30, 0x40,
-	0x00, 0x20, 0x40,
-	0x00, 0x10, 0x40,
-	0x20, 0x20, 0x40,
-	0x28, 0x20, 0x40,
-	0x30, 0x20, 0x40,
-	0x38, 0x20, 0x40,
-	0x40, 0x20, 0x40,
-	0x40, 0x20, 0x38,
-	0x40, 0x20, 0x30,
-	0x40, 0x20, 0x28,
-	0x40, 0x20, 0x20,
-	0x40, 0x28, 0x20,
-	0x40, 0x30, 0x20,
-	0x40, 0x38, 0x20,
-	0x40, 0x40, 0x20,
-	0x38, 0x40, 0x20,
-	0x30, 0x40, 0x20,
-	0x28, 0x40, 0x20,
-	0x20, 0x40, 0x20,
-	0x20, 0x40, 0x28,
-	0x20, 0x40, 0x30,
-	0x20, 0x40, 0x38,
-	0x20, 0x40, 0x40,
-	0x20, 0x38, 0x40,
-	0x20, 0x30, 0x40,
-	0x20, 0x28, 0x40,
-	0x2C, 0x2C, 0x40,
-	0x30, 0x2C, 0x40,
-	0x34, 0x2C, 0x40,
-	0x3C, 0x2C, 0x40,
-	0x40, 0x2C, 0x40,
-	0x40, 0x2C, 0x3C,
-	0x40, 0x2C, 0x34,
-	0x40, 0x2C, 0x30,
-	0x40, 0x2C, 0x2C,
-	0x40, 0x30, 0x2C,
-	0x40, 0x34, 0x2C,
-	0x40, 0x3C, 0x2C,
-	0x40, 0x40, 0x2C,
-	0x3C, 0x40, 0x2C,
-	0x34, 0x40, 0x2C,
-	0x30, 0x40, 0x2C,
-	0x2C, 0x40, 0x2C,
-	0x2C, 0x40, 0x30,
-	0x2C, 0x40, 0x34,
-	0x2C, 0x40, 0x3C,
-	0x2C, 0x40, 0x40,
-	0x2C, 0x3C, 0x40,
-	0x2C, 0x34, 0x40,
-	0x2C, 0x30, 0x40,
-	0x40, 0x40, 0x40,
-	0x38, 0x38, 0x38,
-	0x30, 0x30, 0x30,
-	0x28, 0x28, 0x28,
-	0x24, 0x24, 0x24,
-	0x1C, 0x1C, 0x1C,
-	0x14, 0x14, 0x14,
-	0x0C, 0x0C, 0x0C
-};
+int GfxMgr::deinitVideo() {
+	free(_displayScreen);
+	free(_visualScreen);
+	free(_priorityScreen);
 
-static const uint16 cgaMap[16] = {
-	0x0000,			//  0 - black
-	0x0d00,			//  1 - blue
-	0x0b00,			//  2 - green
-	0x0f00,			//  3 - cyan
-	0x000b,			//  4 - red
-	0x0b0d,			//  5 - magenta
-	0x000d,			//  6 - brown
-	0x0b0b,			//  7 - gray
-	0x0d0d,			//  8 - dark gray
-	0x0b0f,			//  9 - light blue
-	0x0b0d,			// 10 - light green
-	0x0f0d,			// 11 - light cyan
-	0x0f0d,			// 12 - light red
-	0x0f00,			// 13 - light magenta
-	0x0f0b,			// 14 - yellow
-	0x0f0f			// 15 - white
-};
+	return errOK;
+}
 
-struct UpdateBlock {
-	int x1, y1;
-	int x2, y2;
-};
+int GfxMgr::initMachine() {
+	_vm->_clockCount = 0;
 
-static struct UpdateBlock update = {
-	MAX_INT, MAX_INT, 0, 0
-};
+	return errOK;
+}
 
-GfxMgr::GfxMgr(AgiBase *vm) : _vm(vm) {
-	_shakeH = NULL;
-	_shakeV = NULL;
-	_agipalFileNum = 0;
-	_currentCursorPalette = 0;	// cursor palette not set
+int GfxMgr::deinitMachine() {
+	return errOK;
 }
 
+void GfxMgr::setRenderStartOffset(uint16 offsetY) {
+	if (offsetY >= (DISPLAY_HEIGHT - SCRIPT_HEIGHT))
+		error("invalid render start offset");
 
-//
-//  Layer 4:  640x480?  ==================  User display
-//                              ^
-//                              |  do_update(), put_block()
-//                              |
-//  Layer 3:  640x480?  ==================  Framebuffer
-//                              ^
-//                              |  flush_block(), put_pixels()
-//                              |
-//  Layer 2:  320x200   ==================  AGI engine screen (console), put_pixel()
-//                              |
-//  Layer 1:  160x336   ==================  AGI screen
-//
-//  Upper half (160x168) of Layer 1 is for the normal 16 color & control line/priority info.
-//  Lower half (160x168) of Layer 1 is for the 256 color information (Used with AGI256 & AGI256-2).
-//
-
-#define SHAKE_MAG 3
-
-void GfxMgr::shakeStart() {
-	int i;
-
-	if ((_shakeH = (uint8 *)malloc(GFX_WIDTH * SHAKE_MAG)) == NULL)
-		return;
+	_renderStartOffsetY = offsetY;
+}
 
-	if ((_shakeV = (uint8 *)malloc(SHAKE_MAG * (GFX_HEIGHT - SHAKE_MAG))) == NULL) {
-		free(_shakeH);
-		return;
+void GfxMgr::debugShowMap(int mapNr) {
+	switch (mapNr) {
+	case 0:
+		_activeScreen = _visualScreen;
+		break;
+	case 1:
+		_activeScreen = _priorityScreen;
+		break;
+	default:
+		break;
 	}
 
-	for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) {
-		memcpy(_shakeV + i * SHAKE_MAG, _agiScreen + i * GFX_WIDTH, SHAKE_MAG);
+	render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT);
+}
+
+void GfxMgr::clear(byte color, byte priority) {
+	memset(_visualScreen, color, _pixels);
+	memset(_priorityScreen, priority, _pixels);
+}
+
+void GfxMgr::clearDisplay(byte color, bool copyToScreen) {
+	memset(_displayScreen, color, _displayPixels);
+
+	if (copyToScreen) {
+		g_system->copyRectToScreen(_displayScreen, DISPLAY_WIDTH, 0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
 	}
+}
+
+void GfxMgr::putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority) {
+	int offset = y * SCRIPT_WIDTH + x;
 
-	for (i = 0; i < SHAKE_MAG; i++) {
-		memcpy(_shakeH + i * GFX_WIDTH, _agiScreen + i * GFX_WIDTH, GFX_WIDTH);
+	if (drawMask & GFX_SCREEN_MASK_VISUAL) {
+		_visualScreen[offset] = color;
+	}
+	if (drawMask & GFX_SCREEN_MASK_PRIORITY) {
+		_priorityScreen[offset] = priority;
 	}
 }
 
-void GfxMgr::shakeScreen(int n) {
-	int i;
+void GfxMgr::putPixelOnDisplay(int16 x, int16 y, byte color) {
+	int offset = y * DISPLAY_WIDTH + x;
 
-	if (n == 0) {
-		for (i = 0; i < (GFX_HEIGHT - SHAKE_MAG); i++) {
-			memmove(&_agiScreen[GFX_WIDTH * i],
-					&_agiScreen[GFX_WIDTH * (i + SHAKE_MAG) + SHAKE_MAG],
-					GFX_WIDTH - SHAKE_MAG);
-		}
-	} else {
-		for (i = GFX_HEIGHT - SHAKE_MAG - 1; i >= 0; i--) {
-			memmove(&_agiScreen[GFX_WIDTH * (i + SHAKE_MAG) + SHAKE_MAG],
-					&_agiScreen[GFX_WIDTH * i], GFX_WIDTH - SHAKE_MAG);
+	_displayScreen[offset] = color;
+}
+
+byte GfxMgr::getColor(int16 x, int16 y) {
+	int offset = y * SCRIPT_WIDTH + x;
+
+	return _visualScreen[offset];
+}
+
+byte GfxMgr::getPriority(int16 x, int16 y) {
+	int offset = y * SCRIPT_WIDTH + x;
+
+	return _priorityScreen[offset];
+}
+
+// used, when a control pixel is found
+// will search downwards and compare priority in case any is found
+bool GfxMgr::checkControlPixel(int16 x, int16 y, byte viewPriority) {
+	int offset = y * SCRIPT_WIDTH + x;
+	byte curPriority;
+
+	while (1) {
+		y++;
+		offset += SCRIPT_WIDTH;
+		if (y >= SCRIPT_HEIGHT) {
+			// end of screen, nothing but control pixels found
+			return true; // draw view pixel
 		}
+		curPriority = _priorityScreen[offset];
+		if (curPriority > 2) // valid priority found?
+			break;
+	}
+	if (curPriority <= viewPriority)
+		return true; // view priority is higher, draw
+	return false; // view priority is lower, don't draw
+}
+
+static byte CGA_MixtureColorTable[] = {
+	0x00, 0x08, 0x04, 0x0C, 0x01, 0x09, 0x02, 0x05,
+	0x0A, 0x0D, 0x06, 0x0E, 0x0B, 0x03, 0x07, 0x0F
+};
+
+byte GfxMgr::getCGAMixtureColor(byte color) {
+	return CGA_MixtureColorTable[color & 0x0F];
+}
+
+// Attention: y-coordinate points to the LOWER left!
+void GfxMgr::render_Block(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) {
+	if (!render_Clip(x, y, width, height))
+		return;
+
+	switch (_vm->_renderMode) {
+	case RENDERMODE_CGA:
+		render_BlockCGA(x, y, width, height, copyToScreen);
+		break;
+	case RENDERMODE_EGA:
+	default:
+		render_BlockEGA(x, y, width, height, copyToScreen);
+		break;
+	}
+
+	if (copyToScreen) {
+		int16 upperY = y - height + 1 + _renderStartOffsetY;
+		g_system->copyRectToScreen(_displayScreen + upperY * DISPLAY_WIDTH + x * 2, DISPLAY_WIDTH, x * 2, upperY, width * 2, height);
 	}
 }
 
-void GfxMgr::shakeEnd() {
-	int i;
+bool GfxMgr::render_Clip(int16 &x, int16 &y, int16 &width, int16 &height, int16 clipAgainstWidth, int16 clipAgainstHeight) {
+	if ((x >= clipAgainstWidth) || ((x + width - 1) < 0) ||
+		(y < 0) || ((y - (height - 1)) >= clipAgainstHeight)) {
+		return false;
+	}
+
+	if ((y - height + 1) < 0)
+		height = y + 1;
 
-	for (i = 0; i < GFX_HEIGHT - SHAKE_MAG; i++) {
-		memcpy(_agiScreen + i * GFX_WIDTH, _shakeV + i * SHAKE_MAG, SHAKE_MAG);
+	if (y >= clipAgainstHeight) {
+		height -= y - (clipAgainstHeight - 1);
+		y = clipAgainstHeight - 1;
 	}
 
-	for (i = 0; i < SHAKE_MAG; i++) {
-		memcpy(_agiScreen + i * GFX_WIDTH, _shakeH + i * GFX_WIDTH, GFX_WIDTH);
+	if (x < 0) {
+		width += x;
+		x = 0;
 	}
 
-	flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
+	if ((x + width - 1) >= clipAgainstWidth) {
+		width = clipAgainstWidth - x;
+	}
+	return true;
+}
+
+void GfxMgr::render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) {
+	int offsetVisual = SCRIPT_WIDTH * y + x;
+	int offsetDisplay = (DISPLAY_WIDTH * (y + _renderStartOffsetY)) + x * 2;
+	int16 remainingWidth = width;
+	int16 remainingHeight = height;
+	byte curColor = 0;
+
+	while (remainingHeight) {
+		remainingWidth = width;
+		while (remainingWidth) {
+			curColor = _activeScreen[offsetVisual++];
+			_displayScreen[offsetDisplay++] = curColor;
+			_displayScreen[offsetDisplay++] = curColor;
+			remainingWidth--;
+		}
+		offsetVisual -= SCRIPT_WIDTH + width;
+		offsetDisplay -= DISPLAY_WIDTH + width * 2;
 
-	free(_shakeV);
-	free(_shakeH);
+		remainingHeight--;
+	}
 }
 
-void GfxMgr::putTextCharacter(int l, int x, int y, unsigned char c, int fg, int bg, bool checkerboard, const uint8 *font) {
-	int x1, y1, xx, yy, cc;
-	const uint8 *p;
+void GfxMgr::render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen) {
+	int offsetVisual = SCRIPT_WIDTH * y + x;
+	int offsetDisplay = (DISPLAY_WIDTH * (y + _renderStartOffsetY)) + x * 2;
+	int16 remainingWidth = width;
+	int16 remainingHeight = height;
+	byte curColor = 0;
+
+	while (remainingHeight) {
+		remainingWidth = width;
+		while (remainingWidth) {
+			curColor = _activeScreen[offsetVisual++];
+			_displayScreen[offsetDisplay++] = curColor & 0x03; // we process CGA mixture
+			_displayScreen[offsetDisplay++] = curColor >> 2;
+			remainingWidth--;
+		}
+		offsetVisual -= SCRIPT_WIDTH + width;
+		offsetDisplay -= DISPLAY_WIDTH + width * 2;
+
+		remainingHeight--;
+	}
+}
 
-	assert(font);
+void GfxMgr::transition_Amiga() {
+	uint16 screenPos = 1;
+	uint16 screenStepPos = 1;
+	int16  posY = 0, posX = 0;
+	int16  stepCount = 0;
+
+	// disable mouse while transition is taking place
+	if (_vm->_game.mouseEnabled) {
+		CursorMan.showMouse(false);
+	}
+
+	do {
+		if (screenPos & 1) {
+			screenPos = screenPos >> 1;
+			screenPos = screenPos ^ 0x3500; // 13568d
+		} else {
+			screenPos = screenPos >> 1;
+		}
 
-	p = font + ((unsigned int)c * CHAR_LINES);
-	for (y1 = 0; y1 < CHAR_LINES; y1++) {
-		for (x1 = 0; x1 < CHAR_COLS; x1++) {
-			xx = x + x1;
-			yy = y + y1;
-			cc = (*p & (1 << (7 - x1))) ? fg : bg;
-			_agiScreen[xx + yy * GFX_WIDTH] = cc;
+		if ((screenPos < 13440) && (screenPos & 1)) {
+			screenStepPos = screenPos >> 1;
+			posY = screenStepPos / SCRIPT_WIDTH;
+			posX = screenStepPos - (posY * SCRIPT_WIDTH);
+		
+			posY += _renderStartOffsetY; // adjust to only update the main area, not the status bar
+			posX *= 2; // adjust for display screen
+
+			screenStepPos = (screenStepPos * 2) + (_renderStartOffsetY * DISPLAY_WIDTH); // adjust here too for display screen
+			for (int16 multiPixel = 0; multiPixel < 4; multiPixel++) {
+				g_system->copyRectToScreen(_displayScreen + screenStepPos, DISPLAY_WIDTH, posX, posY, 2, 1);
+				screenStepPos += (0x1A40 * 2); // 6720d
+				posY += 42;
+			}
+			stepCount++;
+			if (stepCount == 220) {
+				// 30 times for the whole transition, so should take around 0.5 seconds
+				g_system->updateScreen();
+				g_system->delayMillis(16);
+				stepCount = 0;
+			}
 		}
+	} while (screenPos != 1);
 
-		p++;
+	// Enable mouse again
+	if (_vm->_game.mouseEnabled) {
+		CursorMan.showMouse(true);
 	}
 
-	// Simple checkerboard effect to simulate "greyed out" text.
-	// This is what Sierra's interpreter does for things like menu items
-	// that aren't selectable (such as separators). -- dsymonds
-	if (checkerboard) {
-		for (yy = y; yy < y + CHAR_LINES; yy++)
-			for (xx = x + (~yy & 1); xx < x + CHAR_COLS; xx += 2)
-				_agiScreen[xx + yy * GFX_WIDTH] = 15;
+	g_system->updateScreen();
+}
+
+// This transition code was not reverse engineered, but created based on the Amiga transition code
+// Atari ST definitely had a hi-res transition using the full resolution unlike the Amiga transition.
+void GfxMgr::transition_AtariSt() {
+	uint16 screenPos = 1;
+	uint16 screenStepPos = 1;
+	int16  posY = 0, posX = 0;
+	int16  stepCount = 0;
+
+	// disable mouse while transition is taking place
+	if (_vm->_game.mouseEnabled) {
+		CursorMan.showMouse(false);
+	}
+
+	do {
+		if (screenPos & 1) {
+			screenPos = screenPos >> 1;
+			screenPos = screenPos ^ 0x3500; // 13568d
+		} else {
+			screenPos = screenPos >> 1;
+		}
+
+		if ((screenPos < 13440) && (screenPos & 1)) {
+			screenStepPos = screenPos >> 1;
+			posY = screenStepPos / DISPLAY_WIDTH;
+			posX = screenStepPos - (posY * DISPLAY_WIDTH);
+
+			posY += _renderStartOffsetY; // adjust to only update the main area, not the status bar
+
+			screenStepPos = screenStepPos + (_renderStartOffsetY * DISPLAY_WIDTH); // adjust here too for display screen
+			for (int16 multiPixel = 0; multiPixel < 8; multiPixel++) {
+				g_system->copyRectToScreen(_displayScreen + screenStepPos, DISPLAY_WIDTH, posX, posY, 1, 1);
+				screenStepPos += 0x1a40; // 6720d
+				posY += 21;
+			}
+			stepCount++;
+			if (stepCount == 168) {
+				// 40 times for the whole transition, so should take around 0.7 seconds
+				// When using an Atari ST emulator, the transition seems to be even slower than this
+				// TODO: should get checked on real hardware
+				g_system->updateScreen();
+				g_system->delayMillis(16);
+				stepCount = 0;
+			}
+		}
+	} while (screenPos != 1);
+
+	// Enable mouse again
+	if (_vm->_game.mouseEnabled) {
+		CursorMan.showMouse(true);
 	}
 
-	// FIXME: we don't want this when we're writing on the
-	//        console!
-	flushBlock(x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1);
+	g_system->updateScreen();
 }
 
-void GfxMgr::drawRectangle(int x1, int y1, int x2, int y2, int c) {
-	int y, w, h;
-	uint8 *p0;
-
-	if (x1 >= GFX_WIDTH)
-		x1 = GFX_WIDTH - 1;
-	if (y1 >= GFX_HEIGHT)
-		y1 = GFX_HEIGHT - 1;
-	if (x2 >= GFX_WIDTH)
-		x2 = GFX_WIDTH - 1;
-	if (y2 >= GFX_HEIGHT)
-		y2 = GFX_HEIGHT - 1;
-
-	w = x2 - x1 + 1;
-	h = y2 - y1 + 1;
-	p0 = &_agiScreen[x1 + y1 * GFX_WIDTH];
-	for (y = 0; y < h; y++) {
-		memset(p0, c, w);
-		p0 += GFX_WIDTH;
+// Attention: y coordinate is here supposed to be the upper one!
+void GfxMgr::block_save(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr) {
+	int16 startOffset = y * SCRIPT_WIDTH + x;
+	int16 offset = startOffset;
+	int16 remainingHeight = height;
+	byte *curBufferPtr = bufferPtr;
+
+	//warning("block_save: %d, %d -> %d, %d", x, y, width, height);
+
+	while (remainingHeight) {
+		memcpy(curBufferPtr, _visualScreen + offset, width);
+		offset += SCRIPT_WIDTH;
+		curBufferPtr += width;
+		remainingHeight--;
+	}
+
+	remainingHeight = height;
+	offset = startOffset;
+	while (remainingHeight) {
+		memcpy(curBufferPtr, _priorityScreen + offset, width);
+		offset += SCRIPT_WIDTH;
+		curBufferPtr += width;
+		remainingHeight--;
 	}
 }
 
-void GfxMgr::drawFrame(int x1, int y1, int x2, int y2, int c1, int c2) {
-	int y, w;
-	uint8 *p0;
+// Attention: y coordinate is here supposed to be the upper one!
+void GfxMgr::block_restore(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr) {
+	int16 startOffset = y * SCRIPT_WIDTH + x;
+	int16 offset = startOffset;
+	int16 remainingHeight = height;
+	byte *curBufferPtr = bufferPtr;
 
-	// top line
-	w = x2 - x1 + 1;
-	p0 = &_agiScreen[x1 + y1 * GFX_WIDTH];
-	memset(p0, c1, w);
+	//warning("block_restore: %d, %d -> %d, %d", x, y, width, height);
 
-	// bottom line
-	p0 = &_agiScreen[x1 + y2 * GFX_WIDTH];
-	memset(p0, c2, w);
+	while (remainingHeight) {
+		memcpy(_visualScreen + offset, curBufferPtr, width);
+		offset += SCRIPT_WIDTH;
+		curBufferPtr += width;
+		remainingHeight--;
+	}
 
-	// side lines
-	for (y = y1; y <= y2; y++) {
-		_agiScreen[x1 + y * GFX_WIDTH] = c1;
-		_agiScreen[x2 + y * GFX_WIDTH] = c2;
+	remainingHeight = height;
+	offset = startOffset;
+	while (remainingHeight) {
+		memcpy(_priorityScreen + offset, curBufferPtr, width);
+		offset += SCRIPT_WIDTH;
+		curBufferPtr += width;
+		remainingHeight--;
 	}
 }
 
-void GfxMgr::drawBox(int x1, int y1, int x2, int y2, int color1, int color2, int m) {
-	x1 += m;
-	y1 += m;
-	x2 -= m;
-	y2 -= m;
+// Attention: uses visual screen coordinates!
+void GfxMgr::copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height) {
+	g_system->copyRectToScreen(_displayScreen + y * DISPLAY_WIDTH + x, DISPLAY_WIDTH, x, y, width, height);
+}
+
+// coordinates are for visual screen, but are supposed to point somewhere inside the playscreen
+void GfxMgr::drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroundColor, byte lineColor) {
+	drawRect(x, y, width, height, backgroundColor);
+	drawRect(x + 1, y - 1, width - 2, 1, lineColor);
+	drawRect(x + width - 2, y - 2, 1, height - 4, lineColor);
+	drawRect(x + 1, y - height + 2, width - 2, 1, lineColor);
+	drawRect(x + 1, y - 2, 1, height - 4, lineColor);
+}
+
+// coordinates for visual screen
+// attention: Clipping is done here against 160x200 instead of 160x168
+//            Original interpreter didn't do any clipping, we do it for security.
+//            Clipping against the regular script width/height must not be done,
+//            because at least during the intro one message box goes beyond playscreen
+//            Going beyond 160x168 will result in messageboxes not getting fully removed
+//            In KQ4's case, the scripts clear the screen that's why it works.
+void GfxMgr::drawRect(int16 x, int16 y, int16 width, int16 height, byte color) {
+	if (!render_Clip(x, y, width, height, SCRIPT_WIDTH, DISPLAY_HEIGHT - _renderStartOffsetY))
+		return;
 
-	drawRectangle(x1, y1, x2, y2, color1);
-	drawFrame(x1 + 2, y1 + 2, x2 - 2, y2 - 2, color2, color2);
-	flushBlock(x1, y1, x2, y2);
+	// coordinate translation: visual-screen -> display-screen
+	x = x * 2;
+	y = y + _renderStartOffsetY; // drawDisplayRect paints anywhere on the whole screen, our coordinate is within playscreen
+	width = width * 2; // width was given as visual width, we need display width
+	drawDisplayRect(x, y, width, height, color);
+}
+
+// coordinates are directly for display screen
+void GfxMgr::drawDisplayRect(int16 x, int16 y, int16 width, int16 height, byte color) {
+	switch (_vm->_renderMode) {
+	case RENDERMODE_CGA:
+		drawDisplayRectCGA(x, y, width, height, color);
+		break;
+	case RENDERMODE_EGA:
+	default:
+		drawDisplayRectEGA(x, y, width, height, color);
+		break;
+	}
+	int16 upperY = y - height + 1;
+	g_system->copyRectToScreen(_displayScreen + upperY * DISPLAY_WIDTH + x, DISPLAY_WIDTH, x, upperY, width, height);
 }
 
-void GfxMgr::printCharacter(int x, int y, char c, int fg, int bg) {
-	x *= CHAR_COLS;
-	y *= CHAR_LINES;
+void GfxMgr::drawDisplayRectEGA(int16 x, int16 y, int16 width, int16 height, byte color) {
+	int offsetDisplay = (DISPLAY_WIDTH * y) + x;
+	int16 remainingHeight = height;
 
-	putTextCharacter(0, x, y, c, fg, bg, false, _vm->getFontData());
-	// redundant! already inside put_text_character!
-	// flush_block (x, y, x + CHAR_COLS - 1, y + CHAR_LINES - 1);
+	while (remainingHeight) {
+		memset(_displayScreen + offsetDisplay, color, width);
+
+		offsetDisplay -= DISPLAY_WIDTH;
+		remainingHeight--;
+	}
 }
 
-/**
- * Draw a default style button.
- * Swaps background and foreground color if button is in focus or being pressed.
- * @param x  x coordinate of the button
- * @param y  y coordinate of the button
- * @param a  set if the button has focus
- * @param p  set if the button is pressed
- * @param fgcolor foreground color of the button when it is neither in focus nor being pressed
- * @param bgcolor background color of the button when it is neither in focus nor being pressed
- */
-void GfxMgr::drawDefaultStyleButton(int x, int y, const char *s, int a, int p, int fgcolor, int bgcolor) {
-	int textOffset     = _vm->_defaultButtonStyle.getTextOffset(a > 0, p > 0);
-	AgiTextColor color = _vm->_defaultButtonStyle.getColor     (a > 0, p > 0, fgcolor, bgcolor);
-	bool border        = _vm->_defaultButtonStyle.getBorder    (a > 0, p > 0);
+void GfxMgr::drawDisplayRectCGA(int16 x, int16 y, int16 width, int16 height, byte color) {
+	int offsetDisplay = (DISPLAY_WIDTH * y) + x;
+	int16 remainingHeight = height;
+	int16 remainingWidth = width;
+	byte CGAMixtureColor = getCGAMixtureColor(color);
+	byte *displayScreen = nullptr;
+
+	// we should never get an uneven width
+	assert((width & 1) == 0);
+
+	while (remainingHeight) {
+		remainingWidth = width;
+
+		// set up pointer
+		displayScreen = _displayScreen + offsetDisplay;
 
-	rawDrawButton(x, y, s, color.fg, color.bg, border, textOffset);
+		while (remainingWidth) {
+			*displayScreen++ = CGAMixtureColor & 0x03;
+			*displayScreen++ = CGAMixtureColor >> 2;
+			remainingWidth -= 2;
+		}
+
+		offsetDisplay -= DISPLAY_WIDTH;
+		remainingHeight--;
+	}
 }
 
-/**
- * Draw a button using the currently chosen style.
- * Amiga-style is used for the Amiga-rendering mode, PC-style is used otherwise.
- * @param x  x coordinate of the button
- * @param y  y coordinate of the button
- * @param hasFocus  set if the button has focus
- * @param pressed  set if the button is pressed
- * @param positive  set if button is positive, otherwise button is negative (Only matters with Amiga-style buttons)
- * TODO: Make Amiga-style buttons a bit wider as they were in Amiga AGI games.
- */
-void GfxMgr::drawCurrentStyleButton(int x, int y, const char *label, bool hasFocus, bool pressed, bool positive) {
-	int textOffset     = _vm->_buttonStyle.getTextOffset(hasFocus, pressed);
-	AgiTextColor color = _vm->_buttonStyle.getColor(hasFocus, pressed, positive);
-	bool border        = _vm->_buttonStyle.getBorder(hasFocus, pressed);
+// row + column are text-coordinates
+void GfxMgr::drawCharacter(int16 row, int16 column, byte character, byte foreground, byte background, bool disabledLook) {
+	int16       startX, startY;
+	int16       curX, curY;
+	const byte *fontData;
+	byte        curByte = 0;
+	uint16      curBit;
+	byte        curTransformXOR = 0;
+	byte        curTransformOR = 0;
+
+	startX = column * FONT_DISPLAY_HEIGHT;
+	startY = row * FONT_DISPLAY_WIDTH;
+
+	// get font data of specified character
+	fontData = _vm->getFontData() + character * FONT_BYTES_PER_CHARACTER;
+	
+	// Now figure out, if special handling needs to be done (for graphical mode only)
+	if (_vm->_game.gfxMode) {
+		if (background & 0x08) {
+			// invert enabled
+			background &= 0x07; // remove invert bit
+			curTransformXOR = 0xFF; // inverse all bits of the font
+		}
+		if (disabledLook) {
+			curTransformOR = 0xAA;
+		}
+	}
+
+	curBit = 0;
+	for (curY = 0; curY < FONT_DISPLAY_HEIGHT; curY++) {
+		for (curX = 0; curX < FONT_DISPLAY_WIDTH; curX++) {
+			if (!curBit) {
+				curByte = *fontData;
+				// do transformations in case they are needed (invert/disabled look)
+				curByte ^= curTransformXOR;
+				curByte |= curTransformOR;
+				fontData++;
+				curBit  = 0x80;
+			}
+			if (curByte & curBit) {
+				putPixelOnDisplay(startX + curX, startY + curY, foreground);
+			} else {
+				putPixelOnDisplay(startX + curX, startY + curY, background);
+			}
+			curBit = curBit >> 1;
+		}
+	}
 
-	rawDrawButton(x, y, label, color.fg, color.bg, border, textOffset);
+	copyDisplayRectToScreen(startX, startY, FONT_DISPLAY_WIDTH, FONT_DISPLAY_HEIGHT);
 }
 
-void GfxMgr::rawDrawButton(int x, int y, const char *s, int fgcolor, int bgcolor, bool border, int textOffset) {
-	int len = strlen(s);
-	int x1, y1, x2, y2;
+#define SHAKE_VERTICAL_PIXELS 4
+#define SHAKE_HORIZONTAL_PIXELS 8
 
-	x1 = x - 3;
-	y1 = y - 3;
-	x2 = x + CHAR_COLS * len + 2;
-	y2 = y + CHAR_LINES + 2;
+// Sierra used some EGA port trickery to do it, we have to do it by copying pixels around
+void GfxMgr::shakeScreen(int16 repeatCount) {
+	int shakeNr, shakeCount;
+	uint8 *blackSpace;
 
-	// Draw a filled rectangle that's larger than the button. Used for drawing
-	// a border around the button as the button itself is drawn after this.
-	drawRectangle(x1, y1, x2, y2, border ? BUTTON_BORDER : MSG_BOX_COLOR);
+	if ((blackSpace = (uint8 *)calloc(SHAKE_HORIZONTAL_PIXELS * DISPLAY_WIDTH, 1)) == NULL)
+		return;
 
-	while (*s) {
-		putTextCharacter(0, x + textOffset, y + textOffset, *s++, fgcolor, bgcolor, false, _vm->getFontData());
-		x += CHAR_COLS;
+	shakeCount = repeatCount * 8; // effectively 4 shakes per repeat
+
+	// it's 4 pixels down and 8 pixels to the right
+	// and it's also filling the remaining space with black
+	for (shakeNr = 0; shakeNr < shakeCount; shakeNr++) {
+		if (shakeNr & 1) {
+			// move back
+			copyDisplayRectToScreen(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
+		} else {
+			g_system->copyRectToScreen(_displayScreen, DISPLAY_WIDTH, SHAKE_HORIZONTAL_PIXELS, SHAKE_VERTICAL_PIXELS, DISPLAY_WIDTH - SHAKE_HORIZONTAL_PIXELS, DISPLAY_HEIGHT - SHAKE_VERTICAL_PIXELS);
+			// additionally fill the remaining space with black
+			g_system->copyRectToScreen(blackSpace, DISPLAY_WIDTH, 0, 0, DISPLAY_WIDTH, SHAKE_VERTICAL_PIXELS);
+			g_system->copyRectToScreen(blackSpace, SHAKE_HORIZONTAL_PIXELS, 0, 0, SHAKE_HORIZONTAL_PIXELS, DISPLAY_HEIGHT);
+		}
+		g_system->updateScreen();
+		g_system->delayMillis(66); // Sierra waited for 4 V'Syncs, which is around 66 milliseconds
 	}
 
-	x1 -= 2;
-	y1 -= 2;
-	x2 += 2;
-	y2 += 2;
+	free(blackSpace);
+}
 
-	flushBlock(x1, y1, x2, y2);
+void GfxMgr::updateScreen() {
+	g_system->updateScreen();
 }
 
-int GfxMgr::testButton(int x, int y, const char *s) {
-	int len = strlen(s);
-	Common::Rect rect(x - 3, y - 3, x + CHAR_COLS * len + 3, y + CHAR_LINES + 3);
-	return rect.contains(_vm->_mouse.x, _vm->_mouse.y);
+void GfxMgr::initPriorityTable() {
+	int16 priority, step;
+	int16 yPos = 0;
+
+	_priorityTableSet = false;
+	for (priority = 1; priority < 15; priority++) {
+		for (step = 0; step < 12; step++) {
+			_priorityTable[yPos++] = priority < 4 ? 4 : priority;
+		}
+	}
 }
 
-void GfxMgr::putBlock(int x1, int y1, int x2, int y2) {
-	gfxPutBlock(x1, y1, x2, y2);
+void GfxMgr::setPriorityTable(int16 priorityBase) {
+	int16 x, priorityY, priority;
+
+	_priorityTableSet = true;
+	x = (SCRIPT_HEIGHT - priorityBase) * SCRIPT_HEIGHT / 10;
+
+	for (priorityY = 0; priorityY < SCRIPT_HEIGHT; priorityY++) {
+		priority = (priorityY - priorityBase) < 0 ? 4 : (priorityY - priorityBase) * SCRIPT_HEIGHT / x + 5;
+		if (priority > 15)
+			priority = 15;
+		_priorityTable[priorityY] = priority;
+	}
 }
 
-void GfxMgr::putScreen() {
-	putBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
+// used for restoring
+void GfxMgr::setPriority(int16 yPos, int16 priority) {
+	assert(yPos < SCRIPT_HEIGHT);
+	_priorityTable[yPos] = priority;
 }
 
-/*
- * Public functions
+/**
+ * Convert sprite priority to y value.
  */
+int16 GfxMgr::priorityToY(int16 priority) {
+	int16 currentY;
+
+	if (!_priorityTableSet) {
+		// priority table wasn't set by scripts? calculate directly
+		return (priority - 5) * 12 + 48;
+	}
+
+	// dynamic priority bands were introduced in 3.002.086 (effectively AGI3)
+	// It seems there was a glitch, that caused priority bands to not get calculated properly.
+	// It was caused by this function starting with Y = 168 instead of 167, which meant it always
+	// returned with 168 as result.
+	// This glitch is required in King's Quest 4 2.0, otherwise in room 54 ego will get drawn over
+	//  the last dwarf, that enters the house.
+	//  Dwarf is screen object 13 (view 152), gets fixed priority of 8, which would normally
+	//  result in a Y of 101. Ego is priority (non-fixed) 8, which would mean that dwarf is
+	//  drawn first, followed by ego, which would then draw ego over the dwarf.
+	//  For more information see bug #1712585 (dwarf sprite priority)
+	//
+	// Priority bands were working properly in: 3.001.098 (Black Cauldron)
+	uint16 agiVersion = _vm->getVersion();
+	
+	if (agiVersion <= 0x3086) {
+		return 168; // Buggy behavior, see above
+	}
+
+	currentY = 167;
+	while (_priorityTable[currentY] >= priority) {
+		currentY--;
+		if (currentY < 0) // Original AGI didn't do this, we abort in that case and return -1
+			break;
+	}
+	return currentY;
+}
+
+int16 GfxMgr::priorityFromY(int16 yPos) {
+	assert(yPos < SCRIPT_HEIGHT);
+	return _priorityTable[yPos];
+}
+
 
 /**
  * Initialize the color palette
@@ -800,18 +766,22 @@ void GfxMgr::putScreen() {
  * @param fromBits    Bits per source color component.
  * @param toBits      Bits per destination color component.
  */
-void GfxMgr::initPalette(const uint8 *p, uint colorCount, uint fromBits, uint toBits) {
+void GfxMgr::initPalette(uint8 *destPalette, const uint8 *paletteData, uint colorCount, uint fromBits, uint toBits) {
 	const uint srcMax  = (1 << fromBits) - 1;
 	const uint destMax = (1 << toBits) - 1;
 	for (uint col = 0; col < colorCount; col++) {
 		for (uint comp = 0; comp < 3; comp++) { // Convert RGB components
-			_palette[col * 3 + comp] = (p[col * 3 + comp] * destMax) / srcMax;
+			destPalette[col * 3 + comp] = (paletteData[col * 3 + comp] * destMax) / srcMax;
 		}
 	}
 }
 
-void GfxMgr::gfxSetPalette() {
-	g_system->getPaletteManager()->setPalette(_palette, 0, 256);
+void GfxMgr::setPalette(bool gfxModePalette) {
+	if (gfxModePalette) {
+		g_system->getPaletteManager()->setPalette(_paletteGfxMode, 0, 256);
+	} else {
+		g_system->getPaletteManager()->setPalette(_paletteTextMode, 0, 256);
+	}
 }
 
 //Gets AGIPAL Data
@@ -863,8 +833,8 @@ void GfxMgr::setAGIPal(int p0) {
 
 	_agipalFileNum = p0;
 
-	initPalette(_agipalPalette);
-	gfxSetPalette();
+	initPalette(_paletteGfxMode, _agipalPalette);
+	setPalette(true); // set gfx-mode palette
 
 	debug(1, "Using AGIPAL palette from '%s'", filename);
 }
@@ -873,137 +843,33 @@ int GfxMgr::getAGIPalFileNum() {
 	return _agipalFileNum;
 }
 
-// put a block onto the screen
-void GfxMgr::gfxPutBlock(int x1, int y1, int x2, int y2) {
-	if (x1 >= GFX_WIDTH)
-		x1 = GFX_WIDTH - 1;
-	if (y1 >= GFX_HEIGHT)
-		y1 = GFX_HEIGHT - 1;
-	if (x2 >= GFX_WIDTH)
-		x2 = GFX_WIDTH - 1;
-	if (y2 >= GFX_HEIGHT)
-		y2 = GFX_HEIGHT - 1;
-
-	g_system->copyRectToScreen(_screen + y1 * 320 + x1, 320, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
+void GfxMgr::initMouseCursor(MouseCursorData *mouseCursor, const byte *bitmapData, uint16 width, uint16 height, int hotspotX, int hotspotY) {
+	mouseCursor->bitmapData = bitmapData;
+	mouseCursor->width = width;
+	mouseCursor->height = height;
+	mouseCursor->hotspotX = hotspotX;
+	mouseCursor->hotspotY = hotspotY;
 }
 
-/**
- * A black and white SCI-style arrow cursor (11x16).
- * 0 = Transparent.
- * 1 = Black (#000000 in 24-bit RGB).
- * 2 = White (#FFFFFF in 24-bit RGB).
- */
-static const byte sciMouseCursor[] = {
-	1,1,0,0,0,0,0,0,0,0,0,
-	1,2,1,0,0,0,0,0,0,0,0,
-	1,2,2,1,0,0,0,0,0,0,0,
-	1,2,2,2,1,0,0,0,0,0,0,
-	1,2,2,2,2,1,0,0,0,0,0,
-	1,2,2,2,2,2,1,0,0,0,0,
-	1,2,2,2,2,2,2,1,0,0,0,
-	1,2,2,2,2,2,2,2,1,0,0,
-	1,2,2,2,2,2,2,2,2,1,0,
-	1,2,2,2,2,2,2,2,2,2,1,
-	1,2,2,2,2,2,1,0,0,0,0,
-	1,2,1,0,1,2,2,1,0,0,0,
-	1,1,0,0,1,2,2,1,0,0,0,
-	0,0,0,0,0,1,2,2,1,0,0,
-	0,0,0,0,0,1,2,2,1,0,0,
-	0,0,0,0,0,0,1,2,2,1,0
-};
-
-#if 0
-/**
- * A black and white Apple IIGS style arrow cursor (9x11).
- * 0 = Transparent.
- * 1 = Black (#000000 in 24-bit RGB).
- * 2 = White (#FFFFFF in 24-bit RGB).
- */
-static const byte appleIIgsMouseCursor[] = {
-	2,2,0,0,0,0,0,0,0,
-	2,1,2,0,0,0,0,0,0,
-	2,1,1,2,0,0,0,0,0,
-	2,1,1,1,2,0,0,0,0,
-	2,1,1,1,1,2,0,0,0,
-	2,1,1,1,1,1,2,0,0,
-	2,1,1,1,1,1,1,2,0,
-	2,1,1,1,1,1,1,1,2,
-	2,1,1,2,1,1,2,2,0,
-	2,2,2,0,2,1,1,2,0,
-	0,0,0,0,0,2,2,2,0
-};
-#endif
-
-/**
- * RGB-palette for the black and white SCI and Apple IIGS arrow cursors.
- */
-static const byte sciMouseCursorPalette[] = {
-	0x00, 0x00, 0x00, // Black
-	0xFF, 0xFF, 0xFF  // White
-};
-
-/**
- * An Amiga-style arrow cursor (8x11).
- * 0 = Transparent.
- * 1 = Black     (#000000 in 24-bit RGB).
- * 2 = Red       (#DE2021 in 24-bit RGB).
- * 3 = Light red (#FFCFAD in 24-bit RGB).
- */
-static const byte amigaMouseCursor[] = {
-	2,3,1,0,0,0,0,0,
-	2,2,3,1,0,0,0,0,
-	2,2,2,3,1,0,0,0,
-	2,2,2,2,3,1,0,0,
-	2,2,2,2,2,3,1,0,
-	2,2,2,2,2,2,3,1,
-	2,0,2,2,3,1,0,0,
-	0,0,0,2,3,1,0,0,
-	0,0,0,2,2,3,1,0,
-	0,0,0,0,2,3,1,0,
-	0,0,0,0,2,2,3,1
-};
+void GfxMgr::setMouseCursor(bool busy) {
+	MouseCursorData *mouseCursor = nullptr;
 
-/**
- * RGB-palette for the Amiga-style arrow cursor
- * and the Amiga-style busy cursor.
- */
-static const byte amigaMouseCursorPalette[] = {
-	0x00, 0x00, 0x00, // Black
-	0xDE, 0x20, 0x21, // Red
-	0xFF, 0xCF, 0xAD  // Light red
-};
+	if (!busy) {
+		mouseCursor = &_mouseCursor;
+	} else {
+		mouseCursor = &_mouseCursorBusy;
+	}
 
-/**
- * An Amiga-style busy cursor showing an hourglass (13x16).
- * 0 = Transparent.
- * 1 = Black     (#000000 in 24-bit RGB).
- * 2 = Red       (#DE2021 in 24-bit RGB).
- * 3 = Light red (#FFCFAD in 24-bit RGB).
- */
-static const byte busyAmigaMouseCursor[] = {
-	1,1,1,1,1,1,1,1,1,1,1,1,1,
-	1,2,2,2,2,2,2,2,2,2,2,2,1,
-	1,2,2,2,2,2,2,2,2,2,2,2,1,
-	0,1,3,3,3,3,3,3,3,3,3,1,0,
-	0,0,1,3,3,3,3,3,3,3,1,0,0,
-	0,0,0,1,3,3,3,3,3,1,0,0,0,
-	0,0,0,0,1,3,3,3,1,0,0,0,0,
-	0,0,0,0,0,1,3,1,0,0,0,0,0,
-	0,0,0,0,0,1,3,1,0,0,0,0,0,
-	0,0,0,0,1,2,3,2,1,0,0,0,0,
-	0,0,0,1,2,2,3,2,2,1,0,0,0,
-	0,0,1,2,2,2,3,2,2,2,1,0,0,
-	0,1,2,2,2,3,3,3,2,2,2,1,0,
-	1,3,3,3,3,3,3,3,3,3,3,3,1,
-	1,3,3,3,3,3,3,3,3,3,3,3,1,
-	1,1,1,1,1,1,1,1,1,1,1,1,1
-};
+	if (mouseCursor) {
+		CursorMan.replaceCursor(mouseCursor->bitmapData, mouseCursor->width, mouseCursor->height, mouseCursor->hotspotX, mouseCursor->hotspotY, 0);
+	}
+}
 
+#if 0
 void GfxMgr::setCursor(bool amigaStyleCursor, bool busy) {
 	if (busy) {
-		CursorMan.replaceCursorPalette(amigaMouseCursorPalette, 1, ARRAYSIZE(amigaMouseCursorPalette) / 3);
-		CursorMan.replaceCursor(busyAmigaMouseCursor, 13, 16, 7, 8, 0);
-
+		CursorMan.replaceCursorPalette(MOUSECURSOR_AMIGA_PALETTE, 1, ARRAYSIZE(MOUSECURSOR_AMIGA_PALETTE) / 3);
+		CursorMan.replaceCursor(MOUSECURSOR_AMIGA_BUSY, 13, 16, 7, 8, 0);
 		return;
 	}
 
@@ -1029,241 +895,6 @@ void GfxMgr::setCursorPalette(bool amigaStyleCursor) {
 		}
 	}
 }
-
-/**
- * Initialize graphics device.
- *
- * @see deinit_video()
- */
-int GfxMgr::initVideo() {
-	if (_vm->getFeatures() & (GF_AGI256 | GF_AGI256_2))
-		initPalette(vgaPalette, 256, 8);
-	else if (_vm->_renderMode == Common::kRenderEGA)
-		initPalette(egaPalette);
-	else if (_vm->_renderMode == Common::kRenderAmiga) {
-		if (!ConfMan.getBool("altamigapalette")) {
-			// Set the correct Amiga palette
-			if (_vm->getVersion() < 0x2936)
-				// TODO: This palette isn't used for Apple IIGS games yet, as
-				// we don't set a separate render mode for them yet
-				initPalette(amigaAgiPaletteV1, 16, 4);
-			else if (_vm->getVersion() == 0x2936)
-				initPalette(amigaAgiPaletteV2, 16, 4);
-			else if (_vm->getVersion() > 0x2936)
-				initPalette(amigaAgiPaletteV3, 16, 4);
-		} else
-			// Set the old common alternative Amiga palette
-			initPalette(altAmigaPalette);
-	} else
-		error("initVideo: Unhandled render mode \"%s\"", Common::getRenderModeDescription(_vm->_renderMode));
-
-	if ((_agiScreen = (uint8 *)calloc(GFX_WIDTH, GFX_HEIGHT)) == NULL)
-		return errNotEnoughMemory;
-
-	gfxSetPalette();
-
-	setCursor(_vm->_renderMode == Common::kRenderAmiga);
-
-	return errOK;
-}
-
-/**
- * Deinitialize graphics device.
- *
- * @see init_video()
- */
-int GfxMgr::deinitVideo() {
-	free(_agiScreen);
-
-	return errOK;
-}
-
-int GfxMgr::initMachine() {
-	_screen = (unsigned char *)malloc(320 * 200);
-	_vm->_clockCount = 0;
-
-	return errOK;
-}
-
-int GfxMgr::deinitMachine() {
-	free(_screen);
-
-	return errOK;
-}
-
-/**
- * Write pixels on the output device.
- * This function writes a row of pixels on the output device. Only the
- * lower 4 bits of each pixel in the row will be used, making this
- * function suitable for use with rows from the AGI screen.
- * @param x x coordinate of the row start (AGI coord.)
- * @param y y coordinate of the row start (AGI coord.)
- * @param n number of pixels in the row
- * @param p pointer to the row start in the AGI screen (Always use sbuf16c as base, not sbuf256c)
- * FIXME: CGA rendering doesn't work correctly with AGI256 or AGI256-2.
- */
-void GfxMgr::putPixelsA(int x, int y, int n, uint8 *p) {
-	const uint rShift = _vm->_debug.priority ? 4 : 0; // Priority information is in the top 4 bits of a byte taken from sbuf16c.
-
-	// Choose the correct screen to read from. If AGI256 or AGI256-2 is used and we're not trying to show the priority information,
-	// then choose the 256 color screen, otherwise choose the 16 color screen (Which also has the priority information).
-	p += ((_vm->getFeatures() & (GF_AGI256 | GF_AGI256_2)) && !_vm->_debug.priority) ? FROM_SBUF16_TO_SBUF256_OFFSET : 0;
-
-	if (_vm->_renderMode == Common::kRenderCGA) {
-		for (x *= 2; n--; p++, x += 2) {
-			register uint16 q = (cgaMap[(*p & 0xf0) >> 4] << 4) | cgaMap[*p & 0x0f];
-			*(uint16 *)&_agiScreen[x + y * GFX_WIDTH] = (q >> rShift) & 0x0f0f;
-		}
-	} else {
-		const uint16 mask = ((_vm->getFeatures() & (GF_AGI256 | GF_AGI256_2)) && !_vm->_debug.priority) ? 0xffff : 0x0f0f;
-		for (x *= 2; n--; p++, x += 2) {
-			register uint16 q = ((uint16)*p << 8) | *p;
-			*(uint16 *)&_agiScreen[x + y * GFX_WIDTH] = (q >> rShift) & mask;
-		}
-	}
-}
-
-/**
- * Schedule blocks for blitting on the output device.
- * This function gets the coordinates of a block in the AGI screen and
- * schedule it to be updated in the output device.
- * @param x1 x coordinate of the upper left corner of the block (AGI coord.)
- * @param y1 y coordinate of the upper left corner of the block (AGI coord.)
- * @param x2 x coordinate of the lower right corner of the block (AGI coord.)
- * @param y2 y coordinate of the lower right corner of the block (AGI coord.)
- *
- * @see do_update()
- */
-void GfxMgr::scheduleUpdate(int x1, int y1, int x2, int y2) {
-	if (x1 < update.x1)
-		update.x1 = x1;
-	if (y1 < update.y1)
-		update.y1 = y1;
-	if (x2 > update.x2)
-		update.x2 = x2;
-	if (y2 > update.y2)
-		update.y2 = y2;
-}
-
-/**
- * Update scheduled blocks on the output device.
- * This function exposes the blocks scheduled for updating to the output
- * device. Blocks can be scheduled at any point of the AGI cycle.
- *
- * @see schedule_update()
- */
-void GfxMgr::doUpdate() {
-	if (update.x1 <= update.x2 && update.y1 <= update.y2) {
-		gfxPutBlock(update.x1, update.y1, update.x2, update.y2);
-	}
-
-	// reset update block variables
-	update.x1 = MAX_INT;
-	update.y1 = MAX_INT;
-	update.x2 = 0;
-	update.y2 = 0;
-
-	g_system->updateScreen();
-}
-
-/**
- * Updates a block of the framebuffer with contents of the AGI engine screen.
- * This function updates a block in the output device with the contents of
- * the AGI engine screen, handling console transparency.
- * @param x1 x coordinate of the upper left corner of the block
- * @param y1 y coordinate of the upper left corner of the block
- * @param x2 x coordinate of the lower right corner of the block
- * @param y2 y coordinate of the lower right corner of the block
- *
- * @see flush_block_a()
- */
-void GfxMgr::flushBlock(int x1, int y1, int x2, int y2) {
-	int y, w;
-	uint8 *p0;
-
-	scheduleUpdate(x1, y1, x2, y2);
-
-	p0 = &_agiScreen[x1 + y1 * GFX_WIDTH];
-	w = x2 - x1 + 1;
-
-	for (y = y1; y <= y2; y++) {
-		memcpy(_screen + 320 * y + x1, p0, w);
-		p0 += GFX_WIDTH;
-	}
-}
-
-/**
- * Updates a block of the framebuffer receiving AGI picture coordinates.
- * @param x1 x AGI picture coordinate of the upper left corner of the block
- * @param y1 y AGI picture coordinate of the upper left corner of the block
- * @param x2 x AGI picture coordinate of the lower right corner of the block
- * @param y2 y AGI picture coordinate of the lower right corner of the block
- *
- * @see flush_block()
- */
-void GfxMgr::flushBlockA(int x1, int y1, int x2, int y2) {
-	//y1 += 8;
-	//y2 += 8;
-	flushBlock(DEV_X0(x1), DEV_Y(y1), DEV_X1(x2), DEV_Y(y2));
-}
-
-/**
- * Updates the framebuffer with contents of the AGI engine screen (console-aware).
- * This function updates the output device with the contents of the AGI
- * screen, handling console transparency.
- */
-void GfxMgr::flushScreen() {
-	flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
-
-	doUpdate();
-}
-
-/**
- * Clear the output device screen (console-aware).
- * This function clears the output device screen and updates the
- * output device. Contents of the AGI screen are left untouched. This
- * function can be used to simulate a switch to a text mode screen in
- * a graphic-only device.
- * @param c  color to clear the screen
- */
-void GfxMgr::clearScreen(int c) {
-	memset(_agiScreen, c, GFX_WIDTH * GFX_HEIGHT);
-	flushScreen();
-}
-
-/**
- * Save a block of the AGI engine screen
- */
-void GfxMgr::saveBlock(int x1, int y1, int x2, int y2, uint8 *b) {
-	uint8 *p0;
-	int w, h;
-
-	p0 = &_agiScreen[x1 + GFX_WIDTH * y1];
-	w = x2 - x1 + 1;
-	h = y2 - y1 + 1;
-	while (h--) {
-		memcpy(b, p0, w);
-		b += w;
-		p0 += GFX_WIDTH;
-	}
-}
-
-/**
- * Restore a block of the AGI engine screen
- */
-void GfxMgr::restoreBlock(int x1, int y1, int x2, int y2, uint8 *b) {
-	uint8 *p0;
-	int w, h;
-
-	p0 = &_agiScreen[x1 + GFX_WIDTH * y1];
-	w = x2 - x1 + 1;
-	h = y2 - y1 + 1;
-	while (h--) {
-		memcpy(p0, b, w);
-		b += w;
-		p0 += GFX_WIDTH;
-	}
-	flushBlock(x1, y1, x2, y2);
-}
+#endif
 
 } // End of namespace Agi
diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h
index 506a9d9..a89a7fd 100644
--- a/engines/agi/graphics.h
+++ b/engines/agi/graphics.h
@@ -27,6 +27,11 @@
 
 namespace Agi {
 
+#define SCRIPT_WIDTH	160
+#define SCRIPT_HEIGHT	168
+#define DISPLAY_WIDTH	320
+#define DISPLAY_HEIGHT	200
+
 #define GFX_WIDTH	320
 #define GFX_HEIGHT	200
 #define CHAR_COLS	8
@@ -34,66 +39,115 @@ namespace Agi {
 
 class AgiEngine;
 
+enum GfxScreenMasks {
+	GFX_SCREEN_MASK_VISUAL		= 1,
+	GFX_SCREEN_MASK_PRIORITY	= 2,
+	GFX_SCREEN_MASK_ALL			= GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY
+};
+
+struct MouseCursorData {
+	const byte *bitmapData;
+	uint16 width;
+	uint16 height;
+	int hotspotX;
+	int hotspotY;
+};
+
 class GfxMgr {
 private:
 	AgiBase *_vm;
 
-	uint8 _palette[256 * 3];
-	uint8 *_agiScreen;
-	unsigned char *_screen;
-
-	uint8 *_shakeH, *_shakeV;
+	uint8 _paletteGfxMode[256 * 3];
+	uint8 _paletteTextMode[256 * 3];
 
 	uint8 _agipalPalette[16 * 3];
 	int _agipalFileNum;
-	int _currentCursorPalette;	// 0 - palette not set, 1 - PC, 2 - Amiga
-
-private:
-	void rawDrawButton(int x, int y, const char *s, int fgcolor, int bgcolor, bool border, int textOffset);
 
 public:
 	GfxMgr(AgiBase *vm);
 
-	void gfxPutBlock(int x1, int y1, int x2, int y2);
-
-	void putTextCharacter(int, int, int, unsigned char, int, int, bool checkerboard = false, const uint8 *font = fontData_Sierra);
-	void shakeScreen(int);
-	void shakeStart();
-	void shakeEnd();
-	void saveScreen();
-	void restoreScreen();
-
 	int initVideo();
 	int deinitVideo();
-	void scheduleUpdate(int, int, int, int);
-	void doUpdate();
-	void putScreen();
-	void flushBlock(int, int, int, int);
-	void flushBlockA(int, int, int, int);
-	void putPixelsA(int, int, int, uint8 *);
-	void flushScreen();
-	void clearScreen(int);
-	void clearConsoleScreen(int);
-	void drawBox(int, int, int, int, int, int, int);
-	void drawDefaultStyleButton(int, int, const char *, int, int, int fgcolor = 0, int bgcolor = 0);
-	void drawCurrentStyleButton(int x, int y, const char *label, bool hasFocus, bool pressed = false, bool positive = true);
-	int testButton(int, int, const char *);
-	void drawRectangle(int, int, int, int, int);
-	void saveBlock(int, int, int, int, uint8 *);
-	void restoreBlock(int, int, int, int, uint8 *);
-	void initPalette(const uint8 *p, uint colorCount = 16, uint fromBits = 6, uint toBits = 8);
+	void initPalette(uint8 *destPalette, const uint8 *paletteData, uint colorCount = 16, uint fromBits = 6, uint toBits = 8);
 	void setAGIPal(int);
 	int getAGIPalFileNum();
-	void drawFrame(int x1, int y1, int x2, int y2, int c1, int c2);
+	void setPalette(bool GfxModePalette);
 
-	void putBlock(int x1, int y1, int x2, int y2);
-	void gfxSetPalette();
-	void setCursor(bool amigaStyleCursor = false, bool busy = false);
-	void setCursorPalette(bool amigaStylePalette = false);
+	void initMouseCursor(MouseCursorData *mouseCursor, const byte *bitmapData, uint16 width, uint16 height, int hotspotX, int hotspotY);
+	void setMouseCursor(bool busy = false);
 
-	void printCharacter(int, int, char, int, int);
 	int initMachine();
 	int deinitMachine();
+
+	void setRenderStartOffset(uint16 offsetY);
+
+private:
+	uint _pixels;
+	//uint16 _displayWidth;
+	//uint16 _displayHeight;
+	uint _displayPixels;
+
+	byte *_activeScreen;
+	byte *_visualScreen;   // 160x168
+	byte *_priorityScreen; // 160x168
+	byte *_displayScreen;  // 320x200
+
+	bool  _priorityTableSet;
+	uint8 _priorityTable[SCRIPT_HEIGHT]; /**< priority table */
+
+	MouseCursorData _mouseCursor;
+	MouseCursorData _mouseCursorBusy;
+
+	uint16 _renderStartOffsetY;
+
+public:
+	void debugShowMap(int mapNr);
+
+	void clear(byte color, byte priority);
+	void clearDisplay(byte color, bool copyToScreen = true);
+	void putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority);
+	void putPixelOnDisplay(int16 x, int16 y, byte color);
+
+	byte getColor(int16 x, int16 y);
+	byte getPriority(int16 x, int16 y);
+	bool checkControlPixel(int16 x, int16 y, byte newPriority);
+
+	byte getCGAMixtureColor(byte color);
+
+	void render_Block(int16 x, int16 y, int16 width, int16 height, bool copyToScreen = true);
+	bool render_Clip(int16 &x, int16 &y, int16 &width, int16 &height, int16 clipAgainstWidth = SCRIPT_WIDTH, int16 clipAgainstHeight = SCRIPT_HEIGHT);
+
+private:
+	void render_BlockEGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen);
+	void render_BlockCGA(int16 x, int16 y, int16 width, int16 height, bool copyToScreen);
+
+public:
+	void transition_Amiga();
+	void transition_AtariSt();
+
+	void block_save(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr);
+	void block_restore(int16 x, int16 y, int16 width, int16 height, byte *bufferPtr);
+
+	void copyDisplayRectToScreen(int16 x, int16 y, int16 width, int16 height);
+
+	void drawBox(int16 x, int16 y, int16 width, int16 height, byte backgroundColor, byte lineColor);
+	void drawRect(int16 x, int16 y, int16 width, int16 height, byte color);
+	void drawDisplayRect(int16 x, int16 y, int16 width, int16 height, byte color);
+private:
+	void drawDisplayRectEGA(int16 x, int16 y, int16 width, int16 height, byte color);
+	void drawDisplayRectCGA(int16 x, int16 y, int16 width, int16 height, byte color);
+
+public:
+	void drawCharacter(int16 row, int16 column, byte character, byte foreground, byte background, bool disabledLook);
+
+	void shakeScreen(int16 repeatCount);
+	void updateScreen();
+
+	void initPriorityTable();
+	void setPriorityTable(int16 priorityBase);
+	void setPriority(int16 yPos, int16 priority);
+	int16 priorityToY(int16 priority);
+	int16 priorityFromY(int16 yPos);
 };
 
 } // End of namespace Agi
diff --git a/engines/agi/inv.cpp b/engines/agi/inv.cpp
index f1e4e50..614b016 100644
--- a/engines/agi/inv.cpp
+++ b/engines/agi/inv.cpp
@@ -22,221 +22,193 @@
 
 #include "agi/agi.h"
 #include "agi/graphics.h"
+#include "agi/inv.h"
+#include "agi/text.h"
 #include "agi/keyboard.h"
+#include "agi/systemui.h"
 
 namespace Agi {
 
-//
-// Messages and coordinates
-//
+InventoryMgr::InventoryMgr(AgiEngine *agi, GfxMgr *gfx, TextMgr *text, SystemUI *systemUI) {
+	_vm = agi;
+	_gfx = gfx;
+	_text = text;
+	_systemUI = systemUI;
+}
 
-#define NOTHING_X	16
-#define NOTHING_Y	3
-#define NOTHING_MSG	"nothing"
+InventoryMgr::~InventoryMgr() {
+}
 
-#define ANY_KEY_X	4
-#define ANY_KEY_Y	24
-#define ANY_KEY_MSG	"Press a key to return to the game"
+void InventoryMgr::getPlayerInventory() {
+	AgiGame game = _vm->_game;
+	int16 selectedInventoryItem = _vm->getVar(VM_VAR_SELECTED_INVENTORY_ITEM);
+	uint16 objectNr = 0;
+	int16 curRow = 2; // starting at position 2,1
+	int16 curColumn = 1;
+
+	_array.clear();
+	_activeItemNr = 0;
+
+	for (objectNr = 0; objectNr < game.numObjects; objectNr++) {
+		if (_vm->objectGetLocation(objectNr) == EGO_OWNED) {
+			// item is in the possession of ego, so add it to our internal list
+			if (objectNr == selectedInventoryItem) {
+				// it's the currently selected inventory item, remember that
+				_activeItemNr = _array.size();
+			}
 
-#define YOUHAVE_X	11
-#define YOUHAVE_Y	0
-#define YOUHAVE_MSG	"You are carrying:"
+			InventoryEntry inventoryEntry;
 
-#define SELECT_X	2
-#define SELECT_Y	24
-#define SELECT_MSG	"Press ENTER to select, ESC to cancel"
+			inventoryEntry.objectNr = objectNr;
+			inventoryEntry.name = _vm->objectName(objectNr);
+			inventoryEntry.row = curRow;
+			inventoryEntry.column = curColumn;
+			if (inventoryEntry.column > 1) {
+				// right side, adjust column accordingly
+				inventoryEntry.column -= strlen( inventoryEntry.name );
+			}
+			_array.push_back(inventoryEntry);
+
+			// go to next position
+			if (curColumn == 1) {
+				// current position is left side, go to right side
+				curColumn = 39;
+			} else {
+				// current position is right side, so go to left side again and new row
+				curColumn = 1;
+				curRow++;
+			}
+		}
+	}
 
-#define NOTHING_X_RU	16
-#define NOTHING_Y_RU	3
-#define NOTHING_MSG_RU	"\xad\xa8\xe7\xa5\xa3\xae"
+	if (_array.size() == 0) {
+		// empty inventory
+		InventoryEntry inventoryEntry;
 
-#define ANY_KEY_X_RU	4
-#define ANY_KEY_Y_RU	24
-#define ANY_KEY_MSG_RU	"\x8b\xee\xa1\xa0\xef \xaa\xab\xa0\xa2\xa8\xe8\xa0 - \xa2\xae\xa7\xa2\xe0\xa0\xe2 \xa2 \xa8\xa3\xe0\xe3."
+		inventoryEntry.objectNr = 0;
+		inventoryEntry.name = _systemUI->getInventoryTextNothing();
+		inventoryEntry.row = 2;
+		inventoryEntry.column = 19 - (strlen(inventoryEntry.name) / 2);
+		_array.push_back(inventoryEntry);
+	}
+}
 
-#define YOUHAVE_X_RU	11
-#define YOUHAVE_Y_RU	0
-#define YOUHAVE_MSG_RU	"   \x93 \xa2\xa0\xe1 \xa5\xe1\xe2\xec:   "
+void InventoryMgr::drawAll() {
+	int16 inventoryCount = _array.size();
+	int16 inventoryNr = 0;
 
-#define SELECT_X_RU	2
-#define SELECT_Y_RU	24
-#define SELECT_MSG_RU	"ENTER - \xa2\xeb\xa1\xe0\xa0\xe2\xec, ESC - \xae\xe2\xac\xa5\xad\xa8\xe2\xec."
+	_text->charPos_Set(0, 11);
+	_text->displayText(_systemUI->getInventoryTextYouAreCarrying());
 
-void AgiEngine::printItem(int n, int fg, int bg) {
-	printText(objectName(_intobj[n]), 0, ((n % 2) ? 39 - strlen(objectName(_intobj[n])) : 1),
-			(n / 2) + 2, 40, fg, bg);
+	for (inventoryNr = 0; inventoryNr < inventoryCount; inventoryNr++) {
+		drawItem(inventoryNr);
+	}
 }
 
-int AgiEngine::findItem() {
-	int r, c;
+void InventoryMgr::drawItem(int16 itemNr) {
+	if (itemNr == _activeItemNr) {
+		_text->charAttrib_Set(15, 0);
+	} else {
+		_text->charAttrib_Set(0, 15);
+	}
 
-	r = _mouse.y / CHAR_LINES;
-	c = _mouse.x / CHAR_COLS;
+	_text->charPos_Set(_array[itemNr].row, _array[itemNr].column);
+	// original interpreter used printf here
+	// this doesn't really make sense, because for length calculation it's using strlen without printf
+	// which means right-aligned inventory items on the right side would not be displayed properly
+	// in case printf-formatting was actually used
+	// I have to assume that no game uses this, because behavior in original interpreter would have been buggy.
+	_text->displayText(_array[itemNr].name);
+}
 
-	debugC(6, kDebugLevelInventory, "r = %d, c = %d", r, c);
+void InventoryMgr::show() {
+	bool selectItems = false;
 
-	if (r < 2)
-		return -1;
+	// figure out current inventory of the player
+	getPlayerInventory();
 
-	return (r - 2) * 2 + (c > 20);
-}
+	if (_vm->getflag(VM_FLAG_STATUS_SELECTS_ITEMS)) {
+		selectItems = true;
+	} else{
+		_activeItemNr = -1; // so that none is shown as active
+	}
 
-int AgiEngine::showItems() {
-	unsigned int x, i;
+	drawAll();
 
-	for (x = i = 0; x < _game.numObjects; x++) {
-		if (objectGetLocation(x) == EGO_OWNED) {
-			// add object to our list!
-			_intobj[i] = x;
-			printItem(i, STATUS_FG, STATUS_BG);
-			i++;
-		}
+	_text->charAttrib_Set(0, 15);
+	if (selectItems) {
+		_text->charPos_Set(24, 2);
+		_text->displayText(_systemUI->getInventoryTextSelectItems());
+	} else {
+		_text->charPos_Set(24, 4);
+		_text->displayText(_systemUI->getInventoryTextReturnToGame());
 	}
 
-	if (i == 0) {
-		switch (getLanguage()) {
-		case Common::RU_RUS:
-			printText(NOTHING_MSG_RU, 0, NOTHING_X_RU, NOTHING_Y_RU, 40, STATUS_FG, STATUS_BG);
-			break;
-		default:
-			printText(NOTHING_MSG, 0, NOTHING_X, NOTHING_Y, 40, STATUS_FG, STATUS_BG);
-			break;
-		}
-	}
+	if (selectItems) {
+		_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_INVENTORY);
 
-	return i;
-}
+		do {
+			_vm->mainCycle();
+		} while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
 
-void AgiEngine::selectItems(int n) {
-	int fsel = 0;
-	bool exit_select = false;
-
-	while (!exit_select && !(shouldQuit() || _restartGame)) {
-		if (n > 0)
-			printItem(fsel, STATUS_BG, STATUS_FG);
-
-		switch (waitAnyKey()) {
-		case KEY_ENTER:
-			setvar(vSelItem, _intobj[fsel]);
-			exit_select = true;
-			break;
-		case KEY_ESCAPE:
-			setvar(vSelItem, 0xff);
-			exit_select = true;
-			break;
-		case KEY_UP:
-			if (fsel >= 2)
-				fsel -= 2;
-			break;
-		case KEY_DOWN:
-			if (fsel + 2 < n)
-				fsel += 2;
-			break;
-		case KEY_LEFT:
-			if (fsel % 2 == 1)
-				fsel--;
-			break;
-		case KEY_RIGHT:
-			if (fsel % 2 == 0 && fsel + 1 < n)
-				fsel++;
-			break;
-		case BUTTON_LEFT:{
-				int i = findItem();
-				if (i >= 0 && i < n) {
-					setvar(vSelItem, _intobj[fsel = i]);
-					debugC(6, kDebugLevelInventory, "item found: %d", fsel);
-					showItems();
-					printItem(fsel, STATUS_BG, STATUS_FG);
-					_gfx->doUpdate();
-					exit_select = true;
-				}
-				break;
-			}
-		default:
-			break;
+		if (_activeItemNr >= 0) {
+			// pass selected object number
+			_vm->setVar(VM_VAR_SELECTED_INVENTORY_ITEM, _array[_activeItemNr].objectNr);
+		} else {
+			// nothing was selected
+			_vm->setVar(VM_VAR_SELECTED_INVENTORY_ITEM, 0xff);
 		}
 
-		if (!exit_select) {
-			showItems();
-			_gfx->doUpdate();
-		}
+	} else {
+		// no selection is supposed to be possible, just wait for key and exit
+		_vm->waitAnyKey();
 	}
-
-	debugC(6, kDebugLevelInventory, "selected: %d", fsel);
 }
 
-/*
- * Public functions
- */
-
-/**
- * Display inventory items.
- */
-void AgiEngine::inventory() {
-	int oldFg, oldBg;
-	int n;
-
-	// screen is white with black text
-	oldFg = _game.colorFg;
-	oldBg = _game.colorBg;
-	_game.colorFg = 0;
-	_game.colorBg = 15;
-	_gfx->clearScreen(_game.colorBg);
-
-	switch (getLanguage()) {
-	case Common::RU_RUS:
-		printText(YOUHAVE_MSG_RU, 0, YOUHAVE_X_RU, YOUHAVE_Y_RU, 40, STATUS_FG, STATUS_BG);
-		break;
-	default:
-		printText(YOUHAVE_MSG, 0, YOUHAVE_X, YOUHAVE_Y, 40, STATUS_FG, STATUS_BG);
+void InventoryMgr::charPress(int16 newChar) {
+	switch (newChar) {
+	case AGI_KEY_ENTER: {
+		_vm->cycleInnerLoopInactive(); // exit show-loop
 		break;
 	}
 
-	// FIXME: doesn't check if objects overflow off screen...
-
-	_intobj = (uint8 *)malloc(4 + _game.numObjects);
-	memset(_intobj, 0, (4 + _game.numObjects));
-
-	n = showItems();
+	case AGI_KEY_ESCAPE: {
+		_vm->cycleInnerLoopInactive(); // exit show-loop
+		_activeItemNr = -1; // no item selected
+		break;
+	}
 
-	switch (getLanguage()) {
-	case Common::RU_RUS:
-		if (getflag(fStatusSelectsItems)) {
-			printText(SELECT_MSG_RU, 0, SELECT_X_RU, SELECT_Y_RU, 40, STATUS_FG, STATUS_BG);
-		} else {
-			printText(ANY_KEY_MSG_RU, 0, ANY_KEY_X_RU, ANY_KEY_Y_RU, 40, STATUS_FG, STATUS_BG);
-		}
+	case AGI_KEY_UP:
+		changeActiveItem(-2);
 		break;
+	case AGI_KEY_DOWN:
+		changeActiveItem(+2);
+		break;
+	case AGI_KEY_LEFT:
+		changeActiveItem(-1);
+		break;
+	case AGI_KEY_RIGHT:
+		changeActiveItem(+1);
+		break;
+
 	default:
-		if (getflag(fStatusSelectsItems)) {
-			printText(SELECT_MSG, 0, SELECT_X, SELECT_Y, 40, STATUS_FG, STATUS_BG);
-		} else {
-			printText(ANY_KEY_MSG, 0, ANY_KEY_X, ANY_KEY_Y, 40, STATUS_FG, STATUS_BG);
-		}
 		break;
 	}
+}
 
-	_gfx->flushScreen();
-
-	// If flag 13 is set, we want to highlight & select an item.
-	// opon selection, put objnum in var 25. Then on esc put in
-	// var 25 = 0xff.
-
-	if (getflag(fStatusSelectsItems))
-		selectItems(n);
-
-	free(_intobj);
+void InventoryMgr::changeActiveItem(int16 direction) {
+	int16 orgItemNr = _activeItemNr;
 
-	if (!getflag(fStatusSelectsItems))
-		waitAnyKey();
+	_activeItemNr += direction;
 
-	_gfx->clearScreen(0);
-	writeStatus();
-	_picture->showPic();
-	_game.colorFg = oldFg;
-	_game.colorBg = oldBg;
-	_game.hasPrompt = 0;
-	flushLines(_game.lineUserInput, 24);
+	if ((_activeItemNr >= 0) && (_activeItemNr < (int16)_array.size())) {
+		// within bounds
+		drawItem(orgItemNr);
+		drawItem(_activeItemNr);
+	} else {
+		// out of bounds, revert change
+		_activeItemNr = orgItemNr;
+	}
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/inv.h b/engines/agi/inv.h
new file mode 100644
index 0000000..0c89275
--- /dev/null
+++ b/engines/agi/inv.h
@@ -0,0 +1,61 @@
+/* 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 AGI_INV_H
+#define AGI_INV_H
+
+namespace Agi {
+
+struct InventoryEntry {
+	uint16 objectNr;
+	int16  row;
+	int16  column;
+	const char *name;
+};
+typedef Common::Array<InventoryEntry> InventoryArray;
+
+class InventoryMgr {
+private:
+	GfxMgr *_gfx;
+	TextMgr *_text;
+	AgiEngine *_vm;
+	SystemUI *_systemUI;
+
+	InventoryArray _array;
+	int16 _activeItemNr;
+
+public:
+	InventoryMgr(AgiEngine *agi, GfxMgr *gfx, TextMgr *text, SystemUI *systemUI);
+	~InventoryMgr();
+
+	void getPlayerInventory();
+	void drawAll();
+	void drawItem(int16 itemNr);
+	void show();
+
+	void charPress(int16 newChar);
+	void changeActiveItem(int16 direction);
+};
+
+} // End of namespace Agi
+
+#endif /* AGI_INV_H */
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 0aa521b..c307b07 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -20,12 +20,13 @@
  *
  */
 
+#include "common/events.h"
+
 #include "agi/agi.h"
 #include "agi/graphics.h"
 #include "agi/keyboard.h"
-#ifdef __DS__
-#include "wordcompletion.h"
-#endif
+#include "agi/menu.h"
+#include "agi/text.h"
 
 namespace Agi {
 
@@ -61,21 +62,230 @@ const uint8 scancodeTable[26] = {
 	44			// Z
 };
 
-void AgiEngine::initWords() {
-	_game.numEgoWords = 0;
-}
+void AgiEngine::processEvents() {
+	Common::Event event;
+	int key = 0;
 
-void AgiEngine::cleanInput() {
-	while (_game.numEgoWords)
-		free(_game.egoWords[--_game.numEgoWords].word);
-}
+	while (_eventMan->pollEvent(event)) {
+		switch (event.type) {
+		case Common::EVENT_PREDICTIVE_DIALOG: {
+			GUI::PredictiveDialog _predictiveDialog;
+			_predictiveDialog.runModal();
+#if 0
+			strcpy(_predictiveResult, _predictiveDialog.getResult());
+			if (strcmp(_predictiveResult, "")) {
+				if (_game.inputMode == INPUTMODE_NORMAL) {
+					//strcpy((char *)_game.inputBuffer, _predictiveResult);
+					//handleKeys(KEY_ENTER);
+					// TODO: repair predictive
+				} else if (_game.inputMode == INPUTMODE_GETSTRING) {
+					strcpy(_game.strings[_stringdata.str], _predictiveResult);
+					newInputMode(INPUTMODE_NORMAL);
+					//_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
+					//		_stringdata.y, ' ', 15, 0);
+				} else if (_game.inputMode == INPUTMODE_NONE) {
+					for (int n = 0; _predictiveResult[n]; n++)
+						keyEnqueue(_predictiveResult[n]);
+				}
+			}
+#endif
+			/*
+			if (predictiveDialog()) {
+				if (_game.inputMode == INPUT_NORMAL) {
+					strcpy((char *)_game.inputBuffer, _predictiveResult);
+					handleKeys(KEY_ENTER);
+				} else if (_game.inputMode == INPUT_GETSTRING) {
+					strcpy(_game.strings[_stringdata.str], _predictiveResult);
+					newInputMode(INPUT_NORMAL);
+					_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
+							_stringdata.y, ' ', _game.colorFg, _game.colorBg);
+				} else if (_game.inputMode == INPUT_NONE) {
+					for (int n = 0; _predictiveResult[n]; n++)
+						keyEnqueue(_predictiveResult[n]);
+				}
+			}
+			*/
+			}
+			break;
+		case Common::EVENT_LBUTTONDOWN:
+			if (_game.mouseEnabled) {
+				key = AGI_MOUSE_BUTTON_LEFT;
+				_mouse.button = kAgiMouseButtonLeft;
+				keyEnqueue(key);
+				_mouse.x = event.mouse.x;
+				_mouse.y = event.mouse.y;
+			}
+			break;
+		case Common::EVENT_RBUTTONDOWN:
+			if (_game.mouseEnabled) {
+				key = AGI_MOUSE_BUTTON_RIGHT;
+				_mouse.button = kAgiMouseButtonRight;
+				keyEnqueue(key);
+				_mouse.x = event.mouse.x;
+				_mouse.y = event.mouse.y;
+			}
+			break;
+		case Common::EVENT_WHEELUP:
+			if (_game.mouseEnabled) {
+				key = AGI_MOUSE_WHEEL_UP;
+				keyEnqueue(key);
+			}
+			break;
+		case Common::EVENT_WHEELDOWN:
+			if (_game.mouseEnabled) {
+				key = AGI_MOUSE_WHEEL_DOWN;
+				keyEnqueue(key);
+			}
+			break;
+		case Common::EVENT_MOUSEMOVE:
+			if (_game.mouseEnabled) {
+				_mouse.x = event.mouse.x;
+				_mouse.y = event.mouse.y;
+
+				if (!_game.mouseFence.isEmpty()) {
+					if (_mouse.x < _game.mouseFence.left)
+						_mouse.x = _game.mouseFence.left;
+					if (_mouse.x > _game.mouseFence.right)
+						_mouse.x = _game.mouseFence.right;
+					if (_mouse.y < _game.mouseFence.top)
+						_mouse.y = _game.mouseFence.top;
+					if (_mouse.y > _game.mouseFence.bottom)
+						_mouse.y = _game.mouseFence.bottom;
+
+					g_system->warpMouse(_mouse.x, _mouse.y);
+				}
+			}
+
+			break;
+		case Common::EVENT_LBUTTONUP:
+		case Common::EVENT_RBUTTONUP:
+			if (_game.mouseEnabled) {
+				_mouse.button = kAgiMouseButtonUp;
+				_mouse.x = event.mouse.x;
+				_mouse.y = event.mouse.y;
+			}
+			break;
+		case Common::EVENT_KEYDOWN:
+			if (event.kbd.hasFlags(Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_d) {
+				_console->attach();
+				break;
+			}
 
-void AgiEngine::getString(int x, int y, int len, int str) {
-	newInputMode(INPUT_GETSTRING);
-	_stringdata.x = x;
-	_stringdata.y = y;
-	_stringdata.len = len;
-	_stringdata.str = str;
+			if ((event.kbd.ascii) && (event.kbd.ascii <= 0xFF)) {
+				// No special key, directly accept it
+				// Is ISO-8859-1, we need lower 128 characters only, which is plain ASCII, so no mapping required
+				key = event.kbd.ascii;
+
+				if (Common::isAlpha(key)) {
+					// Key is A-Z.
+					// Map Ctrl-A to 1, Ctrl-B to 2, etc.
+					if (event.kbd.flags & Common::KBD_CTRL) {
+						key = toupper(key) - 'A' + 1;
+					} else if (event.kbd.flags & Common::KBD_ALT) {
+						// Map Alt-A, Alt-B etc. to special scancode values according to an internal scancode table.
+						key = scancodeTable[toupper(key) - 'A'] << 8;
+					}
+				}
+			} else {
+				switch (key = event.kbd.keycode) {
+				case Common::KEYCODE_LEFT:
+				case Common::KEYCODE_KP4:
+					if (_allowSynthetic || !event.synthetic)
+						key = AGI_KEY_LEFT;
+					break;
+				case Common::KEYCODE_RIGHT:
+				case Common::KEYCODE_KP6:
+					if (_allowSynthetic || !event.synthetic)
+						key = AGI_KEY_RIGHT;
+					break;
+				case Common::KEYCODE_UP:
+				case Common::KEYCODE_KP8:
+					if (_allowSynthetic || !event.synthetic)
+						key = AGI_KEY_UP;
+					break;
+				case Common::KEYCODE_DOWN:
+				case Common::KEYCODE_KP2:
+					if (_allowSynthetic || !event.synthetic)
+						key = AGI_KEY_DOWN;
+					break;
+				case Common::KEYCODE_PAGEUP:
+				case Common::KEYCODE_KP9:
+					if (_allowSynthetic || !event.synthetic)
+						key = AGI_KEY_UP_RIGHT;
+					break;
+				case Common::KEYCODE_PAGEDOWN:
+				case Common::KEYCODE_KP3:
+					if (_allowSynthetic || !event.synthetic)
+						key = AGI_KEY_DOWN_RIGHT;
+					break;
+				case Common::KEYCODE_HOME:
+				case Common::KEYCODE_KP7:
+					if (_allowSynthetic || !event.synthetic)
+						key = AGI_KEY_UP_LEFT;
+					break;
+				case Common::KEYCODE_END:
+				case Common::KEYCODE_KP1:
+					if (_allowSynthetic || !event.synthetic)
+						key = AGI_KEY_DOWN_LEFT;
+					break;
+				case Common::KEYCODE_KP5:
+					key = AGI_KEY_STATIONARY;
+					break;
+				case Common::KEYCODE_F1:
+					key = AGI_KEY_F1;
+					break;
+				case Common::KEYCODE_F2:
+					key = AGI_KEY_F2;
+					break;
+				case Common::KEYCODE_F3:
+					key = AGI_KEY_F3;
+					break;
+				case Common::KEYCODE_F4:
+					key = AGI_KEY_F4;
+					break;
+				case Common::KEYCODE_F5:
+					key = AGI_KEY_F5;
+					break;
+				case Common::KEYCODE_F6:
+					key = AGI_KEY_F6;
+					break;
+				case Common::KEYCODE_F7:
+					key = AGI_KEY_F7;
+					break;
+				case Common::KEYCODE_F8:
+					key = AGI_KEY_F8;
+					break;
+				case Common::KEYCODE_F9:
+					key = AGI_KEY_F9;
+					break;
+				case Common::KEYCODE_F10:
+					key = AGI_KEY_F10;
+					break;
+				case Common::KEYCODE_F11:
+					key = AGI_KEY_F11;
+					break;
+				case Common::KEYCODE_F12:
+					key = AGI_KEY_F12;
+					break;
+				case Common::KEYCODE_KP_ENTER:
+					key = AGI_KEY_ENTER;
+					break;
+				default:
+					break;
+				}
+			}
+			if (key)
+				keyEnqueue(key);
+			break;
+
+		case Common::EVENT_KEYUP:
+			if (_egoHoldKey)
+				_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY].direction = 0;
+
+		default:
+			break;
+		}
+	}
 }
 
 /**
@@ -97,54 +307,128 @@ int AgiEngine::doPollKeyboard() {
 	return key;
 }
 
-int AgiEngine::handleController(int key) {
-	VtEntry *v = &_game.viewTable[0];
-	int i;
+int16 AgiEngine::getSpecialMenuControllerSlot() {
+	int16 controllerSlotESC = -1;
+	int16 controllerSlotSpecial = -1;
+
+	for (uint16 curMapping = 0; curMapping < MAX_CONTROLLER_KEYMAPPINGS; curMapping++) {
+		if (_game.controllerKeyMapping[curMapping].keycode == _game.specialMenuTriggerKey) {
+			if (controllerSlotSpecial < 0) {
+				controllerSlotSpecial = _game.controllerKeyMapping[curMapping].controllerSlot;
+			}
+		}
+		if (_game.controllerKeyMapping[curMapping].keycode == AGI_MENU_TRIGGER_PC) {
+			if (controllerSlotESC < 0) {
+				controllerSlotESC = _game.controllerKeyMapping[curMapping].controllerSlot;
+			}
+		}
+	}
+	if (controllerSlotSpecial >= 0) {
+		// special menu controller slot found
+		if (controllerSlotSpecial != controllerSlotESC) {
+			// not the same as the ESC slot (is the same in Manhunter AppleIIgs, we need to replace "pause"
+			if (controllerSlotSpecial >= 10) {
+				// slot needs to be at least 10
+				// Atari ST SQ1 maps the special key, but doesn't trigger any menu with it
+				// the controller slot in this case is 8.
+				return controllerSlotSpecial;
+			}
+		}
+	}
+	return -1;
+}
+
+bool AgiEngine::handleController(uint16 key) {
+	ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
+
+	if (key == 0) // nothing pressed
+		return false;
+
+	// This previously skipped processing, when ESC was pressed and called menu directly.
+	// This original approach was bad, because games check different flags before actually allowing the
+	//  user to enter the menu. We checked a few common flags, like for example the availability of the prompt.
+	//  But this stopped the user being able to enter the menu, when the original interpreter actually allowed it.
+	//  We now instead implement this feature using another way for those platforms.
+	if (key == AGI_KEY_ESCAPE) {
+		// Escape pressed, user probably wants to trigger the menu
+		// For PC, just passing ASCII code for ESC will normally trigger a controller
+		//  and the scripts will then trigger the menu
+		// For other platforms, ESC was handled by platforms to trigger "pause game" instead
+		// We need to change ESC to a platform specific code to make it work properly.
+		//
+		// There are exceptions though. Mixed Up Mother Goose on AppleIIgs for example actually sets up
+		//  ESC for pause only. That's why we also check, if the key is actually mapped to a controller.
+		// For this special case, we actually replace the pause function with a menu trigger.
+		// Replacing "pause" all the time wouldn't work out as well, becaue games like KQ1 on Apple IIgs
+		//  actually disable "pause" when ego has been killed, which means we wouldn't be able to access
+		//  the menu anymore in that case.
+		if (_menu->isAvailable()) {
+			// menu is actually available
+			if (_game.specialMenuTriggerKey) {
+				int16 specialMenuControllerSlot = getSpecialMenuControllerSlot();
+
+				if (specialMenuControllerSlot >= 0) {
+					// menu trigger found, trigger it now
+					_game.controllerOccured[specialMenuControllerSlot] = true;
+					return true;
+				}
+			}
+			// Otherwise go on and look for the ESC controller
+		}
+	}
+
 
 	// AGI 3.149 games, The Black Cauldron and King's Quest 4 need KEY_ESCAPE to use menus
 	// Games with the GF_ESCPAUSE flag need KEY_ESCAPE to pause the game
-	if (key == 0 ||
-		(key == KEY_ESCAPE && getVersion() != 0x3149 && getGameID() != GID_BC && getGameID() != GID_KQ4 && !(getFeatures() & GF_ESCPAUSE)) )
-		return false;
+	//		(key == KEY_ESCAPE && getVersion() != 0x3149 && getGameID() != GID_BC && getGameID() != GID_KQ4 && !(getFeatures() & GF_ESCPAUSE)) )
+	//		return false;
 
-	if ((getGameID() == GID_MH1 || getGameID() == GID_MH2) && (key == KEY_ENTER) &&
-			(_game.inputMode == INPUT_NONE)) {
+	if ((getGameID() == GID_MH1 || getGameID() == GID_MH2) && (key == AGI_KEY_ENTER) &&
+			(_game.inputMode == INPUTMODE_NONE)) {
 		key = 0x20; // Set Enter key to Space in Manhunter when there's no text input
 	}
 
 	debugC(3, kDebugLevelInput, "key = %04x", key);
 
-	for (i = 0; i < MAX_CONTROLLERS; i++) {
-		if (_game.controllers[i].keycode == key) {
-			debugC(3, kDebugLevelInput, "event %d: key press", _game.controllers[i].controller);
-			_game.controllerOccured[_game.controllers[i].controller] = true;
+	for (uint16 curMapping = 0; curMapping < MAX_CONTROLLER_KEYMAPPINGS; curMapping++) {
+		if (_game.controllerKeyMapping[curMapping].keycode == key) {
+			debugC(3, kDebugLevelInput, "event %d: key press", _game.controllerKeyMapping[curMapping].controllerSlot);
+			_game.controllerOccured[_game.controllerKeyMapping[curMapping].controllerSlot] = true;
 			return true;
 		}
 	}
 
-	if (key == BUTTON_LEFT) {
-		if ((getflag(fMenusWork) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) {
-			newInputMode(INPUT_MENU);
-			return true;
-		}
+	if (key == AGI_MOUSE_BUTTON_LEFT) {
+		// call mouse when click is done on status bar
+		// TODO
+		// This should be done in a better way as in simulate ESC key
+		// Sierra seems to have hardcoded it in some way, but we would have to verify, what flags
+		// they checked. The previous way wasn't accurate. Mouse support for menu is missing atm anyway.
+		//if ((getflag(VM_FLAG_MENUS_WORK) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) {
+		//	newInputMode(INPUTMODE_MENU);
+		//	return true;
+		//}
 	}
 
 	// Show predictive dialog if the user clicks on input area
-	if (key == BUTTON_LEFT &&
-			(int)_mouse.y >= _game.lineUserInput * CHAR_LINES &&
-			(int)_mouse.y <= (_game.lineUserInput + 1) * CHAR_LINES) {
+	if (key == AGI_MOUSE_BUTTON_LEFT &&
+			(int)_mouse.y >= _text->promptRow_Get() * FONT_DISPLAY_HEIGHT &&
+			(int)_mouse.y <= (_text->promptRow_Get() + 1) * FONT_DISPLAY_HEIGHT) {
 		GUI::PredictiveDialog _predictiveDialog;
 		_predictiveDialog.runModal();
+#if 0
 		strcpy(_predictiveResult, _predictiveDialog.getResult());
 		if (strcmp(_predictiveResult, "")) {
-			if (_game.inputMode == INPUT_NONE) {
+			if (_game.inputMode == INPUTMODE_NONE) {
 				for (int n = 0; _predictiveResult[n]; n++)
 					keyEnqueue(_predictiveResult[n]);
 			} else {
-				strcpy((char *)_game.inputBuffer, _predictiveResult);
-				handleKeys(KEY_ENTER);
+				//strcpy((char *)_game.inputBuffer, _predictiveResult);
+				//handleKeys(KEY_ENTER);
+				// TODO
 			}
 		}
+#endif
 		/*
 		if (predictiveDialog()) {
 			if (_game.inputMode == INPUT_NONE) {
@@ -160,57 +444,73 @@ int AgiEngine::handleController(int key) {
 	}
 
 	if (_game.playerControl) {
-		int d = 0;
+		int16 newDirection = 0;
 
-		if (!KEY_ASCII(key)) {
-			switch (key) {
-			case KEY_UP:
-				d = 1;
-				break;
-			case KEY_DOWN:
-				d = 5;
-				break;
-			case KEY_LEFT:
-				d = 7;
-				break;
-			case KEY_RIGHT:
-				d = 3;
-				break;
-			case KEY_UP_RIGHT:
-				d = 2;
-				break;
-			case KEY_DOWN_RIGHT:
-				d = 4;
-				break;
-			case KEY_UP_LEFT:
-				d = 8;
-				break;
-			case KEY_DOWN_LEFT:
-				d = 6;
-				break;
-			}
+		switch (key) {
+		case AGI_KEY_UP:
+			newDirection = 1;
+			break;
+		case AGI_KEY_DOWN:
+			newDirection = 5;
+			break;
+		case AGI_KEY_LEFT:
+			newDirection = 7;
+			break;
+		case AGI_KEY_RIGHT:
+			newDirection = 3;
+			break;
+		case AGI_KEY_UP_RIGHT:
+			newDirection = 2;
+			break;
+		case AGI_KEY_DOWN_RIGHT:
+			newDirection = 4;
+			break;
+		case AGI_KEY_UP_LEFT:
+			newDirection = 8;
+			break;
+		case AGI_KEY_DOWN_LEFT:
+			newDirection = 6;
+			break;
+		default:
+			break;
 		}
 
 		if (!(getFeatures() & GF_AGIMOUSE)) {
 			// Handle mouse button events
-			if (key == BUTTON_LEFT) {
-				if (getGameID() == GID_PQ1 && _game.vars[vCurRoom] == 116) {
-					// WORKAROUND: Special handling for mouse clicks in the newspaper
-					// screen of PQ1. Fixes bug #3018770.
-					d = 3;	// fake a right arrow key (next page)
-				} else {
-					// Click-to-walk mouse interface
-					v->flags |= fAdjEgoXY;
-					v->parm1 = WIN_TO_PIC_X(_mouse.x);
-					v->parm2 = WIN_TO_PIC_Y(_mouse.y);
-					return true;
+			if (!_game.mouseHidden) {
+				if (key == AGI_MOUSE_BUTTON_LEFT) {
+					if (getGameID() == GID_PQ1 && _game.vars[VM_VAR_CURRENT_ROOM] == 116) {
+						// WORKAROUND: Special handling for mouse clicks in the newspaper
+						// screen of PQ1. Fixes bug #3018770.
+						newDirection = 3;	// fake a right arrow key (next page)
+
+					} else {
+						// Click-to-walk mouse interface
+						//v->flags |= fAdjEgoXY;
+						// setting fAdjEgoXY here will at least break "climbing the log" in SQ2
+						// in case you walked to the log by using the mouse, so don't!!!
+						int16 egoDestinationX = _mouse.x;
+						int16 egoDestinationY = _mouse.y;
+						adjustPosToGameScreen(egoDestinationX, egoDestinationY);
+
+						screenObjEgo->motionType = kMotionEgo;
+						if (egoDestinationX < (screenObjEgo->xSize / 2)) {
+							screenObjEgo->move_x = -1;
+						} else {
+							screenObjEgo->move_x = egoDestinationX - (screenObjEgo->xSize / 2);
+						}
+						screenObjEgo->move_y        = egoDestinationY;
+						screenObjEgo->move_stepSize = screenObjEgo->stepSize;
+						return true;
+					}
 				}
 			}
 		}
 
-		if (d || key == KEY_STATIONARY) {
-			v->flags &= ~fAdjEgoXY;
-			v->direction = v->direction == d ? 0 : d;
+		if (newDirection || key == AGI_KEY_STATIONARY) {
+			screenObjEgo->flags &= ~fAdjEgoXY;
+			screenObjEgo->direction = screenObjEgo->direction == newDirection ? 0 : newDirection;
+			screenObjEgo->motionType = kMotionNormal;
 			return true;
 		}
 	}
@@ -218,205 +518,22 @@ int AgiEngine::handleController(int key) {
 	return false;
 }
 
-void AgiEngine::handleGetstring(int key) {
-	static int pos = 0;	// Cursor position
-	static char buf[40];
-
-	if (KEY_ASCII(key) == 0)
-		return;
-
-	debugC(3, kDebugLevelInput, "handling key: %02x", key);
-
-	switch (key) {
-	case BUTTON_LEFT:
-		if ((int)_mouse.y >= _stringdata.y * CHAR_LINES &&
-				(int)_mouse.y <= (_stringdata.y + 1) * CHAR_LINES) {
-			GUI::PredictiveDialog _predictiveDialog;
-			_predictiveDialog.runModal();
-			strcpy(_predictiveResult, _predictiveDialog.getResult());
-			if (strcmp(_predictiveResult, "")) {
-				strcpy(_game.strings[_stringdata.str], _predictiveResult);
-				newInputMode(INPUT_NORMAL);
-				_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
-								_stringdata.y, ' ', _game.colorFg, _game.colorBg);
-				return;
-			}
-			/*
-			if (predictiveDialog()) {
-				strcpy(_game.strings[_stringdata.str], _predictiveResult);
-				newInputMode(INPUT_NORMAL);
-				_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
-								_stringdata.y, ' ', _game.colorFg, _game.colorBg);
-				return;
-			}
-			*/
-		}
-		break;
-	case KEY_ENTER:
-		debugC(3, kDebugLevelInput, "KEY_ENTER");
-		_game.hasPrompt = 0;
-		buf[pos] = 0;
-
-		strcpy(_game.strings[_stringdata.str], buf);
-		debugC(3, kDebugLevelInput, "buffer=[%s]", buf);
-		buf[pos = 0] = 0;
-
-		newInputMode(INPUT_NORMAL);
-		_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
-				_stringdata.y, ' ', _game.colorFg, _game.colorBg);
-		return;
-	case KEY_ESCAPE:
-		debugC(3, kDebugLevelInput, "KEY_ESCAPE");
-		_game.hasPrompt = 0;
-		buf[pos = 0] = 0;
-
-		strcpy(_game.strings[_stringdata.str], buf);
-		newInputMode(INPUT_NORMAL);
-
-		// newInputMode(INPUT_MENU);
-		break;
-	case KEY_BACKSPACE:	// 0x08
-		if (!pos)
-			break;
-
-		_gfx->printCharacter(_stringdata.x + (pos + 1), _stringdata.y,
-				' ', _game.colorFg, _game.colorBg);
-		pos--;
-		buf[pos] = 0;
-		break;
-	default:
-		if (key < 0x20 || key > 0x7f)
-			break;
-
-		if (pos >= _stringdata.len)
-			break;
-
-		buf[pos++] = key;
-		buf[pos] = 0;
-
-		// Echo
-		_gfx->printCharacter(_stringdata.x + pos, _stringdata.y, buf[pos - 1],
-				_game.colorFg, _game.colorBg);
-
-		break;
-	}
-
-	// print cursor
-	_gfx->printCharacter(_stringdata.x + pos + 1, _stringdata.y,
-			(char)_game.cursorChar, _game.colorFg, _game.colorBg);
-}
-
-void AgiEngine::handleKeys(int key) {
-	uint8 *p = NULL;
-	int c = 0;
-	static uint8 formattedEntry[40];
-	int l = _game.lineUserInput;
-	int fg = _game.colorFg, bg = _game.colorBg;
-	int promptLength = strlen(agiSprintf(_game.strings[0]));
-
-	setvar(vWordNotFound, 0);
-
-	debugC(3, kDebugLevelInput, "handling key: %02x", key);
-
-	switch (key) {
-	case KEY_ENTER:
-		debugC(3, kDebugLevelInput, "KEY_ENTER");
-		_game.keypress = 0;
-
-		// Remove all leading spaces
-		for (p = _game.inputBuffer; *p && *p == 0x20; p++)
-			;
-
-		// Copy to internal buffer
-		for (; *p && c < 40-1; p++) {
-			// Squash spaces
-			if (*p == 0x20 && *(p + 1) == 0x20) {
-				p++;
-				continue;
-			}
-			formattedEntry[c++] = tolower(*p);
-		}
-		formattedEntry[c++] = 0;
-
-		// Handle string only if it's not empty
-		if (formattedEntry[0]) {
-			strcpy((char *)_game.echoBuffer, (const char *)_game.inputBuffer);
-			strcpy(_lastSentence, (const char *)formattedEntry);
-			dictionaryWords(_lastSentence);
-		}
-
-		// Clear to start a new line
-		_game.hasPrompt = 0;
-		_game.inputBuffer[_game.cursorPos = 0] = 0;
-		debugC(3, kDebugLevelInput | kDebugLevelText, "clear lines");
-		clearLines(l, l + 1, bg);
-		flushLines(l, l + 1);
-#ifdef __DS__
-		DS::findWordCompletions((char *) _game.inputBuffer);
-#endif
-
-		break;
-	case KEY_ESCAPE:
-		debugC(3, kDebugLevelInput, "KEY_ESCAPE");
-		newInputMode(INPUT_MENU);
-		break;
-	case KEY_BACKSPACE:
-		// Ignore backspace at start of line
-		if (_game.cursorPos == 0)
-			break;
-
-		// erase cursor
-		_gfx->printCharacter(_game.cursorPos + promptLength, l, ' ', fg, bg);
-		_game.inputBuffer[--_game.cursorPos] = 0;
-
-		// Print cursor
-		_gfx->printCharacter(_game.cursorPos + promptLength, l, _game.cursorChar, fg, bg);
-
-#ifdef __DS__
-		DS::findWordCompletions((char *) _game.inputBuffer);
-#endif
-		break;
-	default:
-		// Ignore invalid keystrokes
-		if (key < 0x20 || key > 0x7f)
-			break;
-
-		// Maximum input size reached
-		if (_game.cursorPos >= getvar(vMaxInputChars))
-			break;
-
-		_game.inputBuffer[_game.cursorPos++] = key;
-		_game.inputBuffer[_game.cursorPos] = 0;
-
-#ifdef __DS__
-		DS::findWordCompletions((char *) _game.inputBuffer);
-#endif
-
-		// echo
-		_gfx->printCharacter(_game.cursorPos + promptLength - 1, l, _game.inputBuffer[_game.cursorPos - 1], fg, bg);
-
-		// Print cursor
-		_gfx->printCharacter(_game.cursorPos + promptLength, l, _game.cursorChar, fg, bg);
-		break;
-	}
-}
-
 int AgiEngine::waitKey() {
 	int key = 0;
 
 	clearKeyQueue();
 
 	debugC(3, kDebugLevelInput, "waiting...");
-	while (!(shouldQuit() || _restartGame || getflag(fRestoreJustRan))) {
+	while (!(shouldQuit() || _restartGame || getflag(VM_FLAG_RESTORE_JUST_RAN))) {
 		pollTimer();
 		key = doPollKeyboard();
-		if (key == KEY_ENTER || key == KEY_ESCAPE || key == BUTTON_LEFT)
+		if (key == AGI_KEY_ENTER || key == AGI_KEY_ESCAPE || key == AGI_MOUSE_BUTTON_LEFT)
 			break;
 
 		pollTimer();
 		updateTimer();
 
-		_gfx->doUpdate();
+		g_system->updateScreen();
 	}
 
 	// Have to clear it as original did not set this variable, and we do it in doPollKeyboard()
@@ -437,7 +554,7 @@ int AgiEngine::waitAnyKey() {
 		key = doPollKeyboard();
 		if (key)
 			break;
-		_gfx->doUpdate();
+		g_system->updateScreen();
 	}
 
 	// Have to clear it as original did not set this variable, and we do it in doPollKeyboard()
diff --git a/engines/agi/keyboard.h b/engines/agi/keyboard.h
index 89d6a89..e5cf955 100644
--- a/engines/agi/keyboard.h
+++ b/engines/agi/keyboard.h
@@ -46,49 +46,50 @@ public:
 	}
 };
 
-// QNX4 has a KEY_DOWN defined which we don't need to care about
-#undef KEY_DOWN
-
-// Allegro defines these
-#undef KEY_BACKSPACE
-#undef KEY_ENTER
-#undef KEY_LEFT
-#undef KEY_RIGHT
-#undef KEY_UP
-#undef KEY_PGUP
-#undef KEY_PGDN
-#undef KEY_HOME
-#undef KEY_END
-
-#define KEY_BACKSPACE	0x08
-#define	KEY_ESCAPE	0x1B
-#define KEY_ENTER	0x0D
-#define KEY_UP		0x4800
-#define	KEY_DOWN	0x5000
-#define KEY_LEFT	0x4B00
-#define KEY_STATIONARY	0x4C00
-#define KEY_RIGHT	0x4D00
-
-#define KEY_DOWN_LEFT	0x4F00
-#define KEY_DOWN_RIGHT	0x5100
-#define KEY_UP_LEFT	0x4700
-#define KEY_UP_RIGHT	0x4900
-
-#define KEY_STATUSLN	0xd900	// F11
-#define KEY_PRIORITY	0xda00	// F12
-
-#define KEY_PGUP	0x4900	// Page Up (fixed by Ziv Barber)
-#define KEY_PGDN	0x5100	// Page Down
-#define KEY_HOME	0x4700	// Home
-#define KEY_END		0x4f00	// End *
-
-#define BUTTON_LEFT	0xF101	// Left mouse button
-#define BUTTON_RIGHT	0xF202	// Right mouse button
-#define WHEEL_UP	0xF203	// Mouse wheel up
-#define WHEEL_DOWN	0xF204	// Mouse wheel down
-
-#define KEY_SCAN(k)	(k >> 8)
-#define KEY_ASCII(k)	(k & 0xff)
+#define AGI_KEY_BACKSPACE	0x08
+#define	AGI_KEY_ESCAPE	0x1B
+#define AGI_KEY_ENTER	0x0D
+#define AGI_KEY_UP		0x4800
+#define	AGI_KEY_DOWN	0x5000
+#define AGI_KEY_LEFT	0x4B00
+#define AGI_KEY_STATIONARY	0x4C00
+#define AGI_KEY_RIGHT	0x4D00
+
+#define AGI_KEY_DOWN_LEFT	0x4F00
+#define AGI_KEY_DOWN_RIGHT	0x5100
+#define AGI_KEY_UP_LEFT	0x4700
+#define AGI_KEY_UP_RIGHT	0x4900
+
+#define AGI_KEY_F1  0x3B00
+#define AGI_KEY_F2  0x3C00
+#define AGI_KEY_F3  0x3D00
+#define AGI_KEY_F4  0x3E00
+#define AGI_KEY_F5  0x3F00
+#define AGI_KEY_F6  0x4000
+#define AGI_KEY_F7  0x4000
+#define AGI_KEY_F8  0x4100
+#define AGI_KEY_F9  0x4200
+#define AGI_KEY_F10 0x4300
+#define AGI_KEY_F11 0xd900	// F11
+#define AGI_KEY_F12 0xda00	// F12
+
+#define AGI_KEY_PAGE_UP		0x4900	// Page Up (fixed by Ziv Barber)
+#define AGI_KEY_PAGE_DOWN	0x5100	// Page Down
+#define AGI_KEY_HOME		0x4700	// Home
+#define AGI_KEY_END			0x4f00	// End *
+
+#define AGI_MOUSE_BUTTON_LEFT	0xF101	// Left mouse button
+#define AGI_MOUSE_BUTTON_RIGHT	0xF202	// Right mouse button
+#define AGI_MOUSE_WHEEL_UP	0xF203	// Mouse wheel up
+#define AGI_MOUSE_WHEEL_DOWN	0xF204	// Mouse wheel down
+
+// special menu triggers
+// Attention: at least Mixed Up Mother Goose on Apple IIgs actually hooks ESC for menu only
+// Which is why we have to check, if the corresponding trigger is hooked before changing it
+// And otherwise simply use the regular ESC.
+#define AGI_MENU_TRIGGER_PC       0x001B // will trigger menu for PC
+#define AGI_MENU_TRIGGER_APPLE2GS 0x0301 // will trigger menu for AppleIIgs + Amiga
+#define AGI_MENU_TRIGGER_ATARIST  0x0101 // will trigger menu for Atari ST
 
 extern const uint8 scancodeTable[];
 
diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index 404fb6e..fd418f3 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -21,6 +21,8 @@
  */
 
 #include "agi/agi.h"
+#include "agi/words.h"
+
 #include "common/md5.h"
 
 #define IMAGE_SIZE 368640 // = 40 * 2 * 9 * 512 = tracks * sides * sectors * sector size
@@ -69,7 +71,7 @@ int AgiLoader_v1::loadDir_DDP(AgiDir *agid, int offset, int max) {
 		return errBadFileOpen;
 
 	// Cleanup
-	for (int i = 0; i < MAX_DIRS; i++) {
+	for (int i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
 		agid[i].volume = 0xFF;
 		agid[i].offset = _EMPTY;
 	}
@@ -103,7 +105,7 @@ int AgiLoader_v1::loadDir_BC(AgiDir *agid, int offset, int max) {
 		return errBadFileOpen;
 
 	// Cleanup
-	for (int i = 0; i < MAX_DIRS; i++) {
+	for (int i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
 		agid[i].volume = 0xFF;
 		agid[i].offset = _EMPTY;
 	}
@@ -197,84 +199,84 @@ uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) {
 	return data;
 }
 
-int AgiLoader_v1::loadResource(int t, int n) {
+int AgiLoader_v1::loadResource(int16 resourceType, int16 resourceNr) {
 	int ec = errOK;
 	uint8 *data = NULL;
 
-	debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n);
-	if (n >= MAX_DIRS)
+	debugC(3, kDebugLevelResources, "(t = %d, n = %d)", resourceType, resourceNr);
+	if (resourceNr >= MAX_DIRECTORY_ENTRIES)
 		return errBadResource;
 
-	switch (t) {
-	case rLOGIC:
-		if (~_vm->_game.dirLogic[n].flags & RES_LOADED) {
-			debugC(3, kDebugLevelResources, "loading logic resource %d", n);
-			unloadResource(rLOGIC, n);
+	switch (resourceType) {
+	case RESOURCETYPE_LOGIC:
+		if (~_vm->_game.dirLogic[resourceNr].flags & RES_LOADED) {
+			debugC(3, kDebugLevelResources, "loading logic resource %d", resourceNr);
+			unloadResource(RESOURCETYPE_LOGIC, resourceNr);
 
 			// load raw resource into data
-			data = loadVolRes(&_vm->_game.dirLogic[n]);
+			data = loadVolRes(&_vm->_game.dirLogic[resourceNr]);
 
-			_vm->_game.logics[n].data = data;
-			ec = data ? _vm->decodeLogic(n) : errBadResource;
+			_vm->_game.logics[resourceNr].data = data;
+			ec = data ? _vm->decodeLogic(resourceNr) : errBadResource;
 
-			_vm->_game.logics[n].sIP = 2;
+			_vm->_game.logics[resourceNr].sIP = 2;
 		}
 
 		// if logic was cached, we get here
 		// reset code pointers incase it was cached
 
-		_vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP;
+		_vm->_game.logics[resourceNr].cIP = _vm->_game.logics[resourceNr].sIP;
 		break;
-	case rPICTURE:
+	case RESOURCETYPE_PICTURE:
 		// if picture is currently NOT loaded *OR* cacheing is off,
 		// unload the resource (caching == off) and reload it
 
-		debugC(3, kDebugLevelResources, "loading picture resource %d", n);
-		if (_vm->_game.dirPic[n].flags & RES_LOADED)
+		debugC(3, kDebugLevelResources, "loading picture resource %d", resourceNr);
+		if (_vm->_game.dirPic[resourceNr].flags & RES_LOADED)
 			break;
 
 		// if loaded but not cached, unload it
 		// if cached but not loaded, etc
-		unloadResource(rPICTURE, n);
-		data = loadVolRes(&_vm->_game.dirPic[n]);
+		unloadResource(RESOURCETYPE_PICTURE, resourceNr);
+		data = loadVolRes(&_vm->_game.dirPic[resourceNr]);
 
 		if (data != NULL) {
-			_vm->_game.pictures[n].rdata = data;
-			_vm->_game.dirPic[n].flags |= RES_LOADED;
+			_vm->_game.pictures[resourceNr].rdata = data;
+			_vm->_game.dirPic[resourceNr].flags |= RES_LOADED;
 		} else {
 			ec = errBadResource;
 		}
 		break;
-	case rSOUND:
-		debugC(3, kDebugLevelResources, "loading sound resource %d", n);
-		if (_vm->_game.dirSound[n].flags & RES_LOADED)
+	case RESOURCETYPE_SOUND:
+		debugC(3, kDebugLevelResources, "loading sound resource %d", resourceNr);
+		if (_vm->_game.dirSound[resourceNr].flags & RES_LOADED)
 			break;
 
-		data = loadVolRes(&_vm->_game.dirSound[n]);
+		data = loadVolRes(&_vm->_game.dirSound[resourceNr]);
 
 		if (data != NULL) {
 			// Freeing of the raw resource from memory is delegated to the createFromRawResource-function
-			_vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, _vm->_soundemu);
-			_vm->_game.dirSound[n].flags |= RES_LOADED;
+			_vm->_game.sounds[resourceNr] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[resourceNr].len, resourceNr, _vm->_soundemu);
+			_vm->_game.dirSound[resourceNr].flags |= RES_LOADED;
 		} else {
 			ec = errBadResource;
 		}
 		break;
-	case rVIEW:
+	case RESOURCETYPE_VIEW:
 		// Load a VIEW resource into memory...
 		// Since VIEWS alter the view table ALL the time
 		// can we cache the view? or must we reload it all
 		// the time?
-		if (_vm->_game.dirView[n].flags & RES_LOADED)
+		if (_vm->_game.dirView[resourceNr].flags & RES_LOADED)
 			break;
 
-		debugC(3, kDebugLevelResources, "loading view resource %d", n);
-		unloadResource(rVIEW, n);
-		data = loadVolRes(&_vm->_game.dirView[n]);
+		debugC(3, kDebugLevelResources, "loading view resource %d", resourceNr);
+		unloadResource(RESOURCETYPE_VIEW, resourceNr);
+		data = loadVolRes(&_vm->_game.dirView[resourceNr]);
 		if (data) {
-			_vm->_game.views[n].rdata = data;
-			_vm->_game.dirView[n].flags |= RES_LOADED;
-			ec = _vm->decodeView(n);
+			_vm->_game.dirView[resourceNr].flags |= RES_LOADED;
+			ec = _vm->decodeView(data, _vm->_game.dirView[resourceNr].len, resourceNr);
+			free(data);
 		} else {
 			ec = errBadResource;
 		}
@@ -287,19 +289,19 @@ int AgiLoader_v1::loadResource(int t, int n) {
 	return ec;
 }
 
-int AgiLoader_v1::unloadResource(int t, int n) {
-	switch (t) {
-	case rLOGIC:
-		_vm->unloadLogic(n);
+int AgiLoader_v1::unloadResource(int16 resourceType, int16 resourceNr) {
+	switch (resourceType) {
+	case RESOURCETYPE_LOGIC:
+		_vm->unloadLogic(resourceNr);
 		break;
-	case rPICTURE:
-		_vm->_picture->unloadPicture(n);
+	case RESOURCETYPE_PICTURE:
+		_vm->_picture->unloadPicture(resourceNr);
 		break;
-	case rVIEW:
-		_vm->unloadView(n);
+	case RESOURCETYPE_VIEW:
+		_vm->unloadView(resourceNr);
 		break;
-	case rSOUND:
-		_vm->_sound->unloadSound(n);
+	case RESOURCETYPE_SOUND:
+		_vm->_sound->unloadSound(resourceNr);
 		break;
 	}
 
@@ -321,7 +323,7 @@ int AgiLoader_v1::loadWords(const char *fname) {
 		Common::File f;
 		f.open(_filenameDisk0);
 		f.seek(BC_WORDS, SEEK_SET);
-		return _vm->loadWords_v1(f);
+		return _vm->_words->loadDictionary_v1(f);
 	}
 	return errOK;
 }
diff --git a/engines/agi/loader_v2.cpp b/engines/agi/loader_v2.cpp
index 693c53c..76f6900 100644
--- a/engines/agi/loader_v2.cpp
+++ b/engines/agi/loader_v2.cpp
@@ -23,6 +23,7 @@
 #include "common/textconsole.h"
 
 #include "agi/agi.h"
+#include "agi/words.h"
 
 namespace Agi {
 
@@ -60,7 +61,7 @@ int AgiLoader_v2::loadDir(AgiDir *agid, const char *fname) {
 	fp.read(mem, flen);
 
 	// set all directory resources to gone
-	for (i = 0; i < MAX_DIRS; i++) {
+	for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
 		agid[i].volume = 0xff;
 		agid[i].offset = _EMPTY;
 	}
@@ -107,21 +108,21 @@ int AgiLoader_v2::deinit() {
 	return ec;
 }
 
-int AgiLoader_v2::unloadResource(int t, int n) {
+int AgiLoader_v2::unloadResource(int16 resourceType, int16 resourceNr) {
 	debugC(3, kDebugLevelResources, "unload resource");
 
-	switch (t) {
-	case rLOGIC:
-		_vm->unloadLogic(n);
+	switch (resourceType) {
+	case RESOURCETYPE_LOGIC:
+		_vm->unloadLogic(resourceNr);
 		break;
-	case rPICTURE:
-		_vm->_picture->unloadPicture(n);
+	case RESOURCETYPE_PICTURE:
+		_vm->_picture->unloadPicture(resourceNr);
 		break;
-	case rVIEW:
-		_vm->unloadView(n);
+	case RESOURCETYPE_VIEW:
+		_vm->unloadView(resourceNr);
 		break;
-	case rSOUND:
-		_vm->_sound->unloadSound(n);
+	case RESOURCETYPE_SOUND:
+		_vm->_sound->unloadSound(resourceNr);
 		break;
 	}
 
@@ -129,7 +130,7 @@ int AgiLoader_v2::unloadResource(int t, int n) {
 }
 
 /**
- * This function does noting but load a raw resource into memory,
+ * This function loads a raw resource into memory,
  * if further decoding is required, it must be done by another
  * routine. NULL is returned if unsucsessfull.
  */
@@ -173,84 +174,84 @@ uint8 *AgiLoader_v2::loadVolRes(struct AgiDir *agid) {
  * Loads a resource into memory, a raw resource is loaded in
  * with above routine, then further decoded here.
  */
-int AgiLoader_v2::loadResource(int t, int n) {
+int AgiLoader_v2::loadResource(int16 resourceType, int16 resourceNr) {
 	int ec = errOK;
 	uint8 *data = NULL;
 
-	debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n);
-	if (n >= MAX_DIRS)
+	debugC(3, kDebugLevelResources, "(t = %d, n = %d)", resourceType, resourceNr);
+	if (resourceNr >= MAX_DIRECTORY_ENTRIES)
 		return errBadResource;
 
-	switch (t) {
-	case rLOGIC:
-		if (~_vm->_game.dirLogic[n].flags & RES_LOADED) {
-			debugC(3, kDebugLevelResources, "loading logic resource %d", n);
-			unloadResource(rLOGIC, n);
+	switch (resourceType) {
+	case RESOURCETYPE_LOGIC:
+		if (~_vm->_game.dirLogic[resourceNr].flags & RES_LOADED) {
+			debugC(3, kDebugLevelResources, "loading logic resource %d", resourceNr);
+			unloadResource(RESOURCETYPE_LOGIC, resourceNr);
 
 			// load raw resource into data
-			data = loadVolRes(&_vm->_game.dirLogic[n]);
+			data = loadVolRes(&_vm->_game.dirLogic[resourceNr]);
 
-			_vm->_game.logics[n].data = data;
-			ec = data ? _vm->decodeLogic(n) : errBadResource;
+			_vm->_game.logics[resourceNr].data = data;
+			ec = data ? _vm->decodeLogic(resourceNr) : errBadResource;
 
-			_vm->_game.logics[n].sIP = 2;
+			_vm->_game.logics[resourceNr].sIP = 2;
 		}
 
 		// if logic was cached, we get here
 		// reset code pointers incase it was cached
 
-		_vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP;
+		_vm->_game.logics[resourceNr].cIP = _vm->_game.logics[resourceNr].sIP;
 		break;
-	case rPICTURE:
+	case RESOURCETYPE_PICTURE:
 		// if picture is currently NOT loaded *OR* cacheing is off,
 		// unload the resource (caching == off) and reload it
 
-		debugC(3, kDebugLevelResources, "loading picture resource %d", n);
-		if (_vm->_game.dirPic[n].flags & RES_LOADED)
+		debugC(3, kDebugLevelResources, "loading picture resource %d", resourceNr);
+		if (_vm->_game.dirPic[resourceNr].flags & RES_LOADED)
 			break;
 
 		// if loaded but not cached, unload it
 		// if cached but not loaded, etc
-		unloadResource(rPICTURE, n);
-		data = loadVolRes(&_vm->_game.dirPic[n]);
+		unloadResource(RESOURCETYPE_PICTURE, resourceNr);
+		data = loadVolRes(&_vm->_game.dirPic[resourceNr]);
 
 		if (data != NULL) {
-			_vm->_game.pictures[n].rdata = data;
-			_vm->_game.dirPic[n].flags |= RES_LOADED;
+			_vm->_game.pictures[resourceNr].rdata = data;
+			_vm->_game.dirPic[resourceNr].flags |= RES_LOADED;
 		} else {
 			ec = errBadResource;
 		}
 		break;
-	case rSOUND:
-		debugC(3, kDebugLevelResources, "loading sound resource %d", n);
-		if (_vm->_game.dirSound[n].flags & RES_LOADED)
+	case RESOURCETYPE_SOUND:
+		debugC(3, kDebugLevelResources, "loading sound resource %d", resourceNr);
+		if (_vm->_game.dirSound[resourceNr].flags & RES_LOADED)
 			break;
 
-		data = loadVolRes(&_vm->_game.dirSound[n]);
+		data = loadVolRes(&_vm->_game.dirSound[resourceNr]);
 
 		if (data != NULL) {
 			// Freeing of the raw resource from memory is delegated to the createFromRawResource-function
-			_vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, _vm->_soundemu);
-			_vm->_game.dirSound[n].flags |= RES_LOADED;
+			_vm->_game.sounds[resourceNr] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[resourceNr].len, resourceNr, _vm->_soundemu);
+			_vm->_game.dirSound[resourceNr].flags |= RES_LOADED;
 		} else {
 			ec = errBadResource;
 		}
 		break;
-	case rVIEW:
+	case RESOURCETYPE_VIEW:
 		// Load a VIEW resource into memory...
 		// Since VIEWS alter the view table ALL the time
 		// can we cache the view? or must we reload it all
 		// the time?
-		if (_vm->_game.dirView[n].flags & RES_LOADED)
+		if (_vm->_game.dirView[resourceNr].flags & RES_LOADED)
 			break;
 
-		debugC(3, kDebugLevelResources, "loading view resource %d", n);
-		unloadResource(rVIEW, n);
-		data = loadVolRes(&_vm->_game.dirView[n]);
+		debugC(3, kDebugLevelResources, "loading view resource %d", resourceNr);
+		unloadResource(RESOURCETYPE_VIEW, resourceNr);
+		data = loadVolRes(&_vm->_game.dirView[resourceNr]);
 		if (data) {
-			_vm->_game.views[n].rdata = data;
-			_vm->_game.dirView[n].flags |= RES_LOADED;
-			ec = _vm->decodeView(n);
+			_vm->_game.dirView[resourceNr].flags |= RES_LOADED;
+			ec = _vm->decodeView(data, _vm->_game.dirView[resourceNr].len, resourceNr);
+			free(data);
 		} else {
 			ec = errBadResource;
 		}
@@ -268,7 +269,7 @@ int AgiLoader_v2::loadObjects(const char *fname) {
 }
 
 int AgiLoader_v2::loadWords(const char *fname) {
-	return _vm->loadWords(fname);
+	return _vm->_words->loadDictionary(fname);
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/loader_v3.cpp b/engines/agi/loader_v3.cpp
index 39759b4..d7abbac 100644
--- a/engines/agi/loader_v3.cpp
+++ b/engines/agi/loader_v3.cpp
@@ -22,6 +22,7 @@
 
 #include "agi/agi.h"
 #include "agi/lzw.h"
+#include "agi/words.h"
 
 #include "common/config-manager.h"
 #include "common/fs.h"
@@ -76,7 +77,7 @@ int AgiLoader_v3::loadDir(struct AgiDir *agid, Common::File *fp,
 		fp->read(mem, len);
 
 		// set all directory resources to gone
-		for (i = 0; i < MAX_DIRS; i++) {
+		for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
 			agid[i].volume = 0xff;
 			agid[i].offset = _EMPTY;
 		}
@@ -171,19 +172,19 @@ int AgiLoader_v3::deinit() {
 	return ec;
 }
 
-int AgiLoader_v3::unloadResource(int t, int n) {
-	switch (t) {
-	case rLOGIC:
-		_vm->unloadLogic(n);
+int AgiLoader_v3::unloadResource(int16 resourceType, int16 resourceNr) {
+	switch (resourceType) {
+	case RESOURCETYPE_LOGIC:
+		_vm->unloadLogic(resourceNr);
 		break;
-	case rPICTURE:
-		_vm->_picture->unloadPicture(n);
+	case RESOURCETYPE_PICTURE:
+		_vm->_picture->unloadPicture(resourceNr);
 		break;
-	case rVIEW:
-		_vm->unloadView(n);
+	case RESOURCETYPE_VIEW:
+		_vm->unloadView(resourceNr);
 		break;
-	case rSOUND:
-		_vm->_sound->unloadSound(n);
+	case RESOURCETYPE_SOUND:
+		_vm->_sound->unloadSound(resourceNr);
 		break;
 	}
 
@@ -191,7 +192,7 @@ int AgiLoader_v3::unloadResource(int t, int n) {
 }
 
 /**
- * This function does noting but load a raw resource into memory.
+ * This function loads a raw resource into memory.
  * If further decoding is required, it must be done by another
  * routine.
  *
@@ -225,7 +226,11 @@ uint8 *AgiLoader_v3::loadVolRes(AgiDir *agid) {
 		fp.read(compBuffer, agid->clen);
 
 		if (x[2] & 0x80) { // compressed pic
-			data = _vm->_picture->convertV3Pic(compBuffer, agid->clen);
+			// effectively uncompressed, but having only 4-bit parameters for F0 / F2 commands
+			// Manhunter 2 uses such pictures
+			data = compBuffer;
+			agid->flags |= RES_PICTURE_V3_NIBBLE_PARM;
+			//data = _vm->_picture->convertV3Pic(compBuffer, agid->clen);
 			// compBuffer has been freed inside convertV3Pic()
 		} else if (agid->len == agid->clen) {
 			// do not decompress
@@ -252,31 +257,31 @@ uint8 *AgiLoader_v3::loadVolRes(AgiDir *agid) {
  * Loads a resource into memory, a raw resource is loaded in
  * with above routine, then further decoded here.
  */
-int AgiLoader_v3::loadResource(int t, int n) {
+int AgiLoader_v3::loadResource(int16 resourceType, int16 resourceNr) {
 	int ec = errOK;
 	uint8 *data = NULL;
 
-	if (n >= MAX_DIRS)
+	if (resourceNr >= MAX_DIRECTORY_ENTRIES)
 		return errBadResource;
 
-	switch (t) {
-	case rLOGIC:
+	switch (resourceType) {
+	case RESOURCETYPE_LOGIC:
 		// load resource into memory, decrypt messages at the end
 		// and build the message list (if logic is in memory)
-		if (~_vm->_game.dirLogic[n].flags & RES_LOADED) {
+		if (~_vm->_game.dirLogic[resourceNr].flags & RES_LOADED) {
 			// if logic is already in memory, unload it
-			unloadResource(rLOGIC, n);
+			unloadResource(RESOURCETYPE_LOGIC, resourceNr);
 
 			// load raw resource into data
-			data = loadVolRes(&_vm->_game.dirLogic[n]);
-			_vm->_game.logics[n].data = data;
+			data = loadVolRes(&_vm->_game.dirLogic[resourceNr]);
+			_vm->_game.logics[resourceNr].data = data;
 
 			// uncompressed logic files need to be decrypted
 			if (data != NULL) {
 				// resloaded flag gets set by decode logic
 				// needed to build string table
-				ec = _vm->decodeLogic(n);
-				_vm->_game.logics[n].sIP = 2;
+				ec = _vm->decodeLogic(resourceNr);
+				_vm->_game.logics[resourceNr].sIP = 2;
 			} else {
 				ec = errBadResource;
 			}
@@ -284,56 +289,56 @@ int AgiLoader_v3::loadResource(int t, int n) {
 			// logics[n].sIP=2; // saved IP = 2
 			// logics[n].cIP=2; // current IP = 2
 
-			_vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP;
+			_vm->_game.logics[resourceNr].cIP = _vm->_game.logics[resourceNr].sIP;
 		}
 
 		// if logic was cached, we get here
 		// reset code pointers incase it was cached
 
-		_vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP;
+		_vm->_game.logics[resourceNr].cIP = _vm->_game.logics[resourceNr].sIP;
 		break;
-	case rPICTURE:
+	case RESOURCETYPE_PICTURE:
 		// if picture is currently NOT loaded *OR* cacheing is off,
 		// unload the resource (caching==off) and reload it
-		if (~_vm->_game.dirPic[n].flags & RES_LOADED) {
-			unloadResource(rPICTURE, n);
-			data = loadVolRes(&_vm->_game.dirPic[n]);
+		if (~_vm->_game.dirPic[resourceNr].flags & RES_LOADED) {
+			unloadResource(RESOURCETYPE_PICTURE, resourceNr);
+			data = loadVolRes(&_vm->_game.dirPic[resourceNr]);
 			if (data != NULL) {
-				_vm->_game.pictures[n].rdata = data;
-				_vm->_game.dirPic[n].flags |= RES_LOADED;
+				_vm->_game.pictures[resourceNr].rdata = data;
+				_vm->_game.dirPic[resourceNr].flags |= RES_LOADED;
 			} else {
 				ec = errBadResource;
 			}
 		}
 		break;
-	case rSOUND:
-		if (_vm->_game.dirSound[n].flags & RES_LOADED)
+	case RESOURCETYPE_SOUND:
+		if (_vm->_game.dirSound[resourceNr].flags & RES_LOADED)
 			break;
 
-		data = loadVolRes(&_vm->_game.dirSound[n]);
+		data = loadVolRes(&_vm->_game.dirSound[resourceNr]);
 		if (data != NULL) {
 			// Freeing of the raw resource from memory is delegated to the createFromRawResource-function
-			_vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, _vm->_soundemu);
-			_vm->_game.dirSound[n].flags |= RES_LOADED;
+			_vm->_game.sounds[resourceNr] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[resourceNr].len, resourceNr, _vm->_soundemu);
+			_vm->_game.dirSound[resourceNr].flags |= RES_LOADED;
 		} else {
 			ec = errBadResource;
 		}
 		break;
-	case rVIEW:
+	case RESOURCETYPE_VIEW:
 		// Load a VIEW resource into memory...
 		// Since VIEWS alter the view table ALL the time can we
 		// cache the view? or must we reload it all the time?
 		//
 		// load a raw view from a VOL file into data
-		if (_vm->_game.dirView[n].flags & RES_LOADED)
+		if (_vm->_game.dirView[resourceNr].flags & RES_LOADED)
 			break;
 
-		unloadResource(rVIEW, n);
-		data = loadVolRes(&_vm->_game.dirView[n]);
+		unloadResource(RESOURCETYPE_VIEW, resourceNr);
+		data = loadVolRes(&_vm->_game.dirView[resourceNr]);
 		if (data != NULL) {
-			_vm->_game.views[n].rdata = data;
-			_vm->_game.dirView[n].flags |= RES_LOADED;
-			ec = _vm->decodeView(n);
+			_vm->_game.dirView[resourceNr].flags |= RES_LOADED;
+			ec = _vm->decodeView(data, _vm->_game.dirView[resourceNr].len, resourceNr);
+			free(data);
 		} else {
 			ec = errBadResource;
 		}
@@ -351,7 +356,7 @@ int AgiLoader_v3::loadObjects(const char *fname) {
 }
 
 int AgiLoader_v3::loadWords(const char *fname) {
-	return _vm->loadWords(fname);
+	return _vm->_words->loadDictionary(fname);
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/logic.cpp b/engines/agi/logic.cpp
index 7429b11..1aeb7cc 100644
--- a/engines/agi/logic.cpp
+++ b/engines/agi/logic.cpp
@@ -30,15 +30,16 @@ namespace Agi {
  * into a message list.
  * @param n  The number of the logic resource to decode.
  */
-int AgiEngine::decodeLogic(int n) {
+int AgiEngine::decodeLogic(int16 logicNr) {
 	int ec = errOK;
 	int mstart, mend, mc;
 	uint8 *m0;
+	AgiLogic *curLogic = &_game.logics[logicNr];
 
 	// decrypt messages at end of logic + build message list
 
 	// report ("decoding logic #%d\n", n);
-	m0 = _game.logics[n].data;
+	m0 = curLogic->data;
 
 	mstart = READ_LE_UINT16(m0) + 2;
 	mc = *(m0 + mstart);
@@ -48,38 +49,38 @@ int AgiEngine::decodeLogic(int n) {
 
 	// if the logic was not compressed, decrypt the text messages
 	// only if there are more than 0 messages
-	if ((~_game.dirLogic[n].flags & RES_COMPRESSED) && mc > 0)
+	if ((~_game.dirLogic[logicNr].flags & RES_COMPRESSED) && mc > 0)
 		decrypt(m0 + mstart, mend - mstart);	// decrypt messages
 
 	// build message list
-	m0 = _game.logics[n].data;
+	m0 = curLogic->data;
 	mstart = READ_LE_UINT16(m0) + 2;	// +2 covers pointer
-	_game.logics[n].numTexts = *(m0 + mstart);
+	_game.logics[logicNr].numTexts = *(m0 + mstart);
 
 	// resetp logic pointers
-	_game.logics[n].sIP = 2;
-	_game.logics[n].cIP = 2;
-	_game.logics[n].size = READ_LE_UINT16(m0) + 2;	// logic end pointer
+	curLogic->sIP = 2;
+	curLogic->cIP = 2;
+	curLogic->size = READ_LE_UINT16(m0) + 2;	// logic end pointer
 
 	// allocate list of pointers to point into our data
 
-	_game.logics[n].texts = (const char **)calloc(1 + _game.logics[n].numTexts, sizeof(char *));
+	curLogic->texts = (const char **)calloc(1 + curLogic->numTexts, sizeof(char *));
 
 	// cover header info
 	m0 += mstart + 3;
 
-	if (_game.logics[n].texts != NULL) {
+	if (curLogic->texts != NULL) {
 		// move list of strings into list to make real pointers
-		for (mc = 0; mc < _game.logics[n].numTexts; mc++) {
+		for (mc = 0; mc < curLogic->numTexts; mc++) {
 			mend = READ_LE_UINT16(m0 + mc * 2);
-			_game.logics[n].texts[mc] = mend ? (const char *)m0 + mend - 2 : (const char *)"";
+			_game.logics[logicNr].texts[mc] = mend ? (const char *)m0 + mend - 2 : (const char *)"";
 		}
 		// set loaded flag now its all completly loaded
-		_game.dirLogic[n].flags |= RES_LOADED;
+		_game.dirLogic[logicNr].flags |= RES_LOADED;
 	} else {
 		// unload data
 		// Note that not every logic has text
-		free(_game.logics[n].data);
+		free(curLogic->data);
 		ec = errNotEnoughMemory;
 	}
 
@@ -92,18 +93,17 @@ int AgiEngine::decodeLogic(int n) {
  * memory chunks allocated for this resource.
  * @param n  The number of the logic resource to unload
  */
-void AgiEngine::unloadLogic(int n) {
-	if (_game.dirLogic[n].flags & RES_LOADED) {
-		free(_game.logics[n].data);
-		if (_game.logics[n].numTexts)
-			free(_game.logics[n].texts);
-		_game.logics[n].numTexts = 0;
-		_game.dirLogic[n].flags &= ~RES_LOADED;
+void AgiEngine::unloadLogic(int16 logicNr) {
+	if (_game.dirLogic[logicNr].flags & RES_LOADED) {
+		free(_game.logics[logicNr].data);
+		free(_game.logics[logicNr].texts);
+		_game.logics[logicNr].numTexts = 0;
+		_game.dirLogic[logicNr].flags &= ~RES_LOADED;
 	}
 
 	// if cached, we end up here
-	_game.logics[n].sIP = 2;
-	_game.logics[n].cIP = 2;
+	_game.logics[logicNr].sIP = 2;
+	_game.logics[logicNr].cIP = 2;
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp
index 008c208..411cd00 100644
--- a/engines/agi/menu.cpp
+++ b/engines/agi/menu.cpp
@@ -22,534 +22,456 @@
 
 #include "agi/agi.h"
 #include "agi/graphics.h"
+#include "agi/text.h"
 #include "agi/keyboard.h"
 #include "agi/menu.h"
 
 namespace Agi {
 
-// TODO: add constructor/destructor for agi_menu, agi_menu_option
-
-struct AgiMenuOption {
-	int enabled;			/**< option is enabled or disabled */
-	int event;			/**< menu event */
-	int index;			/**< number of option in this menu */
-	char *text;			/**< text of menu option */
-};
-
-struct AgiMenu {
-	MenuOptionList down;		/**< list head for menu options */
-	int index;			/**< number of menu in menubar */
-	int width;			/**< width of menu in characters */
-	int height;			/**< height of menu in characters */
-	int col;			/**< column of menubar entry */
-	int wincol;			/**< column of menu window */
-	char *text;			/**< menu name */
-};
-
-AgiMenu *Menu::getMenu(int i) {
-	MenuList::iterator iter;
-	for (iter = _menubar.begin(); iter != _menubar.end(); ++iter) {
-		AgiMenu *m = *iter;
-		if (m->index == i)
-			return m;
-	}
-	return NULL;
-}
-
-AgiMenuOption *Menu::getMenuOption(int i, int j) {
-	AgiMenu *m = getMenu(i);
-	MenuOptionList::iterator iter;
-
-	for (iter = m->down.begin(); iter != m->down.end(); ++iter) {
-		AgiMenuOption* d = *iter;
-		if (d->index == j)
-			return d;
-	}
-
-	return NULL;
-}
+GfxMenu::GfxMenu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture, TextMgr *text) {
+	_vm = vm;
+	_gfx = gfx;
+	_picture = picture;
+	_text = text;
 
-void Menu::drawMenuBar() {
-	_vm->clearLines(0, 0, MENU_BG);
-	_vm->flushLines(0, 0);
+	_allowed = true;
+	_submitted = false;
+	_delayedExecute = false;
 
-	MenuList::iterator iter;
-	for (iter = _menubar.begin(); iter != _menubar.end(); ++iter) {
-		AgiMenu *m = *iter;
-
-		_vm->printText(m->text, 0, m->col, 0, 40, MENU_FG, MENU_BG);
-	}
+	_setupMenuColumn = 1;
+	_setupMenuItemColumn = 1;
 
+	_selectedMenuNr = 0;
+	_selectedMenuHeight = 0;
+	_selectedMenuWidth = 0;
+	_selectedMenuRow = 0;
+	_selectedMenuColumn = 0;
 }
 
-void Menu::drawMenuHilite(int curMenu) {
-	AgiMenu *m = getMenu(curMenu);
-
-	debugC(6, kDebugLevelMenu, "[%s]", m->text);
+GfxMenu::~GfxMenu() {
+	for (GuiMenuArray::iterator itemIter = _array.begin(); itemIter != _array.end(); ++itemIter)
+		delete *itemIter;
+	_array.clear();
 
-	_vm->printText(m->text, 0, m->col, 0, 40, MENU_BG, MENU_FG);
-	_vm->flushLines(0, 0);
+	for (GuiMenuItemArray::iterator menuIter = _itemArray.begin(); menuIter != _itemArray.end(); ++menuIter)
+		delete *menuIter;
+	_itemArray.clear();
 }
 
-// draw box and pulldowns.
-void Menu::drawMenuOption(int hMenu) {
-	// find which vertical menu it is
-	AgiMenu *m = getMenu(hMenu);
-
-	_gfx->drawBox(m->wincol * CHAR_COLS, 1 * CHAR_LINES, (m->wincol + m->width + 2) * CHAR_COLS,
-			(1 + m->height + 2) * CHAR_LINES, MENU_BG, MENU_LINE, 0);
+void GfxMenu::addMenu(const char *menuText) {
+	// already submitted? in that case no further changes possible
+	if (_submitted)
+		return;
 
-	MenuOptionList::iterator iter;
+	GuiMenuEntry *menuEntry = new GuiMenuEntry();
 
-	for (iter = m->down.begin(); iter != m->down.end(); ++iter) {
-		AgiMenuOption* d = *iter;
+	menuEntry->text = menuText;
+	menuEntry->textLen = menuEntry->text.size();
+	menuEntry->row = 0;
+	menuEntry->column = _setupMenuColumn;
+	menuEntry->itemCount = 0;
+	menuEntry->firstItemNr = _itemArray.size();
+	menuEntry->selectedItemNr = menuEntry->firstItemNr;
+	menuEntry->maxItemTextLen = 0;
+	_array.push_back(menuEntry);
 
-		_vm->printText(d->text, 0, m->wincol + 1, d->index + 2, m->width + 2,
-				MENU_FG, MENU_BG, !d->enabled);
-	}
+	_setupMenuColumn += menuEntry->textLen + 1;
 }
 
-void Menu::drawMenuOptionHilite(int hMenu, int vMenu) {
-	AgiMenu *m = getMenu(hMenu);
-	AgiMenuOption *d = getMenuOption(hMenu, vMenu);
+void GfxMenu::addMenuItem(const char *menuItemText, uint16 controllerSlot) {
+	int16 arrayCount = _array.size();
 
-	// Disabled menu items are "greyed out" with a checkerboard effect,
-	// rather than having a different color. -- dsymonds
-	_vm->printText(d->text, 0, m->wincol + 1, vMenu + 2, m->width + 2,
-			MENU_BG, MENU_FG, !d->enabled);
-}
+	// already submitted? in that case no further changes possible
+	if (_submitted)
+		return;
 
-void Menu::newMenuSelected(int i) {
-	_picture->showPic();
-	drawMenuBar();
-	drawMenuHilite(i);
-	drawMenuOption(i);
-}
+	if (arrayCount == 0)
+		error("tried to add a menu item before adding an actual menu");
 
-bool Menu::mouseOverText(int line, int col, char *s) {
-	if (_vm->_mouse.x < col * CHAR_COLS)
-		return false;
+	// go to latest menu entry
+	GuiMenuEntry *curMenuEntry = _array.back();
 
-	if (_vm->_mouse.x > (int)(col + strlen(s)) * CHAR_COLS)
-		return false;
+	GuiMenuItemEntry *menuItemEntry = new GuiMenuItemEntry();
 
-	if (_vm->_mouse.y < line * CHAR_LINES)
-		return false;
+	menuItemEntry->enabled = true;
+	menuItemEntry->text = menuItemText;
+	menuItemEntry->textLen = menuItemEntry->text.size();
+	menuItemEntry->controllerSlot = controllerSlot;
 
-	if (_vm->_mouse.y >= (line + 1) * CHAR_LINES)
-		return false;
+	// Original interpreter on PC used the length of the first item for drawing
+	// At least in KQ2 on Apple IIgs follow-up items are longer, which would result in graphic glitches.
+	// That's why we remember the longest item and draw according to that
+	if (curMenuEntry->maxItemTextLen < menuItemEntry->textLen) {
+		curMenuEntry->maxItemTextLen = menuItemEntry->textLen;
+	}
 
-	return true;
-}
+	if (curMenuEntry->itemCount == 0) {
+		// for first menu item of menu calculated column
+		if (menuItemEntry->textLen + curMenuEntry->column < (FONT_COLUMN_CHARACTERS - 1)) {
+			_setupMenuItemColumn = curMenuEntry->column;
+		} else {
+			_setupMenuItemColumn = ( FONT_COLUMN_CHARACTERS - 1 ) - menuItemEntry->textLen;
+		}
+	}
 
-#if 0
-static void add_about_option() {
-	const char *text = "About AGI engine";
-
-	agi_menu_option *d = new agi_menu_option;
-	d->text = strdup(text);
-	d->enabled = true;
-	d->event = 255;
-	d->index = (v_max_menu[0] += 1);
-
-	agi_menu *m = *menubar.begin();
-	m->down.push_back(d);
-	m->height++;
-	if (m->width < (int)strlen(text))
-		m->width = strlen(text);
-}
-#endif
+	menuItemEntry->row = 2 + curMenuEntry->itemCount;
+	menuItemEntry->column = _setupMenuItemColumn;
 
-/*
- * Public functions
- */
+	_itemArray.push_back(menuItemEntry);
 
-Menu::Menu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture) {
-	_vm = vm;
-	_gfx = gfx;
-	_picture = picture;
-	_hIndex = 0;
-	_hCol = 1;
-	_hMaxMenu = 0;
-	_hCurMenu = 0;
-	_vCurMenu = 0;
+	curMenuEntry->itemCount++;
 }
 
-Menu::~Menu() {
-	MenuList::iterator iterh;
-	for (iterh = _menubar.reverse_begin(); iterh != _menubar.end(); ) {
-		AgiMenu *m = *iterh;
-
-		debugC(3, kDebugLevelMenu, "deiniting hmenu %s", m->text);
-
-		MenuOptionList::iterator iterv;
-
-		for (iterv = m->down.reverse_begin(); iterv != m->down.end(); ) {
-			AgiMenuOption *d = *iterv;
-
-			debugC(3, kDebugLevelMenu, "  deiniting vmenu %s", d->text);
-
-			free(d->text);
-			delete d;
+void GfxMenu::submit() {
+	GuiMenuEntry *menuEntry = nullptr;
+	GuiMenuItemEntry *menuItemEntry = nullptr;
+	int16 menuCount = _array.size();
+	int16 menuNr = 0;
+	int16 menuItemNr = 0;
+	int16 menuItemLastNr = 0;
+
+	if ((_array.size() == 0) || (_itemArray.size() == 0))
+		return;
+
+	_submitted = true;
+
+	// WORKAROUND: For Apple II gs we try to fix the menu text
+	// On this platform it seems a system font was used and the menu was drawn differently (probably system menu?)
+	// Still the text was misaligned anyway, but it looks worse in our (the original PC) implementation
+	// Atari ST SQ1 had one bad menu entry as well, we fix that too.
+	switch (_vm->getPlatform()) {
+	case Common::kPlatformApple2GS:
+	case Common::kPlatformAtariST:
+		// Go through all menus
+		for (menuNr = 0; menuNr < menuCount; menuNr++) {
+			menuEntry = _array[menuNr];
+			menuItemLastNr = menuEntry->firstItemNr + menuEntry->itemCount;
+
+			// Go through all items of current menu
+			for (menuItemNr = menuEntry->firstItemNr; menuItemNr < menuItemLastNr; menuItemNr++) {
+				menuItemEntry = _itemArray[menuItemNr];
+
+				if (menuItemEntry->textLen < menuEntry->maxItemTextLen) {
+					// current item text is shorter than the maximum?
+					int16 missingCharCount = menuEntry->maxItemTextLen - menuItemEntry->textLen;
+
+					if (menuItemEntry->text.contains('>')) {
+						// text contains '>', we now try to find a '<'
+						// and then add spaces in case this item is shorter than the first item
+						int16 textPos = menuItemEntry->textLen - 1;
+
+						while (textPos > 0) {
+							if (menuItemEntry->text[textPos] == '<')
+								break;
+							textPos--;
+						}
+
+						if (textPos > 0) {
+							while (missingCharCount) {
+								menuItemEntry->text.insertChar(' ', textPos);
+								missingCharCount--;
+							}
+						}
+					} else {
+						// Also check if text consists only of '-', which is the separator
+						// These were sometimes also too small
+						int16 separatorCount = 0;
+						int16 charPos = 0;
+
+						while (charPos < menuItemEntry->textLen) {
+							if (menuItemEntry->text[charPos] != '-')
+								break;
+							separatorCount++;
+							charPos++;
+						}
+
+						if (separatorCount == menuItemEntry->textLen) {
+							// Separator detected
+							while (missingCharCount) {
+								menuItemEntry->text.insertChar('-', 0);
+								missingCharCount--;
+							}
+						} else {
+							// Append spaces to the end to fill it up
+							int16 textPos = menuItemEntry->textLen;
+							while (missingCharCount) {
+								menuItemEntry->text.insertChar(' ', textPos);
+								textPos++;
+								missingCharCount--;
+							}
+						}
+					}
 
-			iterv = m->down.reverse_erase(iterv);
+					menuItemEntry->textLen = menuItemEntry->text.size();
+				}
+			}
 		}
-		free(m->text);
-		delete m;
-
-		iterh = _menubar.reverse_erase(iterh);
+		break;
+	default:
+		break;
 	}
 }
 
-void Menu::add(const char *s) {
-	AgiMenu *m = new AgiMenu;
-	m->text = strdup(s);
-
-	while (m->text[strlen(m->text) - 1] == ' ')
-		m->text[strlen(m->text) - 1] = 0;
-
-	m->width = 0;
-	m->height = 0;
-	m->index = _hIndex++;
-	m->col = _hCol;
-	m->wincol = _hCol - 1;
-	_vIndex = 0;
-	_vMaxMenu[m->index] = 0;
-	_hCol += strlen(m->text) + 1;
-	_hMaxMenu = m->index;
-
-	debugC(3, kDebugLevelMenu, "add menu: '%s' %02x", s, m->text[strlen(m->text)]);
-	_menubar.push_back(m);
+void GfxMenu::itemEnable(uint16 controllerSlot) {
+	itemEnableDisable(controllerSlot, true);
 }
 
-void Menu::addItem(const char *s, int code) {
-	int l;
-
-	AgiMenuOption* d = new AgiMenuOption;
-
-	d->text = strdup(s);
-	d->enabled = true;
-	d->event = code;
-	d->index = _vIndex++;
-
-	// add to last menu in list
-	assert(_menubar.reverse_begin() != _menubar.end());
-	AgiMenu *m = *_menubar.reverse_begin();
-	m->height++;
-
-	_vMaxMenu[m->index] = d->index;
-
-	l = strlen(d->text);
-	if (l > 40)
-		l = 38;
-	if (m->wincol + l > 38)
-		m->wincol = 38 - l;
-	if (l > m->width)
-		m->width = l;
-
-	debugC(3, kDebugLevelMenu, "Adding menu item: %s (size = %d)", s, m->height);
-
-	m->down.push_back(d);
+void GfxMenu::itemDisable(uint16 controllerSlot) {
+	itemEnableDisable(controllerSlot, false);
 }
 
-void Menu::submit() {
-	debugC(3, kDebugLevelMenu, "Submitting menu");
-
-	// add_about_option ();
-
-	// If a menu has no options, delete it
-	MenuList::iterator iter;
-	for (iter = _menubar.reverse_begin(); iter != _menubar.end(); ) {
-		AgiMenu *m = *iter;
+void GfxMenu::itemEnableDisable(uint16 controllerSlot, bool enabled) {
+	GuiMenuItemArray::iterator listIterator;
+	GuiMenuItemArray::iterator listEnd = _itemArray.end();
+	GuiMenuItemEntry *menuItemEntry;
 
-		if (m->down.empty()) {
-			free(m->text);
-			delete m;
-
-			_hMaxMenu--;
-
-			iter = _menubar.reverse_erase(iter);
-		} else {
-			--iter;
+	listIterator = _itemArray.begin();
+	while (listIterator != listEnd) {
+		menuItemEntry = *listIterator;
+		if (menuItemEntry->controllerSlot == controllerSlot) {
+			menuItemEntry->enabled = enabled;
 		}
+
+		listIterator++;
 	}
 }
 
-bool Menu::keyhandler(int key) {
-	static int clockVal;
-	static int menuActive = false;
-	static int buttonUsed = 0;
-	bool exitMenu = false;
+void GfxMenu::itemEnableAll() {
+	GuiMenuItemArray::iterator listIterator;
+	GuiMenuItemArray::iterator listEnd = _itemArray.end();
+	GuiMenuItemEntry *menuItemEntry;
 
-	if (!_vm->getflag(fMenusWork) && !(_vm->getFeatures() & GF_MENUS))
-		return false;
+	listIterator = _itemArray.begin();
+	while (listIterator != listEnd) {
+		menuItemEntry = *listIterator;
+		menuItemEntry->enabled = true;
 
-	if (!menuActive) {
-		clockVal = _vm->_game.clockEnabled;
-		_vm->_game.clockEnabled = false;
-		drawMenuBar();
+		listIterator++;
 	}
+}
 
-	// Mouse handling
-	if (_vm->_mouse.button) {
-		int hmenu, vmenu;
-
-		buttonUsed = 1;	// Button has been used at least once
-
-		if (_vm->_mouse.y <= CHAR_LINES) {
-			// on the menubar
-			hmenu = 0;
+// return true, in case a menu was actually created and submitted by the scripts
+bool GfxMenu::isAvailable() {
+	return _submitted;
+}
 
-			MenuList::iterator iterh;
+void GfxMenu::accessAllow() {
+	_allowed = true;
+}
 
-			for (iterh = _menubar.begin(); iterh != _menubar.end(); ++iterh) {
-				AgiMenu *m = *iterh;
+void GfxMenu::accessDeny() {
+	_allowed = false;
+}
 
-				if (mouseOverText(0, m->col, m->text)) {
-					break;
-				} else {
-					hmenu++;
-				}
-			}
+void GfxMenu::delayedExecute() {
+	_delayedExecute = true;
+}
 
-			if (hmenu <= _hMaxMenu) {
-				if (_hCurMenu != hmenu) {
-					_vCurMenu = -1;
-					newMenuSelected(hmenu);
-				}
-				_hCurMenu = hmenu;
-			}
-		} else {
-			// not in menubar
-			vmenu = 0;
+bool GfxMenu::delayedExecuteActive() {
+	return _delayedExecute;
+}
 
-			AgiMenu *m = getMenu(_hCurMenu);
+void GfxMenu::execute() {
+	_delayedExecute = false;
 
-			MenuOptionList::iterator iterv;
+	// got submitted? -> safety check
+	if (!_submitted)
+		return;
 
-			for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
-				AgiMenuOption *do1 = *iterv;
+	// access allowed at the moment?
+	if (!_allowed)
+		return;
 
-				if (mouseOverText(2 + do1->index, m->wincol + 1, do1->text)) {
-					break;
-				} else {
-					vmenu++;
-				}
-			}
+	_text->charPos_Push();
+	_text->charAttrib_Push();
+	_text->clearLine(0, _text->calculateTextBackground(15));
 
-			if (vmenu <= _vMaxMenu[_hCurMenu]) {
-				if (_vCurMenu != vmenu) {
-					drawMenuOption(_hCurMenu);
-					drawMenuOptionHilite(_hCurMenu, vmenu);
-				}
-				_vCurMenu = vmenu;
-			}
-		}
-	} else if (buttonUsed) {
-		// Button released
-		buttonUsed = 0;
+	// Draw all menus
+	for (uint16 menuNr = 0; menuNr < _array.size(); menuNr++) {
+		drawMenuName(menuNr, false);
+	}
+	drawActiveMenu();
 
-		debugC(6, kDebugLevelMenu | kDebugLevelInput, "button released!");
+	_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_MENU);
+	do {
+		_vm->mainCycle();
+	} while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
 
-		if (_vCurMenu < 0)
-			_vCurMenu = 0;
+	removeActiveMenu();
 
-		drawMenuOptionHilite(_hCurMenu, _vCurMenu);
+	_text->charAttrib_Pop();
+	_text->charPos_Pop();
 
-		if (_vm->_mouse.y <= CHAR_LINES) {
-			// on the menubar
-		} else {
-			// see which option we selected
-			AgiMenu *m = getMenu(_hCurMenu);
-			MenuOptionList::iterator iterv;
-
-			for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
-				AgiMenuOption *d = *iterv;
-
-				if (mouseOverText(2 + d->index, m->wincol + 1, d->text)) {
-					// activate that option
-					if (d->enabled) {
-						debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
-						_vm->_game.controllerOccured[d->event] = true;
-						_vm->_menuSelected = true;
-						break;
-					}
-				}
-			}
-			exitMenu = true;
-		}
+	// Restore status line
+	if (_text->statusEnabled()) {
+		_text->statusDraw();
+	} else {
+		_text->clearLine(0, 0);
 	}
+}
 
-	if (!exitMenu) {
-		if (!menuActive) {
-			if (_hCurMenu >= 0) {
-				drawMenuHilite(_hCurMenu);
-				drawMenuOption(_hCurMenu);
-				if (!buttonUsed && _vCurMenu >= 0)
-					drawMenuOptionHilite(_hCurMenu, _vCurMenu);
-			}
-			menuActive = true;
-		}
+void GfxMenu::drawMenuName(int16 menuNr, bool inverted) {
+	GuiMenuEntry *menuEntry = _array[menuNr];
+	bool disabledLook = false;
 
-		switch (key) {
-		case KEY_ESCAPE:
-			debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ESCAPE");
-			exitMenu = true;
-			break;
-		case KEY_ENTER:
-		{
-			debugC(6, kDebugLevelMenu | kDebugLevelInput, "KEY_ENTER");
-			AgiMenuOption* d = getMenuOption(_hCurMenu, _vCurMenu);
-
-			if (d->enabled) {
-				debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
-				_vm->_game.controllerOccured[d->event] = true;
-				_vm->_menuSelected = true;
-				exitMenu = true;
-			}
-			break;
-		}
-		case KEY_DOWN:
-		case KEY_UP:
-			_vCurMenu += key == KEY_DOWN ? 1 : -1;
-
-			if (_vCurMenu < 0)
-				_vCurMenu = _vMaxMenu[_hCurMenu];
-			if (_vCurMenu > _vMaxMenu[_hCurMenu])
-				_vCurMenu = 0;
-
-			drawMenuOption(_hCurMenu);
-			drawMenuOptionHilite(_hCurMenu, _vCurMenu);
-			break;
-		case KEY_RIGHT:
-		case KEY_LEFT:
-			_hCurMenu += key == KEY_RIGHT ? 1 : -1;
-
-			if (_hCurMenu < 0)
-				_hCurMenu = _hMaxMenu;
-			if (_hCurMenu > _hMaxMenu)
-				_hCurMenu = 0;
-
-			_vCurMenu = 0;
-			newMenuSelected(_hCurMenu);
-			drawMenuOptionHilite(_hCurMenu, _vCurMenu);
-			break;
-		}
+	if (!inverted) {
+		_text->charAttrib_Set(0, _text->calculateTextBackground(15));
+	} else {
+		_text->charAttrib_Set(15, _text->calculateTextBackground(0));
 	}
 
-	if (exitMenu) {
-		buttonUsed = 0;
-		_picture->showPic();
-		_vm->writeStatus();
-
-		_vm->setvar(vKey, 0);
-		_vm->_game.keypress = 0;
-		_vm->_game.clockEnabled = clockVal;
-		_vm->oldInputMode();
+	_text->charPos_Set(menuEntry->row, menuEntry->column);
 
-		debugC(3, kDebugLevelMenu, "exit_menu: input mode reset to %d", _vm->_game.inputMode);
-		menuActive = false;
-	}
+	if (menuEntry->itemCount == 0)
+		disabledLook = true;
 
-	return true;
+	_text->displayText(menuEntry->text.c_str(), disabledLook);
 }
 
-void Menu::setItem(int event, int state) {
-	// scan all menus for event number #
+void GfxMenu::drawItemName(int16 itemNr, bool inverted) {
+	GuiMenuItemEntry *itemEntry = _itemArray[itemNr];
+	bool disabledLook = false;
 
-	debugC(6, kDebugLevelMenu, "event = %d, state = %d", event, state);
-	MenuList::iterator iterh;
+	if (!inverted) {
+		_text->charAttrib_Set(0, _text->calculateTextBackground(15));
+	} else {
+		_text->charAttrib_Set(15, _text->calculateTextBackground(0));
+	}
 
-	for (iterh = _menubar.begin(); iterh != _menubar.end(); ++iterh) {
-		AgiMenu *m = *iterh;
-		MenuOptionList::iterator iterv;
+	_text->charPos_Set(itemEntry->row, itemEntry->column);
 
-		for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
-			AgiMenuOption *d = *iterv;
+	if (itemEntry->enabled == false)
+		disabledLook = true;
 
-			if (d->event == event) {
-				d->enabled = state;
-				// keep going; we need to set the state of every menu item
-				// with this event code. -- dsymonds
-			}
-		}
-	}
+	_text->displayText(itemEntry->text.c_str(), disabledLook);
 }
 
-void Menu::enableAll() {
-	MenuList::iterator iterh;
-	for (iterh = _menubar.begin(); iterh != _menubar.end(); ++iterh) {
-		AgiMenu *m = *iterh;
-		MenuOptionList::iterator iterv;
-
-		for (iterv = m->down.begin(); iterv != m->down.end(); ++iterv) {
-			AgiMenuOption *d = *iterv;
-
-			d->enabled = true;
+void GfxMenu::drawActiveMenu() {
+	GuiMenuEntry *menuEntry = _array[_selectedMenuNr];
+	GuiMenuItemEntry *itemEntry = _itemArray[menuEntry->firstItemNr];
+	int16 itemNr = menuEntry->firstItemNr;
+	int16 itemCount = menuEntry->itemCount;
+	
+	// draw menu name as inverted
+	drawMenuName(_selectedMenuNr, true);
+
+	// calculate active menu dimensions
+	_selectedMenuHeight = (menuEntry->itemCount + 2) * FONT_VISUAL_HEIGHT;
+	_selectedMenuWidth  = (menuEntry->maxItemTextLen * FONT_VISUAL_WIDTH) + 8;
+	_selectedMenuRow    = (menuEntry->itemCount + 3 - _text->getWindowRowMin()) * FONT_VISUAL_HEIGHT - 1;
+	_selectedMenuColumn = (itemEntry->column - 1) * FONT_VISUAL_WIDTH;
+
+	_gfx->drawBox(_selectedMenuColumn, _selectedMenuRow, _selectedMenuWidth, _selectedMenuHeight, 15, 0);
+
+	while (itemCount) {
+		if (itemNr == menuEntry->selectedItemNr) {
+			drawItemName(itemNr, true);
+		} else {
+			drawItemName(itemNr, false);
 		}
+		itemNr++;
+		itemCount--;
 	}
 }
 
+void GfxMenu::removeActiveMenu() {
+	// draw menu name normally again
+	drawMenuName(_selectedMenuNr, false);
 
-AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, bool positive) const {
-	if (_amigaStyle) {
-		if (positive) {
-			if (pressed) { // Positive pressed Amiga-style button
-				if (_olderAgi) {
-					return AgiTextColor(amigaBlack, amigaOrange);
-				} else {
-					return AgiTextColor(amigaBlack, amigaPurple);
-				}
-			} else { // Positive unpressed Amiga-style button
-				return AgiTextColor(amigaWhite, amigaGreen);
-			}
-		} else { // _amigaStyle && !positive
-			if (pressed) { // Negative pressed Amiga-style button
-				return AgiTextColor(amigaBlack, amigaCyan);
-			} else { // Negative unpressed Amiga-style button
-				return AgiTextColor(amigaWhite, amigaRed);
-			}
-		}
-	} else { // PC-style button
-		if (hasFocus || pressed) { // A pressed or in focus PC-style button
-			return AgiTextColor(pcWhite, pcBlack);
-		} else { // An unpressed PC-style button without focus
-			return AgiTextColor(pcBlack, pcWhite);
-		}
-	}
+	// overwrite actual menu items by rendering play screen
+	_gfx->render_Block(_selectedMenuColumn, _selectedMenuRow, _selectedMenuWidth, _selectedMenuHeight);
 }
 
-AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const {
-	return getColor(hasFocus, pressed, AgiTextColor(baseFgColor, baseBgColor));
-}
+void GfxMenu::charPress(int16 newChar) {
+	GuiMenuEntry *menuEntry = _array[_selectedMenuNr];
+	GuiMenuItemEntry *itemEntry = _itemArray[menuEntry->selectedItemNr];
+	int16 newMenuNr = _selectedMenuNr;
+	int16 newItemNr = menuEntry->selectedItemNr;
+
+	switch (newChar) {
+	case AGI_KEY_ENTER:
+		// check, if current item is actually enabled
+		if (!itemEntry->enabled)
+			return;
+
+		// Trigger controller
+		_vm->_game.controllerOccured[itemEntry->controllerSlot] = true;
+
+		_vm->cycleInnerLoopInactive(); // exit execute-loop
+		break;
+	case AGI_KEY_ESCAPE:
+		_vm->cycleInnerLoopInactive(); // exit execute-loop
+		break;
+
+	// these here change menu item
+	case AGI_KEY_UP:
+		newItemNr--;
+		break;
+	case AGI_KEY_DOWN:
+		newItemNr++;
+		break;
+	case AGI_KEY_PAGE_UP:
+		// select first item of current menu
+		newItemNr = menuEntry->firstItemNr;
+		break;
+	case AGI_KEY_PAGE_DOWN:
+		// select last item of current menu
+		newItemNr = menuEntry->firstItemNr + menuEntry->itemCount - 1;
+		break;
+
+	case AGI_KEY_LEFT:
+		newMenuNr--;
+		break;
+	case AGI_KEY_RIGHT:
+		newMenuNr++;
+		break;
+	case AGI_KEY_HOME:
+		// select first menu
+		newMenuNr = 0;
+		break;
+	case AGI_KEY_END:
+		// select last menu
+		newMenuNr = _array.size() - 1;
+		break;
+
+	default:
+		break;
+	}
 
-AgiTextColor AgiButtonStyle::getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const {
-	if (hasFocus || pressed)
-		return baseColor.swap();
-	else
-		return baseColor;
-}
+	if (newMenuNr != _selectedMenuNr) {
+		// selected menu was changed
+		int16 lastMenuNr = _array.size() - 1;
 
-int AgiButtonStyle::getTextOffset(bool hasFocus, bool pressed) const {
-	return (pressed && !_amigaStyle) ? 1 : 0;
-}
+		if (newMenuNr < 0) {
+			newMenuNr = lastMenuNr;
+		} else if (newMenuNr > lastMenuNr) {
+			newMenuNr = 0;
+		}
 
-bool AgiButtonStyle::getBorder(bool hasFocus, bool pressed) const {
-	return _amigaStyle && !_authenticAmiga && (hasFocus || pressed);
-}
+		if (newMenuNr != _selectedMenuNr) {
+			removeActiveMenu();
+			_selectedMenuNr = newMenuNr;
+			drawActiveMenu();
+		}
+	}
 
-void AgiButtonStyle::setAmigaStyle(bool amigaStyle, bool olderAgi, bool authenticAmiga) {
-	_amigaStyle		= amigaStyle;
-	_olderAgi		= olderAgi;
-	_authenticAmiga	= authenticAmiga;
-}
+	if (newItemNr != menuEntry->selectedItemNr) {
+		// selected item was changed
+		int16 lastItemNr = menuEntry->firstItemNr + menuEntry->itemCount - 1;
 
-void AgiButtonStyle::setPcStyle(bool pcStyle) {
-	setAmigaStyle(!pcStyle);
-}
+		if (newItemNr < menuEntry->firstItemNr) {
+			newItemNr = lastItemNr;
+		} else if (newItemNr > lastItemNr) {
+			newItemNr = menuEntry->firstItemNr;
+		}
 
-AgiButtonStyle::AgiButtonStyle(Common::RenderMode renderMode) {
-	setAmigaStyle(renderMode == Common::kRenderAmiga);
+		if (newItemNr != menuEntry->selectedItemNr) {
+			// still changed after clip -> draw changes
+			drawItemName(menuEntry->selectedItemNr, false);
+			drawItemName(newItemNr, true);
+			menuEntry->selectedItemNr = newItemNr;
+		}
+	}
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/menu.h b/engines/agi/menu.h
index 000973d..1781704 100644
--- a/engines/agi/menu.h
+++ b/engines/agi/menu.h
@@ -25,6 +25,88 @@
 
 namespace Agi {
 
+struct GuiMenuEntry {
+	Common::String text;
+	int16 textLen;
+
+	int16 row;
+	int16 column;
+
+	int16 itemCount;
+	int16 firstItemNr;
+	int16 selectedItemNr;
+
+	int16 maxItemTextLen;
+};
+typedef Common::Array<GuiMenuEntry *> GuiMenuArray;
+
+struct GuiMenuItemEntry {
+	Common::String text;
+	int16 textLen;
+
+	int16 row;
+	int16 column;
+
+	bool enabled;
+	uint16 controllerSlot;
+};
+typedef Common::Array<GuiMenuItemEntry *> GuiMenuItemArray;
+
+class GfxMenu {
+public:
+	GfxMenu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture, TextMgr *text);
+	~GfxMenu();
+
+	void addMenu(const char *menuText);
+	void addMenuItem(const char *menuText, uint16 controlCode);
+	void submit();
+	void itemEnable(uint16 controllerSlot);
+	void itemDisable(uint16 controllerSlot);
+	void itemEnableAll();
+	void charPress(int16 newChar);
+
+	bool isAvailable();
+
+	void accessAllow();
+	void accessDeny();
+
+	void delayedExecute();
+	bool delayedExecuteActive();
+	void execute();
+
+private:
+	void itemEnableDisable(uint16 controllerSlot, bool enabled);
+
+	void drawMenuName(int16 menuNr, bool inverted);
+	void drawItemName(int16 itemNr, bool inverted);
+	void drawActiveMenu();
+	void removeActiveMenu();
+
+	AgiEngine *_vm;
+	GfxMgr *_gfx;
+	PictureMgr *_picture;
+	TextMgr *_text;
+
+	bool _allowed;
+	bool _submitted;
+	bool _delayedExecute;
+
+	// for initial setup of the menu
+	int16 _setupMenuColumn;
+	int16 _setupMenuItemColumn;
+
+	GuiMenuArray _array;
+	GuiMenuItemArray _itemArray;
+
+	int16 _selectedMenuNr;
+
+	uint16 _selectedMenuHeight;
+	uint16 _selectedMenuWidth;
+	int16  _selectedMenuRow;
+	int16  _selectedMenuColumn;
+};
+
+#if 0
 #define MENU_BG		0x0f	// White
 #define MENU_DISABLED	0x07	// Grey
 
@@ -44,6 +126,7 @@ private:
 	AgiEngine *_vm;
 	GfxMgr *_gfx;
 	PictureMgr *_picture;
+	TextMgr *_text;
 
 public:
 	Menu(AgiEngine *vm, GfxMgr *gfx, PictureMgr *picture);
@@ -78,6 +161,7 @@ private:
 	bool mouseOverText(int line, int col, char *s);
 
 };
+#endif
 
 } // End of namespace Agi
 
diff --git a/engines/agi/module.mk b/engines/agi/module.mk
index 331a10c..b6cf6fc 100644
--- a/engines/agi/module.mk
+++ b/engines/agi/module.mk
@@ -36,6 +36,7 @@ MODULE_OBJS := \
 	sound_pcjr.o \
 	sound_sarien.o \
 	sprite.o \
+	systemui.o \
 	text.o \
 	view.o \
 	wagparser.o \
diff --git a/engines/agi/motion.cpp b/engines/agi/motion.cpp
index 363291a..3f85059 100644
--- a/engines/agi/motion.cpp
+++ b/engines/agi/motion.cpp
@@ -29,7 +29,7 @@ int AgiEngine::checkStep(int delta, int step) {
 	return (-step >= delta) ? 0 : (step <= delta) ? 2 : 1;
 }
 
-int AgiEngine::checkBlock(int x, int y) {
+bool AgiEngine::checkBlock(int16 x, int16 y) {
 	if (x <= _game.block.x1 || x >= _game.block.x2)
 		return false;
 
@@ -39,87 +39,90 @@ int AgiEngine::checkBlock(int x, int y) {
 	return true;
 }
 
-void AgiEngine::changePos(VtEntry *v) {
-	int b, x, y;
+void AgiEngine::changePos(ScreenObjEntry *screenObj) {
+	bool insideBlock;
+	int16 x, y;
 	int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
 	int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
 
-	x = v->xPos;
-	y = v->yPos;
-	b = checkBlock(x, y);
+	x = screenObj->xPos;
+	y = screenObj->yPos;
+	insideBlock = checkBlock(x, y);
 
-	x += v->stepSize * dx[v->direction];
-	y += v->stepSize * dy[v->direction];
+	x += screenObj->stepSize * dx[screenObj->direction];
+	y += screenObj->stepSize * dy[screenObj->direction];
 
-	if (checkBlock(x, y) == b) {
-		v->flags &= ~fMotion;
+	if (checkBlock(x, y) == insideBlock) {
+		screenObj->flags &= ~fMotion;
 	} else {
-		v->flags |= fMotion;
-		v->direction = 0;
-		if (isEgoView(v))
-			_game.vars[vEgoDir] = 0;
+		screenObj->flags |= fMotion;
+		screenObj->direction = 0;
+		if (isEgoView(screenObj))
+			_game.vars[VM_VAR_EGO_DIRECTION] = 0;
 	}
 }
 
-void AgiEngine::motionWander(VtEntry *v) {
-	if (v->parm1--) {
-		if (~v->flags & fDidntMove)
-			return;
-	}
+void AgiEngine::motionWander(ScreenObjEntry *screenObj) {
+	uint8 originalWanderCount = screenObj->wander_count;
 
-	v->direction = _rnd->getRandomNumber(8);
+	screenObj->wander_count--;
+	if ((originalWanderCount == 0) || (screenObj->flags & fDidntMove)) {
+		screenObj->direction = _rnd->getRandomNumber(8);
 
-	if (isEgoView(v)) {
-		_game.vars[vEgoDir] = v->direction;
-		while (v->parm1 < 6) {
-			v->parm1 = _rnd->getRandomNumber(50);	// huh?
+		if (isEgoView(screenObj)) {
+			_game.vars[VM_VAR_EGO_DIRECTION] = screenObj->direction;
+		}
+
+		while (screenObj->wander_count < 6) {
+			screenObj->wander_count = _rnd->getRandomNumber(50);	// huh?
 		}
 	}
 }
 
-void AgiEngine::motionFollowEgo(VtEntry *v) {
+void AgiEngine::motionFollowEgo(ScreenObjEntry *screenObj) {
+	ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
 	int egoX, egoY;
 	int objX, objY;
 	int dir;
 
-	egoX = _game.viewTable[0].xPos + _game.viewTable[0].xSize / 2;
-	egoY = _game.viewTable[0].yPos;
+	egoX = screenObjEgo->xPos + screenObjEgo->xSize / 2;
+	egoY = screenObjEgo->yPos;
 
-	objX = v->xPos + v->xSize / 2;
-	objY = v->yPos;
+	objX = screenObj->xPos + screenObj->xSize / 2;
+	objY = screenObj->yPos;
 
 	// Get direction to reach ego
-	dir = getDirection(objX, objY, egoX, egoY, v->parm1);
+	dir = getDirection(objX, objY, egoX, egoY, screenObj->follow_stepSize);
 
 	// Already at ego coordinates
 	if (dir == 0) {
-		v->direction = 0;
-		v->motion = kMotionNormal;
-		setflag(v->parm2, true);
+		screenObj->direction = 0;
+		screenObj->motionType = kMotionNormal;
+		setflag(screenObj->follow_flag, true);
 		return;
 	}
 
-	if (v->parm3 == 0xff) {
-		v->parm3 = 0;
-	} else if (v->flags & fDidntMove) {
+	if (screenObj->follow_count == 0xff) {
+		screenObj->follow_count = 0;
+	} else if (screenObj->flags & fDidntMove) {
 		int d;
 
-		while ((v->direction = _rnd->getRandomNumber(8)) == 0) {
+		while ((screenObj->direction = _rnd->getRandomNumber(8)) == 0) {
 		}
 
 		d = (ABS(egoY - objY) + ABS(egoX - objX)) / 2;
 
-		if (d < v->stepSize) {
-			v->parm3 = v->stepSize;
+		if (d < screenObj->stepSize) {
+			screenObj->follow_count = screenObj->stepSize;
 			return;
 		}
 
-		while ((v->parm3 = _rnd->getRandomNumber(d)) < v->stepSize) {
+		while ((screenObj->follow_count = _rnd->getRandomNumber(d)) < screenObj->stepSize) {
 		}
 		return;
 	}
 
-	if (v->parm3 != 0) {
+	if (screenObj->follow_count != 0) {
 		int k;
 
 		// DF: this is ugly and I dont know why this works, but
@@ -128,45 +131,46 @@ void AgiEngine::motionFollowEgo(VtEntry *v) {
 		// if (((int8)v->parm3 -= v->step_size) < 0)
 		//      v->parm3 = 0;
 
-		k = v->parm3;
-		k -= v->stepSize;
-		v->parm3 = k;
+		k = screenObj->follow_count;
+		k -= screenObj->stepSize;
+		screenObj->follow_count = k;
 
-		if ((int8) v->parm3 < 0)
-			v->parm3 = 0;
+		if ((int8) screenObj->follow_count < 0)
+			screenObj->follow_count = 0;
 	} else {
-		v->direction = dir;
+		screenObj->direction = dir;
 	}
 }
 
-void AgiEngine::motionMoveObj(VtEntry *v) {
-	v->direction = getDirection(v->xPos, v->yPos, v->parm1, v->parm2, v->stepSize);
+void AgiEngine::motionMoveObj(ScreenObjEntry *screenObj) {
+	screenObj->direction = getDirection(screenObj->xPos, screenObj->yPos, screenObj->move_x, screenObj->move_y, screenObj->stepSize);
 
 	// Update V6 if ego
-	if (isEgoView(v))
-		_game.vars[vEgoDir] = v->direction;
+	if (isEgoView(screenObj))
+		_game.vars[VM_VAR_EGO_DIRECTION] = screenObj->direction;
 
-	if (v->direction == 0)
-		inDestination(v);
+	if (screenObj->direction == 0)
+		motionMoveObjStop(screenObj);
 }
 
-void AgiEngine::checkMotion(VtEntry *v) {
-	switch (v->motion) {
+void AgiEngine::checkMotion(ScreenObjEntry *screenObj) {
+	switch (screenObj->motionType) {
 	case kMotionNormal:
 		break;
 	case kMotionWander:
-		motionWander(v);
+		motionWander(screenObj);
 		break;
 	case kMotionFollowEgo:
-		motionFollowEgo(v);
+		motionFollowEgo(screenObj);
 		break;
+	case kMotionEgo:
 	case kMotionMoveObj:
-		motionMoveObj(v);
+		motionMoveObj(screenObj);
 		break;
 	}
 
-	if ((_game.block.active && (~v->flags & fIgnoreBlocks)) && v->direction)
-		changePos(v);
+	if ((_game.block.active && (~screenObj->flags & fIgnoreBlocks)) && screenObj->direction)
+		changePos(screenObj);
 }
 
 /*
@@ -177,12 +181,12 @@ void AgiEngine::checkMotion(VtEntry *v) {
  *
  */
 void AgiEngine::checkAllMotions() {
-	VtEntry *v;
+	ScreenObjEntry *screenObj;
 
-	for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) {
-		if ((v->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fUpdate | fDrawn)
-				&& v->stepTimeCount == 1) {
-			checkMotion(v);
+	for (screenObj = _game.screenObjTable; screenObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
+		if ((screenObj->flags & (fAnimated | fUpdate | fDrawn)) == (fAnimated | fUpdate | fDrawn)
+				&& screenObj->stepTimeCount == 1) {
+			checkMotion(screenObj);
 		}
 	}
 }
@@ -193,14 +197,27 @@ void AgiEngine::checkAllMotions() {
  * type motion that * has reached its final destination coordinates.
  * @param  v  Pointer to view table entry
  */
-void AgiEngine::inDestination(VtEntry *v) {
-	if (v->motion == kMotionMoveObj) {
-		v->stepSize = v->parm3;
-		setflag(v->parm4, true);
+void AgiEngine::inDestination(ScreenObjEntry *screenObj) {
+	if (screenObj->motionType == kMotionMoveObj) {
+		screenObj->stepSize = screenObj->move_stepSize;
+		setflag(screenObj->move_flag, true);
+	}
+	screenObj->motionType = kMotionNormal;
+	if (isEgoView(screenObj))
+		_game.playerControl = true;
+}
+
+void AgiEngine::motionMoveObjStop(ScreenObjEntry *screenObj) {
+	screenObj->stepSize = screenObj->move_stepSize;
+	if (screenObj->motionType != kMotionEgo) {
+		setflag(screenObj->move_flag, true);
 	}
-	v->motion = kMotionNormal;
-	if (isEgoView(v))
+
+	screenObj->motionType = kMotionNormal;
+	if (isEgoView(screenObj)) {
 		_game.playerControl = true;
+		_game.vars[VM_VAR_EGO_DIRECTION] = 0;
+	}
 }
 
 /**
@@ -209,8 +226,8 @@ void AgiEngine::inDestination(VtEntry *v) {
  * after setting the motion mode to kMotionMoveObj.
  * @param  v  Pointer to view table entry
  */
-void AgiEngine::moveObj(VtEntry *v) {
-	motionMoveObj(v);
+void AgiEngine::moveObj(ScreenObjEntry *screenObj) {
+	motionMoveObj(screenObj);
 }
 
 /**
@@ -223,9 +240,9 @@ void AgiEngine::moveObj(VtEntry *v) {
  * @param  y   y coordinate of the object
  * @param  s   step size
  */
-int AgiEngine::getDirection(int x0, int y0, int x, int y, int s) {
+int AgiEngine::getDirection(int16 objX, int16 objY, int16 destX, int16 destY, int16 stepSize) {
 	int dirTable[9] = { 8, 1, 2, 7, 0, 3, 6, 5, 4 };
-	return dirTable[checkStep(x - x0, s) + 3 * checkStep(y - y0, s)];
+	return dirTable[checkStep(destX - objX, stepSize) + 3 * checkStep(destY - objY, stepSize)];
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/mouse_cursor.h b/engines/agi/mouse_cursor.h
new file mode 100644
index 0000000..1883960
--- /dev/null
+++ b/engines/agi/mouse_cursor.h
@@ -0,0 +1,183 @@
+/* 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 AGI_MOUSE_CURSOR_H
+#define AGI_MOUSE_CURSOR_H
+
+namespace Agi {
+
+/**
+ * RGB-palette for the Amiga-style arrow cursor
+ * and the Amiga-style busy cursor.
+ */
+static const byte MOUSECURSOR_PALETTE[] = {
+	0x00, 0x00, 0x00, // Black
+	0xFF, 0xFF, 0xFF, // White
+	0xDE, 0x20, 0x21, // Red
+	0xFF, 0xCF, 0xAD  // Light red
+};
+
+/**
+ * A black and white SCI-style arrow cursor (11x16).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 2 = White (#FFFFFF in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_SCI[] = {
+	1,1,0,0,0,0,0,0,0,0,0,
+	1,2,1,0,0,0,0,0,0,0,0,
+	1,2,2,1,0,0,0,0,0,0,0,
+	1,2,2,2,1,0,0,0,0,0,0,
+	1,2,2,2,2,1,0,0,0,0,0,
+	1,2,2,2,2,2,1,0,0,0,0,
+	1,2,2,2,2,2,2,1,0,0,0,
+	1,2,2,2,2,2,2,2,1,0,0,
+	1,2,2,2,2,2,2,2,2,1,0,
+	1,2,2,2,2,2,2,2,2,2,1,
+	1,2,2,2,2,2,1,0,0,0,0,
+	1,2,1,0,1,2,2,1,0,0,0,
+	1,1,0,0,1,2,2,1,0,0,0,
+	0,0,0,0,0,1,2,2,1,0,0,
+	0,0,0,0,0,1,2,2,1,0,0,
+	0,0,0,0,0,0,1,2,2,1,0
+};
+
+/**
+ * A black and white SCI-style busy cursor (15x16).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 2 = White (#FFFFFF in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_SCI_BUSY[] = {
+	0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,
+	0,0,0,0,1,1,1,2,2,1,1,1,0,0,0,
+	0,0,0,1,2,2,1,2,2,1,2,2,1,0,0,
+	0,1,1,1,2,2,1,2,2,1,2,2,1,0,0,
+	1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,
+	1,2,2,1,2,2,1,2,2,1,2,2,1,0,0,
+	1,2,2,1,2,2,1,2,2,1,2,1,2,1,0,
+	1,2,2,1,2,2,1,2,2,1,1,2,2,1,1,
+	1,2,2,1,2,2,1,2,2,1,1,2,2,2,1,
+	1,2,2,2,2,2,2,2,2,1,1,2,2,2,1,
+	1,2,2,2,2,2,2,2,1,2,2,2,2,1,0,
+	1,2,2,2,2,2,2,1,2,2,2,2,2,1,0,
+	0,1,2,2,2,2,2,1,2,2,2,2,1,0,0,
+	0,1,2,2,2,2,2,2,2,2,2,2,1,0,0,
+	0,0,1,2,2,2,2,2,2,2,2,1,0,0,0,
+	0,0,0,1,1,1,1,1,1,1,1,0,0,0,0
+};
+
+/**
+ * A black and white Atari ST style arrow cursor (11x16).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 2 = White (#FFFFFF in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_ATARI_ST[] = {
+	2,2,0,0,0,0,0,0,0,0,0,
+	2,1,2,0,0,0,0,0,0,0,0,
+	2,1,1,2,0,0,0,0,0,0,0,
+	2,1,1,1,2,0,0,0,0,0,0,
+	2,1,1,1,1,2,0,0,0,0,0,
+	2,1,1,1,1,1,2,0,0,0,0,
+	2,1,1,1,1,1,1,2,0,0,0,
+	2,1,1,1,1,1,1,1,2,0,0,
+	2,1,1,1,1,1,1,1,1,2,0,
+	2,1,1,1,1,1,2,2,2,2,2,
+	2,1,1,2,1,1,2,0,0,0,0,
+	2,1,2,0,2,1,1,2,0,0,0,
+	2,2,0,0,2,1,1,2,0,0,0,
+	2,0,0,0,0,2,1,1,2,0,0,
+	0,0,0,0,0,2,1,1,2,0,0,
+	0,0,0,0,0,0,2,2,2,0,0
+};
+
+/**
+ * A black and white Apple IIGS style arrow cursor (9x11).
+ * 0 = Transparent.
+ * 1 = Black (#000000 in 24-bit RGB).
+ * 2 = White (#FFFFFF in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_APPLE_II_GS[] = {
+	2,2,0,0,0,0,0,0,0,
+	2,1,2,0,0,0,0,0,0,
+	2,1,1,2,0,0,0,0,0,
+	2,1,1,1,2,0,0,0,0,
+	2,1,1,1,1,2,0,0,0,
+	2,1,1,1,1,1,2,0,0,
+	2,1,1,1,1,1,1,2,0,
+	2,1,1,1,1,1,1,1,2,
+	2,1,1,2,1,1,2,2,0,
+	2,2,2,0,2,1,1,2,0,
+	0,0,0,0,0,2,2,2,0
+};
+
+/**
+ * An Amiga-style arrow cursor (8x11).
+ * 0 = Transparent.
+ * 1 = Black     (#000000 in 24-bit RGB).
+ * 3 = Red       (#DE2021 in 24-bit RGB).
+ * 4 = Light red (#FFCFAD in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_AMIGA[] = {
+	3,4,1,0,0,0,0,0,
+	3,3,4,1,0,0,0,0,
+	3,3,3,4,1,0,0,0,
+	3,3,3,3,4,1,0,0,
+	3,3,3,3,3,4,1,0,
+	3,3,3,3,3,3,4,1,
+	3,0,3,3,4,1,0,0,
+	0,0,0,3,4,1,0,0,
+	0,0,0,3,3,4,1,0,
+	0,0,0,0,3,4,1,0,
+	0,0,0,0,3,3,4,1
+};
+
+/**
+ * An Amiga-style busy cursor showing an hourglass (13x16).
+ * 0 = Transparent.
+ * 1 = Black     (#000000 in 24-bit RGB).
+ * 2 = Red       (#DE2021 in 24-bit RGB).
+ * 3 = Light red (#FFCFAD in 24-bit RGB).
+ */
+static const byte MOUSECURSOR_AMIGA_BUSY[] = {
+	1,1,1,1,1,1,1,1,1,1,1,1,1,
+	1,3,3,3,3,3,3,3,3,3,3,3,1,
+	1,3,3,3,3,3,3,3,3,3,3,3,1,
+	0,1,4,4,4,4,4,4,4,4,4,1,0,
+	0,0,1,4,4,4,4,4,4,4,1,0,0,
+	0,0,0,1,4,4,4,4,4,1,0,0,0,
+	0,0,0,0,1,4,4,4,1,0,0,0,0,
+	0,0,0,0,0,1,4,1,0,0,0,0,0,
+	0,0,0,0,0,1,4,1,0,0,0,0,0,
+	0,0,0,0,1,3,4,3,1,0,0,0,0,
+	0,0,0,1,3,3,4,3,3,1,0,0,0,
+	0,0,1,3,3,3,4,3,3,3,1,0,0,
+	0,1,3,3,3,4,4,4,3,3,3,1,0,
+	1,4,4,4,4,4,4,4,4,4,4,4,1,
+	1,4,4,4,4,4,4,4,4,4,4,4,1,
+	1,1,1,1,1,1,1,1,1,1,1,1,1
+};
+
+} // End of namespace Agi
+
+#endif /* AGI_MOUSE_CURSOR_H */
diff --git a/engines/agi/objects.cpp b/engines/agi/objects.cpp
index 27cde61..b6c628c 100644
--- a/engines/agi/objects.cpp
+++ b/engines/agi/objects.cpp
@@ -144,28 +144,28 @@ void AgiEngine::unloadObjects() {
 	}
 }
 
-void AgiEngine::objectSetLocation(unsigned int n, int i) {
-	if (n >= _game.numObjects) {
-		warning("AgiEngine::objectSetLocation: Can't access object %d.\n", n);
+void AgiEngine::objectSetLocation(uint16 objectNr, int i) {
+	if (objectNr >= _game.numObjects) {
+		warning("AgiEngine::objectSetLocation: Can't access object %d.\n", objectNr);
 		return;
 	}
-	_objects[n].location = i;
+	_objects[objectNr].location = i;
 }
 
-int AgiEngine::objectGetLocation(unsigned int n) {
-	if (n >= _game.numObjects) {
-		warning("AgiEngine::objectGetLocation: Can't access object %d.\n", n);
+int AgiEngine::objectGetLocation(uint16 objectNr) {
+	if (objectNr >= _game.numObjects) {
+		warning("AgiEngine::objectGetLocation: Can't access object %d.\n", objectNr);
 		return 0;
 	}
-	return _objects[n].location;
+	return _objects[objectNr].location;
 }
 
-const char *AgiEngine::objectName(unsigned int n) {
-	if (n >= _game.numObjects) {
-		warning("AgiEngine::objectName: Can't access object %d.\n", n);
+const char *AgiEngine::objectName(uint16 objectNr) {
+	if (objectNr >= _game.numObjects) {
+		warning("AgiEngine::objectName: Can't access object %d.\n", objectNr);
 		return "";
 	}
-	return _objects[n].name;
+	return _objects[objectNr].name;
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index bf2a2ed..bb10c27 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -23,55 +23,49 @@
 #include "base/version.h"
 
 #include "agi/agi.h"
+#include "agi/inv.h"
 #include "agi/sprite.h"
+#include "agi/text.h"
 #include "agi/graphics.h"
 #include "agi/opcodes.h"
 #include "agi/menu.h"
+#include "agi/systemui.h"
+#include "agi/words.h"
 
 #include "common/random.h"
 #include "common/textconsole.h"
 
 namespace Agi {
 
-#define p0	(p[0])
-#define p1	(p[1])
-#define p2	(p[2])
-#define p3	(p[3])
-#define p4	(p[4])
-#define p5	(p[5])
-#define p6	(p[6])
-
-#define code state->_curLogic->data
-#define ip	state->_curLogic->cIP
-#define vt	state->viewTable[p0]
-#define vt_v state->viewTable[state->vars[p0]]
-
-#define _v state->vars
-
 #define getGameID() state->_vm->getGameID()
 #define getFeatures() state->_vm->getFeatures()
 #define getVersion() state->_vm->getVersion()
 #define getLanguage() state->_vm->getLanguage()
-#define setflag(a,b) state->_vm->setflag(a,b)
-#define getflag(a) state->_vm->getflag(a)
 
-void cmdIncrement(AgiGame *state, uint8 *p) {
+void cmdIncrement(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+
 	if (getVersion() < 0x2000) {
-		if (_v[p0] < 0xf0)
-			++_v[p0];
+		if (state->vars[varNr] < 0xf0)
+			++state->vars[varNr];
 	} else {
-		if (_v[p0] != 0xff)
-			++_v[p0];
+		if (state->vars[varNr] != 0xff)
+			++state->vars[varNr];
 	}
 }
 
-void cmdDecrement(AgiGame *state, uint8 *p) {
-	if (_v[p0] != 0)
-		--_v[p0];
+void cmdDecrement(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+
+	if (state->vars[varNr] != 0)
+		--state->vars[varNr];
 }
 
-void cmdAssignN(AgiGame *state, uint8 *p) {
-	_v[p0] = p1;
+void cmdAssignN(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+	uint16 value = parameter[1];
+
+	state->vars[varNr] = value;
 
 	// WORKAROUND for a bug in fan game "Get outta SQ"
 	// Total number of points is stored in variable 7, which
@@ -80,104 +74,170 @@ void cmdAssignN(AgiGame *state, uint8 *p) {
 	// variable to the correct value here
 	// Fixes bug #1942476 - "AGI: Fan(Get Outta SQ) - Score
 	// is lost on restart"
-	if (getGameID() == GID_GETOUTTASQ && p0 == 7)
-		_v[p0] = 8;
+	if (getGameID() == GID_GETOUTTASQ && varNr == 7)
+		state->vars[varNr] = 8;
 }
 
-void cmdAddN(AgiGame *state, uint8 *p) {
-	_v[p0] += p1;
+void cmdAddN(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+	uint16 value = parameter[1];
+
+	state->vars[varNr] += value;
 }
 
-void cmdSubN(AgiGame *state, uint8 *p) {
-	_v[p0] -= p1;
+void cmdSubN(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+	uint16 value = parameter[1];
+
+	state->vars[varNr] -= value;
 }
 
-void cmdAssignV(AgiGame *state, uint8 *p) {
-	_v[p0] = _v[p1];
+void cmdAssignV(AgiGame *state, uint8 *parameter) {
+	uint16 varNr1 = parameter[0];
+	uint16 varNr2 = parameter[1];
+
+	state->vars[varNr1] = state->vars[varNr2];
 }
 
-void cmdAddV(AgiGame *state, uint8 *p) {
-	_v[p0] += _v[p1];
+void cmdAddV(AgiGame *state, uint8 *parameter) {
+	uint16 varNr1 = parameter[0];
+	uint16 varNr2 = parameter[1];
+
+	state->vars[varNr1] += state->vars[varNr2];
 }
 
-void cmdSubV(AgiGame *state, uint8 *p) {
-	_v[p0] -= _v[p1];
+void cmdSubV(AgiGame *state, uint8 *parameter) {
+	uint16 varNr1 = parameter[0];
+	uint16 varNr2 = parameter[1];
+
+	state->vars[varNr1] -= state->vars[varNr2];
 }
 
-void cmdMulN(AgiGame *state, uint8 *p) {
-	_v[p0] *= p1;
+void cmdMulN(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+	uint16 value = parameter[1];
+
+	state->vars[varNr] *= value;
 }
 
-void cmdMulV(AgiGame *state, uint8 *p) {
-	_v[p0] *= _v[p1];
+void cmdMulV(AgiGame *state, uint8 *parameter) {
+	uint16 varNr1 = parameter[0];
+	uint16 varNr2 = parameter[1];
+
+	state->vars[varNr1] *= state->vars[varNr2];
 }
 
-void cmdDivN(AgiGame *state, uint8 *p) {
-	_v[p0] /= p1;
+void cmdDivN(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+	uint16 value = parameter[1];
+
+	state->vars[varNr] /= value;
 }
 
-void cmdDivV(AgiGame *state, uint8 *p) {
-	_v[p0] /= _v[p1];
+void cmdDivV(AgiGame *state, uint8 *parameter) {
+	uint16 varNr1 = parameter[0];
+	uint16 varNr2 = parameter[1];
+
+	state->vars[varNr1] /= state->vars[varNr2];
 }
 
-void cmdRandomV1(AgiGame *state, uint8 *p) {
-	_v[p0] = state->_vm->_rnd->getRandomNumber(250);
+void cmdRandomV1(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+
+	state->vars[varNr] = state->_vm->_rnd->getRandomNumber(250);
 }
 
-void cmdRandom(AgiGame *state, uint8 *p) {
-	_v[p2] = state->_vm->_rnd->getRandomNumber(p1 - p0) + p0;
+void cmdRandom(AgiGame *state, uint8 *parameter) {
+	uint16 valueMin = parameter[0];
+	uint16 valueMax = parameter[1];
+	uint16 varNr = parameter[2];
+
+	state->vars[varNr] = state->_vm->_rnd->getRandomNumber(valueMax - valueMin) + valueMin;
 }
 
-void cmdLindirectN(AgiGame *state, uint8 *p) {
-	_v[_v[p0]] = p1;
+void cmdLindirectN(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+	uint16 value = parameter[1];
+
+	state->vars[state->vars[varNr]] = value;
 }
 
-void cmdLindirectV(AgiGame *state, uint8 *p) {
-	_v[_v[p0]] = _v[p1];
+void cmdLindirectV(AgiGame *state, uint8 *parameter) {
+	uint16 varNr1 = parameter[0];
+	uint16 varNr2 = parameter[1];
+
+	state->vars[state->vars[varNr1]] = state->vars[varNr2];
 }
 
-void cmdRindirect(AgiGame *state, uint8 *p) {
-	_v[p0] = _v[_v[p1]];
+void cmdRindirect(AgiGame *state, uint8 *parameter) {
+	uint16 varNr1 = parameter[0];
+	uint16 varNr2 = parameter[1];
+
+	state->vars[varNr1] = state->vars[state->vars[varNr2]];
 }
 
-void cmdSet(AgiGame *state, uint8 *p) {
-	setflag(*p, true);
+void cmdSet(AgiGame *state, uint8 *parameter) {
+	uint16 flagNr = parameter[0];
+
+	state->_vm->setflag(flagNr, true);
 }
 
-void cmdReset(AgiGame *state, uint8 *p) {
-	setflag(*p, false);
+void cmdReset(AgiGame *state, uint8 *parameter) {
+	uint16 flagNr = parameter[0];
+
+	state->_vm->setflag(flagNr, false);
 }
 
-void cmdToggle(AgiGame *state, uint8 *p) {
-	setflag(*p, !getflag(*p));
+void cmdToggle(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
+	uint16 flagNr = parameter[0];
+	bool curFlagState = vm->getflag(flagNr);
+
+	vm->setflag(flagNr, !curFlagState);
 }
 
-void cmdSetV(AgiGame *state, uint8 *p) {
+void cmdSetV(AgiGame *state, uint8 *parameter) {
+	uint16 flagNr = parameter[0];
+
 	if (getVersion() < 0x2000) {
-		_v[p0] = 1;
+		state->vars[flagNr] = 1;
 	} else {
-		setflag(_v[p0], true);
+		flagNr = state->vars[flagNr];
+		
+		state->_vm->setflag(flagNr, true);
 	}
 }
 
-void cmdResetV(AgiGame *state, uint8 *p) {
+void cmdResetV(AgiGame *state, uint8 *parameter) {
+	uint16 flagNr = parameter[0];
+
 	if (getVersion() < 0x2000) {
-		_v[p0] = 0;
+		state->vars[flagNr] = 0;
 	} else {
-		setflag(_v[p0], false);
+		flagNr = state->vars[flagNr];
+
+		state->_vm->setflag(flagNr, false);
 	}
 }
 
-void cmdToggleV(AgiGame *state, uint8 *p) {
+void cmdToggleV(AgiGame *state, uint8 *parameter) {
+	uint16 flagNr = parameter[0];
+
 	if (getVersion() < 0x2000) {
-		_v[p0] ^= 1;
+		state->vars[flagNr] ^= 1;
 	} else {
-		setflag(_v[p0], !getflag(_v[p0]));
+		AgiEngine *vm = state->_vm;
+		flagNr = state->vars[flagNr];
+		bool curFlagState = vm->getflag(flagNr);
+
+		vm->setflag(flagNr, !curFlagState);
 	}
 }
 
-void cmdNewRoom(AgiGame *state, uint8 *p) {
-	state->_vm->newRoom(p0);
+void cmdNewRoom(AgiGame *state, uint8 *parameter) {
+	uint16 newRoomNr = parameter[0];
+
+	state->_vm->newRoom(newRoomNr);
 
 	// WORKAROUND: Works around intro skipping bug (#1737343) in Gold Rush.
 	// Intro was skipped because the enter-keypress finalizing the entering
@@ -188,351 +248,524 @@ void cmdNewRoom(AgiGame *state, uint8 *p) {
 	// keyboard buffer when the intro sequence's first room (Room 73) is
 	// loaded so that no keys from the copy protection scene can be left
 	// over to cause the intro to skip to the game's start.
-	if (getGameID() == GID_GOLDRUSH && p0 == 73)
+	if (getGameID() == GID_GOLDRUSH && newRoomNr == 73)
 		state->keypress = 0;
 }
 
-void cmdNewRoomF(AgiGame *state, uint8 *p) {
-	state->_vm->newRoom(_v[p0]);
+void cmdNewRoomF(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+
+	state->_vm->newRoom(state->vars[varNr]);
 }
 
-void cmdLoadView(AgiGame *state, uint8 *p) {
-	state->_vm->agiLoadResource(rVIEW, p0);
+void cmdLoadView(AgiGame *state, uint8 *parameter) {
+	uint16 resourceNr = parameter[0];
+
+	state->_vm->agiLoadResource(RESOURCETYPE_VIEW, resourceNr);
 }
 
-void cmdLoadLogic(AgiGame *state, uint8 *p) {
-	state->_vm->agiLoadResource(rLOGIC, p0);
+void cmdLoadLogic(AgiGame *state, uint8 *parameter) {
+	uint16 resourceNr = parameter[0];
+
+	state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
 }
 
-void cmdLoadSound(AgiGame *state, uint8 *p) {
-	state->_vm->agiLoadResource(rSOUND, p0);
+void cmdLoadSound(AgiGame *state, uint8 *parameter) {
+	uint16 resourceNr = parameter[0];
+
+	state->_vm->agiLoadResource(RESOURCETYPE_SOUND, resourceNr);
 }
 
-void cmdLoadViewF(AgiGame *state, uint8 *p) {
-	state->_vm->agiLoadResource(rVIEW, _v[p0]);
+void cmdLoadViewF(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+
+	state->_vm->agiLoadResource(RESOURCETYPE_VIEW, state->vars[varNr]);
 }
 
-void cmdLoadLogicF(AgiGame *state, uint8 *p) {
-	state->_vm->agiLoadResource(rLOGIC, _v[p0]);
+void cmdLoadLogicF(AgiGame *state, uint8 *parameter) {
+	uint16 varNr = parameter[0];
+
+	state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, state->vars[varNr]);
 }
 
-void cmdDiscardView(AgiGame *state, uint8 *p) {
-	state->_vm->agiUnloadResource(rVIEW, p0);
+void cmdDiscardView(AgiGame *state, uint8 *parameter) {
+	uint16 resourceNr = parameter[0];
+
+	state->_vm->agiUnloadResource(RESOURCETYPE_VIEW, resourceNr);
 }
 
-void cmdObjectOnAnything(AgiGame *state, uint8 *p) {
-	vt.flags &= ~(fOnWater | fOnLand);
+void cmdObjectOnAnything(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags &= ~(fOnWater | fOnLand);
 }
 
-void cmdObjectOnLand(AgiGame *state, uint8 *p) {
-	vt.flags |= fOnLand;
+void cmdObjectOnLand(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags |= fOnLand;
 }
 
-void cmdObjectOnWater(AgiGame *state, uint8 *p) {
-	vt.flags |= fOnWater;
+void cmdObjectOnWater(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags |= fOnWater;
 }
 
-void cmdObserveHorizon(AgiGame *state, uint8 *p) {
-	vt.flags &= ~fIgnoreHorizon;
+void cmdObserveHorizon(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags &= ~fIgnoreHorizon;
 }
 
-void cmdIgnoreHorizon(AgiGame *state, uint8 *p) {
-	vt.flags |= fIgnoreHorizon;
+void cmdIgnoreHorizon(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags |= fIgnoreHorizon;
 }
 
-void cmdObserveObjs(AgiGame *state, uint8 *p) {
-	vt.flags &= ~fIgnoreObjects;
+void cmdObserveObjs(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags &= ~fIgnoreObjects;
 }
 
-void cmdIgnoreObjs(AgiGame *state, uint8 *p) {
-	vt.flags |= fIgnoreObjects;
+void cmdIgnoreObjs(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags |= fIgnoreObjects;
 }
 
-void cmdObserveBlocks(AgiGame *state, uint8 *p) {
-	vt.flags &= ~fIgnoreBlocks;
+void cmdObserveBlocks(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags &= ~fIgnoreBlocks;
 }
 
-void cmdIgnoreBlocks(AgiGame *state, uint8 *p) {
-	vt.flags |= fIgnoreBlocks;
+void cmdIgnoreBlocks(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags |= fIgnoreBlocks;
 }
 
-void cmdSetHorizon(AgiGame *state, uint8 *p) {
-	state->horizon = p0;
+void cmdSetHorizon(AgiGame *state, uint8 *parameter) {
+	uint16 horizonValue = parameter[0];
+
+	state->horizon = horizonValue;
 }
 
-void cmdGetPriority(AgiGame *state, uint8 *p) {
-	_v[p1] = vt.priority;
+void cmdGetPriority(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	uint16 varNr = parameter[1];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	state->vars[varNr] = screenObj->priority;
 }
 
-void cmdSetPriority(AgiGame *state, uint8 *p) {
-	vt.flags |= fFixedPriority;
-	vt.priority = p1;
+void cmdSetPriority(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	uint16 priority = parameter[1];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	// WORKAROUND: this fixes bug #1712585 in KQ4 (dwarf sprite priority)
-	// For this scene, ego (Rosella) hasn't got a fixed priority till script 54
-	// explicitly sets priority 8 for her, so that she can walk back to the table
-	// without being drawn over the other dwarfs
-	// It seems that in this scene, ego's priority is set to 8, but the priority of
-	// the last dwarf with the soup bowls (view 152) is also set to 8, which causes
-	// the dwarf to be drawn behind ego
-	// With this workaround, when the game scripts set the priority of view 152
-	// (seventh dwarf with soup bowls), ego's priority is set to 7
-	// The game script itself sets priotity 8 for ego before she starts walking,
-	// and then releases the fixed priority set on ego after ego is seated
-	// Therefore, this workaround only affects that specific part of this scene
-	// Ego is set to object 19 by script 54
-	if (getGameID() == GID_KQ4 && vt.currentView == 152) {
-		state->viewTable[19].flags |= fFixedPriority;
-		state->viewTable[19].priority = 7;
-	}
+	screenObj->flags |= fFixedPriority;
+	screenObj->priority = priority;
 }
 
-void cmdSetPriorityF(AgiGame *state, uint8 *p) {
-	vt.flags |= fFixedPriority;
-	vt.priority = _v[p1];
+void cmdSetPriorityF(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	uint16 varNr = parameter[1];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags |= fFixedPriority;
+	screenObj->priority = state->vars[varNr];
 }
 
-void cmdReleasePriority(AgiGame *state, uint8 *p) {
-	vt.flags &= ~fFixedPriority;
+void cmdReleasePriority(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	screenObj->flags &= ~fFixedPriority;
 }
 
-void cmdSetUpperLeft(AgiGame *state, uint8 *p) {				// do nothing (AGI 2.917)
+void cmdSetUpperLeft(AgiGame *state, uint8 *parameter) {				// do nothing (AGI 2.917)
 }
 
-void cmdStartUpdate(AgiGame *state, uint8 *p) {
-	state->_vm->startUpdate(&vt);
+void cmdStartUpdate(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	state->_vm->startUpdate(screenObj);
 }
 
-void cmdStopUpdate(AgiGame *state, uint8 *p) {
-	state->_vm->stopUpdate(&vt);
+void cmdStopUpdate(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	state->_vm->stopUpdate(screenObj);
 }
 
-void cmdCurrentView(AgiGame *state, uint8 *p) {
-	_v[p1] = vt.currentView;
+void cmdCurrentView(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	uint16 varNr = parameter[1];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	state->vars[varNr] = screenObj->currentViewNr;
 }
 
-void cmdCurrentCel(AgiGame *state, uint8 *p) {
-	_v[p1] = vt.currentCel;
-	debugC(4, kDebugLevelScripts, "v%d=%d", p1, _v[p1]);
+void cmdCurrentCel(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	uint16 varNr = parameter[1];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+
+	state->vars[varNr] = screenObj->currentCelNr;
+	debugC(4, kDebugLevelScripts, "v%d=%d", varNr, state->vars[varNr]);
 }
 
-void cmdCurrentLoop(AgiGame *state, uint8 *p) {
-	_v[p1] = vt.currentLoop;
+void cmdCurrentLoop(AgiGame *state, uint8 *parameter) {
+	uint16 objectNr = parameter[0];
+	uint16 varNr = parameter[1];
+	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];


Commit: ccfd870c818aa1ecf59399ab18e1ae7d32c11079
    https://github.com/scummvm/scummvm/commit/ccfd870c818aa1ecf59399ab18e1ae7d32c11079
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T14:03:47+01:00

Commit Message:
AGI: adjust mouse pos using render start Y

instead of having it hardcoded.

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



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 19e0595..9362cef 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -275,9 +275,7 @@ AgiBase::~AgiBase() {
 
 	delete _sound;
 
-	if (_fontDataAllocated) {
-		free(_fontDataAllocated);
-	}
+	free(_fontDataAllocated);
 }
 
 void AgiBase::initRenderMode() {
@@ -856,7 +854,10 @@ void AgiEngine::redrawScreen() {
 // Used on mouse cursor coordinates before passing them to scripts
 void AgiEngine::adjustPosToGameScreen(int16 &x, int16 &y) {
 	x = x / 2; // 320 -> 160
-	y = y - 8; // remove status bar line
+	y = y - _gfx->getRenderStartOffsetY(); // remove status bar line
+	if (y < 0) {
+		y = 0;
+	}
 	if (y >= SCRIPT_HEIGHT) {
 		y = SCRIPT_HEIGHT + 1; // 1 beyond
 	}
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index e9ae129..467d63b 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -172,6 +172,9 @@ void GfxMgr::setRenderStartOffset(uint16 offsetY) {
 
 	_renderStartOffsetY = offsetY;
 }
+uint16 GfxMgr::getRenderStartOffsetY() {
+	return _renderStartOffsetY;
+}
 
 void GfxMgr::debugShowMap(int mapNr) {
 	switch (mapNr) {
diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h
index a89a7fd..7fffe32 100644
--- a/engines/agi/graphics.h
+++ b/engines/agi/graphics.h
@@ -80,6 +80,7 @@ public:
 	int deinitMachine();
 
 	void setRenderStartOffset(uint16 offsetY);
+	uint16 getRenderStartOffsetY();
 
 private:
 	uint _pixels;


Commit: df845be116f233b1c47bf63b99fbf0b7359039e1
    https://github.com/scummvm/scummvm/commit/df845be116f233b1c47bf63b99fbf0b7359039e1
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T14:07:48+01:00

Commit Message:
AGI: added/changed font warnings

Changed paths:
    engines/agi/agi.cpp



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 9362cef..695e743 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -397,6 +397,7 @@ void AgiBase::loadFontMickey() {
 
 	if (!interpreterFile.open("mickey.exe")) {
 		// Continue, if file not found
+		warning("Could not open file 'mickey.exe' for Mickey Mouse font");
 		return;
 	}
 
@@ -404,7 +405,7 @@ void AgiBase::loadFontMickey() {
 	if (interpreterFileSize != 55136) {
 		// unexpected file size
 		interpreterFile.close();
-		warning("mickey.exe unexpected file size");
+		warning("File 'mickey.exe': unexpected file size");
 		return;
 	}
 	interpreterFile.seek(32476); // offset of font data
@@ -530,7 +531,7 @@ void AgiBase::loadFontAppleIIgs() {
 	if (!fontFile.open("agifont")) {
 		// Continue,
 		// This also happens when the user selected Apple IIgs as render for the palette for non-AppleIIgs games
-		warning("could not open agifont for Apple IIgs font");
+		warning("Could not open file 'agifont' for Apple IIgs font");
 		return;
 	}
 


Commit: 1a5bef230267a4bccfe20ff11e3ce00a8d410271
    https://github.com/scummvm/scummvm/commit/1a5bef230267a4bccfe20ff11e3ce00a8d410271
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T14:23:33+01:00

Commit Message:
AGI: remove initGraphics comment

Changed paths:
    engines/agi/agi.cpp



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 695e743..23a6474 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -888,10 +888,6 @@ AgiEngine::~AgiEngine() {
 }
 
 Common::Error AgiBase::init() {
-
-	// Initialize backend
-	//initGraphics(320, 200, false);
-
 	initialize();
 
 	_gfx->setPalette(true);


Commit: 1987b4b4e585c2d5fdc2b6553e4ae2d98fc89764
    https://github.com/scummvm/scummvm/commit/1987b4b4e585c2d5fdc2b6553e4ae2d98fc89764
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T15:10:17+01:00

Commit Message:
AGI: remove commented out code in console.cpp

Changed paths:
    engines/agi/console.cpp



diff --git a/engines/agi/console.cpp b/engines/agi/console.cpp
index d8ecb2a..39719a4 100644
--- a/engines/agi/console.cpp
+++ b/engines/agi/console.cpp
@@ -487,9 +487,6 @@ bool Console::Cmd_ScreenObj(int argc, const char **argv) {
 			break;
 		}
 	}
-#if 0
-	CycleType cycle;
-#endif 
 	return true;
 }
 


Commit: a560f7ad01a6d56a56d14e6434715e6cb3b2289d
    https://github.com/scummvm/scummvm/commit/a560f7ad01a6d56a56d14e6434715e6cb3b2289d
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T15:11:07+01:00

Commit Message:
AGI: improve checkPosition() code, remove while(0)

Changed paths:
    engines/agi/checks.cpp



diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp
index 8399c98..1fb437b 100644
--- a/engines/agi/checks.cpp
+++ b/engines/agi/checks.cpp
@@ -29,28 +29,25 @@ bool AgiEngine::checkPosition(ScreenObjEntry *screenObj) {
 	bool result = true; // position is fine
 	debugC(4, kDebugLevelSprites, "check position @ %d, %d", screenObj->xPos, screenObj->yPos);
 
-	do {
-		if (screenObj->xPos < 0) {
-			result = false;
-			break;
-		}
+	if (screenObj->xPos < 0) {
+		result = false;
+	} else {
 		if (screenObj->xPos + screenObj->xSize > SCRIPT_WIDTH) {
 			result = false;
-			break;
-		}
-		if (screenObj->yPos - screenObj->ySize < -1) {
-			result = false;
-			break;
-		}
-		if (screenObj->yPos >= SCRIPT_HEIGHT) {
-			result = false;
-			break;
-		}
-		if (((!(screenObj->flags & fIgnoreHorizon)) && screenObj->yPos <= _game.horizon)) {
-			result = false;
-			break;
+		} else {
+			if (screenObj->yPos - screenObj->ySize < -1) {
+				result = false;
+			} else {
+				if (screenObj->yPos >= SCRIPT_HEIGHT) {
+					result = false;
+				} else {
+					if (((!(screenObj->flags & fIgnoreHorizon)) && screenObj->yPos <= _game.horizon)) {
+						result = false;
+					}
+				}
+			}
 		}
-	} while (0);
+	}
 
 	// MH1 needs this, but it breaks LSL1
 // TODO: *NOT* in disassembly of AGI3 .149, why was this needed?


Commit: 5f43f079472dd2cbd091ba813cf23d0c3315db76
    https://github.com/scummvm/scummvm/commit/5f43f079472dd2cbd091ba813cf23d0c3315db76
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T15:15:18+01:00

Commit Message:
AGI: font.h / change comment to use unix slashes

Changed paths:
    engines/agi/font.h



diff --git a/engines/agi/font.h b/engines/agi/font.h
index 6b6381c..27d495e 100644
--- a/engines/agi/font.h
+++ b/engines/agi/font.h
@@ -32,7 +32,7 @@ static const uint8 fontData_ArrowRightCharacter[8] = {
 	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
 };
 
-// topaz data, same as in engines\parallaction\staticres.cpp
+// topaz data, same as in engines/parallaction/staticres.cpp
 // seems to have been recreated and is not the original amiga font
 static const uint8 fontData_AmigaPseudoTopaz[2600] = {
 	0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,


Commit: 41620c95ccd771b78ead14bebaab0045079f95c4
    https://github.com/scummvm/scummvm/commit/41620c95ccd771b78ead14bebaab0045079f95c4
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T15:28:17+01:00

Commit Message:
AGI: remove commented out code from CmdSetSimple()

should have been removed already.

Changed paths:
    engines/agi/op_cmd.cpp



diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index bb10c27..00b8dbf 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -861,14 +861,12 @@ void cmdSetSimple(AgiGame *state, uint8 *parameter) {
 		state->automaticSave = false;
 
 		// Try to get description for automatic saves
-//		if (state->strings_curLogic->texts && state->_curLogic->numTexts >= textNr) {
-			textPtr = state->strings[stringNr];
-			strncpy(state->automaticSaveDescription, textPtr, sizeof(state->automaticSaveDescription));
-			if (state->automaticSaveDescription[0]) {
-				// We got it and it's set, so enable automatic saving
-				state->automaticSave = true;
-			}
-//		}
+		textPtr = state->strings[stringNr];
+		strncpy(state->automaticSaveDescription, textPtr, sizeof(state->automaticSaveDescription));
+		if (state->automaticSaveDescription[0]) {
+			// We got it and it's set, so enable automatic saving
+			state->automaticSave = true;
+		}
 
 	} else { // AGI256 and AGI256-2 use this unknown170 command to load 256 color pictures.
 		// Load the picture. Similar to void cmdLoad_pic(AgiGame *state, uint8 *p).


Commit: 0f15ec2ce827d157f4459b966088ec0792ff5be8
    https://github.com/scummvm/scummvm/commit/0f15ec2ce827d157f4459b966088ec0792ff5be8
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T15:43:45+01:00

Commit Message:
AGI: use Common::RenderMode instead of its own

AppleIIgs + Atari ST weren't available back then in the enum.
They now are, so I can use the Common one.

Changed paths:
    engines/agi/agi.cpp
    engines/agi/agi.h
    engines/agi/cycle.cpp
    engines/agi/graphics.cpp
    engines/agi/picture.cpp
    engines/agi/preagi_mickey.cpp
    engines/agi/text.cpp
    engines/agi/view.cpp



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 23a6474..9902d99 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -283,31 +283,31 @@ void AgiBase::initRenderMode() {
 	Common::RenderMode configRenderMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str());
 
 	// Default to EGA PC rendering
-	_renderMode = RENDERMODE_EGA;
+	_renderMode = Common::kRenderEGA;
 
 	switch (platform) {
 	case Common::kPlatformDOS:
 		switch (configRenderMode) {
 		case Common::kRenderCGA:
-			_renderMode = RENDERMODE_CGA;
+			_renderMode = Common::kRenderCGA;
 			break;
 		// Hercules is not supported atm
 		//case Common::kRenderHercA:
 		//case Common::kRenderHercG:
-		//	_renderMode = RENDERMODE_HERCULES;
+		//	_renderMode = Common::kRenderHercG;
 		//	break;
 		default:
 			break;
 		}
 		break;
 	case Common::kPlatformAmiga:
-		_renderMode = RENDERMODE_AMIGA;
+		_renderMode = Common::kRenderAmiga;
 		break;
 	case Common::kPlatformApple2GS:
-		_renderMode = RENDERMODE_APPLE_II_GS;
+		_renderMode = Common::kRenderApple2GS;
 		break;
 	case Common::kPlatformAtariST:
-		_renderMode = RENDERMODE_ATARI_ST;
+		_renderMode = Common::kRenderAtariST;
 		break;
 	default:
 		break;
@@ -316,13 +316,13 @@ void AgiBase::initRenderMode() {
 	// If render mode is explicitly set, force rendermode
 	switch (configRenderMode) {
 	case Common::kRenderAmiga:
-		_renderMode = RENDERMODE_AMIGA;
+		_renderMode = Common::kRenderAmiga;
 		break;
 	case Common::kRenderApple2GS:
-		_renderMode = RENDERMODE_APPLE_II_GS;
+		_renderMode = Common::kRenderApple2GS;
 		break;
 	case Common::kRenderAtariST:
-		_renderMode = RENDERMODE_ATARI_ST;
+		_renderMode = Common::kRenderAtariST;
 		break;
 	default:
 		break;
@@ -330,7 +330,7 @@ void AgiBase::initRenderMode() {
 
 	if (getFeatures() & (GF_AGI256 | GF_AGI256_2)) {
 		// If current game is AGI256, switch (force) to VGA render mode
-		_renderMode = RENDERMODE_VGA;
+		_renderMode = Common::kRenderVGA;
 	}
 }
 
@@ -343,21 +343,21 @@ void AgiBase::initFont() {
 	}
 
 	switch (_renderMode) {
-	case RENDERMODE_AMIGA:
+	case Common::kRenderAmiga:
 		loadFontAmigaPseudoTopaz();
 		//_fontData = fontData_Amiga; // use Amiga Topaz font
 		break;
-	case RENDERMODE_APPLE_II_GS:
+	case Common::kRenderApple2GS:
 		// Special font, stored in file AGIFONT
 		loadFontAppleIIgs();
 		break;
-	case RENDERMODE_ATARI_ST:
+	case Common::kRenderAtariST:
 		// TODO: Atari ST uses another font
 		// Seems to be the standard Atari ST 8x8 system font
 
-	case RENDERMODE_CGA:
-	case RENDERMODE_EGA:
-	case RENDERMODE_VGA:
+	case Common::kRenderCGA:
+	case Common::kRenderEGA:
+	case Common::kRenderVGA:
 		switch (getGameID()) {
 		case GID_MICKEY:
 			// load mickey mouse font from interpreter file
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index fd44afd..a070d5e 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -140,16 +140,6 @@ enum AgiGameType {
 	 BooterDisk2 = 1
  };
 
-enum AgiRenderMode {
-	RENDERMODE_EGA = 0,
-	RENDERMODE_CGA = 1,
-	RENDERMODE_VGA = 2,
-	RENDERMODE_HERCULES = 3,
-	RENDERMODE_AMIGA = 4,
-	RENDERMODE_APPLE_II_GS = 5,
-	RENDERMODE_ATARI_ST = 6
-};
-
 //
 // GF_OLDAMIGAV20 means that the interpreter is an old Amiga AGI interpreter that
 // uses value 20 for the computer type (v20 i.e. vComputer) rather than the usual value 5.
@@ -666,7 +656,7 @@ public:
 
 	GfxMgr *_gfx;
 
-	AgiRenderMode _renderMode;
+	Common::RenderMode _renderMode;
 	volatile uint32 _clockCount;
 	AgiDebug _debug;
 	AgiGame _game;
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index 98f29ec..3d9803e 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -494,19 +494,20 @@ int AgiEngine::runGame() {
 
 		// Set monitor type (v26 i.e. vMonitor)
 		switch (_renderMode) {
-		case RENDERMODE_CGA:
+		case Common::kRenderCGA:
 			setVar(VM_VAR_MONITOR, kAgiMonitorCga);
 			break;
-		case RENDERMODE_HERCULES:
+		case Common::kRenderHercA:
+		case Common::kRenderHercG:
 			setVar(VM_VAR_MONITOR, kAgiMonitorHercules);
 			break;
 		// Don't know if Amiga AGI games use a different value than kAgiMonitorEga
 		// for vMonitor so I just use kAgiMonitorEga for them (As was done before too).
-		case RENDERMODE_AMIGA:
-		case RENDERMODE_APPLE_II_GS:
-		case RENDERMODE_ATARI_ST:
-		case RENDERMODE_EGA:
-		case RENDERMODE_VGA:
+		case Common::kRenderAmiga:
+		case Common::kRenderApple2GS:
+		case Common::kRenderAtariST:
+		case Common::kRenderEGA:
+		case Common::kRenderVGA:
 		default:
 			setVar(VM_VAR_MONITOR, kAgiMonitorEga);
 			break;
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index 467d63b..b19e729 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -63,16 +63,16 @@ int GfxMgr::initVideo() {
 	initPalette(_paletteTextMode, PALETTE_EGA);
 
 	switch (_vm->_renderMode) {
-	case RENDERMODE_EGA:
+	case Common::kRenderEGA:
 		initPalette(_paletteGfxMode, PALETTE_EGA);
 		break;
-	case RENDERMODE_CGA:
+	case Common::kRenderCGA:
 		initPalette(_paletteGfxMode, PALETTE_CGA, 4, 8);
 		break;
-	case RENDERMODE_VGA:
+	case Common::kRenderVGA:
 		initPalette(_paletteGfxMode, PALETTE_VGA, 256, 8);
 		break;
-	case RENDERMODE_AMIGA:
+	case Common::kRenderAmiga:
 		if (!ConfMan.getBool("altamigapalette")) {
 			// Set the correct Amiga palette depending on AGI interpreter version
 			if (_vm->getVersion() < 0x2936)
@@ -86,10 +86,10 @@ int GfxMgr::initVideo() {
 			initPalette(_paletteGfxMode, PALETTE_AMIGA_ALT);
 		}
 		break;
-	case RENDERMODE_APPLE_II_GS:
+	case Common::kRenderApple2GS:
 		initPalette(_paletteGfxMode, PALETTE_APPLE_II_GS, 16, 4);
 		break;
-	case RENDERMODE_ATARI_ST:
+	case Common::kRenderAtariST:
 		initPalette(_paletteGfxMode, PALETTE_ATARI_ST, 16, 3);
 		break;
 	default:
@@ -99,22 +99,22 @@ int GfxMgr::initVideo() {
 
 	// set up mouse cursors
 	switch (_vm->_renderMode) {
-	case RENDERMODE_EGA:
-	case RENDERMODE_CGA:
-	case RENDERMODE_VGA:
+	case Common::kRenderEGA:
+	case Common::kRenderCGA:
+	case Common::kRenderVGA:
 		initMouseCursor(&_mouseCursor, MOUSECURSOR_SCI, 11, 16, 1, 1);
 		initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
 		break;
-	case RENDERMODE_AMIGA:
+	case Common::kRenderAmiga:
 		initMouseCursor(&_mouseCursor, MOUSECURSOR_AMIGA, 8, 11, 1, 1);
 		initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_AMIGA_BUSY, 13, 16, 7, 8);
 		break;
-	case RENDERMODE_APPLE_II_GS:
+	case Common::kRenderApple2GS:
 		// had no special busy mouse cursor
 		initMouseCursor(&_mouseCursor, MOUSECURSOR_APPLE_II_GS, 9, 11, 1, 1);
 		initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
 		break;
-	case RENDERMODE_ATARI_ST:
+	case Common::kRenderAtariST:
 		initMouseCursor(&_mouseCursor, MOUSECURSOR_ATARI_ST, 11, 16, 1, 1);
 		initMouseCursor(&_mouseCursorBusy, MOUSECURSOR_SCI_BUSY, 15, 16, 7, 8);
 		break;
@@ -270,10 +270,10 @@ void GfxMgr::render_Block(int16 x, int16 y, int16 width, int16 height, bool copy
 		return;
 
 	switch (_vm->_renderMode) {
-	case RENDERMODE_CGA:
+	case Common::kRenderCGA:
 		render_BlockCGA(x, y, width, height, copyToScreen);
 		break;
-	case RENDERMODE_EGA:
+	case Common::kRenderEGA:
 	default:
 		render_BlockEGA(x, y, width, height, copyToScreen);
 		break;
@@ -546,10 +546,10 @@ void GfxMgr::drawRect(int16 x, int16 y, int16 width, int16 height, byte color) {
 // coordinates are directly for display screen
 void GfxMgr::drawDisplayRect(int16 x, int16 y, int16 width, int16 height, byte color) {
 	switch (_vm->_renderMode) {
-	case RENDERMODE_CGA:
+	case Common::kRenderCGA:
 		drawDisplayRectCGA(x, y, width, height, color);
 		break;
-	case RENDERMODE_EGA:
+	case Common::kRenderEGA:
 	default:
 		drawDisplayRectEGA(x, y, width, height, color);
 		break;
diff --git a/engines/agi/picture.cpp b/engines/agi/picture.cpp
index 951d67a..965145c 100644
--- a/engines/agi/picture.cpp
+++ b/engines/agi/picture.cpp
@@ -632,7 +632,7 @@ void PictureMgr::draw_SetColor() {
 
 	// For CGA, replace the color with its mixture color
 	switch (_vm->_renderMode) {
-	case RENDERMODE_CGA:
+	case Common::kRenderCGA:
 		_scrColor = _gfx->getCGAMixtureColor(_scrColor);
 		break;
 	default:
@@ -651,7 +651,7 @@ void PictureMgr::draw_SetNibbleColor() {
 
 	// For CGA, replace the color with its mixture color
 	switch (_vm->_renderMode) {
-	case RENDERMODE_CGA:
+	case Common::kRenderCGA:
 		_scrColor = _gfx->getCGAMixtureColor(_scrColor);
 		break;
 	default:
@@ -1030,14 +1030,14 @@ void PictureMgr::showPicWithTransition() {
 		}
 
 		switch (_vm->_renderMode) {
-		case RENDERMODE_AMIGA:
-		case RENDERMODE_APPLE_II_GS:
+		case Common::kRenderAmiga:
+		case Common::kRenderApple2GS:
 			// Platform Amiga/Apple II GS -> render and do Amiga transition
 			_gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT, false);
 			_gfx->transition_Amiga();
 			return;
 			break;
-		case RENDERMODE_ATARI_ST:
+		case Common::kRenderAtariST:
 			// Platform Atari ST used a different transition, looks "high-res" (full 320x168)
 			_gfx->render_Block(0, 167, SCRIPT_WIDTH, SCRIPT_HEIGHT, false);
 			_gfx->transition_AtariSt();
diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp
index 02c48b0..ad1bddf 100644
--- a/engines/agi/preagi_mickey.cpp
+++ b/engines/agi/preagi_mickey.cpp
@@ -921,7 +921,7 @@ void MickeyEngine::drawLogo() {
 	const byte *BCGColorMapping = BCGColorMappingCGAToEGA;
 
 	// disable color mapping in case we are in CGA mode
-	if (_renderMode == RENDERMODE_CGA)
+	if (_renderMode == Common::kRenderCGA)
 		BCGColorMapping = BCGColorMappingCGAToCGA;
 
 	// read logos.bcg
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index 8367929..f7b4ef6 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -155,7 +155,7 @@ void TextMgr::charAttrib_Set(byte foreground, byte background) {
 	} else {
 		// Graphics-mode:
 		switch (_vm->_renderMode) {
-		case RENDERMODE_CGA:
+		case Common::kRenderCGA:
 			// CGA
 			if (background) {
 				_textAttrib.combinedForeground = 3;
diff --git a/engines/agi/view.cpp b/engines/agi/view.cpp
index 66508a6..e9ed169 100644
--- a/engines/agi/view.cpp
+++ b/engines/agi/view.cpp
@@ -321,7 +321,7 @@ void AgiEngine::unpackViewCelData(AgiViewCel *celData, byte *compressedData, uin
 
 	// for CGA rendering, apply dithering
 	switch (_renderMode) {
-	case RENDERMODE_CGA: {
+	case Common::kRenderCGA: {
 		uint16 totalPixels = celData->width * celData->height;
 
 		// dither clear key


Commit: 0c2de081553c3d4a2c0ac83c1bda6c8177ad4718
    https://github.com/scummvm/scummvm/commit/0c2de081553c3d4a2c0ac83c1bda6c8177ad4718
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T16:18:31+01:00

Commit Message:
AGI: new font class created

moved font stuff into GfxFont class
removed Mickey Mouse font data (is loaded from mickey.exe)

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



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 9902d99..3c111fd 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -40,6 +40,7 @@
 #include "audio/mixer.h"
 
 #include "agi/agi.h"
+#include "agi/font.h"
 #include "agi/graphics.h"
 #include "agi/inv.h"
 #include "agi/sprite.h"
@@ -263,9 +264,6 @@ AgiBase::AgiBase(OSystem *syst, const AGIGameDescription *gameDesc) : Engine(sys
 	_rnd = new Common::RandomSource("agi");
 	_sound = 0;
 
-	_fontData = nullptr;
-	_fontDataAllocated = nullptr;
-
 	initFeatures();
 	initVersion();
 }
@@ -274,8 +272,6 @@ AgiBase::~AgiBase() {
 	delete _rnd;
 
 	delete _sound;
-
-	free(_fontDataAllocated);
 }
 
 void AgiBase::initRenderMode() {
@@ -334,351 +330,8 @@ void AgiBase::initRenderMode() {
 	}
 }
 
-void AgiBase::initFont() {
-	// We are currently using the custom font for all fanmade games
-	if (getFeatures() & (GF_FANMADE | GF_AGDS)) {
-		// fanmade game, use custom font for now
-		_fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc.
-		return;
-	}
-
-	switch (_renderMode) {
-	case Common::kRenderAmiga:
-		loadFontAmigaPseudoTopaz();
-		//_fontData = fontData_Amiga; // use Amiga Topaz font
-		break;
-	case Common::kRenderApple2GS:
-		// Special font, stored in file AGIFONT
-		loadFontAppleIIgs();
-		break;
-	case Common::kRenderAtariST:
-		// TODO: Atari ST uses another font
-		// Seems to be the standard Atari ST 8x8 system font
-
-	case Common::kRenderCGA:
-	case Common::kRenderEGA:
-	case Common::kRenderVGA:
-		switch (getGameID()) {
-		case GID_MICKEY:
-			// load mickey mouse font from interpreter file
-			loadFontMickey();
-			break;
-		default:
-			break;
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	if (!_fontData) {
-		// no font asigned?
-		switch (getGameID()) {
-		case GID_MICKEY:
-		case GID_TROLL:
-		case GID_WINNIE:
-			// use IBM font for pre-AGI games as standard
-			_fontData = fontData_IBM;
-			break;
-		default:
-			// for everything else use Sierra PC font
-			_fontData = fontData_Sierra;
-			break;
-		}
-	}
-}
-
-// We load the Mickey Mouse font from MICKEY.EXE
-void AgiBase::loadFontMickey() {
-	Common::File interpreterFile;
-	int32 interpreterFileSize = 0;
-	byte *fontData = nullptr;
-
-	if (!interpreterFile.open("mickey.exe")) {
-		// Continue, if file not found
-		warning("Could not open file 'mickey.exe' for Mickey Mouse font");
-		return;
-	}
-
-	interpreterFileSize = interpreterFile.size();
-	if (interpreterFileSize != 55136) {
-		// unexpected file size
-		interpreterFile.close();
-		warning("File 'mickey.exe': unexpected file size");
-		return;
-	}
-	interpreterFile.seek(32476); // offset of font data
-
-	// allocate space for font bitmap data
-	fontData = (uint8 *)calloc(256, 8);
-	_fontData = fontData;
-	_fontDataAllocated = fontData;
- 
-	// read font data, is already in the format that we need (plain bitmap 8x8)
-	interpreterFile.read(fontData, 256 * 8);
-	interpreterFile.close();
-}
-
-// we create a bitmap out of the topaz data used in parallaction (which is normally found in staticres.cpp)
-// it's a recreation of the Amiga Topaz font but not really accurate
-void AgiBase::loadFontAmigaPseudoTopaz() {
-	const byte *topazStart = fontData_AmigaPseudoTopaz + 32;
-	const byte *topazHeader = topazStart + 78;
-	const byte *topazData = nullptr;
-	const byte *topazLocations = nullptr;
-	byte *fontData = nullptr;
-	uint16 topazHeight = 0;
-	uint16 topazWidth = 0;
-	uint16 topazModulo = 0;
-	uint32 topazDataOffset = 0;
-	uint32 topazLocationOffset = 0;
-	byte   topazLowChar = 0;
-	byte   topazHighChar = 0;
-	uint16 topazTotalChars = 0;
-	uint16 topazBitLength = 0;
-	uint16 topazBitOffset = 0;
-	uint16 topazByteOffset = 0;
-
-	// allocate space for font bitmap data
-	fontData = (uint8 *)calloc(256, 8);
-	_fontData = fontData;
-	_fontDataAllocated = fontData;
-
-	topazHeight = READ_BE_UINT16(topazHeader + 0);
-	topazWidth = READ_BE_UINT16(topazHeader + 4);
-
-	// we expect 8x8
-	assert(topazHeight == 8);
-	assert(topazWidth == 8);
-
-	topazLowChar = topazHeader[12];
-	topazHighChar = topazHeader[13];
-	topazTotalChars = topazHighChar - topazLowChar + 1;
-	topazDataOffset = READ_BE_UINT32(topazHeader + 14);
-	topazModulo = READ_BE_UINT16(topazHeader + 18);
-	topazLocationOffset = READ_BE_UINT32(topazHeader + 20);
-
-	// Security checks
-	assert(topazLowChar == ' ');
-	assert(topazHighChar == 0xFF);
-
-	// copy first 32 characters over
-	memcpy(fontData, fontData_Sierra, FONT_DISPLAY_WIDTH * 32);
-	fontData += FONT_DISPLAY_WIDTH * 32;
-
-	// now actually convert from topaz data
-	topazData = topazStart + topazDataOffset;
-	topazLocations = topazStart + topazLocationOffset;
-
-	for (uint16 curChar = 0; curChar < topazTotalChars; curChar++) {
-		topazBitOffset = READ_BE_UINT16(topazLocations + (curChar * 4) + 0);
-		topazBitLength = READ_BE_UINT16(topazLocations + (curChar * 4) + 2);
-
-		if (topazBitLength == 8) {
-			assert((topazBitOffset & 7) == 0);
-
-			topazByteOffset = topazBitOffset >> 3;
-			for (uint16 curHeight = 0; curHeight < topazHeight; curHeight++) {
-				*fontData = topazData[topazByteOffset];
-				fontData++;
-				topazByteOffset += topazModulo;
-			}
-		} else {
-			memset(fontData, 0, 8);
-			fontData += 8;
-		}
-	}
-}
-
-void AgiBase::loadFontAppleIIgs() {
-	Common::File fontFile;
-	uint16 headerIIgs_OffsetMacHeader = 0;
-	uint16 headerIIgs_Version = 0;
-	uint16 macRecord_FirstChar = 0;
-	uint16 macRecord_LastChar = 0;
-	int16 macRecord_MaxKern = 0;
-	uint16 macRecord_RectHeight = 0;
-	uint16 macRecord_StrikeWidth = 0;
-	uint16 strikeDataLen = 0;
-	byte *strikeDataPtr = nullptr;
-	uint16 actualCharacterCount = 0;
-	uint16 totalCharacterCount = 0;
-	uint16 *locationTablePtr = nullptr;
-	uint16 *offsetWidthTablePtr = nullptr;
-
-	uint16 curCharNr = 0;
-	uint16 curRow = 0;
-	uint16 curLocation = 0;
-	uint16 curLocationBytes = 0;
-	uint16 curLocationBits = 0;
-	uint16 curCharOffsetWidth = 0;
-	uint16 curCharOffset = 0;
-	uint16 curCharWidth = 0;
-	uint16 curStrikeWidth = 0;
-
-	uint16 curPixelNr = 0;
-	uint16 curBitMask = 0;
-	int16 positionAdjust = 0;
-	byte curByte = 0;
-	byte fontByte = 0;
-
-	uint16 strikeRowOffset = 0;
-	uint16 strikeCurOffset = 0;
-
-	byte *fontData = nullptr;
-
-	if (!fontFile.open("agifont")) {
-		// Continue,
-		// This also happens when the user selected Apple IIgs as render for the palette for non-AppleIIgs games
-		warning("Could not open file 'agifont' for Apple IIgs font");
-		return;
-	}
-
-	// Apple IIgs header
-	headerIIgs_OffsetMacHeader = fontFile.readUint16LE();
-	fontFile.skip(2); // font family
-	fontFile.skip(2); // font style
-	fontFile.skip(2); // point size
-	headerIIgs_Version = fontFile.readUint16LE();
-	fontFile.skip(2); // bounds type
-	// end of Apple IIgs header
-	// Macintosh font record
-	fontFile.skip(2); // font type
-	macRecord_FirstChar = fontFile.readUint16LE();
-	macRecord_LastChar = fontFile.readUint16LE();
-	fontFile.skip(2); // max width
-	macRecord_MaxKern = fontFile.readSint16LE();
-	fontFile.skip(2); // negative descent
-	fontFile.skip(2); // rect width
-	macRecord_RectHeight = fontFile.readUint16LE();
-	fontFile.skip(2); // low word ptr table
-	fontFile.skip(2); // font ascent
-	fontFile.skip(2); // font descent
-	fontFile.skip(2); // leading
-	macRecord_StrikeWidth = fontFile.readUint16LE();
-
-	// security-checks
-	if (headerIIgs_OffsetMacHeader != 6)
-		error("AppleIIgs-font: unexpected header");
-	if (headerIIgs_Version != 0x0101)
-		error("AppleIIgs-font: not a 1.1 font");
-	if ((macRecord_FirstChar != 0) || (macRecord_LastChar != 255))
-		error("AppleIIgs-font: unexpected characters");
-	if (macRecord_RectHeight != 8)
-		error("AppleIIgs-font: expected 8x8 font");
-
-	// Calculate table sizes
-	strikeDataLen = macRecord_StrikeWidth * macRecord_RectHeight * 2;
-	actualCharacterCount = (macRecord_LastChar - macRecord_FirstChar + 1);
-	totalCharacterCount = actualCharacterCount + 2; // replacement-char + extra character
-
-	// Allocate memory for tables
-	strikeDataPtr = (byte *)calloc(strikeDataLen, 1);
-	locationTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // 1 word per character
-	offsetWidthTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // ditto
-
-	// read tables
-	fontFile.read(strikeDataPtr, strikeDataLen);
-	for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
-		locationTablePtr[curCharNr] = fontFile.readUint16LE();
-	}
-	for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
-		offsetWidthTablePtr[curCharNr] = fontFile.readUint16LE();
-	}
-	fontFile.close();
-
-	// allocate space for font bitmap data
-	fontData = (uint8 *)calloc(256, 8);
-	_fontData = fontData;
-	_fontDataAllocated = fontData;
-
-	// extract font bitmap data
-	for (curCharNr = 0; curCharNr < actualCharacterCount; curCharNr++) {
-		curCharOffsetWidth = offsetWidthTablePtr[curCharNr];
-		curLocation = locationTablePtr[curCharNr];
-		if (curCharOffsetWidth == 0xFFFF) {
-			// character does not exist in font, use replacement character instead
-			curCharOffsetWidth = offsetWidthTablePtr[actualCharacterCount];
-			curLocation = locationTablePtr[actualCharacterCount];
-			curStrikeWidth = locationTablePtr[actualCharacterCount + 1] - curLocation;
-		} else {
-			curStrikeWidth = locationTablePtr[curCharNr + 1] - curLocation;
-		}
-
-		// Figure out bytes + bits location
-		curLocationBytes = curLocation >> 3;
-		curLocationBits = curLocation & 0x0007;
-		curCharWidth = curCharOffsetWidth & 0x00FF; // isolate width
-		curCharOffset = curCharOffsetWidth >> 8; // isolate offset
-
-		if (!curCharWidth) {
-			fontData += 8; // skip over this character
-			continue;
-		}
-
-		if (curCharWidth != 8) {
-			if (curCharNr != 0x3B)
-				error("AppleIIgs-font: expected 8x8 font");
-		}
-
-		// Get all rows of the current character
-		strikeRowOffset = 0;
-		for (curRow = 0; curRow < macRecord_RectHeight; curRow++) {
-			strikeCurOffset = strikeRowOffset + curLocationBytes;
-
-			// Copy over bits
-			fontByte = 0;
-			curByte = strikeDataPtr[strikeCurOffset];
-			curBitMask = 0x80 >> curLocationBits;
-
-			for (curPixelNr = 0; curPixelNr < curStrikeWidth; curPixelNr++) {
-				fontByte = fontByte << 1;
-				if (curByte & curBitMask) {
-					fontByte |= 0x01;
-				}
-				curBitMask = curBitMask >> 1;
-				if (!curBitMask) {
-					curByte = strikeDataPtr[strikeCurOffset + 1];
-					curBitMask = 0x80;
-				}
-			}
-
-			// adjust, so that it's aligned to the left (starting at 0x80 bit)
-			fontByte = fontByte << (8 - curStrikeWidth);
-
-			// now adjust according to offset + MaxKern
-			positionAdjust = macRecord_MaxKern + curCharOffset;
-
-			// adjust may be negative for space, or 8 for "empty" characters
-			if (positionAdjust > 8)
-				error("AppleIIgs-font: invalid character spacing");
-
-			if (positionAdjust < 0) {
-				// negative adjust strangely happens for empty characters like space
-				if (curStrikeWidth)
-					error("AppleIIgs-font: invalid character spacing");
-			}
-
-			if (positionAdjust > 0) {
-				// move the amount of pixels to the right
-				fontByte = fontByte >> positionAdjust;
-			}
-
-			*fontData = fontByte;
-			fontData++;
-
-			strikeRowOffset += macRecord_StrikeWidth * 2;
-		}
-	}
-
-	free(offsetWidthTablePtr);
-	free(locationTablePtr);
-	free(strikeDataPtr);
-
-	// overwrite character 0x1A with the standard Sierra arrow to the right character
-	// required for the original save/restore dialogs
-	memcpy(_fontDataAllocated + (0x1A * 8), fontData_ArrowRightCharacter, sizeof(fontData_ArrowRightCharacter));
+const byte *AgiBase::getFontData() {
+	return _font->getFontData();
 }
 
 AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBase(syst, gameDesc) {
@@ -711,9 +364,6 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
 		_game.mouseHidden = true;
 	}
 
-	_fontData = nullptr;
-	_fontDataAllocated = nullptr;
-
 	_game._vm = this;
 
 	_game.gfxMode = true;
@@ -797,10 +447,10 @@ void AgiEngine::initialize() {
 	}
 
 	initRenderMode();
-	initFont();
 
 	_console = new Console(this);
 	_words = new Words(this);
+	_font = new GfxFont(this);
 	_gfx = new GfxMgr(this);
 	_sound = new SoundMgr(this, _mixer);
 	_picture = new PictureMgr(this, _gfx);
@@ -809,6 +459,7 @@ void AgiEngine::initialize() {
 	_systemUI = new SystemUI(this, _gfx, _text);
 	_inventory = new InventoryMgr(this, _gfx, _text, _systemUI);
 
+	_font->init();
 	_text->init(_systemUI);
 
 	_gfx->initMachine();
@@ -883,6 +534,7 @@ AgiEngine::~AgiEngine() {
 	delete _picture;
 	_gfx->deinitMachine();
 	delete _gfx;
+	delete _font;
 	delete _words;
 	delete _console;
 }
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index a070d5e..f82e6ae 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -592,7 +592,7 @@ public:
 	virtual int loadWords(const char *);
 };
 
-
+class GfxFont;
 class GfxMgr;
 class SpritesMgr;
 class InventoryMgr;
@@ -642,19 +642,12 @@ protected:
 	virtual void initialize() = 0;
 
 	void initRenderMode();
-	void initFont();
-
-	void loadFontMickey();
-	void loadFontAmigaPseudoTopaz();
-	void loadFontAppleIIgs();
-
-	const uint8 *_fontData; // pointer to the currently used font
-	uint8 *_fontDataAllocated;
 
 public:
 	Words *_words;
 
-	GfxMgr *_gfx;
+	GfxFont *_font;
+	GfxMgr  *_gfx;
 
 	Common::RenderMode _renderMode;
 	volatile uint32 _clockCount;
@@ -715,7 +708,7 @@ public:
 	bool canLoadGameStateCurrently();
 	bool canSaveGameStateCurrently();
 
-	const uint8 *getFontData() { return _fontData; };
+	const byte *getFontData();
 
 	void cycleInnerLoopActive(int16 loopType) {
 		_game.cycleInnerLoopActive = true;
diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
new file mode 100644
index 0000000..0a6ac54
--- /dev/null
+++ b/engines/agi/font.cpp
@@ -0,0 +1,1346 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "agi/agi.h"
+#include "agi/font.h"
+#include "agi/text.h"
+
+namespace Agi {
+
+GfxFont::GfxFont(AgiBase *vm) {
+	_vm = vm;
+
+	_fontData = nullptr;
+	_fontDataAllocated = nullptr;
+}
+
+GfxFont::~GfxFont() {
+	free(_fontDataAllocated);
+}
+
+// Arrow to the right character, used for original saved game dialogs
+// Needs to get patched into at least the Apple IIgs font, because the font didn't support
+// that character and original AGI on Apple IIgs used Apple II menus for saving/restoring.
+static const uint8 fontData_ArrowRightCharacter[8] = {
+	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
+};
+
+// topaz data, same as in engines/parallaction/staticres.cpp
+// seems to have been recreated and is not the original amiga font
+static const uint8 fontData_AmigaPseudoTopaz[2600] = {
+	0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79,
+	0x70, 0xff, 0x4e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
+	0x00, 0x1a, 0x0f, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x45, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x74, 0x00, 0x08,
+	0x00, 0x40, 0x00, 0x08, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x00, 0x6e,
+	0x00, 0xbe, 0x00, 0x00, 0x06, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
+	0x6c, 0x6c, 0x18, 0x00, 0x38, 0x18, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x18,
+	0x3c, 0x3c, 0x1c, 0x7e, 0x1c, 0x7e, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7c, 0x3c,
+	0x7c, 0x1e, 0x78, 0x7e, 0x7e, 0x3c, 0x66, 0x3c, 0x06, 0xc6, 0x60, 0xc6, 0xc6, 0x3c, 0x7c, 0x78,
+	0x7c, 0x3c, 0x7e, 0x66, 0x66, 0xc6, 0xc3, 0xc3, 0xfe, 0x3c, 0xc0, 0x3c, 0x10, 0x00, 0x18, 0x00,
+	0x60, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x60, 0x18, 0x0c, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x18, 0x70, 0x72, 0x0f, 0x00, 0x18,
+	0x00, 0x1c, 0x42, 0xc3, 0x18, 0x3c, 0x66, 0x7e, 0x1c, 0x00, 0x3e, 0x7e, 0x7e, 0x3c, 0x18, 0x78,
+	0x78, 0x18, 0x00, 0x3e, 0x00, 0x00, 0x30, 0x38, 0x00, 0x40, 0x40, 0xc0, 0x18, 0x3c, 0x3c, 0x7e,
+	0x06, 0x66, 0x18, 0x7e, 0x7e, 0x36, 0x0c, 0x0c, 0x18, 0x3c, 0xc6, 0x3c, 0x60, 0x76, 0x18, 0x00,
+	0x0c, 0x7e, 0x71, 0x66, 0x00, 0x66, 0x60, 0x0e, 0x7e, 0x66, 0x18, 0x6e, 0x3c, 0x00, 0x18, 0x7e,
+	0x06, 0x66, 0x18, 0x00, 0x7e, 0x34, 0x0c, 0x0c, 0x18, 0x0c, 0x60, 0x00, 0x18, 0x3c, 0x0c, 0x00,
+	0x0c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x7e, 0x00, 0x18, 0x3c, 0x00, 0x18, 0x6c, 0x6c,
+	0x3e, 0x66, 0x6c, 0x18, 0x18, 0x18, 0x66, 0x18, 0x00, 0x00, 0x00, 0x06, 0x66, 0x38, 0x66, 0x66,
+	0x3c, 0x60, 0x30, 0x06, 0x66, 0x66, 0x18, 0x18, 0x06, 0x00, 0x60, 0x66, 0xc6, 0x66, 0x66, 0x30,
+	0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x06, 0xcc, 0x60, 0xee, 0xe6, 0x66, 0x66, 0xcc, 0x66, 0x66,
+	0x18, 0x66, 0x66, 0xc6, 0x66, 0x66, 0x0c, 0x30, 0x60, 0x0c, 0x38, 0x00, 0x18, 0x00, 0x60, 0x00,
+	0x06, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x9c, 0x3c, 0x7e, 0x00, 0x0c, 0x36,
+	0x3c, 0x66, 0x18, 0x60, 0x66, 0x81, 0x24, 0x33, 0x06, 0x81, 0x00, 0x66, 0x18, 0x0c, 0x0c, 0x30,
+	0x00, 0x7a, 0x00, 0x00, 0x70, 0x44, 0xcc, 0xc6, 0xc6, 0x23, 0x00, 0x66, 0x18, 0x00, 0x1c, 0x00,
+	0x24, 0x60, 0x00, 0x1c, 0x18, 0x18, 0x00, 0x66, 0xcc, 0x00, 0x60, 0x3c, 0x30, 0xc6, 0x18, 0x00,
+	0x8e, 0x00, 0xc6, 0x66, 0x60, 0x38, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x0c, 0x00,
+	0x24, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x7e,
+	0x8e, 0x66, 0x18, 0x00, 0x18, 0x18, 0x00, 0x66, 0x00, 0x18, 0x00, 0x18, 0x00, 0xfe, 0x60, 0xac,
+	0x68, 0x30, 0x30, 0x0c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x78, 0x06, 0x06, 0x6c, 0x7c,
+	0x60, 0x06, 0x66, 0x66, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x06, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60,
+	0x60, 0x60, 0x66, 0x18, 0x06, 0xd8, 0x60, 0xfe, 0xf6, 0x66, 0x66, 0xcc, 0x66, 0x70, 0x18, 0x66,
+	0x66, 0xc6, 0x3c, 0x3c, 0x18, 0x30, 0x30, 0x0c, 0x6c, 0x00, 0x0c, 0x3c, 0x7c, 0x3c, 0x3e, 0x3c,
+	0x7c, 0x3e, 0x7c, 0x18, 0x0c, 0x66, 0x18, 0xec, 0x7c, 0x3c, 0x7c, 0x3e, 0x7c, 0x3c, 0x7c, 0x66,
+	0x66, 0xc6, 0xc6, 0x66, 0x7e, 0x18, 0x18, 0x18, 0x00, 0xf0, 0x66, 0x18, 0x3e, 0x30, 0x66, 0x3c,
+	0x18, 0x3c, 0x00, 0x9d, 0x44, 0x66, 0x00, 0xb9, 0x00, 0x3c, 0x7e, 0x18, 0x18, 0x60, 0x66, 0x7a,
+	0x18, 0x00, 0x30, 0x44, 0x66, 0x4c, 0x4c, 0x66, 0x18, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x60,
+	0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x60, 0xd8, 0x3c, 0x60, 0x66, 0xc6, 0xe6, 0x3c, 0x3c, 0x3c, 0x3c,
+	0x6c, 0x66, 0x6c, 0x66, 0x66, 0x66, 0x7e, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0x3c, 0x3c, 0x3c,
+	0x3c, 0x18, 0x3c, 0x7e, 0x3c, 0x3e, 0x6c, 0x00, 0x18, 0x3c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x66, 0x1e, 0x3c, 0x66, 0x00, 0x7e, 0x7e, 0x00, 0x18, 0x00, 0x6c, 0x3c, 0xd8, 0x76, 0x00,
+	0x30, 0x0c, 0xff, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x7e, 0x18, 0x0c, 0x1c, 0xcc, 0x06, 0x7c, 0x0c,
+	0x3c, 0x3e, 0x00, 0x00, 0x60, 0x00, 0x06, 0x0c, 0xd6, 0x7e, 0x7c, 0x60, 0x66, 0x78, 0x78, 0x6e,
+	0x7e, 0x18, 0x06, 0xf0, 0x60, 0xd6, 0xde, 0x66, 0x7c, 0xcc, 0x7c, 0x3c, 0x18, 0x66, 0x66, 0xd6,
+	0x18, 0x18, 0x30, 0x30, 0x18, 0x0c, 0xc6, 0x00, 0x00, 0x06, 0x66, 0x60, 0x66, 0x66, 0x30, 0x66,
+	0x66, 0x18, 0x0c, 0x6c, 0x18, 0xfe, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x30, 0x66, 0x66, 0xc6,
+	0x6c, 0x66, 0x0c, 0x70, 0x18, 0x0e, 0x00, 0xc3, 0x66, 0x18, 0x6c, 0x78, 0x3c, 0x18, 0x00, 0x66,
+	0x00, 0xb1, 0x3c, 0xcc, 0x00, 0xa5, 0x00, 0x00, 0x18, 0x30, 0x0c, 0x00, 0x66, 0x3a, 0x18, 0x00,
+	0x30, 0x38, 0x33, 0x58, 0x58, 0x2c, 0x30, 0x7e, 0x18, 0x66, 0x66, 0x66, 0x66, 0x78, 0x60, 0x66,
+	0x60, 0x4c, 0x60, 0x6e, 0xf0, 0x18, 0x60, 0x30, 0xe6, 0xf6, 0x66, 0x66, 0x66, 0x66, 0x38, 0x66,
+	0x70, 0x30, 0x66, 0x66, 0x4c, 0x4c, 0x6c, 0x06, 0x18, 0x06, 0x3c, 0x06, 0x06, 0x66, 0x66, 0x3c,
+	0x66, 0x0c, 0x66, 0x66, 0x78, 0x18, 0x18, 0x60, 0x7c, 0x66, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x66,
+	0x78, 0x60, 0x66, 0x66, 0x0c, 0x0c, 0x00, 0x18, 0x00, 0xfe, 0x06, 0x36, 0xdc, 0x00, 0x30, 0x0c,
+	0x3c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x76, 0x18, 0x18, 0x06, 0xfe, 0x06, 0x66, 0x18, 0x66, 0x06,
+	0x00, 0x00, 0x18, 0x7e, 0x18, 0x18, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60, 0x60, 0x66, 0x66, 0x18,
+	0x06, 0xd8, 0x60, 0xc6, 0xce, 0x66, 0x60, 0xcc, 0x6c, 0x0e, 0x18, 0x66, 0x3c, 0xfe, 0x3c, 0x18,
+	0x60, 0x30, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x60, 0x66, 0x7e, 0x30, 0x66, 0x66, 0x18,
+	0x0c, 0x78, 0x18, 0xd6, 0x66, 0x66, 0x66, 0x66, 0x60, 0x3c, 0x30, 0x66, 0x66, 0xd6, 0x38, 0x66,
+	0x18, 0x18, 0x18, 0x18, 0x00, 0x0f, 0x66, 0x18, 0x3e, 0x30, 0x42, 0x3c, 0x18, 0x3c, 0x00, 0x9d,
+	0x00, 0x66, 0x00, 0xb9, 0x00, 0x00, 0x18, 0x7c, 0x78, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x30, 0x00,
+	0x66, 0x32, 0x3e, 0xd9, 0x60, 0x66, 0x18, 0x7e, 0x40, 0x7e, 0x7e, 0x60, 0x78, 0x40, 0x78, 0x18,
+	0x78, 0x66, 0xd8, 0x18, 0x60, 0x0c, 0xf6, 0xde, 0x66, 0x66, 0x66, 0x66, 0x6c, 0x66, 0xe0, 0x0c,
+	0x66, 0x66, 0x18, 0x18, 0x66, 0x3e, 0x18, 0x3e, 0x60, 0x3e, 0x3e, 0x7e, 0x7e, 0x60, 0x7e, 0x18,
+	0x7e, 0x66, 0x6c, 0x18, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x18, 0x3c,
+	0x66, 0x66, 0x18, 0x18, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x6a, 0xce, 0x00, 0x18, 0x18, 0x66, 0x18,
+	0x18, 0x00, 0x18, 0x60, 0x66, 0x18, 0x30, 0x66, 0x0c, 0x66, 0x66, 0x18, 0x66, 0x0c, 0x18, 0x18,
+	0x06, 0x00, 0x60, 0x00, 0xc0, 0x66, 0x66, 0x30, 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x66, 0xcc,
+	0x60, 0xc6, 0xc6, 0x66, 0x60, 0xdc, 0x66, 0x66, 0x18, 0x66, 0x3c, 0xee, 0x66, 0x18, 0xc0, 0x30,
+	0x06, 0x0c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x60, 0x66, 0x60, 0x30, 0x3e, 0x66, 0x18, 0x0c, 0x6c,
+	0x18, 0xc6, 0x66, 0x66, 0x7c, 0x3e, 0x60, 0x06, 0x30, 0x66, 0x3c, 0xfe, 0x6c, 0x3c, 0x30, 0x18,
+	0x18, 0x18, 0x00, 0x3c, 0x66, 0x18, 0x0c, 0x30, 0x00, 0x18, 0x18, 0x06, 0x00, 0x81, 0x7e, 0x33,
+	0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x00, 0x7c, 0xcc, 0x66,
+	0x62, 0x33, 0x66, 0x66, 0x18, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0x66, 0x60, 0x32, 0x60, 0x3e,
+	0xcc, 0x18, 0x7e, 0x66, 0xde, 0xce, 0x66, 0x66, 0x66, 0x66, 0xc6, 0x66, 0x60, 0x66, 0x66, 0x66,
+	0x32, 0x32, 0x66, 0x66, 0x18, 0x66, 0x60, 0x66, 0x66, 0x60, 0x60, 0x60, 0x60, 0x30, 0x60, 0x3e,
+	0x66, 0x18, 0x18, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x18, 0x66, 0x18, 0x06, 0x66, 0x66,
+	0x30, 0x30, 0x00, 0x18, 0x00, 0x6c, 0x18, 0xcc, 0x7b, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x18, 0x00,
+	0x18, 0xc0, 0x3c, 0x18, 0x7e, 0x3c, 0x0c, 0x3c, 0x3c, 0x18, 0x3c, 0x38, 0x18, 0x18, 0x00, 0x00,
+	0x00, 0x18, 0x78, 0x66, 0x7c, 0x1e, 0x78, 0x7e, 0x60, 0x3e, 0x66, 0x3c, 0x3c, 0xc6, 0x7e, 0xc6,
+	0xc6, 0x3c, 0x60, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0xc6, 0xc3, 0x18, 0xfe, 0x3c, 0x03, 0x3c,
+	0x00, 0x00, 0x00, 0x3e, 0x7c, 0x3c, 0x3e, 0x3c, 0x30, 0x06, 0x66, 0x0c, 0x0c, 0x66, 0x0c, 0xc6,
+	0x66, 0x3c, 0x60, 0x06, 0x60, 0x7c, 0x1c, 0x3e, 0x18, 0x6c, 0xc6, 0x18, 0x7e, 0x0e, 0x18, 0x70,
+	0x00, 0xf0, 0x7e, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x3c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x81,
+	0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00, 0xcf, 0xc4, 0x67,
+	0x3c, 0x67, 0x3e, 0x66, 0x3c, 0x66, 0x66, 0x7f, 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x18, 0x30, 0x3c,
+	0x18, 0x3c, 0xce, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x7e, 0x3c, 0x3c, 0x3c, 0x7e, 0x7e,
+	0x6c, 0x3f, 0x1e, 0x3e, 0x3c, 0x3e, 0x3e, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x3c, 0x06, 0x18, 0x0c,
+	0x0c, 0x7c, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x0c, 0x7c, 0x3e, 0x3e, 0x7e, 0x7e,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x01, 0x00, 0x03,
+	0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x00, 0x30, 0x00,
+	0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03,
+	0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x18, 0x00,
+	0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x18, 0x00, 0x08, 0x00, 0x20,
+	0x00, 0x08, 0x00, 0x28, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x00, 0x40,
+	0x00, 0x08, 0x00, 0x48, 0x00, 0x08, 0x00, 0x50, 0x00, 0x08, 0x00, 0x58, 0x00, 0x08, 0x00, 0x60,
+	0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x00, 0x70, 0x00, 0x08, 0x00, 0x78, 0x00, 0x08, 0x00, 0x80,
+	0x00, 0x08, 0x00, 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0x98, 0x00, 0x08, 0x00, 0xa0,
+	0x00, 0x08, 0x00, 0xa8, 0x00, 0x08, 0x00, 0xb0, 0x00, 0x08, 0x00, 0xb8, 0x00, 0x08, 0x00, 0xc0,
+	0x00, 0x08, 0x00, 0xc8, 0x00, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x00, 0xd8, 0x00, 0x08, 0x00, 0xe0,
+	0x00, 0x08, 0x00, 0xe8, 0x00, 0x08, 0x00, 0xf0, 0x00, 0x08, 0x00, 0xf8, 0x00, 0x08, 0x01, 0x00,
+	0x00, 0x08, 0x01, 0x08, 0x00, 0x08, 0x01, 0x10, 0x00, 0x08, 0x01, 0x18, 0x00, 0x08, 0x01, 0x20,
+	0x00, 0x08, 0x01, 0x28, 0x00, 0x08, 0x01, 0x30, 0x00, 0x08, 0x01, 0x38, 0x00, 0x08, 0x01, 0x40,
+	0x00, 0x08, 0x01, 0x48, 0x00, 0x08, 0x01, 0x50, 0x00, 0x08, 0x01, 0x58, 0x00, 0x08, 0x01, 0x60,
+	0x00, 0x08, 0x01, 0x68, 0x00, 0x08, 0x01, 0x70, 0x00, 0x08, 0x01, 0x78, 0x00, 0x08, 0x01, 0x80,
+	0x00, 0x08, 0x01, 0x88, 0x00, 0x08, 0x01, 0x90, 0x00, 0x08, 0x01, 0x98, 0x00, 0x08, 0x01, 0xa0,
+	0x00, 0x08, 0x01, 0xa8, 0x00, 0x08, 0x01, 0xb0, 0x00, 0x08, 0x01, 0xb8, 0x00, 0x08, 0x01, 0xc0,
+	0x00, 0x08, 0x01, 0xc8, 0x00, 0x08, 0x01, 0xd0, 0x00, 0x08, 0x01, 0xd8, 0x00, 0x08, 0x01, 0xe0,
+	0x00, 0x08, 0x01, 0xe8, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xf8, 0x00, 0x08, 0x02, 0x00,
+	0x00, 0x08, 0x02, 0x08, 0x00, 0x08, 0x02, 0x10, 0x00, 0x08, 0x02, 0x18, 0x00, 0x08, 0x02, 0x20,
+	0x00, 0x08, 0x02, 0x28, 0x00, 0x08, 0x02, 0x30, 0x00, 0x08, 0x02, 0x38, 0x00, 0x08, 0x02, 0x40,
+	0x00, 0x08, 0x02, 0x48, 0x00, 0x08, 0x02, 0x50, 0x00, 0x08, 0x02, 0x58, 0x00, 0x08, 0x02, 0x60,
+	0x00, 0x08, 0x02, 0x68, 0x00, 0x08, 0x02, 0x70, 0x00, 0x08, 0x02, 0x78, 0x00, 0x08, 0x02, 0x80,
+	0x00, 0x08, 0x02, 0x88, 0x00, 0x08, 0x02, 0x90, 0x00, 0x08, 0x02, 0x98, 0x00, 0x08, 0x02, 0xa0,
+	0x00, 0x08, 0x02, 0xa8, 0x00, 0x08, 0x02, 0xb0, 0x00, 0x08, 0x02, 0xb8, 0x00, 0x08, 0x02, 0xc0,
+	0x00, 0x08, 0x02, 0xc8, 0x00, 0x08, 0x02, 0xd0, 0x00, 0x08, 0x02, 0xd8, 0x00, 0x08, 0x02, 0xe0,
+	0x00, 0x08, 0x02, 0xe8, 0x00, 0x08, 0x02, 0xf0, 0x00, 0x08, 0x02, 0xf8, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00,
+	0x00, 0x08, 0x03, 0x08, 0x00, 0x08, 0x03, 0x10, 0x00, 0x08, 0x03, 0x18, 0x00, 0x08, 0x03, 0x20,
+	0x00, 0x08, 0x03, 0x28, 0x00, 0x08, 0x03, 0x30, 0x00, 0x08, 0x03, 0x38, 0x00, 0x08, 0x03, 0x40,
+	0x00, 0x08, 0x03, 0x48, 0x00, 0x08, 0x03, 0x50, 0x00, 0x08, 0x03, 0x58, 0x00, 0x08, 0x03, 0x60,
+	0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x03, 0x68, 0x00, 0x08, 0x03, 0x70, 0x00, 0x08, 0x03, 0x78,
+	0x00, 0x08, 0x03, 0x80, 0x00, 0x08, 0x03, 0x88, 0x00, 0x08, 0x03, 0x90, 0x00, 0x08, 0x03, 0x98,
+	0x00, 0x08, 0x03, 0xa0, 0x00, 0x08, 0x03, 0xa8, 0x00, 0x08, 0x03, 0xb0, 0x00, 0x08, 0x03, 0xb8,
+	0x00, 0x08, 0x03, 0xc0, 0x00, 0x08, 0x03, 0xc8, 0x00, 0x08, 0x03, 0xd0, 0x00, 0x08, 0x03, 0xd8,
+	0x00, 0x08, 0x03, 0xe0, 0x00, 0x08, 0x03, 0xe8, 0x00, 0x08, 0x03, 0xf0, 0x00, 0x08, 0x03, 0xf8,
+	0x00, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x08, 0x00, 0x08, 0x04, 0x10, 0x00, 0x08, 0x04, 0x18,
+	0x00, 0x08, 0x04, 0x20, 0x00, 0x08, 0x04, 0x28, 0x00, 0x08, 0x04, 0x30, 0x00, 0x08, 0x04, 0x38,
+	0x00, 0x08, 0x04, 0x40, 0x00, 0x08, 0x04, 0x48, 0x00, 0x08, 0x04, 0x50, 0x00, 0x08, 0x04, 0x58,
+	0x00, 0x08, 0x04, 0x60, 0x00, 0x08, 0x04, 0x68, 0x00, 0x08, 0x04, 0x70, 0x00, 0x08, 0x04, 0x78,
+	0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04, 0x88, 0x00, 0x08, 0x04, 0x90, 0x00, 0x08, 0x04, 0x98,
+	0x00, 0x08, 0x04, 0xa0, 0x00, 0x08, 0x04, 0xa8, 0x00, 0x08, 0x04, 0xb0, 0x00, 0x08, 0x04, 0xb8,
+	0x00, 0x08, 0x04, 0xc0, 0x00, 0x08, 0x04, 0xc8, 0x00, 0x08, 0x04, 0xd0, 0x00, 0x08, 0x04, 0xd8,
+	0x00, 0x08, 0x04, 0xe0, 0x00, 0x08, 0x04, 0xe8, 0x00, 0x08, 0x04, 0xf0, 0x00, 0x08, 0x04, 0xf8,
+	0x00, 0x08, 0x05, 0x00, 0x00, 0x08, 0x05, 0x08, 0x00, 0x08, 0x05, 0x10, 0x00, 0x08, 0x05, 0x18,
+	0x00, 0x08, 0x05, 0x20, 0x00, 0x08, 0x05, 0x28, 0x00, 0x08, 0x05, 0x30, 0x00, 0x08, 0x05, 0x38,
+	0x00, 0x08, 0x05, 0x40, 0x00, 0x08, 0x05, 0x48, 0x00, 0x08, 0x05, 0x50, 0x00, 0x08, 0x05, 0x58,
+	0x00, 0x08, 0x05, 0x60, 0x00, 0x08, 0x05, 0x68, 0x00, 0x08, 0x05, 0x70, 0x00, 0x08, 0x05, 0x78,
+	0x00, 0x08, 0x05, 0x80, 0x00, 0x08, 0x05, 0x88, 0x00, 0x08, 0x05, 0x90, 0x00, 0x08, 0x05, 0x98,
+	0x00, 0x08, 0x05, 0xa0, 0x00, 0x08, 0x05, 0xa8, 0x00, 0x08, 0x05, 0xb0, 0x00, 0x08, 0x05, 0xb8,
+	0x00, 0x08, 0x05, 0xc0, 0x00, 0x08, 0x05, 0xc8, 0x00, 0x08, 0x05, 0xd0, 0x00, 0x08, 0x05, 0xd8,
+	0x00, 0x08, 0x05, 0xe0, 0x00, 0x08, 0x05, 0xe8, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x03, 0x00,
+	0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf2
+};
+
+// 8x8 font patterns
+static const uint8 fontData_Sierra[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E,	// cursor hollow
+	0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,	// cursor solid
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// cursor empty
+	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+	0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00,
+	0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00,
+	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
+	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
+	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// \n
+	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
+	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
+	0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00,
+	0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C,
+	0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00,
+	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
+	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
+	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00,
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+	0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00,
+	0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
+	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
+	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E,
+	0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00,
+	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
+	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
+	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
+	0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00,
+	0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00,
+	0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00,
+	// original sierra font starts here
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 Space
+	0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+	0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
+	0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
+	0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
+	0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
+	0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
+	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+	0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
+	0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30
+	0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
+	0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
+	0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
+	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
+	0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
+	0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
+	0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
+	0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
+	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+	0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
+	0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
+	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
+	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
+	0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40
+	0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
+	0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
+	0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
+	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
+	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
+	0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
+	0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
+	0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
+	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
+	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
+	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
+	0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50
+	0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
+	0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
+	0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
+	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+	0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
+	0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
+	0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
+	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
+	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
+	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
+	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
+	0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
+	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
+	0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+	0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
+	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
+	0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
+	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
+	0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+	0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
+	0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70
+	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
+	0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
+	0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
+	0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+	0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
+	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
+	0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
+	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+	0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
+	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	// custom font starting here at 0x80
+	0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80
+	0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
+	0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
+	0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
+	0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
+	0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+	0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
+	0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
+	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
+	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
+	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
+	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
+	0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
+	0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+	0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
+	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
+	0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
+	0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
+	0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
+	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
+	0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
+	0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+	0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+	0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+	0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
+	0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
+	0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+	0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+	0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
+	0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
+	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
+	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
+	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+	0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
+	0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
+	0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
+	0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
+	0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
+	0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
+	0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
+	0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
+	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
+	0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
+	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
+	0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
+	0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
+	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
+	0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
+};
+
+static const uint8 fontData_FanGames[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E,	/* cursor hollow */
+	0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,	/* cursor solid */
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* cursor empty */
+	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+	0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00,
+	0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00,
+	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
+	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
+	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* \n */
+	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
+	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
+	0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00,
+	0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C,
+	0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00,
+	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
+	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
+	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00,
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+	0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00,
+	0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
+	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
+	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E,
+	0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00,
+	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
+	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
+	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
+	0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00,
+	0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00,
+	0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00,
+	0x6C, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
+	0x10, 0x7C, 0xD0, 0x7C, 0x16, 0xFC, 0x10, 0x00,
+	0x00, 0x66, 0xAC, 0xD8, 0x36, 0x6A, 0xCC, 0x00,
+	0x38, 0x4C, 0x38, 0x78, 0xCE, 0xCC, 0x7A, 0x00,
+	0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
+	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
+	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
+	0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00,
+	0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xE6, 0x7C, 0x00,
+	0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x00,
+	0x7C, 0xC6, 0x06, 0x1C, 0x70, 0xC6, 0xFE, 0x00,
+	0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00,
+	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
+	0xFE, 0xC0, 0xFC, 0x06, 0x06, 0xC6, 0x7C, 0x00,
+	0x7C, 0xC6, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00,
+	0xFE, 0xC6, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
+	0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
+	0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0xC6, 0x7C, 0x00,
+	0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
+	0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
+	0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00,
+	0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00,
+	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
+	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
+	0x7C, 0x82, 0x9E, 0xA6, 0x9E, 0x80, 0x7C, 0x00,
+	0x7C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
+	0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00,
+	0xFC, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00,
+	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
+	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
+	0x7C, 0xC6, 0xC6, 0xC0, 0xCE, 0xC6, 0x7E, 0x00,
+	0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
+	0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
+	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
+	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
+	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
+	0x82, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
+	0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
+	0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x06,
+	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xE6, 0x00,
+	0x7C, 0xC6, 0xC0, 0x7C, 0x06, 0xC6, 0x7C, 0x00,
+	0x7E, 0x5A, 0x5A, 0x18, 0x18, 0x18, 0x3C, 0x00,
+	0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
+	0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
+	0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x82, 0x00,
+	0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00,
+	0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00,
+	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
+	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
+	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00,
+	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
+	0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00,
+	0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00,
+	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x78,
+	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
+	0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
+	0x00, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0x78,
+	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
+	0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
+	0x00, 0x00, 0xCC, 0xFE, 0xD6, 0xD6, 0xD6, 0x00,
+	0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
+	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
+	0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
+	0x00, 0x00, 0xDE, 0x76, 0x60, 0x60, 0xF0, 0x00,
+	0x00, 0x00, 0x7C, 0xC0, 0x7C, 0x06, 0x7C, 0x00,
+	0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+	0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
+	0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00,
+	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
+	0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00,
+	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+	0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00,
+	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/*replacement 0x7F */
+	0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
+	0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
+	0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
+	0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
+	0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
+	0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+	0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
+	0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
+	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
+	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
+	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
+	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
+	0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
+	0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+	0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
+	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
+	0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
+	0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
+	0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
+	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
+	0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
+	0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+	0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+	0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+	0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
+	0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
+	0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+	0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+	0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
+	0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
+	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
+	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
+	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+	0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
+	0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
+	0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
+	0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
+	0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
+	0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
+	0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
+	0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
+	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
+	0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
+	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
+	0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
+	0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
+	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
+	0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
+};
+
+static const uint8 fontData_IBM[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
+	0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
+	0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
+	0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
+	0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
+	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
+	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
+	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
+	0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
+	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
+	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
+	0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0,
+	0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0,
+	0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99,
+	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
+	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
+	0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18,
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
+	0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00,
+	0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78,
+	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
+	0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF,
+	0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
+	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
+	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
+	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
+	0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00,
+	0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00,
+	0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
+	0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
+	0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
+	0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
+	0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
+	0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
+	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
+	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
+	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
+	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
+	0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
+	0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00,
+	0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
+	0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
+	0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
+	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
+	0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
+	0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
+	0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
+	0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
+	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
+	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
+	0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
+	0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
+	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
+	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
+	0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00,
+	0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
+	0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
+	0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
+	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
+	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
+	0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
+	0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
+	0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
+	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
+	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
+	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
+	0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
+	0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
+	0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
+	0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
+	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+	0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
+	0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
+	0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
+	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
+	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
+	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
+	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
+	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
+	0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
+	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
+	0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
+	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
+	0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+	0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
+	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
+	0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
+	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
+	0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+	0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
+	0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
+	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
+	0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
+	0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
+	0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
+	0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
+	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
+	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
+	0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
+	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
+	0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
+	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
+	0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78,
+	0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+	0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+	0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00,
+	0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+	0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+	0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+	0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38,
+	0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+	0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+	0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
+	0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
+	0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
+	0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
+	0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00,
+	0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00,
+	0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00,
+	0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+	0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+	0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
+	0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00,
+	0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
+	0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18,
+	0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00,
+	0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30,
+	0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7,
+	0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70,
+	0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
+	0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
+	0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
+	0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00,
+	0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00,
+	0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00,
+	0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00,
+	0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00,
+	0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00,
+	0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F,
+	0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03,
+	0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
+	0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
+	0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+	0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36,
+	0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36,
+	0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00,
+	0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0,
+	0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
+	0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00,
+	0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00,
+	0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00,
+	0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0,
+	0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC,
+	0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00,
+	0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00,
+	0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00,
+	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00,
+	0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0,
+	0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00,
+	0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
+	0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00,
+	0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
+	0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00,
+	0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00,
+	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
+	0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00,
+	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
+	0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+	0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C,
+	0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
+	0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+void GfxFont::init() {
+	// We are currently using the custom font for all fanmade games
+	if (_vm->getFeatures() & (GF_FANMADE | GF_AGDS)) {
+		// fanmade game, use custom font for now
+		_fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc.
+		return;
+	}
+
+	switch (_vm->_renderMode) {
+	case Common::kRenderAmiga:
+		loadFontAmigaPseudoTopaz();
+		//_fontData = fontData_Amiga; // use Amiga Topaz font
+		break;
+	case Common::kRenderApple2GS:
+		// Special font, stored in file AGIFONT
+		loadFontAppleIIgs();
+		break;
+	case Common::kRenderAtariST:
+		// TODO: Atari ST uses another font
+		// Seems to be the standard Atari ST 8x8 system font
+
+	case Common::kRenderCGA:
+	case Common::kRenderEGA:
+	case Common::kRenderVGA:
+		switch (_vm->getGameID()) {
+		case GID_MICKEY:
+			// load mickey mouse font from interpreter file
+			loadFontMickey();
+			break;
+		default:
+			break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	if (!_fontData) {
+		// no font asigned?
+		switch (_vm->getGameID()) {
+		case GID_MICKEY:
+		case GID_TROLL:
+		case GID_WINNIE:
+			// use IBM font for pre-AGI games as standard
+			_fontData = fontData_IBM;
+			break;
+		default:
+			// for everything else use Sierra PC font
+			_fontData = fontData_Sierra;
+			break;
+		}
+	}
+}
+
+const byte *GfxFont::getFontData() {
+	return _fontData;
+}
+
+// We load the Mickey Mouse font from MICKEY.EXE
+void GfxFont::loadFontMickey() {
+	Common::File interpreterFile;
+	int32 interpreterFileSize = 0;
+	byte *fontData = nullptr;
+
+	if (!interpreterFile.open("mickey.exe")) {
+		// Continue, if file not found
+		warning("Could not open file 'mickey.exe' for Mickey Mouse font");
+		return;
+	}
+
+	interpreterFileSize = interpreterFile.size();
+	if (interpreterFileSize != 55136) {
+		// unexpected file size
+		interpreterFile.close();
+		warning("File 'mickey.exe': unexpected file size");
+		return;
+	}
+	interpreterFile.seek(32476); // offset of font data
+
+	// allocate space for font bitmap data
+	fontData = (uint8 *)calloc(256, 8);
+	_fontData = fontData;
+	_fontDataAllocated = fontData;
+ 
+	// read font data, is already in the format that we need (plain bitmap 8x8)
+	interpreterFile.read(fontData, 256 * 8);
+	interpreterFile.close();
+}
+
+// we create a bitmap out of the topaz data used in parallaction (which is normally found in staticres.cpp)
+// it's a recreation of the Amiga Topaz font but not really accurate
+void GfxFont::loadFontAmigaPseudoTopaz() {
+	const byte *topazStart = fontData_AmigaPseudoTopaz + 32;
+	const byte *topazHeader = topazStart + 78;
+	const byte *topazData = nullptr;
+	const byte *topazLocations = nullptr;
+	byte *fontData = nullptr;
+	uint16 topazHeight = 0;
+	uint16 topazWidth = 0;
+	uint16 topazModulo = 0;
+	uint32 topazDataOffset = 0;
+	uint32 topazLocationOffset = 0;
+	byte   topazLowChar = 0;
+	byte   topazHighChar = 0;
+	uint16 topazTotalChars = 0;
+	uint16 topazBitLength = 0;
+	uint16 topazBitOffset = 0;
+	uint16 topazByteOffset = 0;
+
+	// allocate space for font bitmap data
+	fontData = (uint8 *)calloc(256, 8);
+	_fontData = fontData;
+	_fontDataAllocated = fontData;
+
+	topazHeight = READ_BE_UINT16(topazHeader + 0);
+	topazWidth = READ_BE_UINT16(topazHeader + 4);
+
+	// we expect 8x8
+	assert(topazHeight == 8);
+	assert(topazWidth == 8);
+
+	topazLowChar = topazHeader[12];
+	topazHighChar = topazHeader[13];
+	topazTotalChars = topazHighChar - topazLowChar + 1;
+	topazDataOffset = READ_BE_UINT32(topazHeader + 14);
+	topazModulo = READ_BE_UINT16(topazHeader + 18);
+	topazLocationOffset = READ_BE_UINT32(topazHeader + 20);
+
+	// Security checks
+	assert(topazLowChar == ' ');
+	assert(topazHighChar == 0xFF);
+
+	// copy first 32 characters over
+	memcpy(fontData, fontData_Sierra, FONT_DISPLAY_WIDTH * 32);
+	fontData += FONT_DISPLAY_WIDTH * 32;
+
+	// now actually convert from topaz data
+	topazData = topazStart + topazDataOffset;
+	topazLocations = topazStart + topazLocationOffset;
+
+	for (uint16 curChar = 0; curChar < topazTotalChars; curChar++) {
+		topazBitOffset = READ_BE_UINT16(topazLocations + (curChar * 4) + 0);
+		topazBitLength = READ_BE_UINT16(topazLocations + (curChar * 4) + 2);
+
+		if (topazBitLength == 8) {
+			assert((topazBitOffset & 7) == 0);
+
+			topazByteOffset = topazBitOffset >> 3;
+			for (uint16 curHeight = 0; curHeight < topazHeight; curHeight++) {
+				*fontData = topazData[topazByteOffset];
+				fontData++;
+				topazByteOffset += topazModulo;
+			}
+		} else {
+			memset(fontData, 0, 8);
+			fontData += 8;
+		}
+	}
+}
+
+void GfxFont::loadFontAppleIIgs() {
+	Common::File fontFile;
+	uint16 headerIIgs_OffsetMacHeader = 0;
+	uint16 headerIIgs_Version = 0;
+	uint16 macRecord_FirstChar = 0;
+	uint16 macRecord_LastChar = 0;
+	int16 macRecord_MaxKern = 0;
+	uint16 macRecord_RectHeight = 0;
+	uint16 macRecord_StrikeWidth = 0;
+	uint16 strikeDataLen = 0;
+	byte *strikeDataPtr = nullptr;
+	uint16 actualCharacterCount = 0;
+	uint16 totalCharacterCount = 0;
+	uint16 *locationTablePtr = nullptr;
+	uint16 *offsetWidthTablePtr = nullptr;
+
+	uint16 curCharNr = 0;
+	uint16 curRow = 0;
+	uint16 curLocation = 0;
+	uint16 curLocationBytes = 0;
+	uint16 curLocationBits = 0;
+	uint16 curCharOffsetWidth = 0;
+	uint16 curCharOffset = 0;
+	uint16 curCharWidth = 0;
+	uint16 curStrikeWidth = 0;
+
+	uint16 curPixelNr = 0;
+	uint16 curBitMask = 0;
+	int16 positionAdjust = 0;
+	byte curByte = 0;
+	byte fontByte = 0;
+
+	uint16 strikeRowOffset = 0;
+	uint16 strikeCurOffset = 0;
+
+	byte *fontData = nullptr;
+
+	if (!fontFile.open("agifont")) {
+		// Continue,
+		// This also happens when the user selected Apple IIgs as render for the palette for non-AppleIIgs games
+		warning("Could not open file 'agifont' for Apple IIgs font");
+		return;
+	}
+
+	// Apple IIgs header
+	headerIIgs_OffsetMacHeader = fontFile.readUint16LE();
+	fontFile.skip(2); // font family
+	fontFile.skip(2); // font style
+	fontFile.skip(2); // point size
+	headerIIgs_Version = fontFile.readUint16LE();
+	fontFile.skip(2); // bounds type
+	// end of Apple IIgs header
+	// Macintosh font record
+	fontFile.skip(2); // font type
+	macRecord_FirstChar = fontFile.readUint16LE();
+	macRecord_LastChar = fontFile.readUint16LE();
+	fontFile.skip(2); // max width
+	macRecord_MaxKern = fontFile.readSint16LE();
+	fontFile.skip(2); // negative descent
+	fontFile.skip(2); // rect width
+	macRecord_RectHeight = fontFile.readUint16LE();
+	fontFile.skip(2); // low word ptr table
+	fontFile.skip(2); // font ascent
+	fontFile.skip(2); // font descent
+	fontFile.skip(2); // leading
+	macRecord_StrikeWidth = fontFile.readUint16LE();
+
+	// security-checks
+	if (headerIIgs_OffsetMacHeader != 6)
+		error("AppleIIgs-font: unexpected header");
+	if (headerIIgs_Version != 0x0101)
+		error("AppleIIgs-font: not a 1.1 font");
+	if ((macRecord_FirstChar != 0) || (macRecord_LastChar != 255))
+		error("AppleIIgs-font: unexpected characters");
+	if (macRecord_RectHeight != 8)
+		error("AppleIIgs-font: expected 8x8 font");
+
+	// Calculate table sizes
+	strikeDataLen = macRecord_StrikeWidth * macRecord_RectHeight * 2;
+	actualCharacterCount = (macRecord_LastChar - macRecord_FirstChar + 1);
+	totalCharacterCount = actualCharacterCount + 2; // replacement-char + extra character
+
+	// Allocate memory for tables
+	strikeDataPtr = (byte *)calloc(strikeDataLen, 1);
+	locationTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // 1 word per character
+	offsetWidthTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // ditto
+
+	// read tables
+	fontFile.read(strikeDataPtr, strikeDataLen);
+	for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+		locationTablePtr[curCharNr] = fontFile.readUint16LE();
+	}
+	for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+		offsetWidthTablePtr[curCharNr] = fontFile.readUint16LE();
+	}
+	fontFile.close();
+
+	// allocate space for font bitmap data
+	fontData = (uint8 *)calloc(256, 8);
+	_fontData = fontData;
+	_fontDataAllocated = fontData;
+
+	// extract font bitmap data
+	for (curCharNr = 0; curCharNr < actualCharacterCount; curCharNr++) {
+		curCharOffsetWidth = offsetWidthTablePtr[curCharNr];
+		curLocation = locationTablePtr[curCharNr];
+		if (curCharOffsetWidth == 0xFFFF) {
+			// character does not exist in font, use replacement character instead
+			curCharOffsetWidth = offsetWidthTablePtr[actualCharacterCount];
+			curLocation = locationTablePtr[actualCharacterCount];
+			curStrikeWidth = locationTablePtr[actualCharacterCount + 1] - curLocation;
+		} else {
+			curStrikeWidth = locationTablePtr[curCharNr + 1] - curLocation;
+		}
+
+		// Figure out bytes + bits location
+		curLocationBytes = curLocation >> 3;
+		curLocationBits = curLocation & 0x0007;
+		curCharWidth = curCharOffsetWidth & 0x00FF; // isolate width
+		curCharOffset = curCharOffsetWidth >> 8; // isolate offset
+
+		if (!curCharWidth) {
+			fontData += 8; // skip over this character
+			continue;
+		}
+
+		if (curCharWidth != 8) {
+			if (curCharNr != 0x3B)
+				error("AppleIIgs-font: expected 8x8 font");
+		}
+
+		// Get all rows of the current character
+		strikeRowOffset = 0;
+		for (curRow = 0; curRow < macRecord_RectHeight; curRow++) {
+			strikeCurOffset = strikeRowOffset + curLocationBytes;
+
+			// Copy over bits
+			fontByte = 0;
+			curByte = strikeDataPtr[strikeCurOffset];
+			curBitMask = 0x80 >> curLocationBits;
+
+			for (curPixelNr = 0; curPixelNr < curStrikeWidth; curPixelNr++) {
+				fontByte = fontByte << 1;
+				if (curByte & curBitMask) {
+					fontByte |= 0x01;
+				}
+				curBitMask = curBitMask >> 1;
+				if (!curBitMask) {
+					curByte = strikeDataPtr[strikeCurOffset + 1];
+					curBitMask = 0x80;
+				}
+			}
+
+			// adjust, so that it's aligned to the left (starting at 0x80 bit)
+			fontByte = fontByte << (8 - curStrikeWidth);
+
+			// now adjust according to offset + MaxKern
+			positionAdjust = macRecord_MaxKern + curCharOffset;
+
+			// adjust may be negative for space, or 8 for "empty" characters
+			if (positionAdjust > 8)
+				error("AppleIIgs-font: invalid character spacing");
+
+			if (positionAdjust < 0) {
+				// negative adjust strangely happens for empty characters like space
+				if (curStrikeWidth)
+					error("AppleIIgs-font: invalid character spacing");
+			}
+
+			if (positionAdjust > 0) {
+				// move the amount of pixels to the right
+				fontByte = fontByte >> positionAdjust;
+			}
+
+			*fontData = fontByte;
+			fontData++;
+
+			strikeRowOffset += macRecord_StrikeWidth * 2;
+		}
+	}
+
+	free(offsetWidthTablePtr);
+	free(locationTablePtr);
+	free(strikeDataPtr);
+
+	// overwrite character 0x1A with the standard Sierra arrow to the right character
+	// required for the original save/restore dialogs
+	memcpy(_fontDataAllocated + (0x1A * 8), fontData_ArrowRightCharacter, sizeof(fontData_ArrowRightCharacter));
+}
+
+} // End of namespace Agi
diff --git a/engines/agi/font.h b/engines/agi/font.h
index 27d495e..130e863 100644
--- a/engines/agi/font.h
+++ b/engines/agi/font.h
@@ -25,1220 +25,25 @@
 
 namespace Agi {
 
-// Arrow to the right character, used for original saved game dialogs
-// Needs to get patched into at least the Apple IIgs font, because the font didn't support
-// that character and original AGI on Apple IIgs used Apple II menus for saving/restoring.
-static const uint8 fontData_ArrowRightCharacter[8] = {
-	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
-};
-
-// topaz data, same as in engines/parallaction/staticres.cpp
-// seems to have been recreated and is not the original amiga font
-static const uint8 fontData_AmigaPseudoTopaz[2600] = {
-	0x00, 0x00, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x79, 0x00, 0x00, 0x03, 0xe9, 0x00, 0x00, 0x02, 0x79,
-	0x70, 0xff, 0x4e, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
-	0x00, 0x1a, 0x0f, 0x80, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x45, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x09, 0x74, 0x00, 0x08,
-	0x00, 0x40, 0x00, 0x08, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x20, 0xff, 0x00, 0x00, 0x00, 0x6e,
-	0x00, 0xbe, 0x00, 0x00, 0x06, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
-	0x6c, 0x6c, 0x18, 0x00, 0x38, 0x18, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3c, 0x18,
-	0x3c, 0x3c, 0x1c, 0x7e, 0x1c, 0x7e, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x7c, 0x3c,
-	0x7c, 0x1e, 0x78, 0x7e, 0x7e, 0x3c, 0x66, 0x3c, 0x06, 0xc6, 0x60, 0xc6, 0xc6, 0x3c, 0x7c, 0x78,
-	0x7c, 0x3c, 0x7e, 0x66, 0x66, 0xc6, 0xc3, 0xc3, 0xfe, 0x3c, 0xc0, 0x3c, 0x10, 0x00, 0x18, 0x00,
-	0x60, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x60, 0x18, 0x0c, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x18, 0x70, 0x72, 0x0f, 0x00, 0x18,
-	0x00, 0x1c, 0x42, 0xc3, 0x18, 0x3c, 0x66, 0x7e, 0x1c, 0x00, 0x3e, 0x7e, 0x7e, 0x3c, 0x18, 0x78,
-	0x78, 0x18, 0x00, 0x3e, 0x00, 0x00, 0x30, 0x38, 0x00, 0x40, 0x40, 0xc0, 0x18, 0x3c, 0x3c, 0x7e,
-	0x06, 0x66, 0x18, 0x7e, 0x7e, 0x36, 0x0c, 0x0c, 0x18, 0x3c, 0xc6, 0x3c, 0x60, 0x76, 0x18, 0x00,
-	0x0c, 0x7e, 0x71, 0x66, 0x00, 0x66, 0x60, 0x0e, 0x7e, 0x66, 0x18, 0x6e, 0x3c, 0x00, 0x18, 0x7e,
-	0x06, 0x66, 0x18, 0x00, 0x7e, 0x34, 0x0c, 0x0c, 0x18, 0x0c, 0x60, 0x00, 0x18, 0x3c, 0x0c, 0x00,
-	0x0c, 0x00, 0x71, 0x00, 0x00, 0x00, 0x18, 0x0c, 0x7e, 0x00, 0x18, 0x3c, 0x00, 0x18, 0x6c, 0x6c,
-	0x3e, 0x66, 0x6c, 0x18, 0x18, 0x18, 0x66, 0x18, 0x00, 0x00, 0x00, 0x06, 0x66, 0x38, 0x66, 0x66,
-	0x3c, 0x60, 0x30, 0x06, 0x66, 0x66, 0x18, 0x18, 0x06, 0x00, 0x60, 0x66, 0xc6, 0x66, 0x66, 0x30,
-	0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x06, 0xcc, 0x60, 0xee, 0xe6, 0x66, 0x66, 0xcc, 0x66, 0x66,
-	0x18, 0x66, 0x66, 0xc6, 0x66, 0x66, 0x0c, 0x30, 0x60, 0x0c, 0x38, 0x00, 0x18, 0x00, 0x60, 0x00,
-	0x06, 0x00, 0x30, 0x00, 0x60, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x9c, 0x3c, 0x7e, 0x00, 0x0c, 0x36,
-	0x3c, 0x66, 0x18, 0x60, 0x66, 0x81, 0x24, 0x33, 0x06, 0x81, 0x00, 0x66, 0x18, 0x0c, 0x0c, 0x30,
-	0x00, 0x7a, 0x00, 0x00, 0x70, 0x44, 0xcc, 0xc6, 0xc6, 0x23, 0x00, 0x66, 0x18, 0x00, 0x1c, 0x00,
-	0x24, 0x60, 0x00, 0x1c, 0x18, 0x18, 0x00, 0x66, 0xcc, 0x00, 0x60, 0x3c, 0x30, 0xc6, 0x18, 0x00,
-	0x8e, 0x00, 0xc6, 0x66, 0x60, 0x38, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x0c, 0x00,
-	0x24, 0x00, 0x00, 0x18, 0x18, 0x18, 0x00, 0x18, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x7e,
-	0x8e, 0x66, 0x18, 0x00, 0x18, 0x18, 0x00, 0x66, 0x00, 0x18, 0x00, 0x18, 0x00, 0xfe, 0x60, 0xac,
-	0x68, 0x30, 0x30, 0x0c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x0c, 0x6e, 0x78, 0x06, 0x06, 0x6c, 0x7c,
-	0x60, 0x06, 0x66, 0x66, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x06, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60,
-	0x60, 0x60, 0x66, 0x18, 0x06, 0xd8, 0x60, 0xfe, 0xf6, 0x66, 0x66, 0xcc, 0x66, 0x70, 0x18, 0x66,
-	0x66, 0xc6, 0x3c, 0x3c, 0x18, 0x30, 0x30, 0x0c, 0x6c, 0x00, 0x0c, 0x3c, 0x7c, 0x3c, 0x3e, 0x3c,
-	0x7c, 0x3e, 0x7c, 0x18, 0x0c, 0x66, 0x18, 0xec, 0x7c, 0x3c, 0x7c, 0x3e, 0x7c, 0x3c, 0x7c, 0x66,
-	0x66, 0xc6, 0xc6, 0x66, 0x7e, 0x18, 0x18, 0x18, 0x00, 0xf0, 0x66, 0x18, 0x3e, 0x30, 0x66, 0x3c,
-	0x18, 0x3c, 0x00, 0x9d, 0x44, 0x66, 0x00, 0xb9, 0x00, 0x3c, 0x7e, 0x18, 0x18, 0x60, 0x66, 0x7a,
-	0x18, 0x00, 0x30, 0x44, 0x66, 0x4c, 0x4c, 0x66, 0x18, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x60,
-	0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x60, 0xd8, 0x3c, 0x60, 0x66, 0xc6, 0xe6, 0x3c, 0x3c, 0x3c, 0x3c,
-	0x6c, 0x66, 0x6c, 0x66, 0x66, 0x66, 0x7e, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0x3c, 0x3c, 0x3c,
-	0x3c, 0x18, 0x3c, 0x7e, 0x3c, 0x3e, 0x6c, 0x00, 0x18, 0x3c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x66, 0x1e, 0x3c, 0x66, 0x00, 0x7e, 0x7e, 0x00, 0x18, 0x00, 0x6c, 0x3c, 0xd8, 0x76, 0x00,
-	0x30, 0x0c, 0xff, 0x7e, 0x00, 0x7e, 0x00, 0x18, 0x7e, 0x18, 0x0c, 0x1c, 0xcc, 0x06, 0x7c, 0x0c,
-	0x3c, 0x3e, 0x00, 0x00, 0x60, 0x00, 0x06, 0x0c, 0xd6, 0x7e, 0x7c, 0x60, 0x66, 0x78, 0x78, 0x6e,
-	0x7e, 0x18, 0x06, 0xf0, 0x60, 0xd6, 0xde, 0x66, 0x7c, 0xcc, 0x7c, 0x3c, 0x18, 0x66, 0x66, 0xd6,
-	0x18, 0x18, 0x30, 0x30, 0x18, 0x0c, 0xc6, 0x00, 0x00, 0x06, 0x66, 0x60, 0x66, 0x66, 0x30, 0x66,
-	0x66, 0x18, 0x0c, 0x6c, 0x18, 0xfe, 0x66, 0x66, 0x66, 0x66, 0x66, 0x60, 0x30, 0x66, 0x66, 0xc6,
-	0x6c, 0x66, 0x0c, 0x70, 0x18, 0x0e, 0x00, 0xc3, 0x66, 0x18, 0x6c, 0x78, 0x3c, 0x18, 0x00, 0x66,
-	0x00, 0xb1, 0x3c, 0xcc, 0x00, 0xa5, 0x00, 0x00, 0x18, 0x30, 0x0c, 0x00, 0x66, 0x3a, 0x18, 0x00,
-	0x30, 0x38, 0x33, 0x58, 0x58, 0x2c, 0x30, 0x7e, 0x18, 0x66, 0x66, 0x66, 0x66, 0x78, 0x60, 0x66,
-	0x60, 0x4c, 0x60, 0x6e, 0xf0, 0x18, 0x60, 0x30, 0xe6, 0xf6, 0x66, 0x66, 0x66, 0x66, 0x38, 0x66,
-	0x70, 0x30, 0x66, 0x66, 0x4c, 0x4c, 0x6c, 0x06, 0x18, 0x06, 0x3c, 0x06, 0x06, 0x66, 0x66, 0x3c,
-	0x66, 0x0c, 0x66, 0x66, 0x78, 0x18, 0x18, 0x60, 0x7c, 0x66, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x66,
-	0x78, 0x60, 0x66, 0x66, 0x0c, 0x0c, 0x00, 0x18, 0x00, 0xfe, 0x06, 0x36, 0xdc, 0x00, 0x30, 0x0c,
-	0x3c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x76, 0x18, 0x18, 0x06, 0xfe, 0x06, 0x66, 0x18, 0x66, 0x06,
-	0x00, 0x00, 0x18, 0x7e, 0x18, 0x18, 0xde, 0x66, 0x66, 0x60, 0x66, 0x60, 0x60, 0x66, 0x66, 0x18,
-	0x06, 0xd8, 0x60, 0xc6, 0xce, 0x66, 0x60, 0xcc, 0x6c, 0x0e, 0x18, 0x66, 0x3c, 0xfe, 0x3c, 0x18,
-	0x60, 0x30, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x66, 0x60, 0x66, 0x7e, 0x30, 0x66, 0x66, 0x18,
-	0x0c, 0x78, 0x18, 0xd6, 0x66, 0x66, 0x66, 0x66, 0x60, 0x3c, 0x30, 0x66, 0x66, 0xd6, 0x38, 0x66,
-	0x18, 0x18, 0x18, 0x18, 0x00, 0x0f, 0x66, 0x18, 0x3e, 0x30, 0x42, 0x3c, 0x18, 0x3c, 0x00, 0x9d,
-	0x00, 0x66, 0x00, 0xb9, 0x00, 0x00, 0x18, 0x7c, 0x78, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x30, 0x00,
-	0x66, 0x32, 0x3e, 0xd9, 0x60, 0x66, 0x18, 0x7e, 0x40, 0x7e, 0x7e, 0x60, 0x78, 0x40, 0x78, 0x18,
-	0x78, 0x66, 0xd8, 0x18, 0x60, 0x0c, 0xf6, 0xde, 0x66, 0x66, 0x66, 0x66, 0x6c, 0x66, 0xe0, 0x0c,
-	0x66, 0x66, 0x18, 0x18, 0x66, 0x3e, 0x18, 0x3e, 0x60, 0x3e, 0x3e, 0x7e, 0x7e, 0x60, 0x7e, 0x18,
-	0x7e, 0x66, 0x6c, 0x18, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x18, 0x3c,
-	0x66, 0x66, 0x18, 0x18, 0x00, 0x00, 0x00, 0x6c, 0x7c, 0x6a, 0xce, 0x00, 0x18, 0x18, 0x66, 0x18,
-	0x18, 0x00, 0x18, 0x60, 0x66, 0x18, 0x30, 0x66, 0x0c, 0x66, 0x66, 0x18, 0x66, 0x0c, 0x18, 0x18,
-	0x06, 0x00, 0x60, 0x00, 0xc0, 0x66, 0x66, 0x30, 0x6c, 0x60, 0x60, 0x66, 0x66, 0x18, 0x66, 0xcc,
-	0x60, 0xc6, 0xc6, 0x66, 0x60, 0xdc, 0x66, 0x66, 0x18, 0x66, 0x3c, 0xee, 0x66, 0x18, 0xc0, 0x30,
-	0x06, 0x0c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x60, 0x66, 0x60, 0x30, 0x3e, 0x66, 0x18, 0x0c, 0x6c,
-	0x18, 0xc6, 0x66, 0x66, 0x7c, 0x3e, 0x60, 0x06, 0x30, 0x66, 0x3c, 0xfe, 0x6c, 0x3c, 0x30, 0x18,
-	0x18, 0x18, 0x00, 0x3c, 0x66, 0x18, 0x0c, 0x30, 0x00, 0x18, 0x18, 0x06, 0x00, 0x81, 0x7e, 0x33,
-	0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x0a, 0x00, 0x00, 0x00, 0x7c, 0xcc, 0x66,
-	0x62, 0x33, 0x66, 0x66, 0x18, 0x66, 0x66, 0x66, 0x66, 0x60, 0x60, 0x66, 0x60, 0x32, 0x60, 0x3e,
-	0xcc, 0x18, 0x7e, 0x66, 0xde, 0xce, 0x66, 0x66, 0x66, 0x66, 0xc6, 0x66, 0x60, 0x66, 0x66, 0x66,
-	0x32, 0x32, 0x66, 0x66, 0x18, 0x66, 0x60, 0x66, 0x66, 0x60, 0x60, 0x60, 0x60, 0x30, 0x60, 0x3e,
-	0x66, 0x18, 0x18, 0x06, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x18, 0x66, 0x18, 0x06, 0x66, 0x66,
-	0x30, 0x30, 0x00, 0x18, 0x00, 0x6c, 0x18, 0xcc, 0x7b, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x18, 0x00,
-	0x18, 0xc0, 0x3c, 0x18, 0x7e, 0x3c, 0x0c, 0x3c, 0x3c, 0x18, 0x3c, 0x38, 0x18, 0x18, 0x00, 0x00,
-	0x00, 0x18, 0x78, 0x66, 0x7c, 0x1e, 0x78, 0x7e, 0x60, 0x3e, 0x66, 0x3c, 0x3c, 0xc6, 0x7e, 0xc6,
-	0xc6, 0x3c, 0x60, 0x7e, 0x66, 0x3c, 0x18, 0x3c, 0x18, 0xc6, 0xc3, 0x18, 0xfe, 0x3c, 0x03, 0x3c,
-	0x00, 0x00, 0x00, 0x3e, 0x7c, 0x3c, 0x3e, 0x3c, 0x30, 0x06, 0x66, 0x0c, 0x0c, 0x66, 0x0c, 0xc6,
-	0x66, 0x3c, 0x60, 0x06, 0x60, 0x7c, 0x1c, 0x3e, 0x18, 0x6c, 0xc6, 0x18, 0x7e, 0x0e, 0x18, 0x70,
-	0x00, 0xf0, 0x7e, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x3c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x81,
-	0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x0a, 0x00, 0x18, 0x00, 0x00, 0x00, 0xcf, 0xc4, 0x67,
-	0x3c, 0x67, 0x3e, 0x66, 0x3c, 0x66, 0x66, 0x7f, 0x7e, 0x3c, 0x7e, 0x7e, 0x7e, 0x18, 0x30, 0x3c,
-	0x18, 0x3c, 0xce, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x7e, 0x3c, 0x3c, 0x3c, 0x7e, 0x7e,
-	0x6c, 0x3f, 0x1e, 0x3e, 0x3c, 0x3e, 0x3e, 0x3c, 0x3c, 0x3c, 0x3c, 0x7e, 0x3c, 0x06, 0x18, 0x0c,
-	0x0c, 0x7c, 0x66, 0x18, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x3f, 0x0c, 0x7c, 0x3e, 0x3e, 0x7e, 0x7e,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x60, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x01, 0x00, 0x03,
-	0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0x00, 0x30, 0x00,
-	0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03,
-	0x06, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x00, 0x18, 0x00,
-	0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x10, 0x00, 0x08, 0x00, 0x18, 0x00, 0x08, 0x00, 0x20,
-	0x00, 0x08, 0x00, 0x28, 0x00, 0x08, 0x00, 0x30, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x00, 0x40,
-	0x00, 0x08, 0x00, 0x48, 0x00, 0x08, 0x00, 0x50, 0x00, 0x08, 0x00, 0x58, 0x00, 0x08, 0x00, 0x60,
-	0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x00, 0x70, 0x00, 0x08, 0x00, 0x78, 0x00, 0x08, 0x00, 0x80,
-	0x00, 0x08, 0x00, 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0x98, 0x00, 0x08, 0x00, 0xa0,
-	0x00, 0x08, 0x00, 0xa8, 0x00, 0x08, 0x00, 0xb0, 0x00, 0x08, 0x00, 0xb8, 0x00, 0x08, 0x00, 0xc0,
-	0x00, 0x08, 0x00, 0xc8, 0x00, 0x08, 0x00, 0xd0, 0x00, 0x08, 0x00, 0xd8, 0x00, 0x08, 0x00, 0xe0,
-	0x00, 0x08, 0x00, 0xe8, 0x00, 0x08, 0x00, 0xf0, 0x00, 0x08, 0x00, 0xf8, 0x00, 0x08, 0x01, 0x00,
-	0x00, 0x08, 0x01, 0x08, 0x00, 0x08, 0x01, 0x10, 0x00, 0x08, 0x01, 0x18, 0x00, 0x08, 0x01, 0x20,
-	0x00, 0x08, 0x01, 0x28, 0x00, 0x08, 0x01, 0x30, 0x00, 0x08, 0x01, 0x38, 0x00, 0x08, 0x01, 0x40,
-	0x00, 0x08, 0x01, 0x48, 0x00, 0x08, 0x01, 0x50, 0x00, 0x08, 0x01, 0x58, 0x00, 0x08, 0x01, 0x60,
-	0x00, 0x08, 0x01, 0x68, 0x00, 0x08, 0x01, 0x70, 0x00, 0x08, 0x01, 0x78, 0x00, 0x08, 0x01, 0x80,
-	0x00, 0x08, 0x01, 0x88, 0x00, 0x08, 0x01, 0x90, 0x00, 0x08, 0x01, 0x98, 0x00, 0x08, 0x01, 0xa0,
-	0x00, 0x08, 0x01, 0xa8, 0x00, 0x08, 0x01, 0xb0, 0x00, 0x08, 0x01, 0xb8, 0x00, 0x08, 0x01, 0xc0,
-	0x00, 0x08, 0x01, 0xc8, 0x00, 0x08, 0x01, 0xd0, 0x00, 0x08, 0x01, 0xd8, 0x00, 0x08, 0x01, 0xe0,
-	0x00, 0x08, 0x01, 0xe8, 0x00, 0x08, 0x01, 0xf0, 0x00, 0x08, 0x01, 0xf8, 0x00, 0x08, 0x02, 0x00,
-	0x00, 0x08, 0x02, 0x08, 0x00, 0x08, 0x02, 0x10, 0x00, 0x08, 0x02, 0x18, 0x00, 0x08, 0x02, 0x20,
-	0x00, 0x08, 0x02, 0x28, 0x00, 0x08, 0x02, 0x30, 0x00, 0x08, 0x02, 0x38, 0x00, 0x08, 0x02, 0x40,
-	0x00, 0x08, 0x02, 0x48, 0x00, 0x08, 0x02, 0x50, 0x00, 0x08, 0x02, 0x58, 0x00, 0x08, 0x02, 0x60,
-	0x00, 0x08, 0x02, 0x68, 0x00, 0x08, 0x02, 0x70, 0x00, 0x08, 0x02, 0x78, 0x00, 0x08, 0x02, 0x80,
-	0x00, 0x08, 0x02, 0x88, 0x00, 0x08, 0x02, 0x90, 0x00, 0x08, 0x02, 0x98, 0x00, 0x08, 0x02, 0xa0,
-	0x00, 0x08, 0x02, 0xa8, 0x00, 0x08, 0x02, 0xb0, 0x00, 0x08, 0x02, 0xb8, 0x00, 0x08, 0x02, 0xc0,
-	0x00, 0x08, 0x02, 0xc8, 0x00, 0x08, 0x02, 0xd0, 0x00, 0x08, 0x02, 0xd8, 0x00, 0x08, 0x02, 0xe0,
-	0x00, 0x08, 0x02, 0xe8, 0x00, 0x08, 0x02, 0xf0, 0x00, 0x08, 0x02, 0xf8, 0x00, 0x08, 0x03, 0x00,
-	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
-	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
-	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
-	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
-	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
-	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
-	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00,
-	0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x03, 0x00, 0x00, 0x08, 0x00, 0x00,
-	0x00, 0x08, 0x03, 0x08, 0x00, 0x08, 0x03, 0x10, 0x00, 0x08, 0x03, 0x18, 0x00, 0x08, 0x03, 0x20,
-	0x00, 0x08, 0x03, 0x28, 0x00, 0x08, 0x03, 0x30, 0x00, 0x08, 0x03, 0x38, 0x00, 0x08, 0x03, 0x40,
-	0x00, 0x08, 0x03, 0x48, 0x00, 0x08, 0x03, 0x50, 0x00, 0x08, 0x03, 0x58, 0x00, 0x08, 0x03, 0x60,
-	0x00, 0x08, 0x00, 0x68, 0x00, 0x08, 0x03, 0x68, 0x00, 0x08, 0x03, 0x70, 0x00, 0x08, 0x03, 0x78,
-	0x00, 0x08, 0x03, 0x80, 0x00, 0x08, 0x03, 0x88, 0x00, 0x08, 0x03, 0x90, 0x00, 0x08, 0x03, 0x98,
-	0x00, 0x08, 0x03, 0xa0, 0x00, 0x08, 0x03, 0xa8, 0x00, 0x08, 0x03, 0xb0, 0x00, 0x08, 0x03, 0xb8,
-	0x00, 0x08, 0x03, 0xc0, 0x00, 0x08, 0x03, 0xc8, 0x00, 0x08, 0x03, 0xd0, 0x00, 0x08, 0x03, 0xd8,
-	0x00, 0x08, 0x03, 0xe0, 0x00, 0x08, 0x03, 0xe8, 0x00, 0x08, 0x03, 0xf0, 0x00, 0x08, 0x03, 0xf8,
-	0x00, 0x08, 0x04, 0x00, 0x00, 0x08, 0x04, 0x08, 0x00, 0x08, 0x04, 0x10, 0x00, 0x08, 0x04, 0x18,
-	0x00, 0x08, 0x04, 0x20, 0x00, 0x08, 0x04, 0x28, 0x00, 0x08, 0x04, 0x30, 0x00, 0x08, 0x04, 0x38,
-	0x00, 0x08, 0x04, 0x40, 0x00, 0x08, 0x04, 0x48, 0x00, 0x08, 0x04, 0x50, 0x00, 0x08, 0x04, 0x58,
-	0x00, 0x08, 0x04, 0x60, 0x00, 0x08, 0x04, 0x68, 0x00, 0x08, 0x04, 0x70, 0x00, 0x08, 0x04, 0x78,
-	0x00, 0x08, 0x04, 0x80, 0x00, 0x08, 0x04, 0x88, 0x00, 0x08, 0x04, 0x90, 0x00, 0x08, 0x04, 0x98,
-	0x00, 0x08, 0x04, 0xa0, 0x00, 0x08, 0x04, 0xa8, 0x00, 0x08, 0x04, 0xb0, 0x00, 0x08, 0x04, 0xb8,
-	0x00, 0x08, 0x04, 0xc0, 0x00, 0x08, 0x04, 0xc8, 0x00, 0x08, 0x04, 0xd0, 0x00, 0x08, 0x04, 0xd8,
-	0x00, 0x08, 0x04, 0xe0, 0x00, 0x08, 0x04, 0xe8, 0x00, 0x08, 0x04, 0xf0, 0x00, 0x08, 0x04, 0xf8,
-	0x00, 0x08, 0x05, 0x00, 0x00, 0x08, 0x05, 0x08, 0x00, 0x08, 0x05, 0x10, 0x00, 0x08, 0x05, 0x18,
-	0x00, 0x08, 0x05, 0x20, 0x00, 0x08, 0x05, 0x28, 0x00, 0x08, 0x05, 0x30, 0x00, 0x08, 0x05, 0x38,
-	0x00, 0x08, 0x05, 0x40, 0x00, 0x08, 0x05, 0x48, 0x00, 0x08, 0x05, 0x50, 0x00, 0x08, 0x05, 0x58,
-	0x00, 0x08, 0x05, 0x60, 0x00, 0x08, 0x05, 0x68, 0x00, 0x08, 0x05, 0x70, 0x00, 0x08, 0x05, 0x78,
-	0x00, 0x08, 0x05, 0x80, 0x00, 0x08, 0x05, 0x88, 0x00, 0x08, 0x05, 0x90, 0x00, 0x08, 0x05, 0x98,
-	0x00, 0x08, 0x05, 0xa0, 0x00, 0x08, 0x05, 0xa8, 0x00, 0x08, 0x05, 0xb0, 0x00, 0x08, 0x05, 0xb8,
-	0x00, 0x08, 0x05, 0xc0, 0x00, 0x08, 0x05, 0xc8, 0x00, 0x08, 0x05, 0xd0, 0x00, 0x08, 0x05, 0xd8,
-	0x00, 0x08, 0x05, 0xe0, 0x00, 0x08, 0x05, 0xe8, 0x00, 0x08, 0x00, 0x38, 0x00, 0x08, 0x03, 0x00,
-	0x00, 0x08, 0x03, 0x00, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf2
-};
+class GfxFont {
+public:
+	GfxFont(AgiBase *vm);
+	~GfxFont();
 
-// 8x8 font patterns
-static const uint8 fontData_Sierra[] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E,	// cursor hollow
-	0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,	// cursor solid
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// cursor empty
-	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
-	0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00,
-	0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00,
-	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
-	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
-	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// \n
-	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
-	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
-	0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00,
-	0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C,
-	0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00,
-	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
-	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
-	0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00,
-	0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
-	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E,
-	0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00,
-	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
-	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
-	0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00,
-	0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00,
-	0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00,
-	// original sierra font starts here
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 Space
-	0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
-	0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
-	0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
-	0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
-	0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
-	0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
-	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
-	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
-	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
-	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
-	0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
-	0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30
-	0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
-	0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
-	0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
-	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
-	0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
-	0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
-	0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
-	0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
-	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
-	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
-	0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
-	0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
-	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
-	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
-	0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40
-	0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
-	0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
-	0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
-	0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
-	0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
-	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
-	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
-	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
-	0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50
-	0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
-	0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
-	0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
-	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
-	0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
-	0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
-	0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
-	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
-	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
-	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
-	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
-	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-	0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
-	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
-	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
-	0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
-	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
-	0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
-	0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
-	0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
-	0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
-	0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
-	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
-	0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
-	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
-	0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
-	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	// custom font starting here at 0x80
-	0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80
-	0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
-	0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
-	0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
-	0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
-	0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
-	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
-	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
-	0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
-	0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
-	0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
-	0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
-	0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
-	0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
-	0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
-	0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
-	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
-	0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
-	0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
-	0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
-	0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
-	0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
-	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
-	0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
-	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
-	0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
-	0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
-	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
-	0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
-};
+private:
+	AgiBase *_vm;
 
-static const uint8 fontData_FanGames[] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E,	/* cursor hollow */
-	0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,	/* cursor solid */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* cursor empty */
-	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
-	0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00,
-	0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00,
-	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
-	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
-	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* \n */
-	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
-	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
-	0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00,
-	0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C,
-	0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00,
-	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
-	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
-	0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00,
-	0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
-	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E,
-	0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00,
-	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
-	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
-	0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00,
-	0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00,
-	0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00,
-	0x6C, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
-	0x10, 0x7C, 0xD0, 0x7C, 0x16, 0xFC, 0x10, 0x00,
-	0x00, 0x66, 0xAC, 0xD8, 0x36, 0x6A, 0xCC, 0x00,
-	0x38, 0x4C, 0x38, 0x78, 0xCE, 0xCC, 0x7A, 0x00,
-	0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
-	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
-	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
-	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
-	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
-	0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00,
-	0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xE6, 0x7C, 0x00,
-	0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x00,
-	0x7C, 0xC6, 0x06, 0x1C, 0x70, 0xC6, 0xFE, 0x00,
-	0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00,
-	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
-	0xFE, 0xC0, 0xFC, 0x06, 0x06, 0xC6, 0x7C, 0x00,
-	0x7C, 0xC6, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00,
-	0xFE, 0xC6, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
-	0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
-	0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0xC6, 0x7C, 0x00,
-	0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
-	0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
-	0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00,
-	0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00,
-	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
-	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
-	0x7C, 0x82, 0x9E, 0xA6, 0x9E, 0x80, 0x7C, 0x00,
-	0x7C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
-	0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00,
-	0xFC, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
-	0x7C, 0xC6, 0xC6, 0xC0, 0xCE, 0xC6, 0x7E, 0x00,
-	0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
-	0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
-	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
-	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
-	0x82, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
-	0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
-	0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x06,
-	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xE6, 0x00,
-	0x7C, 0xC6, 0xC0, 0x7C, 0x06, 0xC6, 0x7C, 0x00,
-	0x7E, 0x5A, 0x5A, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
-	0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
-	0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x82, 0x00,
-	0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00,
-	0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00,
-	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
-	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
-	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
-	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
-	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-	0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00,
-	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00,
-	0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00,
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x78,
-	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
-	0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0x00, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0x78,
-	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
-	0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0x00, 0x00, 0xCC, 0xFE, 0xD6, 0xD6, 0xD6, 0x00,
-	0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
-	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
-	0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
-	0x00, 0x00, 0xDE, 0x76, 0x60, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x7C, 0xC0, 0x7C, 0x06, 0x7C, 0x00,
-	0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
-	0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00,
-	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
-	0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00,
-	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
-	0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00,
-	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/*replacement 0x7F */
-	0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
-	0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
-	0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
-	0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
-	0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
-	0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
-	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
-	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
-	0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
-	0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
-	0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
-	0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
-	0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
-	0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
-	0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
-	0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
-	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
-	0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
-	0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
-	0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
-	0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
-	0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
-	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
-	0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
-	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
-	0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
-	0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
-	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
-	0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
-};
+public:
+	void init();
+	const byte *getFontData();
 
-#if 0
-static const uint8 fontData_Mickey[] = {
-	0x00, 0x36, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, 0x00,
-	0x00, 0x00, 0x3F, 0x20, 0x2F, 0x28, 0x28, 0x28,
-	0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
-	0x28, 0x28, 0x2F, 0x20, 0x2F, 0x28, 0x28, 0x28,
-	0x28, 0x28, 0x2F, 0x20, 0x3F, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0xFF, 0x00, 0xEF, 0x28, 0x28, 0x28,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x28, 0x28, 0xEF, 0x00, 0xEF, 0x28, 0x28, 0x28,
-	0x28, 0x28, 0xEF, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0xF8, 0x08, 0xE8, 0x28, 0x28, 0x28,
-	0x28, 0x28, 0xE8, 0x08, 0xE8, 0x28, 0x28, 0x28,
-	0x28, 0x28, 0xE8, 0x08, 0xF8, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0x10,
-	0x10, 0x10, 0xFF, 0x00, 0xFF, 0x10, 0x10, 0x10,
-	0x10, 0x10, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10,
-	0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
-	0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00,
-	0x78, 0x60, 0x78, 0x60, 0x7E, 0x18, 0x1E, 0x00,
-	0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
-	0x00, 0x18, 0x30, 0x7E, 0x30, 0x18, 0x00, 0x00,
-	0x00, 0x18, 0x0C, 0x7E, 0x0C, 0x18, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x66, 0xFF, 0x66, 0x66, 0xFF, 0x66, 0x00,
-	0x18, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x18, 0x00,
-	0x00, 0x66, 0x6C, 0x18, 0x30, 0x66, 0x46, 0x00,
-	0x1C, 0x36, 0x1C, 0x38, 0x6F, 0x66, 0x3B, 0x00,
-	0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x0E, 0x1C, 0x18, 0x18, 0x18, 0x1C, 0x0E, 0x00,
-	0x70, 0x38, 0x18, 0x18, 0x18, 0x38, 0x70, 0x00,
-	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
-	0x00, 0x18, 0x18, 0x7E, 0x18, 0x18, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30,
-	0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00,
-	0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00,
-	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x3C, 0x00,
-	0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00,
-	0x3C, 0x66, 0x06, 0x0C, 0x18, 0x30, 0x7E, 0x00,
-	0x7E, 0x0C, 0x18, 0x0C, 0x06, 0x66, 0x3C, 0x00,
-	0x0C, 0x1C, 0x3C, 0x6C, 0x6C, 0x7E, 0x0C, 0x00,
-	0x7E, 0x60, 0x7C, 0x06, 0x06, 0x66, 0x3C, 0x00,
-	0x3C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x3C, 0x00,
-	0x7E, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
-	0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, 0x00,
-	0x3C, 0x66, 0x66, 0x3E, 0x06, 0x0C, 0x38, 0x00,
-	0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00,
-	0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x30,
-	0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00,
-	0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00,
-	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
-	0x3C, 0x66, 0x04, 0x0C, 0x18, 0x00, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x3C, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
-	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
-	0x78, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0x78, 0x00,
-	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
-	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x60, 0x00,
-	0x3E, 0x60, 0x60, 0x6E, 0x66, 0x66, 0x3E, 0x00,
-	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
-	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, 0x00,
-	0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x3C, 0x00,
-	0x66, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0x66, 0x00,
-	0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x00,
-	0x63, 0x77, 0x7F, 0x6B, 0x63, 0x63, 0x63, 0x00,
-	0x66, 0x76, 0x7E, 0x7E, 0x6E, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
-	0x3C, 0x66, 0x66, 0x66, 0x66, 0x6C, 0x36, 0x00,
-	0x7C, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0x66, 0x00,
-	0x3C, 0x60, 0x60, 0x3C, 0x06, 0x06, 0x3C, 0x00,
-	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00,
-	0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00,
-	0x66, 0x66, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x00,
-	0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x18, 0x00,
-	0x7E, 0x0C, 0x18, 0x30, 0x60, 0x60, 0x7E, 0x00,
-	0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00,
-	0x00, 0x40, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00,
-	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
-	0x00, 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00,
-	0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x00,
-	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3E, 0x00,
-	0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x3C, 0x60, 0x60, 0x60, 0x3C, 0x00,
-	0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
-	0x0E, 0x18, 0x18, 0x3E, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x7C,
-	0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0x06, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x3C,
-	0x60, 0x60, 0x6C, 0x78, 0x6C, 0x66, 0x66, 0x00,
-	0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0x00, 0x00, 0x66, 0x7F, 0x7F, 0x6B, 0x63, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60,
-	0x00, 0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06,
-	0x00, 0x00, 0x7C, 0x66, 0x60, 0x60, 0x60, 0x00,
-	0x00, 0x00, 0x3E, 0x60, 0x3C, 0x06, 0x7C, 0x00,
-	0x18, 0x18, 0x7E, 0x18, 0x18, 0x18, 0x0E, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3E, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x00,
-	0x00, 0x00, 0x63, 0x6B, 0x7F, 0x3E, 0x36, 0x00,
-	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x66, 0x3E, 0x0C, 0x78,
-	0x00, 0x00, 0x7E, 0x0C, 0x18, 0x30, 0x7E, 0x00,
-	0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x18, 0x3C, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x7E, 0x78, 0x7C, 0x6E, 0x66, 0x06, 0x00,
-	0x08, 0x18, 0x38, 0x78, 0x38, 0x18, 0x08, 0x00,
-	0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00,
-	0xFF, 0xC9, 0x80, 0x80, 0xC1, 0xE3, 0xF7, 0xFF,
-	0xFF, 0xFF, 0xC0, 0xDF, 0xD0, 0xD7, 0xD7, 0xD7,
-	0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7,
-	0xD7, 0xD7, 0xD0, 0xDF, 0xD0, 0xD7, 0xD7, 0xD7,
-	0xD7, 0xD7, 0xD0, 0xDF, 0xC0, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0x00, 0xFF, 0x10, 0xD7, 0xD7, 0xD7,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0xD7, 0xD7, 0x10, 0xFF, 0x10, 0xD7, 0xD7, 0xD7,
-	0xD7, 0xD7, 0x10, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0x07, 0xF7, 0x17, 0xD7, 0xD7, 0xD7,
-	0xD7, 0xD7, 0x17, 0xF7, 0x17, 0xD7, 0xD7, 0xD7,
-	0xD7, 0xD7, 0x17, 0xF7, 0x07, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xEF, 0xEF, 0xEF,
-	0xEF, 0xEF, 0x00, 0xFF, 0x00, 0xEF, 0xEF, 0xEF,
-	0xEF, 0xEF, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xEF, 0xEF, 0xEF, 0x00, 0xEF, 0xEF, 0xEF, 0xEF,
-	0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
-	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
-	0x18, 0x18, 0x18, 0x1F, 0x1F, 0x00, 0x00, 0x00,
-	0x78, 0x60, 0x78, 0x60, 0x7E, 0x18, 0x1E, 0x00,
-	0x00, 0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
-	0x00, 0x18, 0x30, 0x7E, 0x30, 0x18, 0x00, 0x00,
-	0x00, 0x18, 0x0C, 0x7E, 0x0C, 0x18, 0x00, 0x00,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xE7, 0xE7, 0xE7, 0xE7, 0xFF, 0xE7, 0xE7, 0xFF,
-	0x99, 0x99, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0x99, 0x00, 0x99, 0x99, 0x00, 0x99, 0xFF,
-	0xE7, 0xC1, 0x9F, 0xC3, 0xF9, 0x83, 0xE7, 0xFF,
-	0xFF, 0x99, 0x93, 0xE7, 0xCF, 0x99, 0xB9, 0xFF,
-	0xE3, 0xC9, 0xE3, 0xC7, 0x90, 0x99, 0xC4, 0xFF,
-	0xE7, 0xE7, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xF1, 0xE3, 0xE7, 0xE7, 0xE7, 0xE3, 0xF1, 0xFF,
-	0x8F, 0xC7, 0xE7, 0xE7, 0xE7, 0xC7, 0x8F, 0xFF,
-	0xFF, 0x99, 0xC3, 0x00, 0xC3, 0x99, 0xFF, 0xFF,
-	0xFF, 0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF,
-	0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF,
-	0xFD, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0xBF, 0xFF,
-	0xC3, 0x99, 0x91, 0x81, 0x89, 0x99, 0xC3, 0xFF,
-	0xE7, 0xC7, 0xE7, 0xE7, 0xE7, 0xE7, 0x81, 0xFF,
-	0xC3, 0x99, 0xF9, 0xF3, 0xE7, 0xCF, 0x81, 0xFF,
-	0x81, 0xF3, 0xE7, 0xF3, 0xF9, 0x99, 0xC3, 0xFF,
-	0xF3, 0xE3, 0xC3, 0x93, 0x93, 0x81, 0xF3, 0xFF,
-	0x81, 0x9F, 0x83, 0xF9, 0xF9, 0x99, 0xC3, 0xFF,
-	0xC3, 0x9F, 0x9F, 0x83, 0x99, 0x99, 0xC3, 0xFF,
-	0x81, 0xF9, 0xF3, 0xE7, 0xCF, 0xCF, 0xCF, 0xFF,
-	0xC3, 0x99, 0x99, 0xC3, 0x99, 0x99, 0xC3, 0xFF,
-	0xC3, 0x99, 0x99, 0xC1, 0xF9, 0xF3, 0xC7, 0xFF,
-	0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xFF,
-	0xFF, 0xE7, 0xE7, 0xFF, 0xFF, 0xE7, 0xE7, 0xCF,
-	0xF9, 0xF3, 0xE7, 0xCF, 0xE7, 0xF3, 0xF9, 0xFF,
-	0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0x81, 0xFF, 0xFF,
-	0x9F, 0xCF, 0xE7, 0xF3, 0xE7, 0xCF, 0x9F, 0xFF,
-	0xC3, 0x99, 0xFB, 0xF3, 0xE7, 0xFF, 0xE7, 0xFF,
-	0xC3, 0x99, 0x99, 0x91, 0x91, 0x9F, 0xC1, 0xFF,
-	0xE7, 0xC3, 0x99, 0x99, 0x81, 0x99, 0x99, 0xFF,
-	0x83, 0x99, 0x99, 0x83, 0x99, 0x99, 0x83, 0xFF,
-	0xC3, 0x99, 0x9F, 0x9F, 0x9F, 0x99, 0xC3, 0xFF,
-	0x87, 0x93, 0x99, 0x99, 0x99, 0x93, 0x87, 0xFF,
-	0x81, 0x9F, 0x9F, 0x83, 0x9F, 0x9F, 0x81, 0xFF,
-	0x81, 0x9F, 0x9F, 0x83, 0x9F, 0x9F, 0x9F, 0xFF,
-	0xC1, 0x9F, 0x9F, 0x91, 0x99, 0x99, 0xC1, 0xFF,
-	0x99, 0x99, 0x99, 0x81, 0x99, 0x99, 0x99, 0xFF,
-	0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x81, 0xFF,
-	0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0x99, 0xC3, 0xFF,
-	0x99, 0x93, 0x87, 0x87, 0x93, 0x99, 0x99, 0xFF,
-	0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x81, 0xFF,
-	0x9C, 0x88, 0x80, 0x94, 0x9C, 0x9C, 0x9C, 0xFF,
-	0x99, 0x89, 0x81, 0x81, 0x91, 0x99, 0x99, 0xFF,
-	0xC3, 0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xFF,
-	0x83, 0x99, 0x99, 0x99, 0x83, 0x9F, 0x9F, 0xFF,
-	0xC3, 0x99, 0x99, 0x99, 0x99, 0x93, 0xC9, 0xFF,
-	0x83, 0x99, 0x99, 0x83, 0x93, 0x99, 0x99, 0xFF,
-	0xC3, 0x9F, 0x9F, 0xC3, 0xF9, 0xF9, 0xC3, 0xFF,
-	0x81, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xFF,
-	0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x81, 0xFF,
-	0x99, 0x99, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF,
-	0x9C, 0x9C, 0x9C, 0x94, 0x80, 0x88, 0x9C, 0xFF,
-	0x99, 0x99, 0xC3, 0xC3, 0x99, 0x99, 0x99, 0xFF,
-	0x99, 0x99, 0x99, 0xC3, 0xE7, 0xE7, 0xE7, 0xFF,
-	0x81, 0xF3, 0xE7, 0xCF, 0x9F, 0x9F, 0x81, 0xFF,
-	0xE1, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE1, 0xFF,
-	0xFF, 0xBF, 0x9F, 0xCF, 0xE7, 0xF3, 0xF9, 0xFF,
-	0x87, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0x87, 0xFF,
-	0xFF, 0xF7, 0xE3, 0xC9, 0x9C, 0xFF, 0xFF, 0xFF,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,
-	0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x3C, 0x18, 0x00,
-	0xFF, 0xFF, 0xC3, 0xF9, 0xC1, 0x99, 0xC1, 0xFF,
-	0x9F, 0x9F, 0x83, 0x99, 0x99, 0x99, 0x83, 0xFF,
-	0xFF, 0xFF, 0xC3, 0x9F, 0x9F, 0x9F, 0xC3, 0xFF,
-	0xF9, 0xF9, 0xC1, 0x99, 0x99, 0x99, 0xC1, 0xFF,
-	0xFF, 0xFF, 0xC3, 0x99, 0x81, 0x9F, 0xC3, 0xFF,
-	0xF1, 0xE7, 0xE7, 0xC1, 0xE7, 0xE7, 0xE7, 0xFF,
-	0xFF, 0xFF, 0xC1, 0x99, 0x99, 0xC1, 0xF9, 0x83,
-	0x9F, 0x9F, 0x83, 0x99, 0x99, 0x99, 0x99, 0xFF,
-	0xE7, 0xFF, 0xC7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF,
-	0xF9, 0xFF, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xC3,
-	0x9F, 0x9F, 0x93, 0x87, 0x93, 0x99, 0x99, 0xFF,
-	0xC7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xC3, 0xFF,
-	0xFF, 0xFF, 0x99, 0x80, 0x80, 0x94, 0x9C, 0xFF,
-	0xFF, 0xFF, 0x83, 0x99, 0x99, 0x99, 0x99, 0xFF,
-	0xFF, 0xFF, 0xC3, 0x99, 0x99, 0x99, 0xC3, 0xFF,
-	0xFF, 0xFF, 0x83, 0x99, 0x99, 0x83, 0x9F, 0x9F,
-	0xFF, 0xFF, 0xC1, 0x99, 0x99, 0xC1, 0xF9, 0xF9,
-	0xFF, 0xFF, 0x83, 0x99, 0x9F, 0x9F, 0x9F, 0xFF,
-	0xFF, 0xFF, 0xC1, 0x9F, 0xC3, 0xF9, 0x83, 0xFF,
-	0xE7, 0xE7, 0x81, 0xE7, 0xE7, 0xE7, 0xF1, 0xFF,
-	0xFF, 0xFF, 0x99, 0x99, 0x99, 0x99, 0xC1, 0xFF,
-	0xFF, 0xFF, 0x99, 0x99, 0x99, 0xC3, 0xE7, 0xFF,
-	0xFF, 0xFF, 0x9C, 0x94, 0x80, 0xC1, 0xC9, 0xFF,
-	0xFF, 0xFF, 0x99, 0xC3, 0xE7, 0xC3, 0x99, 0xFF,
-	0xFF, 0xFF, 0x99, 0x99, 0x99, 0xC1, 0xF3, 0x87,
-	0xFF, 0xFF, 0x81, 0xF3, 0xE7, 0xCF, 0x81, 0xFF,
-	0x00, 0x18, 0x3C, 0x7E, 0x7E, 0x18, 0x3C, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x7E, 0x78, 0x7C, 0x6E, 0x66, 0x06, 0x00,
-	0x08, 0x18, 0x38, 0x78, 0x38, 0x18, 0x08, 0x00,
-	0x10, 0x18, 0x1C, 0x1E, 0x1C, 0x18, 0x10, 0x00,
-};
-#endif
+private:
+	void loadFontMickey();
+	void loadFontAmigaPseudoTopaz();
+	void loadFontAppleIIgs();
 
-static const uint8 fontData_IBM[] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
-	0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
-	0x6C, 0xFE, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00,
-	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
-	0x38, 0x7C, 0x38, 0xFE, 0xFE, 0x7C, 0x38, 0x7C,
-	0x10, 0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x7C,
-	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
-	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
-	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
-	0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
-	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
-	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
-	0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0,
-	0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0,
-	0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99,
-	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
-	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
-	0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
-	0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00,
-	0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78,
-	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
-	0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF,
-	0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
-	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
-	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
-	0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00,
-	0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00,
-	0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
-	0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
-	0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
-	0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
-	0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
-	0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
-	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
-	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
-	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
-	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
-	0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
-	0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00,
-	0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
-	0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
-	0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
-	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
-	0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
-	0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
-	0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
-	0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
-	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
-	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
-	0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
-	0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
-	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
-	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
-	0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00,
-	0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
-	0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
-	0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
-	0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
-	0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
-	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
-	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
-	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
-	0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
-	0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
-	0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
-	0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
-	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
-	0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
-	0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
-	0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
-	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
-	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
-	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
-	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
-	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-	0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
-	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
-	0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
-	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
-	0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
-	0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
-	0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
-	0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
-	0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
-	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
-	0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
-	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
-	0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
-	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
-	0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78,
-	0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
-	0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00,
-	0xCC, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
-	0xE0, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
-	0x30, 0x30, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
-	0x00, 0x00, 0x78, 0xC0, 0xC0, 0x78, 0x0C, 0x38,
-	0x7E, 0xC3, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
-	0xCC, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0xE0, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0xCC, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x7C, 0xC6, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0xE0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0xC6, 0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0xC6, 0x00,
-	0x30, 0x30, 0x00, 0x78, 0xCC, 0xFC, 0xCC, 0x00,
-	0x1C, 0x00, 0xFC, 0x60, 0x78, 0x60, 0xFC, 0x00,
-	0x00, 0x00, 0x7F, 0x0C, 0x7F, 0xCC, 0x7F, 0x00,
-	0x3E, 0x6C, 0xCC, 0xFE, 0xCC, 0xCC, 0xCE, 0x00,
-	0x78, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0xCC, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0xE0, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x78, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
-	0x00, 0xE0, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
-	0x00, 0xCC, 0x00, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0xC3, 0x18, 0x3C, 0x66, 0x66, 0x3C, 0x18, 0x00,
-	0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
-	0x18, 0x18, 0x7E, 0xC0, 0xC0, 0x7E, 0x18, 0x18,
-	0x38, 0x6C, 0x64, 0xF0, 0x60, 0xE6, 0xFC, 0x00,
-	0xCC, 0xCC, 0x78, 0xFC, 0x30, 0xFC, 0x30, 0x30,
-	0xF8, 0xCC, 0xCC, 0xFA, 0xC6, 0xCF, 0xC6, 0xC7,
-	0x0E, 0x1B, 0x18, 0x3C, 0x18, 0x18, 0xD8, 0x70,
-	0x1C, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x7E, 0x00,
-	0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x00, 0x1C, 0x00, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0x1C, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
-	0x00, 0xF8, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0x00,
-	0xFC, 0x00, 0xCC, 0xEC, 0xFC, 0xDC, 0xCC, 0x00,
-	0x3C, 0x6C, 0x6C, 0x3E, 0x00, 0x7E, 0x00, 0x00,
-	0x38, 0x6C, 0x6C, 0x38, 0x00, 0x7C, 0x00, 0x00,
-	0x30, 0x00, 0x30, 0x60, 0xC0, 0xCC, 0x78, 0x00,
-	0x00, 0x00, 0x00, 0xFC, 0xC0, 0xC0, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xFC, 0x0C, 0x0C, 0x00, 0x00,
-	0xC3, 0xC6, 0xCC, 0xDE, 0x33, 0x66, 0xCC, 0x0F,
-	0xC3, 0xC6, 0xCC, 0xDB, 0x37, 0x6F, 0xCF, 0x03,
-	0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x33, 0x66, 0xCC, 0x66, 0x33, 0x00, 0x00,
-	0x00, 0xCC, 0x66, 0x33, 0x66, 0xCC, 0x00, 0x00,
-	0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
-	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
-	0xDB, 0x77, 0xDB, 0xEE, 0xDB, 0x77, 0xDB, 0xEE,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36,
-	0x18, 0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36,
-	0x18, 0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
-	0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x76, 0xDC, 0xC8, 0xDC, 0x76, 0x00,
-	0x00, 0x78, 0xCC, 0xF8, 0xCC, 0xF8, 0xC0, 0xC0,
-	0x00, 0xFC, 0xCC, 0xC0, 0xC0, 0xC0, 0xC0, 0x00,
-	0x00, 0xFE, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x00,
-	0xFC, 0xCC, 0x60, 0x30, 0x60, 0xCC, 0xFC, 0x00,
-	0x00, 0x00, 0x7E, 0xD8, 0xD8, 0xD8, 0x70, 0x00,
-	0x00, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0xC0,
-	0x00, 0x76, 0xDC, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0xFC, 0x30, 0x78, 0xCC, 0xCC, 0x78, 0x30, 0xFC,
-	0x38, 0x6C, 0xC6, 0xFE, 0xC6, 0x6C, 0x38, 0x00,
-	0x38, 0x6C, 0xC6, 0xC6, 0x6C, 0x6C, 0xEE, 0x00,
-	0x1C, 0x30, 0x18, 0x7C, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x00, 0x00,
-	0x06, 0x0C, 0x7E, 0xDB, 0xDB, 0x7E, 0x60, 0xC0,
-	0x38, 0x60, 0xC0, 0xF8, 0xC0, 0x60, 0x38, 0x00,
-	0x78, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x00, 0xFC, 0x00, 0xFC, 0x00, 0xFC, 0x00, 0x00,
-	0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0xFC, 0x00,
-	0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xFC, 0x00,
-	0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xFC, 0x00,
-	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
-	0x30, 0x30, 0x00, 0xFC, 0x00, 0x30, 0x30, 0x00,
-	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
-	0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-	0x0F, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C,
-	0x78, 0x6C, 0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00,
-	0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x3C, 0x3C, 0x3C, 0x3C, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	const uint8 *_fontData; // pointer to the currently used font
+	uint8 *_fontDataAllocated;
 };
 
 } // End of namespace Agi
diff --git a/engines/agi/module.mk b/engines/agi/module.mk
index b6cf6fc..32c3ac2 100644
--- a/engines/agi/module.mk
+++ b/engines/agi/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS := \
 	console.o \
 	cycle.o \
 	detection.o \
+	font.o \
 	global.o \
 	graphics.o \
 	id.o \
diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp
index c0a53e7..833b2d3 100644
--- a/engines/agi/preagi.cpp
+++ b/engines/agi/preagi.cpp
@@ -56,11 +56,12 @@ PreAgiEngine::PreAgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) :
 
 void PreAgiEngine::initialize() {
 	initRenderMode();
-	initFont();
 
+	_font = new GfxFont(this);
 	_gfx = new GfxMgr(this);
 	_picture = new PictureMgr(this, _gfx);
 
+	_font->init();
 	_gfx->initMachine();
 
 	_game.gameFlags = 0;
@@ -93,6 +94,10 @@ void PreAgiEngine::initialize() {
 PreAgiEngine::~PreAgiEngine() {
 	_mixer->stopHandle(_speakerHandle);
 	delete _speakerStream;
+
+	delete _picture;
+	delete _gfx;
+	delete _font;
 }
 
 int PreAgiEngine::rnd(int hi) {


Commit: 614884ed39d011c91291c1a3307e82f853dcfe78
    https://github.com/scummvm/scummvm/commit/614884ed39d011c91291c1a3307e82f853dcfe78
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T16:43:15+01:00

Commit Message:
AGI: support for user-supplied font-file

agi-font-atarist.bin -> used for platform Atari ST
agi-font-amiga.bin -> used for platform Amiga
agi-font-dos.bin -> used for platform DOS
agi-font-fanmade.bin -> used for fan-made games

That way users can get a more accurate font.

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



diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
index 0a6ac54..b3547c2 100644
--- a/engines/agi/font.cpp
+++ b/engines/agi/font.cpp
@@ -996,14 +996,20 @@ void GfxFont::init() {
 	// We are currently using the custom font for all fanmade games
 	if (_vm->getFeatures() & (GF_FANMADE | GF_AGDS)) {
 		// fanmade game, use custom font for now
-		_fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc.
+		loadFontScummVMFile("agi-font-fangame.bin");
+		if (_fontData) {
+			_fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc.
+		}
 		return;
 	}
 
 	switch (_vm->_renderMode) {
 	case Common::kRenderAmiga:
-		loadFontAmigaPseudoTopaz();
-		//_fontData = fontData_Amiga; // use Amiga Topaz font
+		// Try user-file first, if that fails use our internal inaccurate topaz font
+		loadFontScummVMFile("agi-font-amiga.bin");
+		if (!_fontData) {
+			loadFontAmigaPseudoTopaz();
+		}
 		break;
 	case Common::kRenderApple2GS:
 		// Special font, stored in file AGIFONT
@@ -1012,7 +1018,11 @@ void GfxFont::init() {
 	case Common::kRenderAtariST:
 		// TODO: Atari ST uses another font
 		// Seems to be the standard Atari ST 8x8 system font
-
+		loadFontScummVMFile("agi-font-atarist.bin");
+		if (!_fontData) {
+			// TODO: in case we find a recreation of the font, add it in here
+		}
+		break;
 	case Common::kRenderCGA:
 	case Common::kRenderEGA:
 	case Common::kRenderVGA:
@@ -1022,6 +1032,7 @@ void GfxFont::init() {
 			loadFontMickey();
 			break;
 		default:
+			loadFontScummVMFile("agi-font-dos.bin");
 			break;
 		}
 		break;
@@ -1051,6 +1062,42 @@ const byte *GfxFont::getFontData() {
 	return _fontData;
 }
 
+// This code loads a ScummVM-specific user-supplied binary font file
+// It's assumed that it's a plain binary file, that contains 256 characters. 8 bytes per character.
+// 8x8 pixels per character. File size 2048 bytes.
+//
+// Currently used for:
+//  Atari ST - "agi-font-atarist.bin" -> should be the Atari ST 8x8 system font
+//  Amiga    - "agi-font-amiga.bin"   -> should be the Amiga 8x8 Topaz font
+//  DOS      - "agi-font-dos.bin"
+//  Fangames - "agi-font-fangame.bin"
+void GfxFont::loadFontScummVMFile(Common::String fontFilename) {
+	Common::File fontFile;
+	int32 fontFileSize = 0;
+
+	if (!fontFile.open(fontFilename)) {
+		// Continue, if file not found
+		// These ScummVM font files are totally optional, so don't show a warning
+		return;
+	}
+
+	fontFileSize = fontFile.size();
+	if (fontFileSize != (256 * 8)) {
+		// unexpected file size
+		fontFile.close();
+		warning("Fontfile '%s': unexpected file size", fontFilename.c_str());
+		return;
+	}
+
+	// allocate space for font bitmap data
+	_fontDataAllocated = (uint8 *)calloc(256, 8);
+	_fontData = _fontDataAllocated;
+ 
+	// read font data, is already in the format that we need (plain bitmap 8x8)
+	fontFile.read(_fontDataAllocated, 256 * 8);
+	fontFile.close();
+}
+
 // We load the Mickey Mouse font from MICKEY.EXE
 void GfxFont::loadFontMickey() {
 	Common::File interpreterFile;
diff --git a/engines/agi/font.h b/engines/agi/font.h
index 130e863..791b1b0 100644
--- a/engines/agi/font.h
+++ b/engines/agi/font.h
@@ -38,6 +38,7 @@ public:
 	const byte *getFontData();
 
 private:
+	void loadFontScummVMFile(Common::String fontFilename);
 	void loadFontMickey();
 	void loadFontAmigaPseudoTopaz();
 	void loadFontAppleIIgs();


Commit: 72161adf1c7eec7f1ca889fb5ed9017029e6e6da
    https://github.com/scummvm/scummvm/commit/72161adf1c7eec7f1ca889fb5ed9017029e6e6da
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T17:14:49+01:00

Commit Message:
AGI: overwrite save restore dialog font character

Overwrite it, to make sure that original save/restore dialogs
look properly.

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



diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
index b3547c2..b9a7795 100644
--- a/engines/agi/font.cpp
+++ b/engines/agi/font.cpp
@@ -1062,6 +1062,12 @@ const byte *GfxFont::getFontData() {
 	return _fontData;
 }
 
+void GfxFont::overwriteSaveRestoreDialogCharacter() {
+	// overwrite character 0x1A with the standard Sierra arrow to the right character
+	// required for the original save/restore dialogs
+	memcpy(_fontDataAllocated + (0x1A * 8), fontData_ArrowRightCharacter, sizeof(fontData_ArrowRightCharacter));
+}
+
 // This code loads a ScummVM-specific user-supplied binary font file
 // It's assumed that it's a plain binary file, that contains 256 characters. 8 bytes per character.
 // 8x8 pixels per character. File size 2048 bytes.
@@ -1096,6 +1102,8 @@ void GfxFont::loadFontScummVMFile(Common::String fontFilename) {
 	// read font data, is already in the format that we need (plain bitmap 8x8)
 	fontFile.read(_fontDataAllocated, 256 * 8);
 	fontFile.close();
+
+	overwriteSaveRestoreDialogCharacter();
 }
 
 // We load the Mickey Mouse font from MICKEY.EXE
@@ -1198,6 +1206,8 @@ void GfxFont::loadFontAmigaPseudoTopaz() {
 			fontData += 8;
 		}
 	}
+
+	overwriteSaveRestoreDialogCharacter();
 }
 
 void GfxFont::loadFontAppleIIgs() {
@@ -1385,9 +1395,7 @@ void GfxFont::loadFontAppleIIgs() {
 	free(locationTablePtr);
 	free(strikeDataPtr);
 
-	// overwrite character 0x1A with the standard Sierra arrow to the right character
-	// required for the original save/restore dialogs
-	memcpy(_fontDataAllocated + (0x1A * 8), fontData_ArrowRightCharacter, sizeof(fontData_ArrowRightCharacter));
+	overwriteSaveRestoreDialogCharacter();
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/font.h b/engines/agi/font.h
index 791b1b0..bff02f9 100644
--- a/engines/agi/font.h
+++ b/engines/agi/font.h
@@ -38,6 +38,8 @@ public:
 	const byte *getFontData();
 
 private:
+	void overwriteSaveRestoreDialogCharacter();
+
 	void loadFontScummVMFile(Common::String fontFilename);
 	void loadFontMickey();
 	void loadFontAmigaPseudoTopaz();


Commit: 855059ca059ce1d2c770475eac66ae1abaff2372
    https://github.com/scummvm/scummvm/commit/855059ca059ce1d2c770475eac66ae1abaff2372
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T21:13:33+01:00

Commit Message:
AGI: font loader support for Atari ST font

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



diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
index b9a7795..b7cadf0 100644
--- a/engines/agi/font.cpp
+++ b/engines/agi/font.cpp
@@ -997,8 +997,9 @@ void GfxFont::init() {
 	if (_vm->getFeatures() & (GF_FANMADE | GF_AGDS)) {
 		// fanmade game, use custom font for now
 		loadFontScummVMFile("agi-font-fangame.bin");
-		if (_fontData) {
+		if (!_fontData) {
 			_fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc.
+			debug("Using fanmade custom font");
 		}
 		return;
 	}
@@ -1020,7 +1021,10 @@ void GfxFont::init() {
 		// Seems to be the standard Atari ST 8x8 system font
 		loadFontScummVMFile("agi-font-atarist.bin");
 		if (!_fontData) {
-			// TODO: in case we find a recreation of the font, add it in here
+			loadFontAtariST("agi-font-atarist-system.fnt");
+			if (!_fontData) {
+				// TODO: in case we find a recreation of the font, add it in here
+			}
 		}
 		break;
 	case Common::kRenderCGA:
@@ -1059,6 +1063,7 @@ void GfxFont::init() {
 }
 
 const byte *GfxFont::getFontData() {
+	assert(_fontData);
 	return _fontData;
 }
 
@@ -1104,6 +1109,8 @@ void GfxFont::loadFontScummVMFile(Common::String fontFilename) {
 	fontFile.close();
 
 	overwriteSaveRestoreDialogCharacter();
+
+	debug("Using user-supplied font");
 }
 
 // We load the Mickey Mouse font from MICKEY.EXE
@@ -1135,6 +1142,8 @@ void GfxFont::loadFontMickey() {
 	// read font data, is already in the format that we need (plain bitmap 8x8)
 	interpreterFile.read(fontData, 256 * 8);
 	interpreterFile.close();
+
+	debug("Using Mickey Mouse font");
 }
 
 // we create a bitmap out of the topaz data used in parallaction (which is normally found in staticres.cpp)
@@ -1208,6 +1217,8 @@ void GfxFont::loadFontAmigaPseudoTopaz() {
 	}
 
 	overwriteSaveRestoreDialogCharacter();
+
+	debug("Using recreation of Amiga Topaz font");
 }
 
 void GfxFont::loadFontAppleIIgs() {
@@ -1398,4 +1409,131 @@ void GfxFont::loadFontAppleIIgs() {
 	overwriteSaveRestoreDialogCharacter();
 }
 
+// Loads Atari ST font file
+// It's found inside Atari ST ROMs. Just search for "8x8 system font". Font starts 4 bytes before that.
+void GfxFont::loadFontAtariST(Common::String fontFilename) {
+	Common::File fontFile;
+	uint16 header_FirstChar = 0;
+	uint16 header_LastChar = 0;
+	uint16 header_MaxWidth = 0;
+	uint16 header_MaxHeight = 0;
+	uint16 header_Flags = 0;
+	uint32 header_OffsetOfCharOffsets = 0;
+	uint32 header_OffsetOfFontData = 0;
+	uint16 header_FormWidth = 0;
+	uint16 header_FormHeight = 0;
+	uint16 totalCharacterCount = 0;
+	uint16 *charOffsetTablePtr = nullptr;
+	byte *rawDataTablePtr = nullptr;
+
+	uint16 curCharNr = 0;
+	uint16 curCharRawOffset = 0;
+	uint16 curCharDestOffset = 0;
+	uint16 curRow = 0;
+
+	byte *fontData = nullptr;
+
+	if (!fontFile.open(fontFilename)) {
+		// Continue, if file not found
+		warning("Could not open file 'agi-font-atarist-system.bin' for Atari ST 8x8 system font");
+		return;
+	}
+
+	// Atari ST font header
+	fontFile.skip(2); // face identifier
+	fontFile.skip(2); // point size
+	fontFile.skip(32); // font name
+	header_FirstChar = fontFile.readUint16BE();
+	header_LastChar = fontFile.readUint16BE();
+	fontFile.skip(10); // aligntment of cells
+	header_MaxWidth = fontFile.readUint16BE();
+	header_MaxHeight = fontFile.readUint16BE();
+	fontFile.skip(2); // left offset cel
+	fontFile.skip(2); // right offset cel
+	fontFile.skip(2); // number of pixels to thicken pixels
+	fontFile.skip(2); // underline width
+	fontFile.skip(2); // lightening mask
+	fontFile.skip(2); // skewing mask
+	header_Flags = fontFile.readUint16BE();
+	// bit 0 - default system font
+	// bit 1 - horizontal offset table (not supported)
+	// bit 2 - byte orientation word is high->low
+	// bit 3 - mono spaced font
+	fontFile.skip(4); // horizontal table offset
+	header_OffsetOfCharOffsets = fontFile.readUint32BE();
+	header_OffsetOfFontData = fontFile.readUint32BE();
+	header_FormWidth = fontFile.readUint16BE();
+	header_FormHeight = fontFile.readUint16BE();
+	fontFile.skip(4); // pointer to next font
+
+	totalCharacterCount = header_LastChar - header_FirstChar + 1;
+
+	// security-checks
+	if (header_MaxWidth > 8)
+		error("AtariST-font: not a 8x8 font");
+	if (header_MaxHeight != 8)
+		error("AtariST-font: not a 8x8 font");
+	if (header_FormHeight != 8)
+		error("AtariST-font: not a 8x8 font");
+	if ((header_FirstChar != 0) || (header_LastChar != 255))
+		error("AtariST-font: unexpected characters");
+	if (header_FormWidth != totalCharacterCount)
+		error("AtariST-font: header inconsistency");
+	if (!(header_Flags & 0x04))
+		error("AtariST-font: font data not in high->low order");
+	if (!(header_Flags & 0x08))
+		error("AtariST-font: not a mono-spaced font");
+
+	// Now we should normally use the offsets, but they don't make sense to me
+	// So I just read the data directly. For the 8x8 system font that works
+	fontFile.skip(2); // extra bytes
+
+	// Allocate memory for tables
+	charOffsetTablePtr = (uint16 *)calloc(totalCharacterCount, 2); // 1 word per character
+	rawDataTablePtr = (byte *)calloc(header_FormWidth, header_FormHeight);
+
+	// Char-Offset Table (2 * total number of characters)
+	for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+		charOffsetTablePtr[curCharNr] = fontFile.readUint16BE();
+	}
+
+	// Followed by actual font data
+	// Attention: Atari ST fonts contain every same row of all characters after each other.
+	// So it's basically like this:
+	// [character data of first row of first character]
+	// [character data of first row of second character]
+	// ...
+	// [character data of first row of last character]
+	// [character data of second row of first character]
+	fontFile.skip(2); // extra bytes
+	fontFile.read(rawDataTablePtr, header_FormWidth * header_FormHeight);
+	fontFile.close();
+
+	// allocate space for font bitmap data
+	fontData = (uint8 *)calloc(256, 8);
+	_fontData = fontData;
+	_fontDataAllocated = fontData;
+
+	// extract font bitmap data
+	for (curCharNr = 0; curCharNr < totalCharacterCount; curCharNr++) {
+		// Figure out base offset from char offset table
+		curCharRawOffset = charOffsetTablePtr[curCharNr] >> 3;
+		curCharDestOffset = curCharNr * 8; // destination offset into our font data
+
+		// now copy over every row of the character
+		for (curRow = 0; curRow < header_FormHeight; curRow++) {
+			fontData[curCharDestOffset] = rawDataTablePtr[curCharRawOffset];
+			curCharDestOffset++;
+			curCharRawOffset += header_FormWidth;
+		}
+	}
+
+	free(rawDataTablePtr);
+	free(charOffsetTablePtr);
+
+	overwriteSaveRestoreDialogCharacter();
+
+	debug("Using Atari ST 8x8 system font");
+}
+
 } // End of namespace Agi
diff --git a/engines/agi/font.h b/engines/agi/font.h
index bff02f9..833cf73 100644
--- a/engines/agi/font.h
+++ b/engines/agi/font.h
@@ -44,6 +44,7 @@ private:
 	void loadFontMickey();
 	void loadFontAmigaPseudoTopaz();
 	void loadFontAppleIIgs();
+	void loadFontAtariST(Common::String fontFilename);
 
 	const uint8 *_fontData; // pointer to the currently used font
 	uint8 *_fontDataAllocated;


Commit: e8791ac979b30b710774bc852f1cc433d09dfc4f
    https://github.com/scummvm/scummvm/commit/e8791ac979b30b710774bc852f1cc433d09dfc4f
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-29T22:49:24+01:00

Commit Message:
AGI: add hack to make numpad cursor keys work

should probably get fixed at some point in backend

Changed paths:
    engines/agi/keyboard.cpp



diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index c307b07..3368ea5 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -171,11 +171,19 @@ void AgiEngine::processEvents() {
 				break;
 			}
 
-			if ((event.kbd.ascii) && (event.kbd.ascii <= 0xFF)) {
+			key = event.kbd.ascii;
+			if (event.kbd.keycode >= Common::KEYCODE_KP0 && event.kbd.keycode <= Common::KEYCODE_KP9) {
+				if (!(event.kbd.flags & Common::KBD_NUM)) {
+					// HACK: Num-Lock not enabled
+					// We shouldn't get a valid ascii code in these cases. We fix it here, so that cursor keys
+					// on the numpad work properly.
+					key = 0;
+				}
+			}
+
+			if ((key) && (key <= 0xFF)) {
 				// No special key, directly accept it
 				// Is ISO-8859-1, we need lower 128 characters only, which is plain ASCII, so no mapping required
-				key = event.kbd.ascii;
-
 				if (Common::isAlpha(key)) {
 					// Key is A-Z.
 					// Map Ctrl-A to 1, Ctrl-B to 2, etc.
@@ -187,7 +195,9 @@ void AgiEngine::processEvents() {
 					}
 				}
 			} else {
-				switch (key = event.kbd.keycode) {
+				key = event.kbd.keycode;
+
+				switch (key) {
 				case Common::KEYCODE_LEFT:
 				case Common::KEYCODE_KP4:
 					if (_allowSynthetic || !event.synthetic)


Commit: bd59851300564d32cefc0950a9809356f9b841c8
    https://github.com/scummvm/scummvm/commit/bd59851300564d32cefc0950a9809356f9b841c8
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-30T00:14:29+01:00

Commit Message:
AGI: fix amiga mouse cursor comment

Changed paths:
    engines/agi/mouse_cursor.h



diff --git a/engines/agi/mouse_cursor.h b/engines/agi/mouse_cursor.h
index 1883960..381ad9f 100644
--- a/engines/agi/mouse_cursor.h
+++ b/engines/agi/mouse_cursor.h
@@ -156,8 +156,8 @@ static const byte MOUSECURSOR_AMIGA[] = {
  * An Amiga-style busy cursor showing an hourglass (13x16).
  * 0 = Transparent.
  * 1 = Black     (#000000 in 24-bit RGB).
- * 2 = Red       (#DE2021 in 24-bit RGB).
- * 3 = Light red (#FFCFAD in 24-bit RGB).
+ * 3 = Red       (#DE2021 in 24-bit RGB).
+ * 4 = Light red (#FFCFAD in 24-bit RGB).
  */
 static const byte MOUSECURSOR_AMIGA_BUSY[] = {
 	1,1,1,1,1,1,1,1,1,1,1,1,1,


Commit: 243c8612645e2dae2f4bbeb09d8e93e3960da5ff
    https://github.com/scummvm/scummvm/commit/243c8612645e2dae2f4bbeb09d8e93e3960da5ff
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-30T01:56:25+01:00

Commit Message:
AGI: fix F7-F10 keys

Changed paths:
    engines/agi/keyboard.h



diff --git a/engines/agi/keyboard.h b/engines/agi/keyboard.h
index e5cf955..accc167 100644
--- a/engines/agi/keyboard.h
+++ b/engines/agi/keyboard.h
@@ -66,10 +66,10 @@ public:
 #define AGI_KEY_F4  0x3E00
 #define AGI_KEY_F5  0x3F00
 #define AGI_KEY_F6  0x4000
-#define AGI_KEY_F7  0x4000
-#define AGI_KEY_F8  0x4100
-#define AGI_KEY_F9  0x4200
-#define AGI_KEY_F10 0x4300
+#define AGI_KEY_F7  0x4100
+#define AGI_KEY_F8  0x4200
+#define AGI_KEY_F9  0x4300
+#define AGI_KEY_F10 0x4400
 #define AGI_KEY_F11 0xd900	// F11
 #define AGI_KEY_F12 0xda00	// F12
 


Commit: 125cec693f234a46e0386445c2e87b722597a8b9
    https://github.com/scummvm/scummvm/commit/125cec693f234a46e0386445c2e87b722597a8b9
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-30T02:29:52+01:00

Commit Message:
AGI: do not allow load/save while in inner loop

load/saving via ScummVM menu

Mixed up mother goose has an endless script loop, when no user name
was entered, which means restoring while in there would result
in us staying in the inner loop until the user entered something

Changed paths:
    engines/agi/detection.cpp



diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 17358e0..641fe55 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -570,17 +570,39 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 namespace Agi {
 
 bool AgiBase::canLoadGameStateCurrently() {
-	return (!(getGameType() == GType_PreAGI) && getflag(VM_FLAG_MENUS_WORK) && !_noSaveLoadAllowed);
+	if (!(getGameType() == GType_PreAGI)) {
+		if (getflag(VM_FLAG_MENUS_WORK)) {
+			if (!_noSaveLoadAllowed) {
+				if (!cycleInnerLoopIsActive()) {
+					// We can't allow to restore a game, while inner loop is active
+					// For example Mixed Up Mother Goose has an endless loop for user name input
+					// Which means even if we abort the inner loop, the game would keep on calling
+					// GetString() until something is entered. And this would of course also happen
+					// right after restoring a saved game.
+					return true;
+				}
+			}
+		}
+	}
+	return false;
 }
 
 bool AgiBase::canSaveGameStateCurrently() {
-	bool promptEnabled = false;
-
 	if (getGameID() == GID_BC) // Technically in Black Cauldron we may save anytime
 		return true;
 
-	promptEnabled = promptIsEnabled();
-	return (!(getGameType() == GType_PreAGI) && getflag(VM_FLAG_MENUS_WORK) && !_noSaveLoadAllowed && promptEnabled);
+	if (!(getGameType() == GType_PreAGI)) {
+		if (getflag(VM_FLAG_MENUS_WORK)) {
+			if (!_noSaveLoadAllowed) {
+				if (!cycleInnerLoopIsActive()) {
+					if (promptIsEnabled()) {
+						return true;
+					}
+				}
+			}
+		}
+	}
+	return false;
 }
 
 int AgiEngine::agiDetectGame() {


Commit: 72f0d012c6fe907c944fe61f465f286981d3a6de
    https://github.com/scummvm/scummvm/commit/72f0d012c6fe907c944fe61f465f286981d3a6de
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-30T02:43:08+01:00

Commit Message:
AGI: fix keyboard input code for keycodes

Reset key, when no valid .ascii was received.

Changed paths:
    engines/agi/keyboard.cpp



diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 3368ea5..62bcfc2 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -195,9 +195,8 @@ void AgiEngine::processEvents() {
 					}
 				}
 			} else {
-				key = event.kbd.keycode;
-
-				switch (key) {
+				key = 0;
+				switch (event.kbd.keycode) {
 				case Common::KEYCODE_LEFT:
 				case Common::KEYCODE_KP4:
 					if (_allowSynthetic || !event.synthetic)


Commit: 98730cb962eef946b039bf5170cddccb7af6fbba
    https://github.com/scummvm/scummvm/commit/98730cb962eef946b039bf5170cddccb7af6fbba
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-30T03:13:17+01:00

Commit Message:
AGI: Fix some word parsing issues

- Keep a non-lowercased user input copy for copying out words
- Check for user input word end after matching a dictionary word
- Fix detection of "a" and "i" words

Changed paths:
    engines/agi/words.cpp



diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp
index 7eca2b8..3c248e9 100644
--- a/engines/agi/words.cpp
+++ b/engines/agi/words.cpp
@@ -215,23 +215,20 @@ void Words::cleanUpInput(const char *rawUserInput, Common::String &cleanInput) {
 		// ends with a space? remove it
 		cleanInput.deleteLastChar();
 	}
-
-	// Sierra compared independent of upper case and lower case
-	cleanInput.toLowercase();
 }
 
-int16 Words::findWordInDictionary(const Common::String &userInput, uint16 userInputLen, uint16 userInputPos, uint16 &foundWordLen) {
+int16 Words::findWordInDictionary(const Common::String &userInputLowcased, uint16 userInputLen, uint16 userInputPos, uint16 &foundWordLen) {
 	uint16 userInputLeft = userInputLen - userInputPos;
 	uint16 wordStartPos = userInputPos;
 	int16 wordId = DICTIONARY_RESULT_UNKNOWN;
-	byte  firstChar = userInput[userInputPos];
+	byte  firstChar = userInputLowcased[userInputPos];
 	byte  curUserInputChar = 0;
 
 	foundWordLen = 0;
 
 	if ((firstChar >= 'a') && (firstChar <= 'z')) {
 		// word has to start with a letter
-		if (((userInputPos + 1) == userInputLen) || (userInput[1] == ' ')) {
+		if (((userInputPos + 1) < userInputLen) && (userInputLowcased[userInputPos + 1] == ' ')) {
 			// current word is 1 char only?
 			if ((firstChar == 'a') || (firstChar == 'i')) {
 				// and it's "a" or "i"? -> then set current type to ignore
@@ -254,7 +251,7 @@ int16 Words::findWordInDictionary(const Common::String &userInput, uint16 userIn
 
 				userInputPos = wordStartPos;
 				while (curCompareLeft) {
-					curUserInputChar = userInput[userInputPos];
+					curUserInputChar = userInputLowcased[userInputPos];
 					curDictionaryChar = dictionaryEntry->word[dictionaryWordPos];
 
 					if (curUserInputChar != curDictionaryChar)
@@ -266,14 +263,17 @@ int16 Words::findWordInDictionary(const Common::String &userInput, uint16 userIn
 				}
 
 				if (!curCompareLeft) {
-					// fully matched, remember match
-					wordId = dictionaryEntry->id;
-					foundWordLen = dictionaryWordLen;
-
-					// follow-up character in user-input is a space? add that to the word length
-					if (userInputLeft == foundWordLen) {
-						// perfect match -> break
-						break;
+					// check, if there is also nothing more of user input left or if a space the follow-up char?
+					if ((userInputPos >= userInputLen) || (userInputLowcased[userInputPos] == ' ')) {
+						// so fully matched, remember match
+						wordId = dictionaryEntry->id;
+						foundWordLen = dictionaryWordLen;
+
+						// perfect match? -> exit loop
+						if (userInputLeft == foundWordLen) {
+							// perfect match -> break
+							break;
+						}
 					}
 				}
 			}
@@ -283,7 +283,7 @@ int16 Words::findWordInDictionary(const Common::String &userInput, uint16 userIn
 	if (foundWordLen == 0) {
 		userInputPos = wordStartPos;
 		while (userInputPos < userInputLen) {
-			if (userInput[userInputPos] == ' ') {
+			if (userInputLowcased[userInputPos] == ' ') {
 				break;
 			}
 			userInputPos++;
@@ -295,6 +295,7 @@ int16 Words::findWordInDictionary(const Common::String &userInput, uint16 userIn
 
 void Words::parseUsingDictionary(char *rawUserInput) {
 	Common::String userInput;
+	Common::String userInputLowcased;
 	const char *userInputPtr = nullptr;
 	uint16 userInputLen;
 	uint16 userInputPos = 0;
@@ -312,6 +313,10 @@ void Words::parseUsingDictionary(char *rawUserInput) {
 	// clean up user input
 	cleanUpInput(rawUserInput, userInput);
 
+	// Sierra compared independent of upper case and lower case
+	userInputLowcased = userInput;
+	userInputLowcased.toLowercase();
+
 	userInputLen = userInput.size();
 	userInputPtr = userInput.c_str();
 
@@ -321,7 +326,7 @@ void Words::parseUsingDictionary(char *rawUserInput) {
 			userInputPos++;
 
 		foundWordPos = userInputPos;
-		foundWordId = findWordInDictionary(userInput, userInputLen, userInputPos, foundWordLen);
+		foundWordId = findWordInDictionary(userInputLowcased, userInputLen, userInputPos, foundWordLen);
 
 		if (foundWordId != DICTIONARY_RESULT_IGNORE) {
 			// word not supposed to get ignored


Commit: cb3b5d5e31570d6b6757e6b5e414414972d1b5d6
    https://github.com/scummvm/scummvm/commit/cb3b5d5e31570d6b6757e6b5e414414972d1b5d6
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-30T23:08:19+01:00

Commit Message:
AGI: fix agi256 view decompression

+ add extra security checks

Changed paths:
    engines/agi/view.cpp



diff --git a/engines/agi/view.cpp b/engines/agi/view.cpp
index e9ed169..3793272 100644
--- a/engines/agi/view.cpp
+++ b/engines/agi/view.cpp
@@ -240,6 +240,9 @@ int AgiEngine::decodeView(byte *resourceData, uint16 resourceSize, int16 viewNr)
 				celCompressedData = resourceData + celOffset + 3;
 				celCompressedSize = resourceSize - (celOffset + 3);
 
+				if (celCompressedSize == 0)
+					error("compressed size of loop within view %d is 0 bytes", viewNr);
+
 				if (!isAGI256Data) {
 					unpackViewCelData(celData, celCompressedData, celCompressedSize);
 				} else {
@@ -350,7 +353,7 @@ void AgiEngine::unpackViewCelDataAGI256(AgiViewCel *celData, byte *compressedDat
 
 	while (remainingHeight) {
 		if (!compressedSize)
-			error("unexpected end of data, while unpacking AGI256 data");
+			error("unexpected end of data, while unpacking AGI256 view");
 
 		curByte = *compressedData++;
 		compressedSize--;
@@ -364,8 +367,13 @@ void AgiEngine::unpackViewCelDataAGI256(AgiViewCel *celData, byte *compressedDat
 				remainingWidth = 0;
 			}
 		} else {
+			if (!remainingWidth) {
+				error("broken view data, while unpacking AGI256 view");
+				break;
+			}
 			*rawBitmap = curByte;
 			rawBitmap++;
+			remainingWidth--;
 		}
 
 		if (curByte == 0) {


Commit: 26cb39beeefa03c7d0343b60b058334752527a08
    https://github.com/scummvm/scummvm/commit/26cb39beeefa03c7d0343b60b058334752527a08
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-30T23:54:41+01:00

Commit Message:
AGI: Ego motion type change on newroom only agi3

Ego motion type change on newRoom() was only done for AGI3

Changed paths:
    engines/agi/cycle.cpp



diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index 3d9803e..060dcd3 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -89,7 +89,9 @@ void AgiEngine::newRoom(int16 newRoomNr) {
 		break;
 	}
 
-	if (getVersion() < 0x2000) {
+	uint16 agiVersion = getVersion();
+
+	if (agiVersion < 0x2000) {
 		warning("STUB: NewRoom(%d)", newRoomNr);
 
 		screenObjEgo->flags &= ~fDidntMove;
@@ -98,9 +100,12 @@ void AgiEngine::newRoom(int16 newRoomNr) {
 		setView(screenObjEgo, screenObjEgo->currentViewNr);
 
 	} else {
-		if (screenObjEgo->motionType == kMotionEgo) {
-			screenObjEgo->motionType = kMotionNormal;
-			_game.vars[VM_VAR_EGO_DIRECTION] = 0;
+		if (agiVersion >= 0x3000) {
+			// this was only done in AGI3
+			if (screenObjEgo->motionType == kMotionEgo) {
+				screenObjEgo->motionType = kMotionNormal;
+				_game.vars[VM_VAR_EGO_DIRECTION] = 0;
+			}
 		}
 
 		_game.vars[VM_VAR_BORDER_TOUCH_EGO] = 0;


Commit: 428df3e6cb1e3d37c6b596ecd7049c1430905667
    https://github.com/scummvm/scummvm/commit/428df3e6cb1e3d37c6b596ecd7049c1430905667
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T01:04:53+01:00

Commit Message:
AGI: copying between var + ego screen obj fixed

We copied the wrong way see cycle.cpp
This fixes the fan game 13th disciple. bug #3563
Also cleanup
playercontrol variable is now a boolean

Changed paths:
    engines/agi/agi.h
    engines/agi/checks.cpp
    engines/agi/cycle.cpp
    engines/agi/motion.cpp
    engines/agi/op_cmd.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index f82e6ae..54dcd57 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -441,7 +441,7 @@ struct AgiGame {
 	Common::Array<ScriptPos> execStack;
 
 	// internal flags
-	int playerControl;		/**< player is in control */
+	bool playerControl;		/**< player is in control */
 	int clockEnabled;		/**< clock is on/off */
 	int exitAllLogics;	/**< break cycle after new.room */
 	bool pictureShown;		/**< show.pic has been issued */
diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp
index 1fb437b..1734517 100644
--- a/engines/agi/checks.cpp
+++ b/engines/agi/checks.cpp
@@ -276,7 +276,7 @@ void AgiEngine::updatePosition() {
 				_game.vars[VM_VAR_BORDER_CODE] = screenObj->objectNr;
 				_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = border;
 			}
-			if (screenObj->motionType == kMotionMoveObj) { // ANGEPASST
+			if (screenObj->motionType == kMotionMoveObj) {
 				motionMoveObjStop(screenObj);
 			}
 		}
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index 060dcd3..6b70019 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -104,7 +104,7 @@ void AgiEngine::newRoom(int16 newRoomNr) {
 			// this was only done in AGI3
 			if (screenObjEgo->motionType == kMotionEgo) {
 				screenObjEgo->motionType = kMotionNormal;
-				_game.vars[VM_VAR_EGO_DIRECTION] = 0;
+				setVar(VM_VAR_EGO_DIRECTION, 0);
 			}
 		}
 
@@ -130,10 +130,10 @@ void AgiEngine::interpretCycle() {
 	ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
 	int oldSound, oldScore;
 
-	if (_game.playerControl)
-		_game.vars[VM_VAR_EGO_DIRECTION] = screenObjEgo->direction;
+	if (!_game.playerControl)
+		setVar(VM_VAR_EGO_DIRECTION, screenObjEgo->direction);
 	else
-		screenObjEgo->direction = _game.vars[VM_VAR_EGO_DIRECTION];
+		screenObjEgo->direction = getVar(VM_VAR_EGO_DIRECTION);
 
 	checkAllMotions();
 
@@ -154,7 +154,7 @@ void AgiEngine::interpretCycle() {
 	nonBlockingText_CycleDone();
 	resetControllers();
 
-	screenObjEgo->direction = _game.vars[VM_VAR_EGO_DIRECTION];
+	screenObjEgo->direction = getVar(VM_VAR_EGO_DIRECTION);
 
 	if (_game.vars[VM_VAR_SCORE] != oldScore || getflag(VM_FLAG_SOUND_ON) != oldSound)
 		_game._vm->_text->statusDraw();
diff --git a/engines/agi/motion.cpp b/engines/agi/motion.cpp
index 3f85059..4af8a48 100644
--- a/engines/agi/motion.cpp
+++ b/engines/agi/motion.cpp
@@ -58,7 +58,7 @@ void AgiEngine::changePos(ScreenObjEntry *screenObj) {
 		screenObj->flags |= fMotion;
 		screenObj->direction = 0;
 		if (isEgoView(screenObj))
-			_game.vars[VM_VAR_EGO_DIRECTION] = 0;
+			setVar(VM_VAR_EGO_DIRECTION, 0);
 	}
 }
 
@@ -70,7 +70,7 @@ void AgiEngine::motionWander(ScreenObjEntry *screenObj) {
 		screenObj->direction = _rnd->getRandomNumber(8);
 
 		if (isEgoView(screenObj)) {
-			_game.vars[VM_VAR_EGO_DIRECTION] = screenObj->direction;
+			setVar(VM_VAR_EGO_DIRECTION, screenObj->direction);
 		}
 
 		while (screenObj->wander_count < 6) {
@@ -147,7 +147,7 @@ void AgiEngine::motionMoveObj(ScreenObjEntry *screenObj) {
 
 	// Update V6 if ego
 	if (isEgoView(screenObj))
-		_game.vars[VM_VAR_EGO_DIRECTION] = screenObj->direction;
+		setVar(VM_VAR_EGO_DIRECTION, screenObj->direction);
 
 	if (screenObj->direction == 0)
 		motionMoveObjStop(screenObj);
@@ -216,7 +216,7 @@ void AgiEngine::motionMoveObjStop(ScreenObjEntry *screenObj) {
 	screenObj->motionType = kMotionNormal;
 	if (isEgoView(screenObj)) {
 		_game.playerControl = true;
-		_game.vars[VM_VAR_EGO_DIRECTION] = 0;
+		setVar(VM_VAR_EGO_DIRECTION, 0);
 	}
 }
 
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 00b8dbf..fbabfd3 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -1477,7 +1477,7 @@ void cmdStopMotion(AgiGame *state, uint8 *parameter) {
 	screenObj->direction = 0;
 	screenObj->motionType = kMotionNormal;
 	if (objectNr == 0) {		// ego only
-		state->vars[VM_VAR_EGO_DIRECTION] = 0;
+		state->_vm->setVar(VM_VAR_EGO_DIRECTION, 0);
 		state->playerControl = false;
 	}
 }
@@ -1495,7 +1495,7 @@ void cmdStartMotion(AgiGame *state, uint8 *parameter) {
 
 	screenObj->motionType = kMotionNormal;
 	if (objectNr == 0) {		// ego only
-		state->vars[VM_VAR_EGO_DIRECTION] = 0;
+		state->_vm->setVar(VM_VAR_EGO_DIRECTION, 0);
 		state->playerControl = true;
 	}
 }


Commit: 4afda5bbea086dff5f9e90c6d49f5fa017dd92d2
    https://github.com/scummvm/scummvm/commit/4afda5bbea086dff5f9e90c6d49f5fa017dd92d2
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T01:24:09+01:00

Commit Message:
AGI: motion type check in objectstop was AGI3 only

verified via disassembly

Changed paths:
    engines/agi/motion.cpp



diff --git a/engines/agi/motion.cpp b/engines/agi/motion.cpp
index 4af8a48..a7a1b91 100644
--- a/engines/agi/motion.cpp
+++ b/engines/agi/motion.cpp
@@ -209,7 +209,14 @@ void AgiEngine::inDestination(ScreenObjEntry *screenObj) {
 
 void AgiEngine::motionMoveObjStop(ScreenObjEntry *screenObj) {
 	screenObj->stepSize = screenObj->move_stepSize;
-	if (screenObj->motionType != kMotionEgo) {
+
+	uint16 agiVersion = getVersion();
+	if (agiVersion >= 0x3000) {
+		// this check was only done for AGI3
+		if (screenObj->motionType != kMotionEgo) {
+			setflag(screenObj->move_flag, true);
+		}
+	} else {
 		setflag(screenObj->move_flag, true);
 	}
 


Commit: 83495eab28d5f8967e2ce26b34af06c568019739
    https://github.com/scummvm/scummvm/commit/83495eab28d5f8967e2ce26b34af06c568019739
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T01:52:00+01:00

Commit Message:
AGI: change key -> direction handling

After the VM Var 6 <-> ego direction change, this is required
Also our original behavior was inaccurate in that part as well.

Changed paths:
    engines/agi/keyboard.cpp



diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 62bcfc2..00c6a36 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -452,38 +452,38 @@ bool AgiEngine::handleController(uint16 key) {
 		return true;
 	}
 
-	if (_game.playerControl) {
-		int16 newDirection = 0;
-
-		switch (key) {
-		case AGI_KEY_UP:
-			newDirection = 1;
-			break;
-		case AGI_KEY_DOWN:
-			newDirection = 5;
-			break;
-		case AGI_KEY_LEFT:
-			newDirection = 7;
-			break;
-		case AGI_KEY_RIGHT:
-			newDirection = 3;
-			break;
-		case AGI_KEY_UP_RIGHT:
-			newDirection = 2;
-			break;
-		case AGI_KEY_DOWN_RIGHT:
-			newDirection = 4;
-			break;
-		case AGI_KEY_UP_LEFT:
-			newDirection = 8;
-			break;
-		case AGI_KEY_DOWN_LEFT:
-			newDirection = 6;
-			break;
-		default:
-			break;
-		}
+	int16 newDirection = 0;
+
+	switch (key) {
+	case AGI_KEY_UP:
+		newDirection = 1;
+		break;
+	case AGI_KEY_DOWN:
+		newDirection = 5;
+		break;
+	case AGI_KEY_LEFT:
+		newDirection = 7;
+		break;
+	case AGI_KEY_RIGHT:
+		newDirection = 3;
+		break;
+	case AGI_KEY_UP_RIGHT:
+		newDirection = 2;
+		break;
+	case AGI_KEY_DOWN_RIGHT:
+		newDirection = 4;
+		break;
+	case AGI_KEY_UP_LEFT:
+		newDirection = 8;
+		break;
+	case AGI_KEY_DOWN_LEFT:
+		newDirection = 6;
+		break;
+	default:
+		break;
+	}
 
+	if (_game.playerControl) {
 		if (!(getFeatures() & GF_AGIMOUSE)) {
 			// Handle mouse button events
 			if (!_game.mouseHidden) {
@@ -515,13 +515,20 @@ bool AgiEngine::handleController(uint16 key) {
 				}
 			}
 		}
+	}
 
-		if (newDirection || key == AGI_KEY_STATIONARY) {
-			screenObjEgo->flags &= ~fAdjEgoXY;
-			screenObjEgo->direction = screenObjEgo->direction == newDirection ? 0 : newDirection;
+	if (newDirection || key == AGI_KEY_STATIONARY) {
+		// TODO: not sure, what original AGI did with AdjEgoXY
+		screenObjEgo->flags &= ~fAdjEgoXY;
+		if (screenObjEgo->direction == newDirection) {
+			setVar(VM_VAR_EGO_DIRECTION, 0);
+		} else {
+			setVar(VM_VAR_EGO_DIRECTION, newDirection);
+		}
+		if (_game.playerControl) {
 			screenObjEgo->motionType = kMotionNormal;
-			return true;
 		}
+		return true;
 	}
 
 	return false;


Commit: 6baadff8d371584caaf6c83238847c54ec4b8261
    https://github.com/scummvm/scummvm/commit/6baadff8d371584caaf6c83238847c54ec4b8261
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T13:49:42+01:00

Commit Message:
AGI: font cleanup

We now only offer the original VGA font (a few characters
were modified) and overwrite the extended set range with a
Russian set, when needed.

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



diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
index b7cadf0..8b20cb4 100644
--- a/engines/agi/font.cpp
+++ b/engines/agi/font.cpp
@@ -213,527 +213,9 @@ static const uint8 fontData_AmigaPseudoTopaz[2600] = {
 };
 
 // 8x8 font patterns
-static const uint8 fontData_Sierra[] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E,	// cursor hollow
-	0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,	// cursor solid
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// cursor empty
-	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
-	0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00,
-	0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00,
-	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
-	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
-	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	// \n
-	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
-	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
-	0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00,
-	0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C,
-	0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00,
-	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
-	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
-	0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00,
-	0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
-	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E,
-	0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00,
-	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
-	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
-	0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00,
-	0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00,
-	0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00,
-	// original sierra font starts here
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20 Space
-	0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
-	0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
-	0x30, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x30, 0x00,
-	0x00, 0xC6, 0xCC, 0x18, 0x30, 0x66, 0xC6, 0x00,
-	0x38, 0x6C, 0x38, 0x76, 0xDC, 0xCC, 0x76, 0x00,
-	0x60, 0x60, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
-	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
-	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
-	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60,
-	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
-	0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
-	0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30
-	0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
-	0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
-	0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
-	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
-	0xFC, 0xC0, 0xF8, 0x0C, 0x0C, 0xCC, 0x78, 0x00,
-	0x38, 0x60, 0xC0, 0xF8, 0xCC, 0xCC, 0x78, 0x00,
-	0xFC, 0xCC, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
-	0x78, 0xCC, 0xCC, 0x78, 0xCC, 0xCC, 0x78, 0x00,
-	0x78, 0xCC, 0xCC, 0x7C, 0x0C, 0x18, 0x70, 0x00,
-	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00,
-	0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60,
-	0x18, 0x30, 0x60, 0xC0, 0x60, 0x30, 0x18, 0x00,
-	0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
-	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
-	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
-	0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40
-	0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
-	0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
-	0xF8, 0x6C, 0x66, 0x66, 0x66, 0x6C, 0xF8, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
-	0x3C, 0x66, 0xC0, 0xC0, 0xCE, 0x66, 0x3E, 0x00,
-	0xCC, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
-	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
-	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
-	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
-	0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50
-	0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
-	0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
-	0xFC, 0xB4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xFC, 0x00,
-	0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
-	0xC6, 0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x00,
-	0xC6, 0xC6, 0x6C, 0x38, 0x38, 0x6C, 0xC6, 0x00,
-	0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x30, 0x78, 0x00,
-	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
-	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
-	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
-	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
-	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-	0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
-	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
-	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
-	0x38, 0x6C, 0x60, 0xF0, 0x60, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
-	0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x0C, 0x00, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78,
-	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
-	0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00,
-	0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
-	0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
-	0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
-	0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
-	0x10, 0x30, 0x7C, 0x30, 0x30, 0x34, 0x18, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x78, 0x30, 0x00,
-	0x00, 0x00, 0xC6, 0xD6, 0xFE, 0xFE, 0x6C, 0x00,
-	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
-	0x1C, 0x30, 0x30, 0xE0, 0x30, 0x30, 0x1C, 0x00,
-	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
-	0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
-	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	// custom font starting here at 0x80
-	0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80
-	0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
-	0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
-	0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
-	0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
-	0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
-	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
-	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
-	0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
-	0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
-	0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
-	0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
-	0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
-	0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
-	0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
-	0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
-	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
-	0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
-	0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
-	0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
-	0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
-	0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
-	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
-	0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
-	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
-	0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
-	0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
-	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
-	0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
-};
-
-static const uint8 fontData_FanGames[] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x7E, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x7E,	/* cursor hollow */
-	0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,	/* cursor solid */
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* cursor empty */
-	0x10, 0x38, 0x7C, 0xFE, 0x7C, 0x38, 0x10, 0x00,
-	0x3C, 0x3C, 0x18, 0xFF, 0xE7, 0x18, 0x3C, 0x00,
-	0x10, 0x38, 0x7C, 0xFE, 0xEE, 0x10, 0x38, 0x00,
-	0x00, 0x00, 0x18, 0x3C, 0x3C, 0x18, 0x00, 0x00,
-	0xFF, 0xFF, 0xE7, 0xC3, 0xC3, 0xE7, 0xFF, 0xFF,
-	0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	/* \n */
-	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
-	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
-	0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00,
-	0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C,
-	0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00,
-	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
-	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
-	0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00,
-	0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
-	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
-	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E,
-	0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00,
-	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
-	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
-	0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00,
-	0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00,
-	0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00,
-	0x6C, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
-	0x10, 0x7C, 0xD0, 0x7C, 0x16, 0xFC, 0x10, 0x00,
-	0x00, 0x66, 0xAC, 0xD8, 0x36, 0x6A, 0xCC, 0x00,
-	0x38, 0x4C, 0x38, 0x78, 0xCE, 0xCC, 0x7A, 0x00,
-	0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00,
-	0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
-	0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00,
-	0x00, 0x30, 0x30, 0xFC, 0x30, 0x30, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
-	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00,
-	0x02, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x00,
-	0x7C, 0xCE, 0xDE, 0xF6, 0xE6, 0xE6, 0x7C, 0x00,
-	0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7E, 0x00,
-	0x7C, 0xC6, 0x06, 0x1C, 0x70, 0xC6, 0xFE, 0x00,
-	0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00,
-	0x1C, 0x3C, 0x6C, 0xCC, 0xFE, 0x0C, 0x1E, 0x00,
-	0xFE, 0xC0, 0xFC, 0x06, 0x06, 0xC6, 0x7C, 0x00,
-	0x7C, 0xC6, 0xC0, 0xFC, 0xC6, 0xC6, 0x7C, 0x00,
-	0xFE, 0xC6, 0x0C, 0x18, 0x30, 0x30, 0x30, 0x00,
-	0x7C, 0xC6, 0xC6, 0x7C, 0xC6, 0xC6, 0x7C, 0x00,
-	0x7C, 0xC6, 0xC6, 0x7E, 0x06, 0xC6, 0x7C, 0x00,
-	0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
-	0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
-	0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x00,
-	0x00, 0x00, 0x7E, 0x00, 0x00, 0x7E, 0x00, 0x00,
-	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
-	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
-	0x7C, 0x82, 0x9E, 0xA6, 0x9E, 0x80, 0x7C, 0x00,
-	0x7C, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
-	0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00,
-	0xFC, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x62, 0xFE, 0x00,
-	0xFE, 0x62, 0x68, 0x78, 0x68, 0x60, 0xF0, 0x00,
-	0x7C, 0xC6, 0xC6, 0xC0, 0xCE, 0xC6, 0x7E, 0x00,
-	0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00,
-	0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0x1E, 0x0C, 0x0C, 0x0C, 0xCC, 0xCC, 0x78, 0x00,
-	0xE6, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0xE6, 0x00,
-	0xF0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xFE, 0x00,
-	0x82, 0xC6, 0xEE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
-	0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
-	0x7C, 0xC6, 0xC6, 0xC6, 0xD6, 0xDE, 0x7C, 0x06,
-	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xE6, 0x00,
-	0x7C, 0xC6, 0xC0, 0x7C, 0x06, 0xC6, 0x7C, 0x00,
-	0x7E, 0x5A, 0x5A, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
-	0xC6, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
-	0xC6, 0xC6, 0xD6, 0xFE, 0xEE, 0xC6, 0x82, 0x00,
-	0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00,
-	0x66, 0x66, 0x66, 0x3C, 0x18, 0x18, 0x3C, 0x00,
-	0xFE, 0xC6, 0x8C, 0x18, 0x32, 0x66, 0xFE, 0x00,
-	0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
-	0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x02, 0x00,
-	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
-	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-	0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC6, 0x7C, 0x00,
-	0x1C, 0x0C, 0x0C, 0x7C, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0x7C, 0xC6, 0xFE, 0xC0, 0x7C, 0x00,
-	0x1C, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00,
-	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x78,
-	0xE0, 0x60, 0x6C, 0x76, 0x66, 0x66, 0xE6, 0x00,
-	0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0x00, 0x0C, 0x00, 0x1C, 0x0C, 0x0C, 0xCC, 0x78,
-	0xE0, 0x60, 0x66, 0x6C, 0x78, 0x6C, 0xE6, 0x00,
-	0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00,
-	0x00, 0x00, 0xCC, 0xFE, 0xD6, 0xD6, 0xD6, 0x00,
-	0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0x7C, 0x00,
-	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
-	0x00, 0x00, 0x7C, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
-	0x00, 0x00, 0xDE, 0x76, 0x60, 0x60, 0xF0, 0x00,
-	0x00, 0x00, 0x7C, 0xC0, 0x7C, 0x06, 0x7C, 0x00,
-	0x10, 0x30, 0xFC, 0x30, 0x30, 0x34, 0x18, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0x76, 0x00,
-	0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x38, 0x10, 0x00,
-	0x00, 0x00, 0xC6, 0xD6, 0xD6, 0xFE, 0x6C, 0x00,
-	0x00, 0x00, 0xC6, 0x6C, 0x38, 0x6C, 0xC6, 0x00,
-	0x00, 0x00, 0xCC, 0xCC, 0xCC, 0x7C, 0x0C, 0xF8,
-	0x00, 0x00, 0xFC, 0x98, 0x30, 0x64, 0xFC, 0x00,
-	0x0E, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0E, 0x00,
-	0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00,
-	0xE0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xE0, 0x00,
-	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,	/*replacement 0x7F */
-	0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
-	0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
-	0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
-	0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
-	0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
-	0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
-	0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
-	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
-	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
-	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
-	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
-	0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
-	0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
-	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
-	0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
-	0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
-	0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
-	0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
-	0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
-	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
-	0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
-	0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
-	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
-	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
-	0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
-	0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
-	0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
-	0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
-	0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
-	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
-	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
-	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
-	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
-	0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
-	0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
-	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
-	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
-	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
-	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
-	0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
-	0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
-	0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
-	0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
-	0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
-	0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
-	0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
-	0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
-	0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
-	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
-	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
-	0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
-	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
-	0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
-	0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
-	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
-	0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
-};
 
-static const uint8 fontData_IBM[] = {
+// this is basically the PC VGA font, taken from Dos-Box, with a few modifications
+static const uint8 fontData_VGA[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
 	0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
@@ -747,26 +229,38 @@ static const uint8 fontData_IBM[] = {
 	0xFF, 0xC3, 0x99, 0xBD, 0xBD, 0x99, 0xC3, 0xFF,
 	0x0F, 0x07, 0x0F, 0x7D, 0xCC, 0xCC, 0xCC, 0x78,
 	0x3C, 0x66, 0x66, 0x66, 0x3C, 0x18, 0x7E, 0x18,
-	0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0,
-	0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0,
-	0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99,
+	0x08, 0x0C, 0x0A, 0x0A, 0x08, 0x78, 0xF0, 0x00, // 0x0D changed
+	0x18, 0x14, 0x1A, 0x16, 0x72, 0xE2, 0x0E, 0x1C, // 0x0E changed
+	0x10, 0x54, 0x38, 0xEE, 0x38, 0x54, 0x10, 0x00, // 0x0F changed
+	//0x3F, 0x33, 0x3F, 0x30, 0x30, 0x70, 0xF0, 0xE0, // 0x0D original
+	//0x7F, 0x63, 0x7F, 0x63, 0x63, 0x67, 0xE6, 0xC0, // 0x0E original
+	//0x99, 0x5A, 0x3C, 0xE7, 0xE7, 0x3C, 0x5A, 0x99, // 0x0F original
 	0x80, 0xE0, 0xF8, 0xFE, 0xF8, 0xE0, 0x80, 0x00,
 	0x02, 0x0E, 0x3E, 0xFE, 0x3E, 0x0E, 0x02, 0x00,
-	0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18,
+	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x12 changed
+	//0x18, 0x3C, 0x7E, 0x18, 0x18, 0x7E, 0x3C, 0x18, // 0x12 original
 	0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
-	0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00,
-	0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78,
+	0x7F, 0xDB, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x00, // 0x14 changed
+	0x1C, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, // 0x14 changed
+	//0x7F, 0xDB, 0xDB, 0x7B, 0x1B, 0x1B, 0x1B, 0x00, // 0x14 original
+	//0x3E, 0x63, 0x38, 0x6C, 0x6C, 0x38, 0xCC, 0x78, // 0x15 original
 	0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x00,
-	0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF,
-	0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
-	0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00,
+	0x18, 0x3C, 0x5A, 0x18, 0x5A, 0x3C, 0x18, 0x7E, // 0x17 changed
+	0x18, 0x3C, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 changed
+	0x18, 0x18, 0x18, 0x18, 0x5A, 0x3C, 0x18, 0x00, // 0x19 changed
+	//0x18, 0x3C, 0x7E, 0x18, 0x7E, 0x3C, 0x18, 0xFF, // 0x17 original
+	//0x18, 0x3C, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00, // 0x18 original
+	//0x18, 0x18, 0x18, 0x18, 0x7E, 0x3C, 0x18, 0x00, // 0x19 original
 	0x00, 0x18, 0x0C, 0xFE, 0x0C, 0x18, 0x00, 0x00,
 	0x00, 0x30, 0x60, 0xFE, 0x60, 0x30, 0x00, 0x00,
 	0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xFE, 0x00, 0x00,
-	0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00,
-	0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00,
-	0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x24, 0x42, 0xFF, 0x42, 0x24, 0x00, 0x00, // 0x1D changed
+	0x00, 0x10, 0x38, 0x7C, 0xFE, 0xFE, 0x00, 0x00, // 0x1E changed
+	0x00, 0xFE, 0xFE, 0x7C, 0x38, 0x10, 0x00, 0x00, // 0x1F changed
+	//0x00, 0x24, 0x66, 0xFF, 0x66, 0x24, 0x00, 0x00, // 0x1D original
+	//0x00, 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x00, 0x00, // 0x1E original
+	//0x00, 0xFF, 0xFF, 0x7E, 0x3C, 0x18, 0x00, 0x00, // 0x1F original
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x20
 	0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00,
 	0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x6C, 0x6C, 0xFE, 0x6C, 0xFE, 0x6C, 0x6C, 0x00,
@@ -782,7 +276,7 @@ static const uint8 fontData_IBM[] = {
 	0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00,
 	0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00,
-	0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00,
+	0x7C, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0x7C, 0x00, // 0x30
 	0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xFC, 0x00,
 	0x78, 0xCC, 0x0C, 0x38, 0x60, 0xCC, 0xFC, 0x00,
 	0x78, 0xCC, 0x0C, 0x38, 0x0C, 0xCC, 0x78, 0x00,
@@ -798,7 +292,7 @@ static const uint8 fontData_IBM[] = {
 	0x00, 0x00, 0xFC, 0x00, 0x00, 0xFC, 0x00, 0x00,
 	0x60, 0x30, 0x18, 0x0C, 0x18, 0x30, 0x60, 0x00,
 	0x78, 0xCC, 0x0C, 0x18, 0x30, 0x00, 0x30, 0x00,
-	0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00,
+	0x7C, 0xC6, 0xDE, 0xDE, 0xDE, 0xC0, 0x78, 0x00, // 0x40
 	0x30, 0x78, 0xCC, 0xCC, 0xFC, 0xCC, 0xCC, 0x00,
 	0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00,
 	0x3C, 0x66, 0xC0, 0xC0, 0xC0, 0x66, 0x3C, 0x00,
@@ -814,7 +308,7 @@ static const uint8 fontData_IBM[] = {
 	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
 	0xC6, 0xE6, 0xF6, 0xDE, 0xCE, 0xC6, 0xC6, 0x00,
 	0x38, 0x6C, 0xC6, 0xC6, 0xC6, 0x6C, 0x38, 0x00,
-	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00,
+	0xFC, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00, // 0x50
 	0x78, 0xCC, 0xCC, 0xCC, 0xDC, 0x78, 0x1C, 0x00,
 	0xFC, 0x66, 0x66, 0x7C, 0x6C, 0x66, 0xE6, 0x00,
 	0x78, 0xCC, 0xE0, 0x70, 0x1C, 0xCC, 0x78, 0x00,
@@ -830,7 +324,7 @@ static const uint8 fontData_IBM[] = {
 	0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
 	0x10, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
-	0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x60
 	0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0x76, 0x00,
 	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xDC, 0x00,
 	0x00, 0x00, 0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x00,
@@ -846,7 +340,7 @@ static const uint8 fontData_IBM[] = {
 	0x00, 0x00, 0xCC, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
 	0x00, 0x00, 0xF8, 0xCC, 0xCC, 0xCC, 0xCC, 0x00,
 	0x00, 0x00, 0x78, 0xCC, 0xCC, 0xCC, 0x78, 0x00,
-	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0,
+	0x00, 0x00, 0xDC, 0x66, 0x66, 0x7C, 0x60, 0xF0, // 0x70
 	0x00, 0x00, 0x76, 0xCC, 0xCC, 0x7C, 0x0C, 0x1E,
 	0x00, 0x00, 0xDC, 0x76, 0x66, 0x60, 0xF0, 0x00,
 	0x00, 0x00, 0x7C, 0xC0, 0x78, 0x0C, 0xF8, 0x00,
@@ -862,7 +356,7 @@ static const uint8 fontData_IBM[] = {
 	0xE0, 0x30, 0x30, 0x1C, 0x30, 0x30, 0xE0, 0x00,
 	0x76, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x10, 0x38, 0x6C, 0xC6, 0xC6, 0xFE, 0x00,
-	0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78,
+	0x78, 0xCC, 0xC0, 0xCC, 0x78, 0x18, 0x0C, 0x78, // 0x80
 	0x00, 0xCC, 0x00, 0xCC, 0xCC, 0xCC, 0x7E, 0x00,
 	0x1C, 0x00, 0x78, 0xCC, 0xFC, 0xC0, 0x78, 0x00,
 	0x7E, 0xC3, 0x3C, 0x06, 0x3E, 0x66, 0x3F, 0x00,
@@ -992,18 +486,139 @@ static const uint8 fontData_IBM[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-void GfxFont::init() {
-	// We are currently using the custom font for all fanmade games
-	if (_vm->getFeatures() & (GF_FANMADE | GF_AGDS)) {
-		// fanmade game, use custom font for now
-		loadFontScummVMFile("agi-font-fangame.bin");
-		if (!_fontData) {
-			_fontData = fontData_FanGames; // our (own?) custom font, that supports umlauts etc.
-			debug("Using fanmade custom font");
-		}
-		return;
-	}
+// Extended set (0x80-0xFF) for Russian versions of games
+static const uint8 fontData_ExtendedRussian[] = {
+	0x1E, 0x36, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00, // 0x80
+	0x7C, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x7E, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
+	0x38, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+	0x7E, 0x60, 0x60, 0x7C, 0x60, 0x60, 0x7E, 0x00,
+	0xDB, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0xDB, 0x00,
+	0x3C, 0x66, 0x06, 0x1C, 0x06, 0x66, 0x3C, 0x00,
+	0x66, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+	0x3C, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x66, 0x00,
+	0x66, 0x6C, 0x78, 0x70, 0x78, 0x6C, 0x66, 0x00,
+	0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0x00,
+	0x66, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x66, 0x00,
+	0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x00,
+	0x7E, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0x7C, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x00,
+	0x3C, 0x66, 0x60, 0x60, 0x60, 0x66, 0x3C, 0x00,
+	0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x66, 0x66, 0x66, 0x3E, 0x06, 0x66, 0x3C, 0x00,
+	0x7E, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x00,
+	0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, 0x00,
+	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+	0x66, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, 0x00,
+	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+	0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+	0xE0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00,
+	0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x7C, 0x00,
+	0x78, 0x8C, 0x06, 0x3E, 0x06, 0x8C, 0x78, 0x00,
+	0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00,
+	0x3E, 0x66, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x00,
+	0x00, 0x00, 0x3C, 0x06, 0x3E, 0x66, 0x3A, 0x00,
+	0x00, 0x3C, 0x60, 0x3C, 0x66, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7C, 0x66, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0x7E, 0x60, 0x60, 0x60, 0x60, 0x00,
+	0x00, 0x00, 0x3C, 0x6C, 0x6C, 0x6C, 0xFE, 0xC6,
+	0x00, 0x00, 0x3C, 0x66, 0x7E, 0x60, 0x3C, 0x00,
+	0x00, 0x00, 0xDB, 0x7E, 0x3C, 0x7E, 0xDB, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x0C, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+	0x00, 0x18, 0x66, 0x6E, 0x7E, 0x76, 0x66, 0x00,
+	0x00, 0x00, 0x66, 0x6C, 0x78, 0x6C, 0x66, 0x00,
+	0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x00,
+	0x00, 0x00, 0xC6, 0xFE, 0xFE, 0xD6, 0xC6, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x7E, 0x66, 0x66, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00,
+	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
+	0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA,
+	0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0x00, 0x00, 0xFE, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xF8, 0x18, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0xF6, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xFE, 0x06, 0xF6, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0xF6, 0x06, 0xFE, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0xFE, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0xF8, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x18, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x37, 0x30, 0x3F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x3F, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0xF7, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
+	0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0xF7, 0x00, 0xF7, 0x36, 0x36, 0x36, 0x36,
+	0x18, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x36, 0x36, 0x36, 0xFF, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0x00, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0xFF, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0x3F, 0x00, 0x00, 0x00, 0x00,
+	0x18, 0x1F, 0x18, 0x1F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x1F, 0x18, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0x00, 0x00, 0x00, 0x3F, 0x36, 0x36, 0x36, 0x36,
+	0x36, 0x36, 0x36, 0xFF, 0x36, 0x36, 0x36, 0x36,
+	0x18, 0xFF, 0x18, 0xFF, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0xF8, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x1F, 0x18, 0x18, 0x18, 0x18,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F,
+	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x00,
+	0x00, 0x00, 0x3C, 0x66, 0x60, 0x66, 0x3C, 0x00,
+	0x00, 0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x7C, 0x00,
+	0x00, 0x00, 0x7E, 0xDB, 0xDB, 0x7E, 0x18, 0x00,
+	0x00, 0x00, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x00,
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7F, 0x03,
+	0x00, 0x00, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x00,
+	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x00,
+	0x00, 0x00, 0xDB, 0xDB, 0xDB, 0xDB, 0xFF, 0x03,
+	0x00, 0x00, 0xE0, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0xC6, 0xC6, 0xF6, 0xDE, 0xF6, 0x00,
+	0x00, 0x00, 0x60, 0x60, 0x7C, 0x66, 0x7C, 0x00,
+	0x00, 0x00, 0x7C, 0x06, 0x3E, 0x06, 0x7C, 0x00,
+	0x00, 0x00, 0xCE, 0xDB, 0xFB, 0xDB, 0xCE, 0x00,
+	0x00, 0x00, 0x3E, 0x66, 0x3E, 0x36, 0x66, 0x00,
+	0x00, 0x00, 0xFE, 0x00, 0xFE, 0x00, 0xFE, 0x00,
+	0x10, 0x10, 0x7C, 0x10, 0x10, 0x00, 0x7C, 0x00,
+	0x00, 0x30, 0x18, 0x0C, 0x06, 0x0C, 0x18, 0x30,
+	0x00, 0x0C, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0C,
+	0x0E, 0x1B, 0x1B, 0x18, 0x18, 0x18, 0x18, 0x18,
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xD8, 0xD8, 0x70,
+	0x00, 0x18, 0x18, 0x00, 0x7E, 0x00, 0x18, 0x18,
+	0x00, 0x76, 0xDC, 0x00, 0x76, 0xDC, 0x00, 0x00,
+	0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00,
+	0x03, 0x02, 0x06, 0x04, 0xCC, 0x68, 0x38, 0x10,
+	0x3C, 0x42, 0x99, 0xA1, 0xA1, 0x99, 0x42, 0x3C,
+	0x30, 0x48, 0x10, 0x20, 0x78, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x7C, 0x7C, 0x7C, 0x7C, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x7E, 0x00
+};
 
+void GfxFont::init() {
 	switch (_vm->_renderMode) {
 	case Common::kRenderAmiga:
 		// Try user-file first, if that fails use our internal inaccurate topaz font
@@ -1046,19 +661,14 @@ void GfxFont::init() {
 	}
 
 	if (!_fontData) {
-		// no font asigned?
-		switch (_vm->getGameID()) {
-		case GID_MICKEY:
-		case GID_TROLL:
-		case GID_WINNIE:
-			// use IBM font for pre-AGI games as standard
-			_fontData = fontData_IBM;
-			break;
-		default:
-			// for everything else use Sierra PC font
-			_fontData = fontData_Sierra;
-			break;
-		}
+		// no font assigned?
+		// use regular VGA font (taken from Dos-Box with a few modifications)
+		_fontData = fontData_VGA;
+	}
+
+	if (_vm->getLanguage() == Common::RU_RUS) {
+		// Russian versions need special extended set
+		overwriteExtendedWithRussianSet();
 	}
 }
 
@@ -1073,6 +683,18 @@ void GfxFont::overwriteSaveRestoreDialogCharacter() {
 	memcpy(_fontDataAllocated + (0x1A * 8), fontData_ArrowRightCharacter, sizeof(fontData_ArrowRightCharacter));
 }
 
+// Overwrite extended character set (0x80-0xFF) with Russian characters
+void GfxFont::overwriteExtendedWithRussianSet() {
+	if (!_fontDataAllocated) {
+		// nothing allocated, we need to allocate space ourselves to be able to modify an internal font
+		_fontDataAllocated = (uint8 *)calloc(256, 8);
+		memcpy(_fontDataAllocated, _fontData, 128 * 8); // copy ASCII set over
+		_fontData = _fontDataAllocated;
+	}
+	// Overwrite extended set with Russian characters
+	memcpy(_fontDataAllocated + (128 * 8), fontData_ExtendedRussian, 128 * 8);
+}
+
 // This code loads a ScummVM-specific user-supplied binary font file
 // It's assumed that it's a plain binary file, that contains 256 characters. 8 bytes per character.
 // 8x8 pixels per character. File size 2048 bytes.
@@ -1081,7 +703,6 @@ void GfxFont::overwriteSaveRestoreDialogCharacter() {
 //  Atari ST - "agi-font-atarist.bin" -> should be the Atari ST 8x8 system font
 //  Amiga    - "agi-font-amiga.bin"   -> should be the Amiga 8x8 Topaz font
 //  DOS      - "agi-font-dos.bin"
-//  Fangames - "agi-font-fangame.bin"
 void GfxFont::loadFontScummVMFile(Common::String fontFilename) {
 	Common::File fontFile;
 	int32 fontFileSize = 0;
@@ -1189,8 +810,8 @@ void GfxFont::loadFontAmigaPseudoTopaz() {
 	assert(topazLowChar == ' ');
 	assert(topazHighChar == 0xFF);
 
-	// copy first 32 characters over
-	memcpy(fontData, fontData_Sierra, FONT_DISPLAY_WIDTH * 32);
+	// copy first 32 VGA characters over
+	memcpy(fontData, fontData_VGA, FONT_DISPLAY_WIDTH * 32);
 	fontData += FONT_DISPLAY_WIDTH * 32;
 
 	// now actually convert from topaz data
@@ -1216,8 +837,6 @@ void GfxFont::loadFontAmigaPseudoTopaz() {
 		}
 	}
 
-	overwriteSaveRestoreDialogCharacter();
-
 	debug("Using recreation of Amiga Topaz font");
 }
 
diff --git a/engines/agi/font.h b/engines/agi/font.h
index 833cf73..0bb1bbb 100644
--- a/engines/agi/font.h
+++ b/engines/agi/font.h
@@ -39,6 +39,7 @@ public:
 
 private:
 	void overwriteSaveRestoreDialogCharacter();
+	void overwriteExtendedWithRussianSet();
 
 	void loadFontScummVMFile(Common::String fontFilename);
 	void loadFontMickey();


Commit: 8115145e4bbb1d0e7ba961a0376bb1f538a4f132
    https://github.com/scummvm/scummvm/commit/8115145e4bbb1d0e7ba961a0376bb1f538a4f132
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T13:50:37+01:00

Commit Message:
AGI: hardcoded value replaced with VM_VAR_SECONDS

Changed paths:
    engines/agi/op_test.cpp



diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index afb1ddb..701bbcd 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -42,37 +42,37 @@ namespace Agi {
 #define testObjInRoom(obj, v)	(state->_vm->objectGetLocation(obj) == getVar(v))
 
 void condEqual(AgiGame *state, uint8 *p) {
-	if (p[0] == 11)
+	if (p[0] == VM_VAR_SECONDS)
 		state->_vm->_timerHack++;
 	state->testResult = testEqual(p[0], p[1]);
 }
 
 void condEqualV(AgiGame *state, uint8 *p) {
-	if (p[0] == 11 || p[1] == 11)
+	if (p[0] == VM_VAR_SECONDS || p[1] == VM_VAR_SECONDS)
 		state->_vm->_timerHack++;
 	state->testResult = testEqual(p[0], getVar(p[1]));
 }
 
 void condLess(AgiGame *state, uint8 *p) {
-	if (p[0] == 11)
+	if (p[0] == VM_VAR_SECONDS)
 		state->_vm->_timerHack++;
 	state->testResult = testLess(p[0], p[1]);
 }
 
 void condLessV(AgiGame *state, uint8 *p) {
-	if (p[0] == 11 || p[1] == 11)
+	if (p[0] == VM_VAR_SECONDS || p[1] == VM_VAR_SECONDS)
 		state->_vm->_timerHack++;
 	state->testResult = testLess(p[0], getVar(p[1]));
 }
 
 void condGreater(AgiGame *state, uint8 *p) {
-	if (p[0] == 11)
+	if (p[0] == VM_VAR_SECONDS)
 		state->_vm->_timerHack++;
 	state->testResult = testGreater(p[0], p[1]);
 }
 
 void condGreaterV(AgiGame *state, uint8 *p) {
-	if (p[0] == 11 || p[1] == 11)
+	if (p[0] == VM_VAR_SECONDS || p[1] == VM_VAR_SECONDS)
 		state->_vm->_timerHack++;
 	state->testResult = testGreater(p[0], getVar(p[1]));
 }


Commit: 143fb9458f0b810f6209ab4b45ddf172fc98f8a2
    https://github.com/scummvm/scummvm/commit/143fb9458f0b810f6209ab4b45ddf172fc98f8a2
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T13:58:10+01:00

Commit Message:
AGI: added/improved font debug output

Changed paths:
    engines/agi/font.cpp



diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
index 8b20cb4..6624be8 100644
--- a/engines/agi/font.cpp
+++ b/engines/agi/font.cpp
@@ -664,6 +664,7 @@ void GfxFont::init() {
 		// no font assigned?
 		// use regular VGA font (taken from Dos-Box with a few modifications)
 		_fontData = fontData_VGA;
+		debug("AGI: Using VGA font");
 	}
 
 	if (_vm->getLanguage() == Common::RU_RUS) {
@@ -693,6 +694,8 @@ void GfxFont::overwriteExtendedWithRussianSet() {
 	}
 	// Overwrite extended set with Russian characters
 	memcpy(_fontDataAllocated + (128 * 8), fontData_ExtendedRussian, 128 * 8);
+
+	debug("AGI: Using Russian extended font set");
 }
 
 // This code loads a ScummVM-specific user-supplied binary font file
@@ -731,7 +734,7 @@ void GfxFont::loadFontScummVMFile(Common::String fontFilename) {
 
 	overwriteSaveRestoreDialogCharacter();
 
-	debug("Using user-supplied font");
+	debug("AGI: Using user-supplied font");
 }
 
 // We load the Mickey Mouse font from MICKEY.EXE
@@ -764,7 +767,7 @@ void GfxFont::loadFontMickey() {
 	interpreterFile.read(fontData, 256 * 8);
 	interpreterFile.close();
 
-	debug("Using Mickey Mouse font");
+	debug("AGI: Using Mickey Mouse font");
 }
 
 // we create a bitmap out of the topaz data used in parallaction (which is normally found in staticres.cpp)
@@ -837,7 +840,7 @@ void GfxFont::loadFontAmigaPseudoTopaz() {
 		}
 	}
 
-	debug("Using recreation of Amiga Topaz font");
+	debug("AGI: Using recreation of Amiga Topaz font");
 }
 
 void GfxFont::loadFontAppleIIgs() {
@@ -1026,6 +1029,8 @@ void GfxFont::loadFontAppleIIgs() {
 	free(strikeDataPtr);
 
 	overwriteSaveRestoreDialogCharacter();
+
+	debug("AGI: Using Apple IIgs font");
 }
 
 // Loads Atari ST font file
@@ -1152,7 +1157,7 @@ void GfxFont::loadFontAtariST(Common::String fontFilename) {
 
 	overwriteSaveRestoreDialogCharacter();
 
-	debug("Using Atari ST 8x8 system font");
+	debug("AGI: Using Atari ST 8x8 system font");
 }
 
 } // End of namespace Agi


Commit: 121415ef1f391dea223370226e8ee8abd9c5329f
    https://github.com/scummvm/scummvm/commit/121415ef1f391dea223370226e8ee8abd9c5329f
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T14:14:33+01:00

Commit Message:
AGI: rename VGA font to PC BIOS font

probably more accurate

Changed paths:
    engines/agi/font.cpp



diff --git a/engines/agi/font.cpp b/engines/agi/font.cpp
index 6624be8..2ee3e64 100644
--- a/engines/agi/font.cpp
+++ b/engines/agi/font.cpp
@@ -214,8 +214,8 @@ static const uint8 fontData_AmigaPseudoTopaz[2600] = {
 
 // 8x8 font patterns
 
-// this is basically the PC VGA font, taken from Dos-Box, with a few modifications
-static const uint8 fontData_VGA[] = {
+// this is basically the standard PC BIOS font, taken from Dos-Box, with a few modifications
+static const uint8 fontData_PCBIOS[] = {
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x7E, 0x81, 0xA5, 0x81, 0xBD, 0x99, 0x81, 0x7E,
 	0x7E, 0xFF, 0xDB, 0xFF, 0xC3, 0xE7, 0xFF, 0x7E,
@@ -662,8 +662,8 @@ void GfxFont::init() {
 
 	if (!_fontData) {
 		// no font assigned?
-		// use regular VGA font (taken from Dos-Box with a few modifications)
-		_fontData = fontData_VGA;
+		// use regular PC-BIOS font (taken from Dos-Box with a few modifications)
+		_fontData = fontData_PCBIOS;
 		debug("AGI: Using VGA font");
 	}
 
@@ -813,8 +813,8 @@ void GfxFont::loadFontAmigaPseudoTopaz() {
 	assert(topazLowChar == ' ');
 	assert(topazHighChar == 0xFF);
 
-	// copy first 32 VGA characters over
-	memcpy(fontData, fontData_VGA, FONT_DISPLAY_WIDTH * 32);
+	// copy first 32 PC-BIOS characters over
+	memcpy(fontData, fontData_PCBIOS, FONT_DISPLAY_WIDTH * 32);
 	fontData += FONT_DISPLAY_WIDTH * 32;
 
 	// now actually convert from topaz data


Commit: 1548f2cebf49b52505b17c4057ad8048ce6c9baf
    https://github.com/scummvm/scummvm/commit/1548f2cebf49b52505b17c4057ad8048ce6c9baf
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T14:49:52+01:00

Commit Message:
AGI: revert "motion type check in objectstop AGI3"

Caused issues with mouse support (that AGI on DOS never had).
e.g. KQ1/KQ2 on end of mouse click move Graham automatically falls
into water.

The check was added in AGI3 only, but maybe non-DOS interpreters
had it before. Or maybe mouse support was actually implemented
differently. Needs more investigating.

Changed paths:
    engines/agi/motion.cpp
    engines/agi/view.h



diff --git a/engines/agi/motion.cpp b/engines/agi/motion.cpp
index a7a1b91..76f0f91 100644
--- a/engines/agi/motion.cpp
+++ b/engines/agi/motion.cpp
@@ -210,13 +210,9 @@ void AgiEngine::inDestination(ScreenObjEntry *screenObj) {
 void AgiEngine::motionMoveObjStop(ScreenObjEntry *screenObj) {
 	screenObj->stepSize = screenObj->move_stepSize;
 
-	uint16 agiVersion = getVersion();
-	if (agiVersion >= 0x3000) {
-		// this check was only done for AGI3
-		if (screenObj->motionType != kMotionEgo) {
-			setflag(screenObj->move_flag, true);
-		}
-	} else {
+	// This check for motionType was only done in AGI3.
+	// But we use this motion type for mouse movement, so we need to check in any case, otherwise it will cause glitches.
+	if (screenObj->motionType != kMotionEgo) {
 		setflag(screenObj->move_flag, true);
 	}
 
diff --git a/engines/agi/view.h b/engines/agi/view.h
index 3afe3dc..428db1d 100644
--- a/engines/agi/view.h
+++ b/engines/agi/view.h
@@ -58,7 +58,7 @@ enum MotionType {
 	kMotionWander = 1,
 	kMotionFollowEgo = 2,
 	kMotionMoveObj = 3,
-	kMotionEgo = 4
+	kMotionEgo = 4 // used by us for mouse movement only?
 };
 
 enum CycleType {


Commit: 82b958f274affa9d67de0ac2f8cfaa1756405dfb
    https://github.com/scummvm/scummvm/commit/82b958f274affa9d67de0ac2f8cfaa1756405dfb
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T17:35:13+01:00

Commit Message:
AGI: VM Var code cleanup

Don't access variables directly, but through method
Shouldn't include any functional differences
Also changed several hardcoded values to the corresponding enums.

Changed paths:
    engines/agi/agi.cpp
    engines/agi/agi.h
    engines/agi/checks.cpp
    engines/agi/cycle.cpp
    engines/agi/keyboard.cpp
    engines/agi/op_cmd.cpp
    engines/agi/text.cpp



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 3c111fd..8dd663c 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -94,10 +94,8 @@ int AgiEngine::agiInit() {
 	_game.adjMouseX = _game.adjMouseY = 0;
 
 	// reset all flags to false and all variables to 0
-	for (i = 0; i < MAX_FLAGS; i++)
-		_game.flags[i] = 0;
-	for (i = 0; i < MAX_VARS; i++)
-		_game.vars[i] = 0;
+	memset(_game.flags, 0, sizeof(_game.flags));
+	memset(_game.vars, 0, sizeof(_game.vars));
 
 	// clear all resources and events
 	for (i = 0; i < MAX_DIRECTORY_ENTRIES; i++) {
@@ -606,7 +604,7 @@ void AgiEngine::loadingTrigger_NewRoom(int16 newRoomNr) {
 	if (_game.nonBlockingTextShown) {
 		_game.nonBlockingTextShown = false;
 
-		int16 curRoomNr = _game.vars[VM_VAR_CURRENT_ROOM];
+		int16 curRoomNr = getVar(VM_VAR_CURRENT_ROOM);
 
 		if (newRoomNr != curRoomNr) {
 			if (!_game.automaticRestoreGame) {
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 54dcd57..697cf66 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -273,7 +273,10 @@ enum {
 	VM_VAR_VOLUME,					// 23
 	VM_VAR_MAX_INPUT_CHARACTERS,	// 24
 	VM_VAR_SELECTED_INVENTORY_ITEM,	// 25
-	VM_VAR_MONITOR					// 26
+	VM_VAR_MONITOR = 26,			// 26
+	VM_VAR_MOUSE_BUTTONSTATE = 27,  // 27
+	VM_VAR_MOUSE_X = 28,			// 28
+	VM_VAR_MOUSE_Y = 29,			// 29
 };
 
 /**
@@ -422,7 +425,7 @@ struct AgiGame {
 	uint32 crc;		/**< game CRC */
 
 	// game flags and variables
-	uint8 flags[MAX_FLAGS]; /**< 256 1-bit flags */
+	uint8 flags[MAX_FLAGS]; /**< 256 1-bit flags combined into a total of 32 bytes */
 	uint8 vars[MAX_VARS];   /**< 256 variables */
 
 	// internal variables
diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp
index 1734517..2ad0dbd 100644
--- a/engines/agi/checks.cpp
+++ b/engines/agi/checks.cpp
@@ -185,9 +185,9 @@ void AgiEngine::updatePosition() {
 	ScreenObjEntry *screenObj;
 	int x, y, oldX, oldY, border;
 
-	_game.vars[VM_VAR_BORDER_CODE] = 0;
-	_game.vars[VM_VAR_BORDER_TOUCH_EGO] = 0;
-	_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = 0;
+	setVar(VM_VAR_BORDER_CODE, 0);
+	setVar(VM_VAR_BORDER_TOUCH_EGO, 0);
+	setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
 
 	for (screenObj = _game.screenObjTable; screenObj < &_game.screenObjTable[SCREENOBJECTS_MAX]; screenObj++) {
 		if ((screenObj->flags & (fAnimated | fUpdate | fDrawn)) != (fAnimated | fUpdate | fDrawn)) {
@@ -271,10 +271,10 @@ void AgiEngine::updatePosition() {
 
 		if (border) {
 			if (isEgoView(screenObj)) {
-				_game.vars[VM_VAR_BORDER_TOUCH_EGO] = border;
+				setVar(VM_VAR_BORDER_TOUCH_EGO, border);
 			} else {
-				_game.vars[VM_VAR_BORDER_CODE] = screenObj->objectNr;
-				_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = border;
+				setVar(VM_VAR_BORDER_CODE, screenObj->objectNr);
+				setVar(VM_VAR_BORDER_TOUCH_OBJECT, border);
 			}
 			if (screenObj->motionType == kMotionMoveObj) {
 				motionMoveObjStop(screenObj);
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index 6b70019..a2b9d00 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -65,16 +65,16 @@ void AgiEngine::newRoom(int16 newRoomNr) {
 	_game.playerControl = true;
 	_game.block.active = false;
 	_game.horizon = 36;
-	_game.vars[VM_VAR_PREVIOUS_ROOM] = _game.vars[VM_VAR_CURRENT_ROOM];
-	_game.vars[VM_VAR_CURRENT_ROOM] = newRoomNr;
-	_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = 0;
-	_game.vars[VM_VAR_BORDER_CODE] = 0;
-	_game.vars[VM_VAR_EGO_VIEW_RESOURCE] = screenObjEgo->currentViewNr;
+	setVar(VM_VAR_PREVIOUS_ROOM, getVar(VM_VAR_CURRENT_ROOM));
+	setVar(VM_VAR_CURRENT_ROOM, newRoomNr);
+	setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
+	setVar(VM_VAR_BORDER_CODE, 0);
+	setVar(VM_VAR_EGO_VIEW_RESOURCE, screenObjEgo->currentViewNr);
 
 	agiLoadResource(RESOURCETYPE_LOGIC, newRoomNr);
 
 	// Reposition ego in the new room
-	switch (_game.vars[VM_VAR_BORDER_TOUCH_EGO]) {
+	switch (getVar(VM_VAR_BORDER_TOUCH_EGO)) {
 	case 1:
 		screenObjEgo->yPos = SCRIPT_HEIGHT - 1;
 		break;
@@ -108,7 +108,7 @@ void AgiEngine::newRoom(int16 newRoomNr) {
 			}
 		}
 
-		_game.vars[VM_VAR_BORDER_TOUCH_EGO] = 0;
+		setVar(VM_VAR_BORDER_TOUCH_EGO, 0);
 		setflag(VM_FLAG_NEW_ROOM_EXEC, true);
 
 		_game.exitAllLogics = true;
@@ -137,15 +137,15 @@ void AgiEngine::interpretCycle() {
 
 	checkAllMotions();
 
-	oldScore = _game.vars[VM_VAR_SCORE];
+	oldScore = getVar(VM_VAR_SCORE);
 	oldSound = getflag(VM_FLAG_SOUND_ON);
 
 	_game.exitAllLogics = false;
 	while (runLogic(0) == 0 && !(shouldQuit() || _restartGame)) {
-		_game.vars[VM_VAR_WORD_NOT_FOUND] = 0;
-		_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = 0;
-		_game.vars[VM_VAR_BORDER_CODE] = 0;
-		oldScore = _game.vars[VM_VAR_SCORE];
+		setVar(VM_VAR_WORD_NOT_FOUND, 0);
+		setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
+		setVar(VM_VAR_BORDER_CODE, 0);
+		oldScore = getVar(VM_VAR_SCORE);
 		setflag(VM_FLAG_ENTERED_CLI, false);
 		_game.exitAllLogics = false;
 		nonBlockingText_CycleDone();
@@ -156,11 +156,11 @@ void AgiEngine::interpretCycle() {
 
 	screenObjEgo->direction = getVar(VM_VAR_EGO_DIRECTION);
 
-	if (_game.vars[VM_VAR_SCORE] != oldScore || getflag(VM_FLAG_SOUND_ON) != oldSound)
+	if (getVar(VM_VAR_SCORE) != oldScore || getflag(VM_FLAG_SOUND_ON) != oldSound)
 		_game._vm->_text->statusDraw();
 
-	_game.vars[VM_VAR_BORDER_TOUCH_OBJECT] = 0;
-	_game.vars[VM_VAR_BORDER_CODE] = 0;
+	setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
+	setVar(VM_VAR_BORDER_CODE, 0);
 	setflag(VM_FLAG_NEW_ROOM_EXEC, false);
 	setflag(VM_FLAG_RESTART_GAME, false);
 	setflag(VM_FLAG_RESTORE_JUST_RAN, false);
@@ -237,8 +237,8 @@ int AgiEngine::mainCycle(bool onlyCheckForEvents) {
 	//
 	// We run AGIMOUSE always as a side effect
 	//if (getFeatures() & GF_AGIMOUSE) {
-		_game.vars[28] = _mouse.x / 2;
-		_game.vars[29] = _mouse.y;
+		setVar(VM_VAR_MOUSE_X, _mouse.x / 2);
+		setVar(VM_VAR_MOUSE_Y, _mouse.y);
 	//}
 
 	switch (_game.inputMode) {
@@ -381,8 +381,8 @@ int AgiEngine::playGame() {
 
 	setflag(VM_FLAG_ENTERED_CLI, false);
 	setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
-	_game.vars[VM_VAR_WORD_NOT_FOUND] = 0;
-	_game.vars[VM_VAR_KEY] = 0;
+	setVar(VM_VAR_WORD_NOT_FOUND, 0);
+	setVar(VM_VAR_KEY, 0);
 
 	debugC(2, kDebugLevelMain, "Entering main loop");
 	bool firstLoop = !getflag(VM_FLAG_RESTART_GAME); // Do not restore on game restart
@@ -421,8 +421,8 @@ int AgiEngine::playGame() {
 
 			setflag(VM_FLAG_ENTERED_CLI, false);
 			setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
-			_game.vars[VM_VAR_WORD_NOT_FOUND] = 0;
-			_game.vars[VM_VAR_KEY] = 0;
+			setVar(VM_VAR_WORD_NOT_FOUND, 0);
+			setVar(VM_VAR_KEY, 0);
 		}
 
 		if (shouldPerformAutoSave(_lastSaveTime)) {
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 00c6a36..0d5efb6 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -488,7 +488,7 @@ bool AgiEngine::handleController(uint16 key) {
 			// Handle mouse button events
 			if (!_game.mouseHidden) {
 				if (key == AGI_MOUSE_BUTTON_LEFT) {
-					if (getGameID() == GID_PQ1 && _game.vars[VM_VAR_CURRENT_ROOM] == 116) {
+					if (getGameID() == GID_PQ1 && getVar(VM_VAR_CURRENT_ROOM) == 116) {
 						// WORKAROUND: Special handling for mouse clicks in the newspaper
 						// screen of PQ1. Fixes bug #3018770.
 						newDirection = 3;	// fake a right arrow key (next page)
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index fbabfd3..ec24082 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -43,29 +43,40 @@ namespace Agi {
 #define getLanguage() state->_vm->getLanguage()
 
 void cmdIncrement(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
+	byte   varVal = vm->getVar(varNr);
 
 	if (getVersion() < 0x2000) {
-		if (state->vars[varNr] < 0xf0)
-			++state->vars[varNr];
+		if (varVal < 0xf0) {
+			varVal++;
+			vm->setVar(varNr, varVal);
+		}
 	} else {
-		if (state->vars[varNr] != 0xff)
-			++state->vars[varNr];
+		if (varVal != 0xff) {
+			varVal++;
+			vm->setVar(varNr, varVal);
+		}
 	}
 }
 
 void cmdDecrement(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
+	byte   varVal = vm->getVar(varNr);
 
-	if (state->vars[varNr] != 0)
-		--state->vars[varNr];
+	if (varVal != 0) {
+		varVal--;
+		vm->setVar(varNr, varVal);
+	}
 }
 
 void cmdAssignN(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
 	uint16 value = parameter[1];
 
-	state->vars[varNr] = value;
+	vm->setVar(varNr, value);
 
 	// WORKAROUND for a bug in fan game "Get outta SQ"
 	// Total number of points is stored in variable 7, which
@@ -75,117 +86,151 @@ void cmdAssignN(AgiGame *state, uint8 *parameter) {
 	// Fixes bug #1942476 - "AGI: Fan(Get Outta SQ) - Score
 	// is lost on restart"
 	if (getGameID() == GID_GETOUTTASQ && varNr == 7)
-		state->vars[varNr] = 8;
+		vm->setVar(varNr, 8);
 }
 
 void cmdAddN(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
 	uint16 value = parameter[1];
+	byte   varVal = vm->getVar(varNr);
 
-	state->vars[varNr] += value;
+	vm->setVar(varNr, varVal + value);
 }
 
 void cmdSubN(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
 	uint16 value = parameter[1];
+	byte   varVal = vm->getVar(varNr);
 
-	state->vars[varNr] -= value;
+	vm->setVar(varNr, varVal - value);
 }
 
 void cmdAssignV(AgiGame *state, uint8 *parameter) {
-	uint16 varNr1 = parameter[0];
-	uint16 varNr2 = parameter[1];
+	AgiEngine *vm = state->_vm;
+	uint16 varNr1  = parameter[0];
+	uint16 varNr2  = parameter[1];
+	byte   varVal2 = vm->getVar(varNr2);
 
-	state->vars[varNr1] = state->vars[varNr2];
+	vm->setVar(varNr1, varVal2);
 }
 
 void cmdAddV(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr1 = parameter[0];
 	uint16 varNr2 = parameter[1];
+	byte   varVal1 = vm->getVar(varNr1);
+	byte   varVal2 = vm->getVar(varNr2);
 
-	state->vars[varNr1] += state->vars[varNr2];
+	vm->setVar(varNr1, varVal1 + varVal2);
 }
 
 void cmdSubV(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr1 = parameter[0];
 	uint16 varNr2 = parameter[1];
+	byte   varVal1 = vm->getVar(varNr1);
+	byte   varVal2 = vm->getVar(varNr2);
 
-	state->vars[varNr1] -= state->vars[varNr2];
+	vm->setVar(varNr1, varVal1 - varVal2);
 }
 
 void cmdMulN(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
 	uint16 value = parameter[1];
+	byte   varVal = vm->getVar(varNr);
 
-	state->vars[varNr] *= value;
+	vm->setVar(varNr, varVal * value);
 }
 
 void cmdMulV(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr1 = parameter[0];
 	uint16 varNr2 = parameter[1];
+	byte   varVal1 = vm->getVar(varNr1);
+	byte   varVal2 = vm->getVar(varNr2);
 
-	state->vars[varNr1] *= state->vars[varNr2];
+	vm->setVar(varNr1, varVal1 * varVal2);
 }
 
 void cmdDivN(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
 	uint16 value = parameter[1];
+	byte   varVal = vm->getVar(varNr);
 
-	state->vars[varNr] /= value;
+	vm->setVar(varNr, varVal / value);
 }
 
 void cmdDivV(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr1 = parameter[0];
 	uint16 varNr2 = parameter[1];
+	byte   varVal1 = vm->getVar(varNr1);
+	byte   varVal2 = vm->getVar(varNr2);
 
-	state->vars[varNr1] /= state->vars[varNr2];
+	vm->setVar(varNr1, varVal1 / varVal2);
 }
 
 void cmdRandomV1(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
 
-	state->vars[varNr] = state->_vm->_rnd->getRandomNumber(250);
+	vm->setVar(varNr, vm->_rnd->getRandomNumber(250));
 }
 
 void cmdRandom(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 valueMin = parameter[0];
 	uint16 valueMax = parameter[1];
 	uint16 varNr = parameter[2];
 
-	state->vars[varNr] = state->_vm->_rnd->getRandomNumber(valueMax - valueMin) + valueMin;
+	vm->setVar(varNr, vm->_rnd->getRandomNumber(valueMax - valueMin) + valueMin);
 }
 
 void cmdLindirectN(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
 	uint16 value = parameter[1];
+	byte   varVal = vm->getVar(varNr);
 
-	state->vars[state->vars[varNr]] = value;
+	vm->setVar(varVal, value);
 }
 
 void cmdLindirectV(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr1 = parameter[0];
 	uint16 varNr2 = parameter[1];
+	byte   varVal1 = vm->getVar(varNr1);
+	byte   varVal2 = vm->getVar(varNr2);
 
-	state->vars[state->vars[varNr1]] = state->vars[varNr2];
+	vm->setVar(varVal1, varVal2);
 }
 
 void cmdRindirect(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr1 = parameter[0];
 	uint16 varNr2 = parameter[1];
+	byte   varVal2 = vm->getVar(varNr2);
+	byte   value   = vm->getVar(varVal2);
 
-	state->vars[varNr1] = state->vars[state->vars[varNr2]];
+	vm->setVar(varNr1, value);
 }
 
 void cmdSet(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 flagNr = parameter[0];
 
-	state->_vm->setflag(flagNr, true);
+	vm->setflag(flagNr, true);
 }
 
 void cmdReset(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 flagNr = parameter[0];
 
-	state->_vm->setflag(flagNr, false);
+	vm->setflag(flagNr, false);
 }
 
 void cmdToggle(AgiGame *state, uint8 *parameter) {
@@ -197,37 +242,40 @@ void cmdToggle(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdSetV(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 flagNr = parameter[0];
 
 	if (getVersion() < 0x2000) {
-		state->vars[flagNr] = 1;
+		vm->setVar(flagNr, 1);
 	} else {
-		flagNr = state->vars[flagNr];
-		
-		state->_vm->setflag(flagNr, true);
+		flagNr = vm->getVar(flagNr);
+
+		vm->setflag(flagNr, true);
 	}
 }
 
 void cmdResetV(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 flagNr = parameter[0];
 
 	if (getVersion() < 0x2000) {
-		state->vars[flagNr] = 0;
+		vm->setVar(flagNr, 0);
 	} else {
-		flagNr = state->vars[flagNr];
+		flagNr = vm->getVar(flagNr);
 
-		state->_vm->setflag(flagNr, false);
+		vm->setflag(flagNr, false);
 	}
 }
 
 void cmdToggleV(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 flagNr = parameter[0];
 
 	if (getVersion() < 0x2000) {
-		state->vars[flagNr] ^= 1;
+		byte value = vm->getVar(flagNr);
+		vm->setVar(flagNr, value ^ 1);
 	} else {
-		AgiEngine *vm = state->_vm;
-		flagNr = state->vars[flagNr];
+		flagNr = vm->getVar(flagNr);
 		bool curFlagState = vm->getflag(flagNr);
 
 		vm->setflag(flagNr, !curFlagState);
@@ -253,9 +301,11 @@ void cmdNewRoom(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdNewRoomF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
+	byte   value = vm->getVar(varNr);
 
-	state->_vm->newRoom(state->vars[varNr]);
+	state->_vm->newRoom(value);
 }
 
 void cmdLoadView(AgiGame *state, uint8 *parameter) {
@@ -277,15 +327,19 @@ void cmdLoadSound(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdLoadViewF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
+	byte   value = vm->getVar(varNr);
 
-	state->_vm->agiLoadResource(RESOURCETYPE_VIEW, state->vars[varNr]);
+	vm->agiLoadResource(RESOURCETYPE_VIEW, value);
 }
 
 void cmdLoadLogicF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
+	byte   value = vm->getVar(varNr);
 
-	state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, state->vars[varNr]);
+	state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, value);
 }
 
 void cmdDiscardView(AgiGame *state, uint8 *parameter) {
@@ -364,11 +418,12 @@ void cmdSetHorizon(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdGetPriority(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	state->vars[varNr] = screenObj->priority;
+	vm->setVar(varNr, screenObj->priority);
 }
 
 void cmdSetPriority(AgiGame *state, uint8 *parameter) {
@@ -381,12 +436,13 @@ void cmdSetPriority(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdSetPriorityF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
 	screenObj->flags |= fFixedPriority;
-	screenObj->priority = state->vars[varNr];
+	screenObj->priority = vm->getVar(varNr);
 }
 
 void cmdReleasePriority(AgiGame *state, uint8 *parameter) {
@@ -414,55 +470,62 @@ void cmdStopUpdate(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdCurrentView(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	state->vars[varNr] = screenObj->currentViewNr;
+	vm->setVar(varNr, screenObj->currentViewNr);
 }
 
 void cmdCurrentCel(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	state->vars[varNr] = screenObj->currentCelNr;
-	debugC(4, kDebugLevelScripts, "v%d=%d", varNr, state->vars[varNr]);
+	vm->setVar(varNr, screenObj->currentCelNr);
+	debugC(4, kDebugLevelScripts, "v%d=%d", varNr, screenObj->currentCelNr);
 }
 
 void cmdCurrentLoop(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	state->vars[varNr] = screenObj->currentLoopNr;
+	vm->setVar(varNr, screenObj->currentLoopNr);
 }
 
 void cmdLastCel(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	state->vars[varNr] = screenObj->loopData->celCount - 1;
+	vm->setVar(varNr, screenObj->loopData->celCount - 1);
 }
 
 void cmdSetCel(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 celNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	state->_vm->setCel(screenObj, celNr);
+	vm->setCel(screenObj, celNr);
 	if (getVersion() >= 0x2000) {
 		screenObj->flags &= ~fDontupdate;
 	}
 }
 
 void cmdSetCelF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+	byte   value = vm->getVar(varNr);
 
-	state->_vm->setCel(screenObj, state->vars[varNr]);
+	vm->setCel(screenObj, value);
 	screenObj->flags &= ~fDontupdate;
 }
 
@@ -475,11 +538,13 @@ void cmdSetView(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdSetViewF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+	byte   value = vm->getVar(varNr);
 
-	state->_vm->setView(screenObj, state->vars[varNr]);
+	state->_vm->setView(screenObj, value);
 }
 
 void cmdSetLoop(AgiGame *state, uint8 *parameter) {
@@ -491,19 +556,22 @@ void cmdSetLoop(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdSetLoopF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
+	byte   value = vm->getVar(varNr);
 
-	state->_vm->setLoop(screenObj, state->vars[varNr]);
+	state->_vm->setLoop(screenObj, value);
 }
 
 void cmdNumberOfLoops(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	state->vars[varNr] = screenObj->loopCount;
+	vm->setVar(varNr, screenObj->loopCount);
 }
 
 void cmdFixLoop(AgiGame *state, uint8 *parameter) {
@@ -521,27 +589,30 @@ void cmdReleaseLoop(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdStepSize(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	screenObj->stepSize = state->vars[varNr];
+	screenObj->stepSize = vm->getVar(varNr);
 }
 
 void cmdStepTime(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	screenObj->stepTime = screenObj->stepTimeCount = state->vars[varNr];
+	screenObj->stepTime = screenObj->stepTimeCount = vm->getVar(varNr);
 }
 
 void cmdCycleTime(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	screenObj->cycleTime = screenObj->cycleTimeCount = state->vars[varNr];
+	screenObj->cycleTime = screenObj->cycleTimeCount = vm->getVar(varNr);
 }
 
 void cmdStopCycling(AgiGame *state, uint8 *parameter) {
@@ -575,40 +646,49 @@ void cmdReverseCycle(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdSetDir(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	screenObj->direction = state->vars[varNr];
+	screenObj->direction = vm->getVar(varNr);
 }
 
 void cmdGetDir(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	state->vars[varNr] = screenObj->direction;
+	vm->setVar(varNr, screenObj->direction);
 }
 
 void cmdGetRoomF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr1 = parameter[0];
 	uint16 varNr2 = parameter[1];
+	byte   varVal1 = vm->getVar(varNr1);
 
-	state->vars[varNr2] = state->_vm->objectGetLocation(state->vars[varNr1]);
+	vm->setVar(varNr2, state->_vm->objectGetLocation(varVal1));
 }
 
 void cmdPut(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr = parameter[1];
+	byte   varVal = vm->getVar(varNr);
 
-	state->_vm->objectSetLocation(objectNr, state->vars[varNr]);
+	vm->objectSetLocation(objectNr, varVal);
 }
 
 void cmdPutF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr1 = parameter[0];
 	uint16 varNr2 = parameter[1];
+	byte   varVal1 = vm->getVar(varNr1);
+	byte   varVal2 = vm->getVar(varNr2);
 
-	state->_vm->objectSetLocation(state->vars[varNr1], state->vars[varNr2]);
+	state->_vm->objectSetLocation(varVal1, varVal2);
 }
 
 void cmdDrop(AgiGame *state, uint8 *parameter) {
@@ -630,9 +710,11 @@ void cmdGetV1(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdGetF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
+	byte   varVal = vm->getVar(varNr);
 
-	state->_vm->objectSetLocation(state->vars[varNr], EGO_OWNED);
+	state->_vm->objectSetLocation(varVal, EGO_OWNED);
 }
 
 void cmdWordToString(AgiGame *state, uint8 *parameter) {
@@ -643,15 +725,18 @@ void cmdWordToString(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdOpenDialogue(AgiGame *state, uint8 *parameter) {
-	state->_vm->_text->dialogueOpen();
+	AgiEngine *vm = state->_vm;
+	vm->_text->dialogueOpen();
 }
 
 void cmdCloseDialogue(AgiGame *state, uint8 *parameter) {
-	state->_vm->_text->dialogueClose();
+	AgiEngine *vm = state->_vm;
+	vm->_text->dialogueClose();
 }
 
 void cmdCloseWindow(AgiGame *state, uint8 *parameter) {
-	state->_vm->_text->closeWindow();
+	AgiEngine *vm = state->_vm;
+	vm->_text->closeWindow();
 }
 
 void cmdStatusLineOn(AgiGame *state, uint8 *parameter) {
@@ -675,9 +760,11 @@ void cmdShowObj(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdShowObjV(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
+	byte   varVal = vm->getVar(varNr);
 
-	state->_vm->_sprites->showObject(state->vars[varNr]);
+	state->_vm->_sprites->showObject(varVal);
 }
 
 void cmdSound(AgiGame *state, uint8 *parameter) {
@@ -779,8 +866,9 @@ void cmdScriptSize(AgiGame *state, uint8 *parameter) {
 // 471 (When walking on the first screen's bridge),
 // 71 (When walking around, using the mouse or the keyboard).
 void cmdObjStatusF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
-	ScreenObjEntry *screenObj = &state->screenObjTable[state->vars[varNr]];
+	ScreenObjEntry *screenObj = &state->screenObjTable[vm->getVar(varNr)];
 
 	const char *cycleDesc;  // Object's cycle description line
 	const char *motionDesc; // Object's motion description line
@@ -835,7 +923,7 @@ void cmdObjStatusF(AgiGame *state, uint8 *parameter) {
 		"stepsize: %d\n" \
 		"%s\n" \
 		"%s",
-		state->vars[varNr],
+		vm->getVar(varNr),
 		screenObj->xPos, screenObj->xSize,
 		screenObj->yPos, screenObj->ySize,
 		screenObj->priority,
@@ -854,6 +942,7 @@ void cmdObjStatusF(AgiGame *state, uint8 *parameter) {
 // unk_177: Disable menus completely -- j5
 // unk_181: Deactivate keypressed control (default control of ego)
 void cmdSetSimple(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	if (!(getFeatures() & (GF_AGI256 | GF_AGI256_2))) {
 		int16 stringNr = parameter[0];
 		const char *textPtr = nullptr;
@@ -872,7 +961,7 @@ void cmdSetSimple(AgiGame *state, uint8 *parameter) {
 		// Load the picture. Similar to void cmdLoad_pic(AgiGame *state, uint8 *p).
 		SpritesMgr *spritesMgr = state->_vm->_sprites;
 		uint16 varNr = parameter[0];
-		uint16 resourceNr = state->vars[varNr];
+		uint16 resourceNr = vm->getVar(varNr);
 
 		spritesMgr->eraseSprites();
 		state->_vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
@@ -999,14 +1088,15 @@ void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdParse(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	TextMgr *text = state->_vm->_text;
 	uint16 stringNr = parameter[0];
 
-	state->vars[VM_VAR_WORD_NOT_FOUND] = 0;
-	state->_vm->setflag(VM_FLAG_ENTERED_CLI, false);
-	state->_vm->setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+	vm->setVar(VM_VAR_WORD_NOT_FOUND, 0);
+	vm->setflag(VM_FLAG_ENTERED_CLI, false);
+	vm->setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
 
-	state->_vm->_words->parseUsingDictionary(text->stringPrintf(state->strings[stringNr]));
+	vm->_words->parseUsingDictionary(text->stringPrintf(state->strings[stringNr]));
 }
 
 void cmdCall(AgiGame *state, uint8 *parameter) {
@@ -1027,38 +1117,40 @@ void cmdCall(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdCallF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
+	byte   logicNr = vm->getVar(varNr);
 
-	cmdCall(state, &state->vars[varNr]);
+	cmdCall(state, &logicNr);
 }
 
 void cmdDrawPicV1(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
-	uint16 resourceNr = state->vars[varNr];
+	uint16 resourceNr = vm->getVar(varNr);
 
 	debugC(6, kDebugLevelScripts, "=== draw pic V1 %d ===", resourceNr);
 	state->_vm->_picture->decodePicture(resourceNr, true);
 
 	// TODO: check, if this was really done
-	state->_vm->_text->promptClear();
+	vm->_text->promptClear();
 
 	// Loading trigger
-	state->_vm->loadingTrigger_DrawPicture();
+	vm->loadingTrigger_DrawPicture();
 }
 
 void cmdDrawPic(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	SpritesMgr *spritesMgr = state->_vm->_sprites;
 	uint16 varNr = parameter[0];
-	uint16 resourceNr = state->vars[varNr];
+	uint16 resourceNr = vm->getVar(varNr);
 
 	debugC(6, kDebugLevelScripts, "=== draw pic %d ===", resourceNr);
 
-	spritesMgr->eraseSprites(); // === CHANGED ===
-	state->_vm->_picture->decodePicture(resourceNr, true);
+	spritesMgr->eraseSprites();
+	vm->_picture->decodePicture(resourceNr, true);
 	spritesMgr->buildAllSpriteLists();
-	spritesMgr->drawAllSpriteLists(); // === CHANGED ===
-	//state->_vm->_sprites->blitBoth();
-	//state->_vm->_sprites->commitBoth();
+	spritesMgr->drawAllSpriteLists();
 	state->pictureShown = false;
 	debugC(6, kDebugLevelScripts, "--- end of draw pic %d ---", resourceNr);
 
@@ -1075,37 +1167,40 @@ void cmdDrawPic(AgiGame *state, uint8 *parameter) {
 	// that this is a script bug and occurs in the original interpreter as well.
 	// Fixes bug #3056: AGI: SQ1 (2.2 DOS ENG) bizzare exploding roger
 	if (getGameID() == GID_SQ1 && resourceNr == 20)
-		state->_vm->setflag(103, false);
+		vm->setflag(103, false);
 
 	// Loading trigger
-	state->_vm->loadingTrigger_DrawPicture();
+	vm->loadingTrigger_DrawPicture();
 }
 
 void cmdShowPic(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	debugC(6, kDebugLevelScripts, "=== show pic ===");
 
-	state->_vm->setflag(VM_FLAG_OUTPUT_MODE, false);
-	state->_vm->_text->closeWindow();
-	state->_vm->_picture->showPicWithTransition();
+	vm->setflag(VM_FLAG_OUTPUT_MODE, false);
+	vm->_text->closeWindow();
+	vm->_picture->showPicWithTransition();
 	state->pictureShown = true;
 
 	debugC(6, kDebugLevelScripts, "--- end of show pic ---");
 }
 
 void cmdLoadPic(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	SpritesMgr *spritesMgr = state->_vm->_sprites;
 	uint16 varNr = parameter[0];
-	uint16 resourceNr = state->vars[varNr];
+	uint16 resourceNr = vm->getVar(varNr);
 
 	spritesMgr->eraseSprites();
-	state->_vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
+	vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
 	spritesMgr->buildAllSpriteLists();
 	spritesMgr->drawAllSpriteLists();
 }
 
 void cmdLoadPicV1(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 varNr = parameter[0];
-	uint16 resourceNr = state->vars[varNr];
+	uint16 resourceNr = vm->getVar(varNr);
 
 	state->_vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
 }
@@ -1116,21 +1211,22 @@ void cmdDiscardPic(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdOverlayPic(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	SpritesMgr *spritesMgr = state->_vm->_sprites;
 	uint16 varNr = parameter[0];
-	uint16 resourceNr = state->vars[varNr];
+	uint16 resourceNr = vm->getVar(varNr);
 
 	debugC(6, kDebugLevelScripts, "--- overlay pic ---");
 
 	spritesMgr->eraseSprites();
-	state->_vm->_picture->decodePicture(resourceNr, false);
+	vm->_picture->decodePicture(resourceNr, false);
 	spritesMgr->buildAllSpriteLists();
 	spritesMgr->drawAllSpriteLists();
 	spritesMgr->showAllSpriteLists();
 	state->pictureShown = false;
 
 	// Loading trigger
-	state->_vm->loadingTrigger_DrawPicture();
+	vm->loadingTrigger_DrawPicture();
 }
 
 void cmdShowPriScreen(AgiGame *state, uint8 *parameter) {
@@ -1260,41 +1356,45 @@ void cmdPositionV1(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdPositionF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr1 = parameter[1];
 	uint16 varNr2 = parameter[2];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	screenObj->xPos = screenObj->xPos_prev = state->vars[varNr1];
-	screenObj->yPos = screenObj->yPos_prev = state->vars[varNr2];
+	screenObj->xPos = screenObj->xPos_prev = vm->getVar(varNr1);
+	screenObj->yPos = screenObj->yPos_prev = vm->getVar(varNr2);
 }
 
 void cmdPositionFV1(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr1 = parameter[1];
 	uint16 varNr2 = parameter[2];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	screenObj->xPos = state->vars[varNr1];
-	screenObj->yPos = state->vars[varNr2];
+	screenObj->xPos = vm->getVar(varNr1);
+	screenObj->yPos = vm->getVar(varNr2);
 }
 
 void cmdGetPosn(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr1 = parameter[1];
 	uint16 varNr2 = parameter[2];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	state->vars[varNr1] = (unsigned char)screenObj->xPos;
-	state->vars[varNr2] = (unsigned char)screenObj->yPos;
+	vm->setVar(varNr1, (unsigned char)screenObj->xPos);
+	vm->setVar(varNr2, (unsigned char)screenObj->yPos);
 }
 
 void cmdReposition(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr1 = parameter[1];
 	uint16 varNr2 = parameter[2];
-	int16 dx = (int8) state->vars[varNr1];
-	int16 dy = (int8) state->vars[varNr2];
+	int16 dx = (int8) vm->getVar(varNr1);
+	int16 dy = (int8) vm->getVar(varNr2);
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
 	debugC(4, kDebugLevelScripts, "dx=%d, dy=%d", dx, dy);
@@ -1340,13 +1440,14 @@ void cmdRepositionTo(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdRepositionToF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 varNr1 = parameter[1];
 	uint16 varNr2 = parameter[2];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
-	screenObj->xPos = state->vars[varNr1];
-	screenObj->yPos = state->vars[varNr2];
+	screenObj->xPos = vm->getVar(varNr1);
+	screenObj->yPos = vm->getVar(varNr2);
 	screenObj->flags |= fUpdatePos;
 	state->_vm->fixPosition(objectNr);
 }
@@ -1375,13 +1476,14 @@ void cmdAddToPicV1(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdAddToPicF(AgiGame *state, uint8 *parameter) {
-	uint16 viewNr = state->vars[parameter[0]];
-	uint16 loopNr = state->vars[parameter[1]];
-	uint16 celNr = state->vars[parameter[2]];
-	uint16 xPos = state->vars[parameter[3]];
-	uint16 yPos = state->vars[parameter[4]];
-	uint16 priority = state->vars[parameter[5]];
-	uint16 border = state->vars[parameter[6]];
+	AgiEngine *vm = state->_vm;
+	uint16 viewNr = vm->getVar(parameter[0]);
+	uint16 loopNr = vm->getVar(parameter[1]);
+	uint16 celNr = vm->getVar(parameter[2]);
+	uint16 xPos = vm->getVar(parameter[3]);
+	uint16 yPos = vm->getVar(parameter[4]);
+	uint16 priority = vm->getVar(parameter[5]);
+	uint16 border = vm->getVar(parameter[6]);
 
 	state->_vm->_sprites->addToPic(viewNr, loopNr, celNr, xPos, yPos, priority, border);
 }
@@ -1521,6 +1623,7 @@ void cmdProgramControl(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdFollowEgo(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 followStepSize = parameter[1];
 	uint16 followFlag = parameter[2];
@@ -1536,7 +1639,7 @@ void cmdFollowEgo(AgiGame *state, uint8 *parameter) {
 	screenObj->follow_count = 255;
 
 	if (getVersion() < 0x2000) {
-		state->vars[screenObj->follow_flag] = 0;
+		vm->setVar(screenObj->follow_flag, 0);
 		screenObj->flags |= fUpdate | fAnimated;
 	} else {
 		state->_vm->setflag(screenObj->follow_flag, false);
@@ -1545,6 +1648,7 @@ void cmdFollowEgo(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdMoveObj(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 moveX = parameter[1];
 	uint16 moveY = parameter[2];
@@ -1563,10 +1667,10 @@ void cmdMoveObj(AgiGame *state, uint8 *parameter) {
 		screenObj->stepSize = stepSize;
 
 	if (getVersion() < 0x2000) {
-		state->vars[moveFlag] = 0;
+		vm->setVar(moveFlag, 0);
 		screenObj->flags |= fUpdate | fAnimated;
 	} else {
-		state->_vm->setflag(screenObj->move_flag, false);
+		vm->setflag(screenObj->move_flag, false);
 		screenObj->flags |= fUpdate;
 	}
 
@@ -1575,14 +1679,15 @@ void cmdMoveObj(AgiGame *state, uint8 *parameter) {
 
 	// AGI 2.272 (ddp, xmas) doesn't call move_obj!
 	if (getVersion() > 0x2272)
-		state->_vm->moveObj(screenObj);
+		vm->moveObj(screenObj);
 }
 
 void cmdMoveObjF(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
-	uint16 moveX = state->vars[parameter[1]];
-	uint16 moveY = state->vars[parameter[2]];
-	uint16 stepSize = state->vars[parameter[3]];
+	uint16 moveX = vm->getVar(parameter[1]);
+	uint16 moveY = vm->getVar(parameter[2]);
+	uint16 stepSize = vm->getVar(parameter[3]);
 	uint16 moveFlag = parameter[4];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
 
@@ -1812,6 +1917,7 @@ void cmdRestartGame(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdDistance(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr1 = parameter[0];
 	uint16 objectNr2 = parameter[1];
 	uint16 destVarNr = parameter[2];
@@ -1841,7 +1947,7 @@ void cmdDistance(AgiGame *state, uint8 *parameter) {
 	// wouldn't chase Rosella around anymore. If it had worked correctly the zombie
 	// wouldn't have come up at all or it would have come up and gone back down
 	// immediately. The latter approach is the one implemented here.
-	if (getGameID() == GID_KQ4 && (state->vars[VM_VAR_CURRENT_ROOM] == 16 || state->vars[VM_VAR_CURRENT_ROOM] == 18) && destVarNr >= 221 && destVarNr <= 223) {
+	if (getGameID() == GID_KQ4 && (vm->getVar(VM_VAR_CURRENT_ROOM) == 16 || vm->getVar(VM_VAR_CURRENT_ROOM) == 18) && destVarNr >= 221 && destVarNr <= 223) {
 		// Rooms 16 and 18 are graveyards where three zombies come up at night. They use logics 16 and 18.
 		// Variables 221-223 are used to save the distance between each zombie and Rosella.
 		// Variables 155, 156 and 162 are used to save the state of each zombie in room 16.
@@ -1854,16 +1960,16 @@ void cmdDistance(AgiGame *state, uint8 *parameter) {
 		// a zombie or the zombie getting turned away by the scarab) we make it appear the
 		// zombie is far away from Rosella if the zombie is not already up and chasing her.
 		enum zombieStates {ZOMBIE_SET_TO_RISE_UP, ZOMBIE_RISING_UP, ZOMBIE_CHASING_EGO};
-		uint8 zombieStateVarNumList[] = {155, 156, (uint8)((state->vars[VM_VAR_CURRENT_ROOM] == 16) ? 162 : 158)};
+		uint8 zombieStateVarNumList[] = {155, 156, (uint8)((vm->getVar(VM_VAR_CURRENT_ROOM) == 16) ? 162 : 158)};
 		uint8 zombieNum         = destVarNr - 221;                         // Zombie's number (In range 0-2)
 		uint8 zombieStateVarNum = zombieStateVarNumList[zombieNum]; // Number of the variable containing zombie's state
-		uint8 zombieState       = state->vars[zombieStateVarNum];   // Zombie's state
+		uint8 zombieState       = vm->getVar(zombieStateVarNum);   // Zombie's state
 		// If zombie is not chasing Rosella then set its distance from Rosella to the maximum
 		if (zombieState != ZOMBIE_CHASING_EGO)
 			d = 0xff;
 	}
 
-	state->vars[destVarNr] = (unsigned char)d;
+	vm->setVar(destVarNr, (unsigned char)d);
 }
 
 void cmdAcceptInput(AgiGame *state, uint8 *parameter) {
@@ -1959,10 +2065,12 @@ void cmdGetString(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdGetNum(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	TextMgr *textMgr = state->_vm->_text;
 	int16 leadInTextNr = parameter[0] - 1;
 	int16 numberDestVarNr = parameter[1];
 	const char *leadInTextPtr = nullptr;
+	byte  number = 0;
 
 	debugC(4, kDebugLevelScripts, "%d %d", leadInTextNr, numberDestVarNr);
 
@@ -1987,9 +2095,10 @@ void cmdGetNum(AgiGame *state, uint8 *parameter) {
 
 	textMgr->promptRedraw();
 
-	state->vars[numberDestVarNr] = atoi((char *)textMgr->_inputString);
+	number = atoi((char *)textMgr->_inputString);
+	vm->setVar(numberDestVarNr, number);
 
-	debugC(4, kDebugLevelScripts, "[%s] -> %d", state->strings[MAX_STRINGS], state->vars[numberDestVarNr]);
+	debugC(4, kDebugLevelScripts, "[%s] -> %d", state->strings[MAX_STRINGS], number);
 }
 
 void cmdSetCursorChar(AgiGame *state, uint8 *parameter) {
@@ -2048,9 +2157,10 @@ void cmdDisplay(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdDisplayF(AgiGame *state, uint8 *parameter) {
-	int16 textRow = state->vars[parameter[0]];
-	int16 textColumn = state->vars[parameter[1]];
-	int16 textNr = state->vars[parameter[2]];
+	AgiEngine *vm = state->_vm;
+	int16 textRow = vm->getVar(parameter[0]);
+	int16 textColumn = vm->getVar(parameter[1]);
+	int16 textNr = vm->getVar(parameter[2]);
 
 	state->_vm->_text->display(textNr, textRow, textColumn);
 }
@@ -2091,7 +2201,8 @@ void cmdPrint(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdPrintF(AgiGame *state, uint8 *parameter) {
-	int16 textNr = state->vars[parameter[0]];
+	AgiEngine *vm = state->_vm;
+	int16 textNr = vm->getVar(parameter[0]);
 
 	state->_vm->_text->print(textNr);
 }
@@ -2108,7 +2219,8 @@ void cmdPrintAt(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdPrintAtV(AgiGame *state, uint8 *parameter) {
-	int16 textNr = state->vars[parameter[0]];
+	AgiEngine *vm = state->_vm;
+	int16 textNr = vm->getVar(parameter[0]);
 	int16 textRow = parameter[1];
 	int16 textColumn = parameter[2];
 	int16 textWidth = parameter[3];
@@ -2119,11 +2231,12 @@ void cmdPrintAtV(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdPushScript(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	// We run AGIMOUSE always as a side effect
 	//if (getFeatures() & GF_AGIMOUSE || true) {
-		state->vars[27] = state->_vm->_mouse.button;
-		state->vars[28] = state->_vm->_mouse.x / 2;
-		state->vars[29] = state->_vm->_mouse.y;
+	vm->setVar(VM_VAR_MOUSE_BUTTONSTATE, state->_vm->_mouse.button);
+	vm->setVar(VM_VAR_MOUSE_X, state->_vm->_mouse.x / 2);
+	vm->setVar(VM_VAR_MOUSE_Y, state->_vm->_mouse.y);
 	/*} else {
 		if (getVersion() >= 0x2915) {
 			debug(0, "push.script");
@@ -2140,6 +2253,7 @@ void cmdSetPriBase(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdMousePosn(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 destVarNr1 = parameter[0];
 	uint16 destVarNr2 = parameter[1];
 	int16 mouseX = state->_vm->_mouse.x;
@@ -2147,8 +2261,8 @@ void cmdMousePosn(AgiGame *state, uint8 *parameter) {
 
 	state->_vm->adjustPosToGameScreen(mouseX, mouseY);
 
-	state->vars[destVarNr1] = mouseX;
-	state->vars[destVarNr2] = mouseY;
+	vm->setVar(destVarNr1, mouseX);
+	vm->setVar(destVarNr2, mouseY);
 }
 
 void cmdShakeScreen(AgiGame *state, uint8 *parameter) {
@@ -2182,6 +2296,7 @@ void cmdSetItemView(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdCallV1(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 resourceNr = parameter[0];
 
 	state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
@@ -2191,27 +2306,29 @@ void cmdCallV1(AgiGame *state, uint8 *parameter) {
 //	state->logic_list[++state->max_logics];
 	// For now, just do the increment, to silence a clang warning
 	++state->max_logics;
-	state->vars[13] = 1;
+	vm->setVar(13, 1); // ???? maybe create another enum vor VM Vars
 }
 
 void cmdNewRoomV1(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 resourceNr = parameter[0];
 
 	warning("cmdNewRoomV1()");
 	state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
 	state->max_logics = 1;
 	state->logic_list[1] = resourceNr;
-	state->vars[13] = 1;
+	vm->setVar(13, 1);
 }
 
 void cmdNewRoomVV1(AgiGame *state, uint8 *parameter) {
-	uint16 resourceNr = state->vars[parameter[0]];
+	AgiEngine *vm = state->_vm;
+	uint16 resourceNr = vm->getVar(parameter[0]);
 
 	warning("cmdNewRoomVV1()");
 	state->_vm->agiLoadResource(RESOURCETYPE_LOGIC, resourceNr);
 	state->max_logics = 1;
 	state->logic_list[1] = resourceNr;
-	state->vars[13] = 1;
+	vm->setVar(13, 1);
 }
 
 void cmdUnknown(AgiGame *state, uint8 *parameter) {
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index f7b4ef6..8817756 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -341,7 +341,7 @@ bool TextMgr::messageBox(const char *textPtr) {
 	_vm->_noSaveLoadAllowed = true;
 	_vm->nonBlockingText_Forget();
 
-	if (_vm->_game.vars[VM_VAR_WINDOW_RESET] == 0) {
+	if (_vm->getVar(VM_VAR_WINDOW_RESET) == 0) {
 		int userKey;
 		_vm->setVar(VM_VAR_KEY, 0);
 		userKey = _vm->waitKey();


Commit: 4bc01ab7d585f6be9d25a96ce9544b95f459d7e6
    https://github.com/scummvm/scummvm/commit/4bc01ab7d585f6be9d25a96ce9544b95f459d7e6
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T17:56:53+01:00

Commit Message:
AGI: getflag/setflag/etc. cleanup

renamed getflag() to getFlag()
renamed setflag() to setFlag()
renamed flipflag() to flipFlag()
preagi: renamed setFlag for this engine to setWinnieFlag

Changed paths:
    engines/agi/agi.h
    engines/agi/checks.cpp
    engines/agi/console.cpp
    engines/agi/cycle.cpp
    engines/agi/detection.cpp
    engines/agi/global.cpp
    engines/agi/inv.cpp
    engines/agi/keyboard.cpp
    engines/agi/motion.cpp
    engines/agi/op_cmd.cpp
    engines/agi/op_test.cpp
    engines/agi/preagi_mickey.cpp
    engines/agi/preagi_winnie.cpp
    engines/agi/preagi_winnie.h
    engines/agi/saveload.cpp
    engines/agi/sound.cpp
    engines/agi/sound_pcjr.cpp
    engines/agi/sound_sarien.cpp
    engines/agi/sprite.cpp
    engines/agi/text.cpp
    engines/agi/view.cpp
    engines/agi/words.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 697cf66..5119ccd 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -685,9 +685,9 @@ public:
 
 	int _soundemu;
 
-	int getflag(int);
-	void setflag(int, int);
-	void flipflag(int);
+	int getFlag(int16 flagNr);
+	void setFlag(int16 flagNr, bool newState);
+	void flipFlag(int16 flagNr);
 
 	const AGIGameDescription *_gameDescription;
 
diff --git a/engines/agi/checks.cpp b/engines/agi/checks.cpp
index 2ad0dbd..a3698c3 100644
--- a/engines/agi/checks.cpp
+++ b/engines/agi/checks.cpp
@@ -163,8 +163,8 @@ bool AgiEngine::checkPriority(ScreenObjEntry *screenObj) {
 
 	// Check ego
 	if (screenObj->objectNr == 0) {
-		setflag(VM_FLAG_EGO_TOUCHED_P2, touchedTrigger ? true : false);
-		setflag(VM_FLAG_EGO_WATER, touchedWater ? true : false);
+		setFlag(VM_FLAG_EGO_TOUCHED_P2, touchedTrigger ? true : false);
+		setFlag(VM_FLAG_EGO_WATER, touchedWater ? true : false);
 	}
 
 	return touchedControl;
diff --git a/engines/agi/console.cpp b/engines/agi/console.cpp
index 39719a4..0e2101c 100644
--- a/engines/agi/console.cpp
+++ b/engines/agi/console.cpp
@@ -75,7 +75,7 @@ bool Console::Cmd_SetFlag(int argc, const char **argv) {
 	}
 	int p1 = (int)atoi(argv[1]);
 	int p2 = (int)atoi(argv[2]);
-	_vm->setflag(p1, !!p2);
+	_vm->setFlag(p1, !!p2);
 
 	return true;
 }
@@ -290,7 +290,7 @@ bool Console::Cmd_Flags(int argc, const char **argv) {
 	for (i = 0; i < 255;) {
 		debugPrintf("%3d ", i);
 		for (j = 0; j < 10; j++, i++) {
-			debugPrintf("%c ", _vm->getflag(i) ? 'T' : 'F');
+			debugPrintf("%c ", _vm->getFlag(i) ? 'T' : 'F');
 		}
 		debugPrintf("\n");
 	}
@@ -542,7 +542,7 @@ bool Console::Cmd_VmFlags(int argc, const char **argv) {
 
 	if (argc < 3) {
 		// show contents
-		if (_vm->getflag(flagNr)) {
+		if (_vm->getFlag(flagNr)) {
 			debugPrintf("flag %d == set\n", flagNr);
 		} else {
 			debugPrintf("flag %d == not set\n", flagNr);
@@ -557,10 +557,10 @@ bool Console::Cmd_VmFlags(int argc, const char **argv) {
 		}
 
 		if (!newFlagState) {
-			_vm->setflag(flagNr, 0);
+			_vm->setFlag(flagNr, false);
 			debugPrintf("flag %d reset.\n", flagNr);
 		} else {
-			_vm->setflag(flagNr, 1);
+			_vm->setFlag(flagNr, true);
 			debugPrintf("flag %d set.\n", flagNr);
 		}
 	}
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index a2b9d00..e58d018 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -109,7 +109,7 @@ void AgiEngine::newRoom(int16 newRoomNr) {
 		}
 
 		setVar(VM_VAR_BORDER_TOUCH_EGO, 0);
-		setflag(VM_FLAG_NEW_ROOM_EXEC, true);
+		setFlag(VM_FLAG_NEW_ROOM_EXEC, true);
 
 		_game.exitAllLogics = true;
 
@@ -138,7 +138,7 @@ void AgiEngine::interpretCycle() {
 	checkAllMotions();
 
 	oldScore = getVar(VM_VAR_SCORE);
-	oldSound = getflag(VM_FLAG_SOUND_ON);
+	oldSound = getFlag(VM_FLAG_SOUND_ON);
 
 	_game.exitAllLogics = false;
 	while (runLogic(0) == 0 && !(shouldQuit() || _restartGame)) {
@@ -146,7 +146,7 @@ void AgiEngine::interpretCycle() {
 		setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
 		setVar(VM_VAR_BORDER_CODE, 0);
 		oldScore = getVar(VM_VAR_SCORE);
-		setflag(VM_FLAG_ENTERED_CLI, false);
+		setFlag(VM_FLAG_ENTERED_CLI, false);
 		_game.exitAllLogics = false;
 		nonBlockingText_CycleDone();
 		resetControllers();
@@ -156,14 +156,14 @@ void AgiEngine::interpretCycle() {
 
 	screenObjEgo->direction = getVar(VM_VAR_EGO_DIRECTION);
 
-	if (getVar(VM_VAR_SCORE) != oldScore || getflag(VM_FLAG_SOUND_ON) != oldSound)
+	if (getVar(VM_VAR_SCORE) != oldScore || getFlag(VM_FLAG_SOUND_ON) != oldSound)
 		_game._vm->_text->statusDraw();
 
 	setVar(VM_VAR_BORDER_TOUCH_OBJECT, 0);
 	setVar(VM_VAR_BORDER_CODE, 0);
-	setflag(VM_FLAG_NEW_ROOM_EXEC, false);
-	setflag(VM_FLAG_RESTART_GAME, false);
-	setflag(VM_FLAG_RESTORE_JUST_RAN, false);
+	setFlag(VM_FLAG_NEW_ROOM_EXEC, false);
+	setFlag(VM_FLAG_RESTART_GAME, false);
+	setFlag(VM_FLAG_RESTORE_JUST_RAN, false);
 
 	if (_game.gfxMode) {
 		updateScreenObjTable();
@@ -361,9 +361,9 @@ int AgiEngine::playGame() {
 	_game.horizon = 36;
 	_game.playerControl = false;
 
-	setflag(VM_FLAG_LOGIC_ZERO_FIRST_TIME, true);	// not in 2.917
-	setflag(VM_FLAG_NEW_ROOM_EXEC, true);	// needed for MUMG and SQ2!
-	setflag(VM_FLAG_SOUND_ON, true);	// enable sound
+	setFlag(VM_FLAG_LOGIC_ZERO_FIRST_TIME, true);	// not in 2.917
+	setFlag(VM_FLAG_NEW_ROOM_EXEC, true);	// needed for MUMG and SQ2!
+	setFlag(VM_FLAG_SOUND_ON, true);	// enable sound
 	setVar(VM_VAR_TIME_DELAY, 2);	// "normal" speed
 
 	_game.gfxMode = true;
@@ -379,13 +379,13 @@ int AgiEngine::playGame() {
 
 	debug(0, "Running AGI script.\n");
 
-	setflag(VM_FLAG_ENTERED_CLI, false);
-	setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+	setFlag(VM_FLAG_ENTERED_CLI, false);
+	setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
 	setVar(VM_VAR_WORD_NOT_FOUND, 0);
 	setVar(VM_VAR_KEY, 0);
 
 	debugC(2, kDebugLevelMain, "Entering main loop");
-	bool firstLoop = !getflag(VM_FLAG_RESTART_GAME); // Do not restore on game restart
+	bool firstLoop = !getFlag(VM_FLAG_RESTART_GAME); // Do not restore on game restart
 
 	if (firstLoop) {
 		if (ConfMan.hasKey("save_slot")) {
@@ -419,8 +419,8 @@ int AgiEngine::playGame() {
 				checkQuickLoad();
 			}
 
-			setflag(VM_FLAG_ENTERED_CLI, false);
-			setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+			setFlag(VM_FLAG_ENTERED_CLI, false);
+			setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
 			setVar(VM_VAR_WORD_NOT_FOUND, 0);
 			setVar(VM_VAR_KEY, 0);
 		}
@@ -465,7 +465,7 @@ int AgiEngine::runGame() {
 			break;
 
 		if (_restartGame) {
-			setflag(VM_FLAG_RESTART_GAME, true);
+			setFlag(VM_FLAG_RESTART_GAME, true);
 			setVar(VM_VAR_TIME_DELAY, 2);	// "normal" speed
 			_restartGame = false;
 		}
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 641fe55..17e1eef 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -571,7 +571,7 @@ namespace Agi {
 
 bool AgiBase::canLoadGameStateCurrently() {
 	if (!(getGameType() == GType_PreAGI)) {
-		if (getflag(VM_FLAG_MENUS_WORK)) {
+		if (getFlag(VM_FLAG_MENUS_WORK)) {
 			if (!_noSaveLoadAllowed) {
 				if (!cycleInnerLoopIsActive()) {
 					// We can't allow to restore a game, while inner loop is active
@@ -592,7 +592,7 @@ bool AgiBase::canSaveGameStateCurrently() {
 		return true;
 
 	if (!(getGameType() == GType_PreAGI)) {
-		if (getflag(VM_FLAG_MENUS_WORK)) {
+		if (getFlag(VM_FLAG_MENUS_WORK)) {
 			if (!_noSaveLoadAllowed) {
 				if (!cycleInnerLoopIsActive()) {
 					if (promptIsEnabled()) {
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index bf6356d..4cf6c3d 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -24,28 +24,28 @@
 
 namespace Agi {
 
-int AgiBase::getflag(int n) {
-	uint8 *set = (uint8 *)&_game.flags;
+int AgiBase::getFlag(int16 flagNr) {
+	uint8 *flagPtr = _game.flags;
 
-	set += n >> 3;
-	return (*set & (1 << (n & 0x07))) != 0;
+	flagPtr += flagNr >> 3;
+	return (*flagPtr & (1 << (flagNr & 0x07))) != 0;
 }
 
-void AgiBase::setflag(int n, int v) {
-	uint8 *set = (uint8 *)&_game.flags;
+void AgiBase::setFlag(int16 flagNr, bool newState) {
+	uint8 *flagPtr = _game.flags;
 
-	set += n >> 3;
-	if (v)
-		*set |= 1 << (n & 0x07);	// set bit
+	flagPtr += flagNr >> 3;
+	if (newState)
+		*flagPtr |= 1 << (flagNr & 0x07);	// set bit
 	else
-		*set &= ~(1 << (n & 0x07));	// clear bit
+		*flagPtr &= ~(1 << (flagNr & 0x07));	// clear bit
 }
 
-void AgiBase::flipflag(int n) {
-	uint8 *set = (uint8 *)&_game.flags;
+void AgiBase::flipFlag(int16 flagNr) {
+	uint8 *flagPtr = _game.flags;
 
-	set += n >> 3;
-	*set ^= 1 << (n & 0x07);	// flip bit
+	flagPtr += flagNr >> 3;
+	*flagPtr ^= 1 << (flagNr & 0x07);	// flip bit
 }
 
 void AgiEngine::setVar(int16 varNr, int val) {
diff --git a/engines/agi/inv.cpp b/engines/agi/inv.cpp
index 614b016..38e5e11 100644
--- a/engines/agi/inv.cpp
+++ b/engines/agi/inv.cpp
@@ -127,7 +127,7 @@ void InventoryMgr::show() {
 	// figure out current inventory of the player
 	getPlayerInventory();
 
-	if (_vm->getflag(VM_FLAG_STATUS_SELECTS_ITEMS)) {
+	if (_vm->getFlag(VM_FLAG_STATUS_SELECTS_ITEMS)) {
 		selectItems = true;
 	} else{
 		_activeItemNr = -1; // so that none is shown as active
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 0d5efb6..81de225 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -540,7 +540,7 @@ int AgiEngine::waitKey() {
 	clearKeyQueue();
 
 	debugC(3, kDebugLevelInput, "waiting...");
-	while (!(shouldQuit() || _restartGame || getflag(VM_FLAG_RESTORE_JUST_RAN))) {
+	while (!(shouldQuit() || _restartGame || getFlag(VM_FLAG_RESTORE_JUST_RAN))) {
 		pollTimer();
 		key = doPollKeyboard();
 		if (key == AGI_KEY_ENTER || key == AGI_KEY_ESCAPE || key == AGI_MOUSE_BUTTON_LEFT)
diff --git a/engines/agi/motion.cpp b/engines/agi/motion.cpp
index 76f0f91..ad6f6cb 100644
--- a/engines/agi/motion.cpp
+++ b/engines/agi/motion.cpp
@@ -98,7 +98,7 @@ void AgiEngine::motionFollowEgo(ScreenObjEntry *screenObj) {
 	if (dir == 0) {
 		screenObj->direction = 0;
 		screenObj->motionType = kMotionNormal;
-		setflag(screenObj->follow_flag, true);
+		setFlag(screenObj->follow_flag, true);
 		return;
 	}
 
@@ -200,7 +200,7 @@ void AgiEngine::checkAllMotions() {
 void AgiEngine::inDestination(ScreenObjEntry *screenObj) {
 	if (screenObj->motionType == kMotionMoveObj) {
 		screenObj->stepSize = screenObj->move_stepSize;
-		setflag(screenObj->move_flag, true);
+		setFlag(screenObj->move_flag, true);
 	}
 	screenObj->motionType = kMotionNormal;
 	if (isEgoView(screenObj))
@@ -213,7 +213,7 @@ void AgiEngine::motionMoveObjStop(ScreenObjEntry *screenObj) {
 	// This check for motionType was only done in AGI3.
 	// But we use this motion type for mouse movement, so we need to check in any case, otherwise it will cause glitches.
 	if (screenObj->motionType != kMotionEgo) {
-		setflag(screenObj->move_flag, true);
+		setFlag(screenObj->move_flag, true);
 	}
 
 	screenObj->motionType = kMotionNormal;
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index ec24082..57a6d68 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -223,22 +223,22 @@ void cmdSet(AgiGame *state, uint8 *parameter) {
 	AgiEngine *vm = state->_vm;
 	uint16 flagNr = parameter[0];
 
-	vm->setflag(flagNr, true);
+	vm->setFlag(flagNr, true);
 }
 
 void cmdReset(AgiGame *state, uint8 *parameter) {
 	AgiEngine *vm = state->_vm;
 	uint16 flagNr = parameter[0];
 
-	vm->setflag(flagNr, false);
+	vm->setFlag(flagNr, false);
 }
 
 void cmdToggle(AgiGame *state, uint8 *parameter) {
 	AgiEngine *vm = state->_vm;
 	uint16 flagNr = parameter[0];
-	bool curFlagState = vm->getflag(flagNr);
+	bool curFlagState = vm->getFlag(flagNr);
 
-	vm->setflag(flagNr, !curFlagState);
+	vm->setFlag(flagNr, !curFlagState);
 }
 
 void cmdSetV(AgiGame *state, uint8 *parameter) {
@@ -250,7 +250,7 @@ void cmdSetV(AgiGame *state, uint8 *parameter) {
 	} else {
 		flagNr = vm->getVar(flagNr);
 
-		vm->setflag(flagNr, true);
+		vm->setFlag(flagNr, true);
 	}
 }
 
@@ -263,7 +263,7 @@ void cmdResetV(AgiGame *state, uint8 *parameter) {
 	} else {
 		flagNr = vm->getVar(flagNr);
 
-		vm->setflag(flagNr, false);
+		vm->setFlag(flagNr, false);
 	}
 }
 
@@ -276,9 +276,9 @@ void cmdToggleV(AgiGame *state, uint8 *parameter) {
 		vm->setVar(flagNr, value ^ 1);
 	} else {
 		flagNr = vm->getVar(flagNr);
-		bool curFlagState = vm->getflag(flagNr);
+		bool curFlagState = vm->getFlag(flagNr);
 
-		vm->setflag(flagNr, !curFlagState);
+		vm->setFlag(flagNr, !curFlagState);
 	}
 }
 
@@ -781,7 +781,7 @@ void cmdStopSound(AgiGame *state, uint8 *parameter) {
 void cmdMenuInput(AgiGame *state, uint8 *parameter) {
 	AgiEngine *vm = state->_vm;
 
-	if (vm->getflag(VM_FLAG_MENUS_WORK)) {
+	if (vm->getFlag(VM_FLAG_MENUS_WORK)) {
 		vm->_menu->delayedExecute();
 	}
 }
@@ -964,21 +964,21 @@ void cmdSetSimple(AgiGame *state, uint8 *parameter) {
 		uint16 resourceNr = vm->getVar(varNr);
 
 		spritesMgr->eraseSprites();
-		state->_vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
+		vm->agiLoadResource(RESOURCETYPE_PICTURE, resourceNr);
 
 		// Draw the picture. Similar to void cmdDraw_pic(AgiGame *state, uint8 *p).
-		state->_vm->_picture->decodePicture(resourceNr, false, true);
+		vm->_picture->decodePicture(resourceNr, false, true);
 		spritesMgr->drawAllSpriteLists();
 		state->pictureShown = false;
 
 		// Show the picture. Similar to void cmdShow_pic(AgiGame *state, uint8 *p).
-		state->_vm->setflag(VM_FLAG_OUTPUT_MODE, false);
-		state->_vm->_text->closeWindow();
-		state->_vm->_picture->showPic();
+		vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
+		vm->_text->closeWindow();
+		vm->_picture->showPic();
 		state->pictureShown = true;
 
 		// Loading trigger
-		state->_vm->loadingTrigger_DrawPicture();
+		vm->loadingTrigger_DrawPicture();
 	}
 }
 
@@ -1093,8 +1093,8 @@ void cmdParse(AgiGame *state, uint8 *parameter) {
 	uint16 stringNr = parameter[0];
 
 	vm->setVar(VM_VAR_WORD_NOT_FOUND, 0);
-	vm->setflag(VM_FLAG_ENTERED_CLI, false);
-	vm->setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+	vm->setFlag(VM_FLAG_ENTERED_CLI, false);
+	vm->setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
 
 	vm->_words->parseUsingDictionary(text->stringPrintf(state->strings[stringNr]));
 }
@@ -1167,7 +1167,7 @@ void cmdDrawPic(AgiGame *state, uint8 *parameter) {
 	// that this is a script bug and occurs in the original interpreter as well.
 	// Fixes bug #3056: AGI: SQ1 (2.2 DOS ENG) bizzare exploding roger
 	if (getGameID() == GID_SQ1 && resourceNr == 20)
-		vm->setflag(103, false);
+		vm->setFlag(103, false);
 
 	// Loading trigger
 	vm->loadingTrigger_DrawPicture();
@@ -1177,7 +1177,7 @@ void cmdShowPic(AgiGame *state, uint8 *parameter) {
 	AgiEngine *vm = state->_vm;
 	debugC(6, kDebugLevelScripts, "=== show pic ===");
 
-	vm->setflag(VM_FLAG_OUTPUT_MODE, false);
+	vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
 	vm->_text->closeWindow();
 	vm->_picture->showPicWithTransition();
 	state->pictureShown = true;
@@ -1506,7 +1506,7 @@ void cmdReverseLoop(AgiGame *state, uint8 *parameter) {
 	screenObj->cycle = kCycleRevLoop;
 	screenObj->flags |= (fDontupdate | fUpdate | fCycling);
 	screenObj->loop_flag = loopFlag;
-	state->_vm->setflag(screenObj->loop_flag, false);
+	state->_vm->setFlag(screenObj->loop_flag, false);
 }
 
 void cmdReverseLoopV1(AgiGame *state, uint8 *parameter) {
@@ -1523,6 +1523,7 @@ void cmdReverseLoopV1(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdEndOfLoop(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	uint16 objectNr = parameter[0];
 	uint16 loopFlag = parameter[1];
 	ScreenObjEntry *screenObj = &state->screenObjTable[objectNr];
@@ -1531,7 +1532,7 @@ void cmdEndOfLoop(AgiGame *state, uint8 *parameter) {
 	screenObj->cycle = kCycleEndOfLoop;
 	screenObj->flags |= (fDontupdate | fUpdate | fCycling);
 	screenObj->loop_flag = loopFlag;
-	state->_vm->setflag(screenObj->loop_flag, false);
+	vm->setFlag(screenObj->loop_flag, false);
 }
 
 void cmdEndOfLoopV1(AgiGame *state, uint8 *parameter) {
@@ -1642,7 +1643,7 @@ void cmdFollowEgo(AgiGame *state, uint8 *parameter) {
 		vm->setVar(screenObj->follow_flag, 0);
 		screenObj->flags |= fUpdate | fAnimated;
 	} else {
-		state->_vm->setflag(screenObj->follow_flag, false);
+		vm->setFlag(screenObj->follow_flag, false);
 		screenObj->flags |= fUpdate;
 	}
 }
@@ -1670,7 +1671,7 @@ void cmdMoveObj(AgiGame *state, uint8 *parameter) {
 		vm->setVar(moveFlag, 0);
 		screenObj->flags |= fUpdate | fAnimated;
 	} else {
-		vm->setflag(screenObj->move_flag, false);
+		vm->setFlag(screenObj->move_flag, false);
 		screenObj->flags |= fUpdate;
 	}
 
@@ -1700,7 +1701,7 @@ void cmdMoveObjF(AgiGame *state, uint8 *parameter) {
 	if (stepSize != 0)
 		screenObj->stepSize = stepSize;
 
-	state->_vm->setflag(screenObj->move_flag, false);
+	vm->setFlag(screenObj->move_flag, false);
 	screenObj->flags |= fUpdate;
 
 	if (objectNr == 0)
@@ -1708,7 +1709,7 @@ void cmdMoveObjF(AgiGame *state, uint8 *parameter) {
 
 	// AGI 2.272 (ddp, xmas) doesn't call move_obj!
 	if (getVersion() > 0x2272)
-		state->_vm->moveObj(screenObj);
+		vm->moveObj(screenObj);
 }
 
 void cmdWander(AgiGame *state, uint8 *parameter) {
@@ -1899,20 +1900,21 @@ void cmdQuitV1(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdRestartGame(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
 	bool doRestart = false;
 
 	state->_vm->_sound->stopSound();
 
-	if (state->_vm->getflag(VM_FLAG_AUTO_RESTART)) {
+	if (vm->getFlag(VM_FLAG_AUTO_RESTART)) {
 		doRestart = true;
 	} else {
-		doRestart = state->_vm->_systemUI->restartDialog();
+		doRestart = vm->_systemUI->restartDialog();
 	}
 
 	if (doRestart) {
-		state->_vm->_restartGame = true;
-		state->_vm->setflag(VM_FLAG_RESTART_GAME, true);
-		state->_vm->_menu->itemEnableAll();
+		vm->_restartGame = true;
+		vm->setFlag(VM_FLAG_RESTART_GAME, true);
+		vm->_menu->itemEnableAll();
 	}
 }
 
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 701bbcd..c461dfc 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -78,11 +78,11 @@ void condGreaterV(AgiGame *state, uint8 *p) {
 }
 
 void condIsSet(AgiGame *state, uint8 *p) {
-	state->testResult = state->_vm->getflag(p[0]);
+	state->testResult = state->_vm->getFlag(p[0]);
 }
 
 void condIsSetV(AgiGame *state, uint8 *p) {
-	state->testResult = state->_vm->getflag(getVar(p[0]));
+	state->testResult = state->_vm->getFlag(getVar(p[0]));
 }
 
 void condIsSetV1(AgiGame *state, uint8 *p) {
@@ -121,7 +121,7 @@ void condSaid(AgiGame *state, uint8 *p) {
 void condSaid1(AgiGame *state, uint8 *p) {
 	state->testResult = false;
 
-	if (!state->_vm->getflag(VM_FLAG_ENTERED_CLI))
+	if (!state->_vm->getFlag(VM_FLAG_ENTERED_CLI))
 		return;
 
 	int id0 = READ_LE_UINT16(p);
@@ -133,7 +133,7 @@ void condSaid1(AgiGame *state, uint8 *p) {
 void condSaid2(AgiGame *state, uint8 *p) {
 	state->testResult = false;
 
-	if (!state->_vm->getflag(VM_FLAG_ENTERED_CLI))
+	if (!state->_vm->getFlag(VM_FLAG_ENTERED_CLI))
 		return;
 
 	int id0 = READ_LE_UINT16(p);
@@ -147,7 +147,7 @@ void condSaid2(AgiGame *state, uint8 *p) {
 void condSaid3(AgiGame *state, uint8 *p) {
 	state->testResult = false;
 
-	if (!state->_vm->getflag(VM_FLAG_ENTERED_CLI))
+	if (!state->_vm->getFlag(VM_FLAG_ENTERED_CLI))
 		return;
 
 	int id0 = READ_LE_UINT16(p);
@@ -320,7 +320,7 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
 	int c, n = words->getEgoWordCount();
 	int z = 0;
 
-	if (vm->getflag(VM_FLAG_SAID_ACCEPTED_INPUT) || !vm->getflag(VM_FLAG_ENTERED_CLI))
+	if (vm->getFlag(VM_FLAG_SAID_ACCEPTED_INPUT) || !vm->getFlag(VM_FLAG_ENTERED_CLI))
 		return false;
 
 	// FR:
@@ -366,7 +366,7 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
 	if (nwords != 0 && READ_LE_UINT16(cc) != 9999)
 		return false;
 
-	setflag(VM_FLAG_SAID_ACCEPTED_INPUT, true);
+	setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, true);
 
 	return true;
 }
diff --git a/engines/agi/preagi_mickey.cpp b/engines/agi/preagi_mickey.cpp
index ad1bddf..cc5c1f8 100644
--- a/engines/agi/preagi_mickey.cpp
+++ b/engines/agi/preagi_mickey.cpp
@@ -492,7 +492,7 @@ bool MickeyEngine::getMenuSelRow(MSA_MENU menu, int *sel0, int *sel1, int iRow)
 
 					return false;
 				case Common::KEYCODE_s:
-					flipflag(VM_FLAG_SOUND_ON);
+					flipFlag(VM_FLAG_SOUND_ON);
 					break;
 				case Common::KEYCODE_c:
 					inventory();
@@ -672,7 +672,7 @@ void MickeyEngine::playNote(MSA_SND_NOTE note) {
 }
 
 void MickeyEngine::playSound(ENUM_MSA_SOUND iSound) {
-	if (!getflag(VM_FLAG_SOUND_ON))
+	if (!getFlag(VM_FLAG_SOUND_ON))
 		return;
 
 	Common::Event event;
@@ -2297,7 +2297,7 @@ void MickeyEngine::init() {
 
 #endif
 
-	setflag(VM_FLAG_SOUND_ON, true); // enable sound
+	setFlag(VM_FLAG_SOUND_ON, true); // enable sound
 }
 
 Common::Error MickeyEngine::go() {
diff --git a/engines/agi/preagi_winnie.cpp b/engines/agi/preagi_winnie.cpp
index 596f417..5285976 100644
--- a/engines/agi/preagi_winnie.cpp
+++ b/engines/agi/preagi_winnie.cpp
@@ -226,11 +226,11 @@ void WinnieEngine::setTakeDrop(int fCanSel[]) {
 	fCanSel[IDI_WTP_SEL_DROP] = _gameStateWinnie.iObjHave;
 }
 
-void WinnieEngine::setFlag(int iFlag) {
+void WinnieEngine::setWinnieFlag(int iFlag) {
 	_gameStateWinnie.fGame[iFlag] = 1;
 }
 
-void WinnieEngine::clearFlag(int iFlag) {
+void WinnieEngine::clearWinnieFlag(int iFlag) {
 	_gameStateWinnie.fGame[iFlag] = 0;
 }
 
@@ -404,11 +404,11 @@ int WinnieEngine::parser(int pc, int index, uint8 *buffer) {
 				break;
 			case IDO_WTP_FLAG_CLEAR:
 				opcode = *(buffer + pc++);
-				clearFlag(opcode);
+				clearWinnieFlag(opcode);
 				break;
 			case IDO_WTP_FLAG_SET:
 				opcode = *(buffer + pc++);
-				setFlag(opcode);
+				setWinnieFlag(opcode);
 				break;
 			case IDO_WTP_GAME_OVER:
 				gameOver();
@@ -947,7 +947,7 @@ void WinnieEngine::getMenuSel(char *szMenu, int *iSel, int fCanSel[]) {
 					break;
 				case Common::KEYCODE_s:
 					if (event.kbd.flags & Common::KBD_CTRL) {
-						flipflag(VM_FLAG_SOUND_ON);
+						flipFlag(VM_FLAG_SOUND_ON);
 					} else {
 						*iSel = IDI_WTP_SEL_SOUTH;
 						makeSel(iSel, fCanSel);
@@ -1342,7 +1342,7 @@ void WinnieEngine::init() {
 	}
 
 	_sound = new SoundMgr(this, _mixer);
-	setflag(VM_FLAG_SOUND_ON, true); // enable sound
+	setFlag(VM_FLAG_SOUND_ON, true); // enable sound
 
 	memset(&_gameStateWinnie, 0, sizeof(_gameStateWinnie));
 	_gameStateWinnie.fSound = 1;
diff --git a/engines/agi/preagi_winnie.h b/engines/agi/preagi_winnie.h
index b5e8b8d..f05caba 100644
--- a/engines/agi/preagi_winnie.h
+++ b/engines/agi/preagi_winnie.h
@@ -336,8 +336,8 @@ private:
 	bool isRightObj(int, int, int*);
 	void drawObjPic(int, int, int);
 	void getMenuMouseSel(int*, int[], int, int);
-	void setFlag(int);
-	void clearFlag(int);
+	void setWinnieFlag(int);
+	void clearWinnieFlag(int);
 	void gameOver();
 	void saveGame();
 	void loadGame();
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index b11927c..b6974ee 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -134,6 +134,9 @@ int AgiEngine::saveGame(const Common::String &fileName, const Common::String &de
 	out->writeByte(_game.automaticSave);
 	out->write(_game.automaticSaveDescription, 31);
 
+	// touch VM_VAR_SECONDS, so that it gets updated
+	getVar(VM_VAR_SECONDS);
+
 	for (i = 0; i < MAX_FLAGS; i++)
 		out->writeByte(_game.flags[i]);
 	for (i = 0; i < MAX_VARS; i++)
@@ -666,7 +669,7 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
 	delete in;
 	debugC(3, kDebugLevelMain | kDebugLevelSavegame, "Closed %s", fileName.c_str());
 
-	setflag(VM_FLAG_RESTORE_JUST_RAN, true);
+	setFlag(VM_FLAG_RESTORE_JUST_RAN, true);
 
 	_game.hasPrompt = 0;	// force input line repaint if necessary
 	_words->clearEgoWords();
diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp
index 8f678cb..edf1796 100644
--- a/engines/agi/sound.cpp
+++ b/engines/agi/sound.cpp
@@ -140,7 +140,7 @@ void SoundMgr::startSound(int resnum, int flag) {
 	if (_vm->getVersion() < 0x2000) {
 		_vm->_game.vars[_endflag] = 0;
 	} else {
-		_vm->setflag(_endflag, false);
+		_vm->setFlag(_endflag, false);
 	}
 }
 
@@ -160,7 +160,7 @@ void SoundMgr::stopSound() {
 		if (_vm->getVersion() < 0x2000) {
 			_vm->_game.vars[_endflag] = 1;
 		} else {
-			_vm->setflag(_endflag, true);
+			_vm->setFlag(_endflag, true);
 		}
 	}
 
@@ -169,7 +169,7 @@ void SoundMgr::stopSound() {
 
 void SoundMgr::soundIsFinished() {
 	if (_endflag != -1)
-		_vm->setflag(_endflag, true);
+		_vm->setFlag(_endflag, true);
 
 	if (_playingSound != -1)
 		_vm->_game.sounds[_playingSound]->stop();
diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index d875fa0..2042c10 100644
--- a/engines/agi/sound_pcjr.cpp
+++ b/engines/agi/sound_pcjr.cpp
@@ -236,7 +236,7 @@ int SoundGenPCJr::getNextNote_v2(int ch) {
 
 	assert(ch < CHAN_MAX);
 
-	if (!_vm->getflag(VM_FLAG_SOUND_ON))
+	if (!_vm->getFlag(VM_FLAG_SOUND_ON))
 		return -1;
 
 	tpcm = &_tchannel[ch];
diff --git a/engines/agi/sound_sarien.cpp b/engines/agi/sound_sarien.cpp
index d197f85..8cd6af3 100644
--- a/engines/agi/sound_sarien.cpp
+++ b/engines/agi/sound_sarien.cpp
@@ -161,7 +161,7 @@ void SoundGenSarien::stopNote(int i) {
 }
 
 void SoundGenSarien::playNote(int i, int freq, int vol) {
-	if (!_vm->getflag(VM_FLAG_SOUND_ON))
+	if (!_vm->getFlag(VM_FLAG_SOUND_ON))
 		vol = 0;
 	else if (vol && _vm->_soundemu == SOUND_EMU_PC)
 		vol = 160;
diff --git a/engines/agi/sprite.cpp b/engines/agi/sprite.cpp
index 1124aef..a3920c3 100644
--- a/engines/agi/sprite.cpp
+++ b/engines/agi/sprite.cpp
@@ -254,7 +254,7 @@ void SpritesMgr::drawCel(ScreenObjEntry *screenObj) {
 	}
 
 	if (screenObj->objectNr == 0) {	// if ego, update if ego is visible at the moment
-		_vm->setflag(VM_FLAG_EGO_INVISIBLE, isViewHidden);
+		_vm->setFlag(VM_FLAG_EGO_INVISIBLE, isViewHidden);
 	}
 }
 
diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp
index 8817756..8806aee 100644
--- a/engines/agi/text.cpp
+++ b/engines/agi/text.cpp
@@ -328,9 +328,9 @@ void TextMgr::printAt(int16 textNr, int16 textPos_Row, int16 textPos_Column, int
 bool TextMgr::messageBox(const char *textPtr) {
 	drawMessageBox(textPtr);
 
-	if (_vm->getflag(VM_FLAG_OUTPUT_MODE)) {
+	if (_vm->getFlag(VM_FLAG_OUTPUT_MODE)) {
 		// non-blocking window
-		_vm->setflag(VM_FLAG_OUTPUT_MODE, false);
+		_vm->setFlag(VM_FLAG_OUTPUT_MODE, false);
 
 		// Signal, that non-blocking text is shown at the moment
 		_vm->nonBlockingText_IsShown();
@@ -359,7 +359,7 @@ bool TextMgr::messageBox(const char *textPtr) {
 	_vm->setVar(VM_VAR_KEY, 0);
 
 	do {
-		if (_vm->getflag(VM_FLAG_RESTORE_JUST_RAN))
+		if (_vm->getFlag(VM_FLAG_RESTORE_JUST_RAN))
 			break;
 
 		_vm->mainCycle();
@@ -491,7 +491,7 @@ void TextMgr::statusDraw() {
 		displayText(statusTextPtr);
 
 		charPos_Set(_statusRow, 30);
-		if (_vm->getflag(VM_FLAG_SOUND_ON)) {
+		if (_vm->getFlag(VM_FLAG_SOUND_ON)) {
 			statusTextPtr = stringPrintf(_systemUI->getStatusTextSoundOn());
 		} else {
 			statusTextPtr = stringPrintf(_systemUI->getStatusTextSoundOff());
diff --git a/engines/agi/view.cpp b/engines/agi/view.cpp
index 3793272..5c52732 100644
--- a/engines/agi/view.cpp
+++ b/engines/agi/view.cpp
@@ -49,7 +49,7 @@ void AgiEngine::updateView(ScreenObjEntry *screenObj) {
 			if (++celNr != lastCelNr)
 				break;
 		}
-		setflag(screenObj->loop_flag, true);
+		setFlag(screenObj->loop_flag, true);
 		screenObj->flags &= ~fCycling;
 		screenObj->direction = 0;
 		screenObj->cycle = kCycleNormal;
@@ -60,7 +60,7 @@ void AgiEngine::updateView(ScreenObjEntry *screenObj) {
 			if (celNr)
 				break;
 		}
-		setflag(screenObj->loop_flag, true);
+		setFlag(screenObj->loop_flag, true);
 		screenObj->flags &= ~fCycling;
 		screenObj->direction = 0;
 		screenObj->cycle = kCycleNormal;
diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp
index 3c248e9..0b8a4f3 100644
--- a/engines/agi/words.cpp
+++ b/engines/agi/words.cpp
@@ -354,11 +354,11 @@ void Words::parseUsingDictionary(char *rawUserInput) {
 
 	debugC(4, kDebugLevelScripts, "ego word count = %d", _egoWordCount);
 	if (_egoWordCount > 0) {
-		_vm->setflag(VM_FLAG_ENTERED_CLI, true);
+		_vm->setFlag(VM_FLAG_ENTERED_CLI, true);
 	} else {
-		_vm->setflag(VM_FLAG_ENTERED_CLI, false);
+		_vm->setFlag(VM_FLAG_ENTERED_CLI, false);
 	}
-	_vm->setflag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
+	_vm->setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false);
 }
 
 uint16 Words::getEgoWordCount() {


Commit: 9acbe6f3f42a35becf3dcff04d758b3286c05c7e
    https://github.com/scummvm/scummvm/commit/9acbe6f3f42a35becf3dcff04d758b3286c05c7e
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T19:00:32+01:00

Commit Message:
AGI: adjust getFlag(), setVar() and getVar()

Changed paths:
    engines/agi/agi.h
    engines/agi/cycle.cpp
    engines/agi/global.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 5119ccd..4c7580d 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -685,7 +685,7 @@ public:
 
 	int _soundemu;
 
-	int getFlag(int16 flagNr);
+	bool getFlag(int16 flagNr);
 	void setFlag(int16 flagNr, bool newState);
 	void flipFlag(int16 flagNr);
 
@@ -822,8 +822,8 @@ public:
 	void newInputMode(InputMode mode);
 	void oldInputMode();
 
-	int getVar(int16 varNr);
-	void setVar(int16 varNr, int);
+	byte getVar(int16 varNr);
+	void setVar(int16 varNr, byte newValue);
 	void decrypt(uint8 *mem, int len);
 	void releaseSprites();
 	int mainCycle(bool onlyCheckForEvents = false);
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index e58d018..85a465c 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -128,7 +128,8 @@ void AgiEngine::resetControllers() {
 
 void AgiEngine::interpretCycle() {
 	ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY];
-	int oldSound, oldScore;
+	bool oldSound;
+	byte oldScore;
 
 	if (!_game.playerControl)
 		setVar(VM_VAR_EGO_DIRECTION, screenObjEgo->direction);
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index 4cf6c3d..9f3fb45 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -24,7 +24,7 @@
 
 namespace Agi {
 
-int AgiBase::getFlag(int16 flagNr) {
+bool AgiBase::getFlag(int16 flagNr) {
 	uint8 *flagPtr = _game.flags;
 
 	flagPtr += flagNr >> 3;
@@ -48,16 +48,16 @@ void AgiBase::flipFlag(int16 flagNr) {
 	*flagPtr ^= 1 << (flagNr & 0x07);	// flip bit
 }
 
-void AgiEngine::setVar(int16 varNr, int val) {
-	_game.vars[varNr] = val;
+void AgiEngine::setVar(int16 varNr, byte newValue) {
+	_game.vars[varNr] = newValue;
 
 	if (varNr == VM_VAR_VOLUME) {
-		_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, val * 17);
-		_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, val * 17);
+		_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, newValue * 17);
+		_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, newValue * 17);
 	}
 }
 
-int AgiEngine::getVar(int16 varNr) {
+byte AgiEngine::getVar(int16 varNr) {
 	return _game.vars[varNr];
 }
 


Commit: fd9c46831df3bcd09bc6f85d5e41c2beb3f7c024
    https://github.com/scummvm/scummvm/commit/fd9c46831df3bcd09bc6f85d5e41c2beb3f7c024
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T20:53:36+01:00

Commit Message:
AGI: remove timer hack, implement in game timer

in game timer is now updated, when scripts read in game timer
VM variables and during main loop. ScummVM total play time feature
is used for it. Game cycle syncing is done at the same time.

Changed paths:
    engines/agi/agi.cpp
    engines/agi/agi.h
    engines/agi/cycle.cpp
    engines/agi/global.cpp
    engines/agi/graphics.cpp
    engines/agi/graphics.h
    engines/agi/keyboard.cpp
    engines/agi/menu.cpp
    engines/agi/op_cmd.cpp
    engines/agi/op_test.cpp
    engines/agi/preagi.cpp
    engines/agi/saveload.cpp



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 8dd663c..c8490d4 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -390,7 +390,6 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
 
 	setupOpcodes();
 	_game._curLogic = NULL;
-	_timerHack = 0;
 
 	_lastSaveTime = 0;
 	_lastTick = 0;
@@ -460,8 +459,6 @@ void AgiEngine::initialize() {
 	_font->init();
 	_text->init(_systemUI);
 
-	_gfx->initMachine();
-
 	_game.gameFlags = 0;
 
 	_text->charAttrib_Set(15, 0);
@@ -530,7 +527,6 @@ AgiEngine::~AgiEngine() {
 	delete _text;
 	delete _sprites;
 	delete _picture;
-	_gfx->deinitMachine();
 	delete _gfx;
 	delete _font;
 	delete _words;
@@ -549,7 +545,7 @@ Common::Error AgiEngine::go() {
 	if (_game.mouseEnabled) {
 		CursorMan.showMouse(true);
 	}
-	setTotalPlayTime(0);
+	inGameTimerReset();
 
 	if (_game.state < STATE_LOADED) {
 		do {
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 4c7580d..7e1505f 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -653,7 +653,6 @@ public:
 	GfxMgr  *_gfx;
 
 	Common::RenderMode _renderMode;
-	volatile uint32 _clockCount;
 	AgiDebug _debug;
 	AgiGame _game;
 	Common::RandomSource *_rnd;
@@ -824,12 +823,13 @@ public:
 
 	byte getVar(int16 varNr);
 	void setVar(int16 varNr, byte newValue);
+
+public:
 	void decrypt(uint8 *mem, int len);
 	void releaseSprites();
 	int mainCycle(bool onlyCheckForEvents = false);
 	int viewPictures();
 	int runGame();
-	void updateTimer();
 	int getAppDir(char *appDir, unsigned int size);
 
 	int setupV2Game(int ver);
@@ -950,14 +950,23 @@ public:
 public:
 	void redrawScreen();
 
+	void inGameTimerReset(uint32 newPlayTime = 0);
+	void inGameTimerPause();
+	void inGameTimerResume();
+	uint32 inGameTimerGet();
+
+	void inGameTimerUpdate();
+
+private:
+	uint32 _lastUsedPlayTimeInCycles; // 20 per second
+	uint32 _lastUsedPlayTimeInSeconds; // actual seconds
+	uint32 _passedPlayTimeCycles; // increased by 1 every time we passed a cycle
+
 private:
 	AgiCommand _agiCommands[183];
 	AgiCommand _agiCondCommands[256];
 
 	void setupOpcodes();
-
-public:
-	int _timerHack;			// Workaround for timer loop in MH1 logic 153
 };
 
 } // End of namespace Agi
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index 85a465c..6506ee2 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -173,37 +173,6 @@ void AgiEngine::interpretCycle() {
 	//_gfx->doUpdate();
 }
 
-/**
- * Update AGI interpreter timer.
- */
-void AgiEngine::updateTimer() {
-	_clockCount++;
-	if (_clockCount <= TICK_SECONDS)
-		return;
-
-	_clockCount -= TICK_SECONDS;
-
-	if (!_game.clockEnabled)
-		return;
-
-	setVar(VM_VAR_SECONDS, getVar(VM_VAR_SECONDS) + 1);
-	if (getVar(VM_VAR_SECONDS) < 60)
-		return;
-
-	setVar(VM_VAR_SECONDS, 0);
-	setVar(VM_VAR_MINUTES, getVar(VM_VAR_MINUTES) + 1);
-	if (getVar(VM_VAR_MINUTES) < 60)
-		return;
-
-	setVar(VM_VAR_MINUTES, 0);
-	setVar(VM_VAR_HOURS, getVar(VM_VAR_HOURS) + 1);
-	if (getVar(VM_VAR_HOURS) < 24)
-		return;
-
-	setVar(VM_VAR_HOURS, 0);
-	setVar(VM_VAR_DAYS, getVar(VM_VAR_DAYS) + 1);
-}
-
 void AgiEngine::newInputMode(InputMode mode) {
 	//if (mode == INPUTMODE_MENU && !getflag(VM_FLAG_MENUS_WORK) && !(getFeatures() & GF_MENUS))
 	//	return;
@@ -224,7 +193,6 @@ int AgiEngine::mainCycle(bool onlyCheckForEvents) {
 
 	if (!onlyCheckForEvents) {
 		pollTimer();
-		updateTimer();
 	}
 
 	if (_menu->delayedExecuteActive()) {
@@ -402,7 +370,11 @@ int AgiEngine::playGame() {
 		if (!mainCycle())
 			continue;
 
-		if (getVar(VM_VAR_TIME_DELAY) == 0 || (1 + _clockCount) % getVar(VM_VAR_TIME_DELAY) == 0) {
+		inGameTimerUpdate();
+
+		if (_passedPlayTimeCycles >= getVar(VM_VAR_TIME_DELAY)) {
+			_passedPlayTimeCycles = 0;
+
 			if (!_game.hasPrompt && _game.inputMode == INPUTMODE_NORMAL) {
 				_text->promptRedraw();
 				_game.hasPrompt = 1;
@@ -468,6 +440,10 @@ int AgiEngine::runGame() {
 		if (_restartGame) {
 			setFlag(VM_FLAG_RESTART_GAME, true);
 			setVar(VM_VAR_TIME_DELAY, 2);	// "normal" speed
+
+			// Reset in-game timer
+			inGameTimerReset();
+
 			_restartGame = false;
 		}
 
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index 9f3fb45..3cc8ffc 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -58,9 +58,89 @@ void AgiEngine::setVar(int16 varNr, byte newValue) {
 }
 
 byte AgiEngine::getVar(int16 varNr) {
+	switch (varNr) {
+	case VM_VAR_SECONDS:
+	case VM_VAR_MINUTES:
+	case VM_VAR_HOURS:
+	case VM_VAR_DAYS:
+		// Timer Update is necessary in here, because of at least Manhunter 1 script 153
+		// Sierra AGI updated the timer via a timer procedure
+		inGameTimerUpdate();
+		break;
+	default:
+		break;
+	}
 	return _game.vars[varNr];
 }
 
+// In-Game timer, used for timer VM Variables
+void AgiEngine::inGameTimerReset(uint32 newPlayTime) {
+	_passedPlayTimeCycles = 0;
+	_lastUsedPlayTimeInCycles = newPlayTime / 50;
+	_lastUsedPlayTimeInSeconds = newPlayTime / 1000;
+	setTotalPlayTime(newPlayTime);
+}
+void AgiEngine::inGameTimerPause() {
+	pauseEngine(true);
+}
+void AgiEngine::inGameTimerResume() {
+	pauseEngine(false);
+}
+uint32 AgiEngine::inGameTimerGet() {
+	return getTotalPlayTime();
+}
+
+// This is called, when one of the timer variables is read
+// We calculate the latest variables, according to current official playtime
+// This is also called in the main loop, because the game needs to be sync'd to 20 cycles per second
+void AgiEngine::inGameTimerUpdate() {
+	uint32 curPlayTimeMilliseconds = inGameTimerGet();
+	uint32 curPlayTimeCycles = curPlayTimeMilliseconds / 50;
+
+	if (curPlayTimeCycles == _lastUsedPlayTimeInCycles) {
+		// No difference, skip updating
+		return;
+	}
+
+	// Increase passed cycles accordingly
+	int32 playTimeCycleDelta = curPlayTimeCycles - _lastUsedPlayTimeInCycles;
+	if (playTimeCycleDelta > 0) {
+		_passedPlayTimeCycles += playTimeCycleDelta;
+	}
+	_lastUsedPlayTimeInCycles = curPlayTimeCycles;
+
+	// Now calculate current play time in seconds
+	uint32 curPlayTimeSeconds = curPlayTimeMilliseconds / 1000;
+
+	if (curPlayTimeSeconds == _lastUsedPlayTimeInSeconds) {
+		// No difference, skip updating
+		return;
+	}
+
+	uint32 secondsLeft = 0;
+	byte   curDays = 0;
+	byte   curHours = 0;
+	byte   curMinutes = 0;
+	byte   curSeconds = 0;
+
+	curDays = curPlayTimeSeconds / 86400;
+	secondsLeft = curPlayTimeSeconds % 86400;
+
+	curHours = secondsLeft / 3600;
+	secondsLeft = secondsLeft % 3600;
+
+	curMinutes = secondsLeft / 60;
+	curSeconds = secondsLeft % 60;
+
+	// directly set them, otherwise we would go into an endless loop
+	_game.vars[VM_VAR_SECONDS] = curSeconds;
+	_game.vars[VM_VAR_MINUTES] = curMinutes;
+	_game.vars[VM_VAR_HOURS] = curHours;
+	_game.vars[VM_VAR_DAYS] = curDays;
+
+	_lastUsedPlayTimeInSeconds = curPlayTimeSeconds;
+}
+
 void AgiEngine::decrypt(uint8 *mem, int len) {
 	const uint8 *key;
 	int i;
diff --git a/engines/agi/graphics.cpp b/engines/agi/graphics.cpp
index b19e729..f140771 100644
--- a/engines/agi/graphics.cpp
+++ b/engines/agi/graphics.cpp
@@ -156,16 +156,6 @@ int GfxMgr::deinitVideo() {
 	return errOK;
 }
 
-int GfxMgr::initMachine() {
-	_vm->_clockCount = 0;
-
-	return errOK;
-}
-
-int GfxMgr::deinitMachine() {
-	return errOK;
-}
-
 void GfxMgr::setRenderStartOffset(uint16 offsetY) {
 	if (offsetY >= (DISPLAY_HEIGHT - SCRIPT_HEIGHT))
 		error("invalid render start offset");
diff --git a/engines/agi/graphics.h b/engines/agi/graphics.h
index 7fffe32..f321e9e 100644
--- a/engines/agi/graphics.h
+++ b/engines/agi/graphics.h
@@ -76,9 +76,6 @@ public:
 	void initMouseCursor(MouseCursorData *mouseCursor, const byte *bitmapData, uint16 width, uint16 height, int hotspotX, int hotspotY);
 	void setMouseCursor(bool busy = false);
 
-	int initMachine();
-	int deinitMachine();
-
 	void setRenderStartOffset(uint16 offsetY);
 	uint16 getRenderStartOffsetY();
 
diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp
index 81de225..2a5f801 100644
--- a/engines/agi/keyboard.cpp
+++ b/engines/agi/keyboard.cpp
@@ -547,7 +547,6 @@ int AgiEngine::waitKey() {
 			break;
 
 		pollTimer();
-		updateTimer();
 
 		g_system->updateScreen();
 	}
diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp
index 411cd00..ea24bd5 100644
--- a/engines/agi/menu.cpp
+++ b/engines/agi/menu.cpp
@@ -292,11 +292,17 @@ void GfxMenu::execute() {
 	}
 	drawActiveMenu();
 
+	// original AGI did not do this, at least when the menu was called by scripts
+	_vm->inGameTimerPause();
+
 	_vm->cycleInnerLoopActive(CYCLE_INNERLOOP_MENU);
 	do {
 		_vm->mainCycle();
 	} while (_vm->cycleInnerLoopIsActive() && !(_vm->shouldQuit() || _vm->_restartGame));
 
+	// original AGI did not do this, at least when the menu was called by scripts
+	_vm->inGameTimerResume();
+
 	removeActiveMenu();
 
 	_text->charAttrib_Pop();
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 57a6d68..4b82d24 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -811,25 +811,41 @@ void cmdResetScanStart(AgiGame *state, uint8 *parameter) {
 }
 
 void cmdSaveGame(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
+
+	vm->inGameTimerPause();
+
 	if (state->automaticSave) {
-		if (state->_vm->saveGameAutomatic()) {
+		if (vm->saveGameAutomatic()) {
 			// automatic save succeded
+			vm->inGameTimerResume();
 			return;
 		}
 		// fall back to regular dialog otherwise
 	}
-	state->_vm->saveGameDialog();
+
+	vm->saveGameDialog();
+
+	vm->inGameTimerResume();
 }
 
 void cmdLoadGame(AgiGame *state, uint8 *parameter) {
+	AgiEngine *vm = state->_vm;
+
+	vm->inGameTimerPause();
+
 	if (state->automaticSave) {
-		if (state->_vm->loadGameAutomatic()) {
+		if (vm->loadGameAutomatic()) {
 			// automatic restore succeded
+			vm->inGameTimerResume();
 			return;
 		}
 		// fall back to regular dialog otherwise
 	}
-	state->_vm->loadGameDialog();
+
+	vm->loadGameDialog();
+
+	vm->inGameTimerResume();
 }
 
 void cmdInitDisk(AgiGame *state, uint8 *parameter) {				// do nothing
@@ -1740,11 +1756,8 @@ void cmdSetGameID(AgiGame *state, uint8 *parameter) {
 
 void cmdPause(AgiGame *state, uint8 *parameter) {
 	AgiEngine *vm = state->_vm;
-	int originalClockState = state->clockEnabled;
 	bool skipPause = false;
 
-	state->clockEnabled = false;
-
 	// We check in here, if a special key was specified to trigger menus.
 	// If that's the case, normally triggering the menu should be handled inside handleController()
 	// For the rare cases, where this approach doesn't work because the trigger is not mapped to a controller,
@@ -1773,10 +1786,16 @@ void cmdPause(AgiGame *state, uint8 *parameter) {
 
 	if (!skipPause) {
 		// Show pause message box
+		int originalClockState = state->clockEnabled;
+
+		vm->inGameTimerPause();
+		state->clockEnabled = false;
+
 		state->_vm->_systemUI->pauseDialog();
-	}
 
-	state->clockEnabled = originalClockState;
+		vm->inGameTimerPause();
+		state->clockEnabled = originalClockState;
+	}
 }
 
 void cmdSetMenu(AgiGame *state, uint8 *parameter) {
@@ -2370,7 +2389,6 @@ int AgiEngine::runLogic(int n) {
 
 	_game._curLogic->cIP = _game._curLogic->sIP;
 
-	_timerHack = 0;
 	while (state->_curLogic->cIP < _game.logics[n].size && !(shouldQuit() || _restartGame)) {
 		// TODO: old code, needs to be adjusted
 #if 0
@@ -2405,14 +2423,6 @@ int AgiEngine::runLogic(int n) {
 		case 0xfe:	// goto
 			// +2 covers goto size
 			state->_curLogic->cIP += 2 + ((int16)READ_LE_UINT16(state->_curLogic->data + state->_curLogic->cIP));
-
-			// timer must keep running even in goto loops,
-			// but AGI engine can't do that :(
-			if (_timerHack > 20) {
-				pollTimer();
-				updateTimer();
-				_timerHack = 0;
-			}
 			break;
 		case 0x00:	// return
 			debugC(2, kDebugLevelScripts, "%sreturn() // Logic %d", st, n);
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index c461dfc..5836e9a 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -42,38 +42,26 @@ namespace Agi {
 #define testObjInRoom(obj, v)	(state->_vm->objectGetLocation(obj) == getVar(v))
 
 void condEqual(AgiGame *state, uint8 *p) {
-	if (p[0] == VM_VAR_SECONDS)
-		state->_vm->_timerHack++;
 	state->testResult = testEqual(p[0], p[1]);
 }
 
 void condEqualV(AgiGame *state, uint8 *p) {
-	if (p[0] == VM_VAR_SECONDS || p[1] == VM_VAR_SECONDS)
-		state->_vm->_timerHack++;
 	state->testResult = testEqual(p[0], getVar(p[1]));
 }
 
 void condLess(AgiGame *state, uint8 *p) {
-	if (p[0] == VM_VAR_SECONDS)
-		state->_vm->_timerHack++;
 	state->testResult = testLess(p[0], p[1]);
 }
 
 void condLessV(AgiGame *state, uint8 *p) {
-	if (p[0] == VM_VAR_SECONDS || p[1] == VM_VAR_SECONDS)
-		state->_vm->_timerHack++;
 	state->testResult = testLess(p[0], getVar(p[1]));
 }
 
 void condGreater(AgiGame *state, uint8 *p) {
-	if (p[0] == VM_VAR_SECONDS)
-		state->_vm->_timerHack++;
 	state->testResult = testGreater(p[0], p[1]);
 }
 
 void condGreaterV(AgiGame *state, uint8 *p) {
-	if (p[0] == VM_VAR_SECONDS || p[1] == VM_VAR_SECONDS)
-		state->_vm->_timerHack++;
 	state->testResult = testGreater(p[0], getVar(p[1]));
 }
 
diff --git a/engines/agi/preagi.cpp b/engines/agi/preagi.cpp
index 833b2d3..088d23a 100644
--- a/engines/agi/preagi.cpp
+++ b/engines/agi/preagi.cpp
@@ -62,7 +62,6 @@ void PreAgiEngine::initialize() {
 	_picture = new PictureMgr(this, _gfx);
 
 	_font->init();
-	_gfx->initMachine();
 
 	_game.gameFlags = 0;
 
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index b6974ee..b47a0cf 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -331,6 +331,7 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
 	uint8 t;
 	int16 parm[7];
 	Common::InSaveFile *in;
+	bool totalPlayTimeWasSet = false;
 
 	debugC(3, kDebugLevelMain | kDebugLevelSavegame, "AgiEngine::loadGame(%s)", fileName.c_str());
 
@@ -380,7 +381,8 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
 		in->readUint16BE(); // save time
 		if (saveVersion >= 6) {
 			uint32 playTime = in->readUint32BE();
-			g_engine->setTotalPlayTime(playTime * 1000);
+			inGameTimerReset(playTime * 1000);
+			totalPlayTimeWasSet = true;
 		}
 	}
 
@@ -439,6 +441,19 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
 	for (i = 0; i < MAX_VARS; i++)
 		_game.vars[i] = in->readByte();
 
+	if (!totalPlayTimeWasSet) {
+		// If we haven't gotten total play time by now, try to calculate it by using VM Variables
+		// This will happen for at least saves before version 6
+		// Direct access because otherwise we would trigger an update to these variables according to ScummVM total play time
+		byte playTimeSeconds = _game.vars[VM_VAR_SECONDS];
+		byte playTimeMinutes = _game.vars[VM_VAR_MINUTES];
+		byte playTimeHours   = _game.vars[VM_VAR_HOURS];
+		byte playTimeDays    = _game.vars[VM_VAR_DAYS];
+		uint32 playTime = (playTimeSeconds + (playTimeMinutes * 60) + (playTimeHours * 3600) + (playTimeDays * 86400)) * 1000;
+
+		inGameTimerReset(playTime);
+	}
+
 	setVar(VM_VAR_FREE_PAGES, 180); // Set amount of free memory to realistic value (Overwriting the just loaded value)
 
 	_game.horizon = in->readSint16BE();


Commit: a9b25b53d7a7084941553166abd20a602e83e184
    https://github.com/scummvm/scummvm/commit/a9b25b53d7a7084941553166abd20a602e83e184
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T22:14:35+01:00

Commit Message:
AGI: properly implement volume control + sync

Original code did assume that AGI volume level is 0-15
(0 for silence, 15 for maximum volume). It actually is the
other way. 0 is maximum, 15 is silence.
Fixed that. Also implemented sync with ScummVM settings dialog.
In case "mute" is enabled by the user, any volume changes done by
scripts are ignored.
Fixes Manhunter 1 Apple IIgs not getting sound anymore since the
VM Var cleanup (the script volume change by the scripts didn't
reach us before)

Changed paths:
    engines/agi/agi.cpp
    engines/agi/agi.h
    engines/agi/global.cpp
    engines/agi/saveload.cpp



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index c8490d4..9c66c38 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -184,6 +184,12 @@ int AgiEngine::agiInit() {
 
 	_game.mouseFence.setWidth(0); // Reset
 
+	// Reset in-game timer
+	inGameTimerReset();
+
+	// Sync volume settings from ScummVM system settings
+	setVolumeViaSystemSetting();
+
 	return ec;
 }
 
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 7e1505f..f1aec3e 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -824,6 +824,10 @@ public:
 	byte getVar(int16 varNr);
 	void setVar(int16 varNr, byte newValue);
 
+private:
+	void setVolumeViaScripts(byte newVolume);
+	void setVolumeViaSystemSetting();
+
 public:
 	void decrypt(uint8 *mem, int len);
 	void releaseSprites();
diff --git a/engines/agi/global.cpp b/engines/agi/global.cpp
index 3cc8ffc..e117259 100644
--- a/engines/agi/global.cpp
+++ b/engines/agi/global.cpp
@@ -20,6 +20,8 @@
  *
  */
 
+#include "common/config-manager.h"
+
 #include "agi/agi.h"
 
 namespace Agi {
@@ -52,8 +54,7 @@ void AgiEngine::setVar(int16 varNr, byte newValue) {
 	_game.vars[varNr] = newValue;
 
 	if (varNr == VM_VAR_VOLUME) {
-		_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, newValue * 17);
-		_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, newValue * 17);
+		setVolumeViaScripts(newValue);
 	}
 }
 
@@ -73,6 +74,67 @@ byte AgiEngine::getVar(int16 varNr) {
 	return _game.vars[varNr];
 }
 
+// sets volume based on script value
+// 0 - maximum volume
+// 15 - mute
+void AgiEngine::setVolumeViaScripts(byte newVolume) {
+	newVolume = CLIP<byte>(newVolume, 0, 15);
+	newVolume = 15 - newVolume; // turn volume around
+
+	int scummVMVolume = newVolume * Audio::Mixer::kMaxMixerVolume / 15;
+	bool scummVMMute = false;
+
+	// Set ScummVM setting
+	// We do not set "mute". In case "mute" is set, we will not apply the scripts wishes
+	ConfMan.setInt("music_volume", scummVMVolume);
+	ConfMan.setInt("sfx_volume", scummVMVolume);
+
+	if (ConfMan.hasKey("mute"))
+		scummVMMute = ConfMan.getBool("mute");
+
+	if (!scummVMMute) {
+		// Also change volume directly
+		_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, scummVMVolume);
+		_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, scummVMVolume);
+	}
+}
+
+void AgiEngine::setVolumeViaSystemSetting() {
+	int scummVMVolumeMusic = ConfMan.getInt("music_volume");
+	int scummVMVolumeSfx = ConfMan.getInt("sfx_volume");
+	bool scummVMMute = false;
+	int internalVolume = 0;
+
+	if (ConfMan.hasKey("mute"))
+		scummVMMute = ConfMan.getBool("mute");
+
+	// Clip user system setting
+	scummVMVolumeMusic = CLIP<int>(scummVMVolumeMusic, 0, Audio::Mixer::kMaxMixerVolume);
+	scummVMVolumeSfx = CLIP<int>(scummVMVolumeSfx, 0, Audio::Mixer::kMaxMixerVolume);
+
+	if (scummVMMute) {
+		scummVMVolumeMusic = 0;
+		scummVMVolumeSfx = 0;
+	}
+
+	// Now actually set it
+	_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, scummVMVolumeMusic);
+	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, scummVMVolumeSfx);
+
+	// Take lowest volume to the scripts
+	if (scummVMVolumeMusic < scummVMVolumeSfx) {
+		internalVolume = scummVMVolumeMusic;
+	} else {
+		internalVolume = scummVMVolumeSfx;
+	}
+	// Change it to 0-15 range
+	internalVolume = (internalVolume + 1) * 15 / Audio::Mixer::kMaxMixerVolume;
+	// Reverse it
+	internalVolume = 15 - internalVolume;
+	// Put it into the VM variable. Directly set it, otherwise it would call a volume set call
+	_game.vars[VM_VAR_VOLUME] = internalVolume;
+}
+
 // In-Game timer, used for timer VM Variables
 void AgiEngine::inGameTimerReset(uint32 newPlayTime) {
 	_passedPlayTimeCycles = 0;
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index b47a0cf..6b1b549 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -703,6 +703,9 @@ int AgiEngine::loadGame(const Common::String &fileName, bool checkId) {
 	// copy everything over (we should probably only copy over the remaining parts of the screen w/o play screen
 	_gfx->copyDisplayRectToScreen(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
 
+	// Sync volume settings from ScummVM system settings, so that VM volume variable is overwritten
+	setVolumeViaSystemSetting();
+
 	return errOK;
 }
 


Commit: f2fb921f8419a323147b526bee9cc9a7425935e3
    https://github.com/scummvm/scummvm/commit/f2fb921f8419a323147b526bee9cc9a7425935e3
Author: Martin Kiewitz (m_kiewitz at users.sourceforge.net)
Date: 2016-01-31T22:25:35+01:00

Commit Message:
AGI: vol system setting gets sent to scripts

Volume changes in ScummVM system menu now gets sent to scripts
as well.

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



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 9c66c38..34a81b5 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -564,6 +564,12 @@ Common::Error AgiEngine::go() {
 	return Common::kNoError;
 }
 
+void AgiEngine::syncSoundSettings() {
+	Engine::syncSoundSettings();
+
+	setVolumeViaSystemSetting();
+}
+
 // Scenes that need this:
 //
 // Manhunter 1:
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index f1aec3e..02b2c53 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -829,6 +829,9 @@ private:
 	void setVolumeViaSystemSetting();
 
 public:
+	void syncSoundSettings();
+
+public:
 	void decrypt(uint8 *mem, int len);
 	void releaseSprites();
 	int mainCycle(bool onlyCheckForEvents = false);


Commit: 1ef27b3e5b0b2ef955af87c8ac6ff0458299e7bc
    https://github.com/scummvm/scummvm/commit/1ef27b3e5b0b2ef955af87c8ac6ff0458299e7bc
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-01-31T22:36:20+01:00

Commit Message:
Merge pull request #654 from m-kiewitz/master

AGI: graphics rewrite + cleanup

Changed paths:
  A engines/agi/font.cpp
  A engines/agi/inv.h
  A engines/agi/mouse_cursor.h
  A engines/agi/palette.h
  A engines/agi/systemui.cpp
  A engines/agi/systemui.h
  A engines/agi/text.h
  A engines/agi/words.h
    engines/agi/agi.cpp
    engines/agi/agi.h
    engines/agi/checks.cpp
    engines/agi/console.cpp
    engines/agi/console.h
    engines/agi/cycle.cpp
    engines/agi/detection.cpp
    engines/agi/font.h
    engines/agi/global.cpp
    engines/agi/graphics.cpp
    engines/agi/graphics.h
    engines/agi/inv.cpp
    engines/agi/keyboard.cpp
    engines/agi/keyboard.h
    engines/agi/loader_v1.cpp
    engines/agi/loader_v2.cpp
    engines/agi/loader_v3.cpp
    engines/agi/logic.cpp
    engines/agi/menu.cpp
    engines/agi/menu.h
    engines/agi/module.mk
    engines/agi/motion.cpp
    engines/agi/objects.cpp
    engines/agi/op_cmd.cpp
    engines/agi/op_dbg.cpp
    engines/agi/op_test.cpp
    engines/agi/opcodes.cpp
    engines/agi/picture.cpp
    engines/agi/picture.h
    engines/agi/preagi.cpp
    engines/agi/preagi_mickey.cpp
    engines/agi/preagi_troll.cpp
    engines/agi/preagi_winnie.cpp
    engines/agi/preagi_winnie.h
    engines/agi/saveload.cpp
    engines/agi/sound.cpp
    engines/agi/sound_pcjr.cpp
    engines/agi/sound_sarien.cpp
    engines/agi/sprite.cpp
    engines/agi/sprite.h
    engines/agi/text.cpp
    engines/agi/view.cpp
    engines/agi/view.h
    engines/agi/words.cpp









More information about the Scummvm-git-logs mailing list