[Scummvm-git-logs] scummvm master -> d48275970aa78866349f20f44bacdc0aff83e57b

dreammaster dreammaster at scummvm.org
Mon Mar 5 04:44:20 CET 2018


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

Summary:
50630efde6 XEEN: Fix loading saves from main menus and launcher
f2b574d647 XEEN: Move all the dialog classes to their own sub-folder
67d4de1bb8 XEEN: Move Credits and Please Wait classes into their own files
b6b9714ec0 XEEN: Fix scroll effect for Clouds of Xeen main menu
badbeda5e2 XEEN: Implemented Dark Side of Xeen menu
66bd71f6f3 XEEN: Finish World of Xeen main menu
59fc48501c XEEN: Fix game credits text in create_xeen
546059408f XEEN: Added Other Options dialog for Dark Side and World
d48275970a XEEN: Regenerate xeen.ccs and remove accidentally committed dark.cc


Commit: 50630efde6d0f42f4d5f371d6818afac64ba86f5
    https://github.com/scummvm/scummvm/commit/50630efde6d0f42f4d5f371d6818afac64ba86f5
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-03-04T22:40:42-05:00

Commit Message:
XEEN: Fix loading saves from main menus and launcher

Changed paths:
    devtools/create_xeen/constants.cpp
    engines/xeen/dialogs.cpp
    engines/xeen/dialogs.h
    engines/xeen/resources.cpp
    engines/xeen/resources.h
    engines/xeen/scripts.cpp
    engines/xeen/worldofxeen/worldofxeen.cpp
    engines/xeen/worldofxeen/worldofxeen_menu.cpp
    engines/xeen/worldofxeen/worldofxeen_menu.h
    engines/xeen/xeen.cpp
    engines/xeen/xeen.h


diff --git a/devtools/create_xeen/constants.cpp b/devtools/create_xeen/constants.cpp
index cf59918..2df74e2 100644
--- a/devtools/create_xeen/constants.cpp
+++ b/devtools/create_xeen/constants.cpp
@@ -60,7 +60,42 @@ enum MagicSpell {
 	NO_SPELL = 76
 };
 
-const char *const CREDITS =
+const char *const CLOUDS_CREDITS = 
+	"\v012\t000\x3""c\f35Designed and Directed By:\n"
+	"\f17Jon Van Caneghem\x3""l\n"
+	"\n"
+	"\t025\f35Programming:\n"
+	"\t035\f17Mark Caldwell\n"
+	"\t035Dave Hathaway\n"
+	"\n"
+	"\t025\f35Sound System & FX:\n"
+	"\t035\f17Todd Hendrix\n"
+	"\n"
+	"\t025\f35Music & Speech:\n"
+	"\t035\f17Tim Tully\n"
+	"\n"
+	"\t025\f35Writing:\n"
+	"\t035\f17Paul Rattner\n"
+	"\t035Debbie Murphy\n"
+	"\t035Jon Van Caneghem\v012\n"
+	"\n"
+	"\n"
+	"\t180\f35Graphics:\n"
+	"\t190\f17Louis Johnson\n"
+	"\t190Jonathan P. Gwyn\n"
+	"\t190Bonita Long-Hemsath\n"
+	"\t190Julia Ulano\n"
+	"\t190Ricardo Barrera\n"
+	"\n"
+	"\t180\f35Testing:\n"
+	"\t190\f17Benjamin Bent\n"
+	"\t190Mario Escamilla\n"
+	"\t190Richard Espy\n"
+	"\t190Scott McDaniel\n"
+	"\t190Clayton Retzer\n"
+	"\t190Michael Suarez\x3""c";
+
+const char *const DARK_SIDE_CREDITS =
 	"\013""012\010""000\003""c\014""35Designed and Directed By:\n"
 	"\014""17Jon Van Caneghem\003""l\n"
 	"\n"
@@ -94,10 +129,47 @@ const char *const CREDITS =
 	"\t190Robert J. Lupo\n"
 	"\t190Clayton Retzer\n"
 	"\t190David Vela\003""c";
-
-const char *const OPTIONS_TITLE =
-	"\x0D\x01\003""c\014""dMight and Magic Options\n"
-	"World of Xeen\x02\n"
+const char *const SWORDS_CREDITS1 =
+	"\v012\x3""c35Published By New World Computing, Inc.\f17\n"
+	"Developed By CATware, Inc.\x3l\n"
+	"\f01Design and Direction\t180Series Created by\n"
+	"\t020Bill Fawcett\t190John Van Caneghem\n"
+	"\n"
+	"\t010Story Contributions\t180Producer & Manual\n"
+	"\t020Ellen Guon\t190Dean Rettig\n"
+	"\n"
+	"\t010Programming & Ideas\t180Original Programming\n"
+	"\t020David Potter\t190Mark Caldwell\n"
+	"\t020Rod Retterath\t190Dave Hathaway\n"
+	"\n"
+	"\t010Manual Illustrations\t180Graphic Artists\n"
+	"\t020Todd Cameron Hamilton\t190Jonathan P. Gwyn\n"
+	"\t020James Clouse\t190Bonnie Long-Hemsath\n"
+	"\t190Julia Ulano\n"
+	"\t190Ricardo Barrera\n";
+const char *const SWORDS_CREDITS2 =
+	"\f05v012\t000\x3l\n"
+	"\t100Sound Programming\n"
+	"\t110Todd Hendrix\n"
+	"\n"
+	"\t100Music\n"
+	"\t110Tim Tully\n"
+	"\t110Quality Assurance Manager\n"
+	"\t110Peter Ryu\n"
+	"\t100Testers\n"
+	"\t110Walter Johnson\n"
+	"\t110Bryan Farina\n"
+	"\t110David Baton\n"
+	"\t110Jack Nalls\n";
+
+const char *const CLOUDS_MAIN_MENU =
+	"\r\x1\x3""c\fdMight and Magic Options\n"
+	"Clouds of Xeen\x2\n"
+	"\v%03dCopyright (c) 1992 NWC, Inc.\n"
+	"All Rights Reserved\x1";
+const char *const WORLD_MAIN_MENU =
+	"\r\x1\x3""c\fdMight and Magic Options\n"
+	"World of Xeen\x2\n"
 	"\v117Copyright (c) 1993 NWC, Inc.\n"
 	"All Rights Reserved\x01";
 
@@ -1771,8 +1843,12 @@ const char *const DIFFICULTY_TEXT = "\v000\t000\x3""cSelect Game Preference";
 
 void writeConstants(CCArchive &cc) {
 	Common::MemFile file;
-	file.syncString(CREDITS);
-	file.syncString(OPTIONS_TITLE);
+	file.syncString(CLOUDS_CREDITS);
+	file.syncString(DARK_SIDE_CREDITS);
+	file.syncString(SWORDS_CREDITS1);
+	file.syncString(SWORDS_CREDITS2);
+	file.syncString(CLOUDS_MAIN_MENU);
+	file.syncString(WORLD_MAIN_MENU);
 	file.syncString(THE_PARTY_NEEDS_REST);
 	file.syncString(WHO_WILL);
 	file.syncString(HOW_MUCH);
diff --git a/engines/xeen/dialogs.cpp b/engines/xeen/dialogs.cpp
index 276d9a7..4ca69ec 100644
--- a/engines/xeen/dialogs.cpp
+++ b/engines/xeen/dialogs.cpp
@@ -191,11 +191,24 @@ void SettingsBaseDialog::showContents(SpriteResource &title1, bool waitFlag) {
 
 void CreditsScreen::show(XeenEngine *vm) {
 	CreditsScreen *dlg = new CreditsScreen(vm);
-	dlg->execute();
+	
+	switch (vm->getGameID()) {
+	case GType_Clouds:
+		dlg->execute(Res.CLOUDS_CREDITS);
+		break;
+	case GType_Swords:
+		dlg->execute(Res.SWORDS_CREDITS1);
+		dlg->execute(Res.SWORDS_CREDITS2);
+		break;
+	default:
+		dlg->execute(Res.DARK_SIDE_CREDITS);
+		break;
+	}
+	
 	delete dlg;
 }
 
-void CreditsScreen::execute() {
+void CreditsScreen::execute(const char *content) {
 	Screen &screen = *_vm->_screen;
 	Windows &windows = *_vm->_windows;
 	EventsManager &events = *_vm->_events;
@@ -205,7 +218,7 @@ void CreditsScreen::execute() {
 	windows[GAME_WINDOW].close();
 
 	screen.loadBackground("marb.raw");
-	windows[0].writeString(Res.CREDITS);
+	windows[0].writeString(content);
 	doScroll(false, false);
 
 	events.setCursor(0);
diff --git a/engines/xeen/dialogs.h b/engines/xeen/dialogs.h
index b4ad772..cabc921 100644
--- a/engines/xeen/dialogs.h
+++ b/engines/xeen/dialogs.h
@@ -117,7 +117,7 @@ class CreditsScreen: public ButtonContainer {
 private:
 	CreditsScreen(XeenEngine *vm) : ButtonContainer(vm) {}
 
-	void execute();
+	void execute(const char *content);
 public:
 	static void show(XeenEngine *vm);
 };
diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp
index 0aa7d8a..6ea4252 100644
--- a/engines/xeen/resources.cpp
+++ b/engines/xeen/resources.cpp
@@ -62,8 +62,12 @@ Resources::Resources() {
 
 void Resources::loadData() {
 	ResFile file(_buffer);
-	file.syncString(CREDITS);
-	file.syncString(OPTIONS_TITLE);
+	file.syncString(CLOUDS_CREDITS);
+	file.syncString(DARK_SIDE_CREDITS);
+	file.syncString(SWORDS_CREDITS1);
+	file.syncString(SWORDS_CREDITS2);
+	file.syncString(CLOUDS_MAIN_MENU);
+	file.syncString(WORLD_MAIN_MENU);
 	file.syncString(THE_PARTY_NEEDS_REST);
 	file.syncString(WHO_WILL);
 	file.syncString(HOW_MUCH);
diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h
index 67ac992..b14b9f5 100644
--- a/engines/xeen/resources.h
+++ b/engines/xeen/resources.h
@@ -116,8 +116,12 @@ public:
 	const char **ITEM_NAMES[4];
 
 	// Data loaded from xeen.ccs
-	const char *CREDITS;
-	const char *OPTIONS_TITLE;
+	const char *CLOUDS_CREDITS;
+	const char *DARK_SIDE_CREDITS;
+	const char *SWORDS_CREDITS1;
+	const char *SWORDS_CREDITS2;
+	const char *CLOUDS_MAIN_MENU;
+	const char *WORLD_MAIN_MENU;
 	const char *THE_PARTY_NEEDS_REST;
 	const char *WHO_WILL;
 	const char *HOW_MUCH;
diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp
index e08fd1b..679e48c 100644
--- a/engines/xeen/scripts.cpp
+++ b/engines/xeen/scripts.cpp
@@ -1084,6 +1084,10 @@ bool Scripts::cmdCutsceneEndClouds(ParamsIterator &params) {
 	party._mazeId = 28;
 	party._mazePosition = Common::Point(18, 4);
 
+	g_vm->_gameWon[0] = true;
+	g_vm->_finalScore[0] = party.getScore();
+	g_vm->saveSettings();
+
 	doCloudsEnding();
 	return false;
 }
@@ -1416,6 +1420,10 @@ bool Scripts::cmdCutsceneEndDarkside(ParamsIterator &params) {
 	party._mazeDirection = DIR_NORTH;
 	party._mazePosition = Common::Point(25, 21);
 
+	g_vm->_gameWon[1] = true;
+	g_vm->_finalScore[1] = party.getScore();
+	g_vm->saveSettings();
+
 	doDarkSideEnding();
 	return false;
 }
diff --git a/engines/xeen/worldofxeen/worldofxeen.cpp b/engines/xeen/worldofxeen/worldofxeen.cpp
index 20fa7be..962bdfe 100644
--- a/engines/xeen/worldofxeen/worldofxeen.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen.cpp
@@ -186,14 +186,7 @@ void WorldOfXeenEngine::showStartup() {
 }
 
 void WorldOfXeenEngine::showMainMenu() {
-	// TODO: Remove this as the game main menus are properly implemented
-	if (getGameID() == GType_Clouds) {
-		_saves->newGame();
-		_gameMode = GMODE_PLAY_GAME;
-		return;
-	}
-
-	WorldOfXeenMenu::show(this);
+	WorldOfXeenMainMenuContainer::show();
 }
 
 } // End of namespace WorldOfXeen
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.cpp b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
index 7f5e7f3..a91a711 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
@@ -29,236 +29,249 @@
 namespace Xeen {
 namespace WorldOfXeen {
 
-void WorldOfXeenMenu::show(XeenEngine *vm) {
-	WorldOfXeenMenu *menu;
+void MainMenuContainer::show() {
+	MainMenuContainer *menu;
 
-	switch (vm->getGameID()) {
+	switch (g_vm->getGameID()) {
 	case GType_Clouds:
-		menu = new CloudsOptionsMenu(vm);
+		menu = new CloudsMainMenuContainer();
 		break;
 	case GType_DarkSide:
-		menu = new DarkSideOptionsMenu(vm);
+		menu = new DarkSideMainMenuContainer();
 		break;
 	case GType_WorldOfXeen:
-		menu = new WorldOptionsMenu(vm);
+		menu = new WorldOfXeenMainMenuContainer();
 		break;
 	default:
-		error("Unsupported game");
-		break;
+		error("Invalid game");
 	}
 
 	menu->execute();
 	delete menu;
 }
 
-void WorldOfXeenMenu::execute() {
-	_vm->_files->setGameCc(1);
-	SpriteResource special("special.icn");
-	Windows &windows = *_vm->_windows;
-	EventsManager &events = *_vm->_events;
-
-	File newBright("newbrigh.m");
-	_vm->_sound->playSong(newBright);
-
-	windows[GAME_WINDOW].setBounds(Common::Rect(72, 25, 248, 175));
+MainMenuContainer::MainMenuContainer(const Common::String &spritesName) : _animateCtr(0), _dialog(nullptr) {
+	_backgroundSprites.load(spritesName);
+}
 
-	Common::String title1, title2;
-	startup(title1, title2);
-	SpriteResource title1Sprites(title1), title2Sprites(title2);
+MainMenuContainer::~MainMenuContainer() {
+	delete _dialog;
+	g_vm->_windows->closeAll();
+	g_vm->_sound->stopAllAudio();
+	g_vm->_events->clearEvents();
+}
 
-	bool firstTime = true, doFade = true;
-	while (!_vm->shouldExit()) {
-		setBackground(doFade);
+void MainMenuContainer::draw() {
+	g_vm->_screen->restoreBackground();
+	_animateCtr = (_animateCtr + 1) % 9;
+	_backgroundSprites.draw(0, _animateCtr);
+}
 
-		if (firstTime) {
-			firstTime = false;
-			events.setCursor(0);
-			events.showCursor();
+void MainMenuContainer::execute() {
+	EventsManager &events = *g_vm->_events;
+	bool showFlag = false;
+
+	// Show the cursor
+	events.clearEvents();
+	events.setCursor(0);
+	events.showCursor();
+
+	while (!g_vm->shouldExit() && g_vm->_gameMode == GMODE_NONE) {
+		// Draw the menu
+		draw();
+		if (_dialog)
+			_dialog->draw();
+
+		// Fade/scroll in screen if first frame
+		if (!showFlag) {
+			loadBackground();
+			// TODO: doScroll(false, false);
+			showFlag = true;
 		}
 
-		showTitles1(title1Sprites);
-		showTitles2();
-
-		clearButtons();
-		setupButtons(&title2Sprites);
-		openWindow();
-
-		while (!_vm->shouldExit()) {
-			// Show the dialog with a continually animating background
-			while (!_vm->shouldExit() && !_buttonValue)
-				showContents(title1Sprites, true);
-			if (_vm->shouldExit())
-				return;
-
-			// Handle keypress
-			int key = toupper(_buttonValue);
-			_buttonValue = 0;
-
-			if (key == Common::KEYCODE_ESCAPE) {
-				// Hide the options menu
-				closeWindow();
-				break;
-			} else if (key == 'C' || key == 'V') {
-				// Show credits
-				closeWindow();
-				CreditsScreen::show(_vm);
-				break;
-			} else if (key == 'S') {
-				// Start new game
-				int result = DifficultyDialog::show(_vm);
-				if (result == -1)
-					break;
-
-				// Load a new game state and set the difficulty
-				_vm->_saves->newGame();
-				_vm->_party->_difficulty = (Difficulty)result;
-				_vm->_gameMode = GMODE_PLAY_GAME;
-				closeWindow();
-				return;
-			} else if (key == 'L') {
-				_vm->_saves->newGame();
-				if (_vm->_saves->loadGame()) {
-					_vm->_gameMode = GMODE_PLAY_GAME;
-					break;
+		// Check for events
+		events.updateGameCounter();
+		
+		if (events.wait(4, true)) {
+			if (_dialog) {
+				// There's a dialog active, so let it handle the event
+				_dialog->handleEvents();
+
+				// If dialog was removed as a result of the event, flag screen for re-showing
+				// if the menu screen isn't being left
+				if (!_dialog)
+					showFlag = false;
+			} else {
+				// No active dialog. If Escape pressed, exit game entirely. Otherwise,
+				// open up the main menu dialog
+				if (events.isKeyPending()) {
+					Common::KeyState key;
+					if (events.getKey(key) && key.keycode == Common::KEYCODE_ESCAPE)
+						g_vm->_gameMode = GMODE_QUIT;
 				}
+
+				events.clearEvents();
+				showMenuDialog();
 			}
 		}
 	}
 }
 
-void WorldOfXeenMenu::showTitles1(SpriteResource &sprites) {
-	Screen &screen = *_vm->_screen;
-	EventsManager &events = *_vm->_events;
-
-	int frameNum = 0;
-	while (!_vm->shouldExit() && !events.isKeyMousePressed()) {
-		events.updateGameCounter();
-
-		frameNum = (frameNum + 1) % (_vm->getGameID() == GType_WorldOfXeen ? 5 : 10);
-		screen.restoreBackground();
-		sprites.draw(0, frameNum);
+/*------------------------------------------------------------------------*/
 
-		events.wait(4);
-	}
+CloudsMainMenuContainer::CloudsMainMenuContainer() : MainMenuContainer("intro.vga") {
+	g_vm->_sound->playSong("inn.m");
 }
 
-void WorldOfXeenMenu::showTitles2() {
-	Screen &screen = *_vm->_screen;
-	EventsManager &events = *_vm->_events;
-	Sound &sound = *_vm->_sound;
-	Windows &windows = *_vm->_windows;
-
-	SpriteResource titleSprites("title2b.raw");
-	SpriteResource kludgeSprites("kludge.int");
-	SpriteResource title2Sprites[8] = {
-		SpriteResource("title2b.int"), SpriteResource("title2c.int"),
-		SpriteResource("title2d.int"), SpriteResource("title2e.int"),
-		SpriteResource("title2f.int"), SpriteResource("title2g.int"),
-		SpriteResource("title2h.int"), SpriteResource("title2i.int"),
-	};
-
-	kludgeSprites.draw(0, 0);
+void CloudsMainMenuContainer::loadBackground() {
+	Screen &screen = *g_vm->_screen;
+	screen.loadPalette("mm4.pal");
+	screen.loadBackground("intro.raw");
 	screen.saveBackground();
-	sound.playSound("elect.voc");
-
-	for (int i = 0; i < 30 && !_vm->shouldExit(); ++i) {
-		events.updateGameCounter();
-		screen.restoreBackground();
-		title2Sprites[i / 4].draw(0, i % 4);
-		windows[0].update();
+}
 
-		if (i == 19)
-			sound.stopSound();
+void CloudsMainMenuContainer::showMenuDialog() {
+	setOwner(new CloudsMenuDialog(this));
+}
 
-		while (!_vm->shouldExit() && events.timeElapsed() < 2)
-			events.pollEventsAndWait();
-	}
+/*------------------------------------------------------------------------*/
 
-	screen.restoreBackground();
-	windows[0].update();
+DarkSideMainMenuContainer::DarkSideMainMenuContainer() : MainMenuContainer("intro.vga") {
+	g_vm->_sound->playSong("inn.m");
 }
 
-void WorldOfXeenMenu::setupButtons(SpriteResource *buttons) {
-	addButton(Common::Rect(124, 87, 124 + 53, 87 + 10), 'S');
-	addButton(Common::Rect(126, 98, 126 + 47, 98 + 10), 'L');
-	addButton(Common::Rect(91, 110, 91 + 118, 110 + 10), 'C');
-	addButton(Common::Rect(85, 121, 85 + 131, 121 + 10), 'O');
+void DarkSideMainMenuContainer::loadBackground() {
+	Screen &screen = *g_vm->_screen;
+	screen.loadPalette("mm4.pal");
+	screen.loadBackground("intro.raw");
+	screen.saveBackground();
 }
 
-void WorldOptionsMenu::setupButtons(SpriteResource *buttons) {
-	addButton(Common::Rect(93, 53, 93 + 134, 53 + 20), 'S', buttons);
-	addButton(Common::Rect(93, 78, 93 + 134, 78 + 20), 'L', buttons);
-	addButton(Common::Rect(93, 103, 93 + 134, 103 + 20), 'C', buttons);
-	addButton(Common::Rect(93, 128, 93 + 134, 128 + 20), 'O', buttons);
+void DarkSideMainMenuContainer::showMenuDialog() {
+	setOwner(new CloudsMenuDialog(this));
 }
 
 /*------------------------------------------------------------------------*/
 
-void CloudsOptionsMenu::startup(Common::String &title1, Common::String &title2) {
-	title1 = "title1.int";
-	title2 = "title1a.int";
+WorldOfXeenMainMenuContainer::WorldOfXeenMainMenuContainer() : MainMenuContainer("intro.vga") {
+	g_vm->_sound->playSong("inn.m");
 }
 
-/*------------------------------------------------------------------------*/
+void WorldOfXeenMainMenuContainer::loadBackground() {
+	Screen &screen = *g_vm->_screen;
+	screen.loadPalette("mm4.pal");
+	screen.loadBackground("intro.raw");
+	screen.saveBackground();
+}
 
-void DarkSideOptionsMenu::startup(Common::String &title1, Common::String &title2) {
-	title1 = "title2.int";
-	title2 = "title2a.int";
+void WorldOfXeenMainMenuContainer::showMenuDialog() {
+	setOwner(new CloudsMenuDialog(this));
 }
 
-void WorldOptionsMenu::startup(Common::String &title1, Common::String &title2) {
-	title1 = "world.int";
-	title2 = "start.icn";
+/*------------------------------------------------------------------------*/
 
-	Screen &screen = *_vm->_screen;
-	screen.fadeOut();
-	screen.loadPalette("dark.pal");
-	_vm->_events->clearEvents();
-}
+bool MainMenuDialog::handleEvents() {
+	checkEvents(g_vm);
+	int difficulty;
+
+	switch (_buttonValue) {
+	case Common::KEYCODE_s:
+		// Start new game
+		difficulty = DifficultyDialog::show(g_vm);
+		if (difficulty == -1)
+			return true;
+
+		// Load a new game state and set the difficulty
+		g_vm->_saves->newGame();
+		g_vm->_party->_difficulty = (Difficulty)difficulty;
+		g_vm->_gameMode = GMODE_PLAY_GAME;
+		break;
 
-void WorldOptionsMenu::setBackground(bool doFade) {
-	Screen &screen = *_vm->_screen;
-	screen.loadBackground("world.raw");
-	screen.saveBackground();
+	case Common::KEYCODE_l:
+		// Load existing game
+		g_vm->_saves->newGame();
+		if (!g_vm->_saves->loadGame())
+			return true;
+
+		g_vm->_gameMode = GMODE_PLAY_GAME;
+		break;
+
+	case Common::KEYCODE_c:
+	case Common::KEYCODE_v:
+		// Show credits
+		CreditsScreen::show(g_vm);
+		break;
+
+	default:
+		return false;
+	}
 
-	if (doFade)
-		screen.fadeIn();
+	// If this point is reached, delete the dialog itself, which will return the main menu
+	// to it's default "No dialog showing" state
+	delete this;
+	return true;
 }
 
-void WorldOptionsMenu::openWindow() {
-	Windows &windows = *_vm->_windows;
-	windows[GAME_WINDOW].open();
+/*------------------------------------------------------------------------*/
+
+CloudsMenuDialog::CloudsMenuDialog(MainMenuContainer *owner) : MainMenuDialog(owner) {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+	w.setBounds(Common::Rect(72, 25, 248, g_vm->_gameWon[0] ? 175 : 150));
+	w.open();
+
+	loadButtons();
 }
 
-void WorldOptionsMenu::closeWindow() {
-	Windows &windows = *_vm->_windows;
-	windows[GAME_WINDOW].close();
+CloudsMenuDialog::~CloudsMenuDialog() {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+	w.close();
 }
 
-void WorldOptionsMenu::showContents(SpriteResource &title1, bool waitFlag) {
-	EventsManager &events = *_vm->_events;
-	Screen &screen = *_vm->_screen;
-	Windows &windows = *_vm->_windows;
-	events.updateGameCounter();
+void CloudsMenuDialog::loadButtons() {
+	_buttonSprites.load("start.icn");
+	addButton(Common::Rect(93, 53, 227, 73), Common::KEYCODE_s, &_buttonSprites);
+	addButton(Common::Rect(93, 78, 227, 98), Common::KEYCODE_l, &_buttonSprites);
+	addButton(Common::Rect(93, 103, 227, 123), Common::KEYCODE_c, &_buttonSprites);
+	if (g_vm->_gameWon[0])
+		addButton(Common::Rect(93, 128, 227, 148), Common::KEYCODE_e, &_buttonSprites);
+}
 
-	// Draw the background frame in a continous cycle
-	_bgFrame = (_bgFrame + 1) % 5;
-	title1.draw(windows[0], _bgFrame);
+void CloudsMenuDialog::draw() {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+	
+	w.frame();
+	w.writeString(Common::String::format(Res.CLOUDS_MAIN_MENU, g_vm->_gameWon[0] ? 117 : 92));
+	drawButtons(&w);
+}
 
-	// Draw the basic frame for the optitons menu and title text
-	windows[GAME_WINDOW].frame();
-	windows[GAME_WINDOW].writeString(Res.OPTIONS_TITLE);
+bool CloudsMenuDialog::handleEvents() {
+	if (MainMenuDialog::handleEvents())
+		return true;
 
-	drawButtons(&windows[0]);
-	screen.update();
+	switch (_buttonValue) {
+	case Common::KEYCODE_e:
+		if (g_vm->_gameWon[0]) {
+			// Close the window
+			delete this;
 
-	if (waitFlag) {
-		while (!_vm->shouldExit() && !_buttonValue && events.timeElapsed() < 3) {
-			events.pollEventsAndWait();
-			checkEvents(_vm);
+			// Show clouds ending
+			WOX_VM.showCloudsEnding(g_vm->_finalScore[0]);
+			return true;
 		}
+		break;
+
+	default:
+		break;
 	}
+
+	return false;
 }
 
+/*------------------------------------------------------------------------*/
+
+
 } // End of namespace WorldOfXeen
 } // End of namespace Xeen
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.h b/engines/xeen/worldofxeen/worldofxeen_menu.h
index 39d309c..3495f08 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.h
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.h
@@ -29,82 +29,181 @@
 namespace Xeen {
 namespace WorldOfXeen {
 
-class WorldOfXeenMenu : public SettingsBaseDialog {
+class MainMenuDialog;
+
+class MainMenuContainer {
 private:
-	void execute();
-protected:
-	WorldOfXeenMenu(XeenEngine *vm) : SettingsBaseDialog(vm) {}
+	int _animateCtr;
+	SpriteResource _backgroundSprites;
+	MainMenuDialog *_dialog;
 protected:
-	virtual void startup(Common::String &title1, Common::String &title2) = 0;
+	/**
+	 * Draws the main menu background
+	 */
+	void draw();
 
-	virtual void setBackground(bool doFade) {}
+	/**
+	 * Load the background
+	 */
+	virtual void loadBackground() = 0;
 
-	virtual void showTitles1(SpriteResource &sprites);
+	/**
+	 * Shows the main menu dialog
+	 */
+	virtual void showMenuDialog() = 0;
+public:
+	/**
+	 * Show the main menu for the correct game
+	 */
+	static void show();
+public:
+	/**
+	 * Constructor
+	 */
+	MainMenuContainer(const Common::String &spritesName);
 
-	virtual void showTitles2();
+	/**
+	 * Destructor
+	 */
+	virtual ~MainMenuContainer();
 
-	virtual void setupButtons(SpriteResource *buttons);
+	/**
+	 * Execute the menu
+	 */
+	void execute();
 
 	/**
-	 * Opens the menu window
+	 * Sets the dialog being displayed in the menu
 	 */
-	virtual void openWindow() {}
+	void setOwner(MainMenuDialog *dlalog) {
+		_dialog = dlalog;
+	}
+};
 
+class CloudsMainMenuContainer : public MainMenuContainer {
+protected:
 	/**
-	 * Closes the menu window
+	 * Load the background
 	 */
-	virtual void closeWindow() {}
-public:
-	virtual ~WorldOfXeenMenu() {}
+	virtual void loadBackground();
 
-	static void show(XeenEngine *vm);
+	/**
+	 * Shows the main menu dialog
+	 */
+	virtual void showMenuDialog();
+public:
+	CloudsMainMenuContainer();
 };
 
-class CloudsOptionsMenu : public WorldOfXeenMenu {
+class DarkSideMainMenuContainer : public MainMenuContainer {
 protected:
-	virtual void startup(Common::String &title1, Common::String &title2);
-public:
-	CloudsOptionsMenu(XeenEngine *vm) : WorldOfXeenMenu(vm) {}
+	/**
+	 * Load the background
+	 */
+	virtual void loadBackground();
 
-	virtual ~CloudsOptionsMenu() {}
+	/**
+	* Shows the main menu dialog
+	*/
+	virtual void showMenuDialog();
+public:
+	DarkSideMainMenuContainer();
 };
 
-class DarkSideOptionsMenu : public WorldOfXeenMenu {
+class WorldOfXeenMainMenuContainer : public MainMenuContainer {
 protected:
-	virtual void startup(Common::String &title1, Common::String &title2);
-public:
-	DarkSideOptionsMenu(XeenEngine *vm) : WorldOfXeenMenu(vm) {}
+	/**
+	 * Load the background
+	 */
+	virtual void loadBackground();
 
-	virtual ~DarkSideOptionsMenu() {}
+	/**
+	* Shows the main menu dialog
+	*/
+	virtual void showMenuDialog();
+public:
+	WorldOfXeenMainMenuContainer();
 };
 
-class WorldOptionsMenu : public DarkSideOptionsMenu {
+class MenuContainerDialog : public ButtonContainer {
 private:
-	int _bgFrame;
-protected:
-	virtual void startup(Common::String &title1, Common::String &title2);
+	MainMenuContainer *_owner;
+public:
+	/**
+	 * Constructor
+	 */
+	MenuContainerDialog(MainMenuContainer *owner) : ButtonContainer(g_vm), _owner(owner) {}
 
-	virtual void setBackground(bool doFade);
+	/**
+	 * Destructor
+	 */
+	virtual ~MenuContainerDialog() {
+		_owner->setOwner(nullptr);
+	}
+
+	/**
+	 * Draws the dialog
+	 */
+	virtual void draw() = 0;
 
-	virtual void showTitles2() {}
+	/**
+	 * Handles events
+	 */
+	virtual bool handleEvents() = 0;
+};
 
-	virtual void setupButtons(SpriteResource *buttons);
+class MainMenuDialog : public MenuContainerDialog {
+public:
+	/**
+	 * Constructor
+	 */
+	MainMenuDialog(MainMenuContainer *owner) : MenuContainerDialog(owner) {}
 
 	/**
-	 * Opens the menu window
+	 * Destructor
 	 */
-	virtual void openWindow();
+	virtual ~MainMenuDialog() {}
 
 	/**
-	 * Closes the menu window
+	 * Draws the dialog
 	 */
-	virtual void closeWindow();
+	virtual void draw() = 0;
 
-	virtual void showContents(SpriteResource &title1, bool mode);
+	/**
+	 * Handles events
+	 */
+	virtual bool handleEvents();
+
+};
+
+class CloudsMenuDialog : public MainMenuDialog {
+private:
+	SpriteResource _buttonSprites;
+private:
+	/**
+	 * Loads buttons for the dialog
+	 */
+	void loadButtons();
 public:
-	WorldOptionsMenu(XeenEngine *vm) : DarkSideOptionsMenu(vm), _bgFrame(0) {}
+	/**
+	 * Constructor
+	 */
+	CloudsMenuDialog(MainMenuContainer *owner);
 
-	virtual ~WorldOptionsMenu() {}
+	/**
+	 * Destructor
+	 */
+	virtual ~CloudsMenuDialog();
+
+	/**
+	 * Draws the dialog
+	 */
+	virtual void draw();
+
+	/**
+	 * Handles events
+	 */
+	virtual bool handleEvents();
 };
 
 } // End of namespace WorldOfXeen
diff --git a/engines/xeen/xeen.cpp b/engines/xeen/xeen.cpp
index 21db8b2..6122f4d 100644
--- a/engines/xeen/xeen.cpp
+++ b/engines/xeen/xeen.cpp
@@ -62,6 +62,8 @@ XeenEngine::XeenEngine(OSystem *syst, const XeenGameDescription *gameDesc)
 	_mode = MODE_0;
 	_endingScore = 0;
 	_loadSaveSlot = -1;
+	_gameWon[0] = _gameWon[1] = false;
+	_finalScore[0] = _finalScore[1] = 0;
 	g_vm = this;
 }
 
@@ -111,6 +113,12 @@ bool XeenEngine::initialize() {
 	// Setup mixer
 	syncSoundSettings();
 
+	// Load settings
+	_gameWon[0] = ConfMan.hasKey("game_won") && ConfMan.getBool("game_won");
+	_gameWon[1] = ConfMan.hasKey("game_won2") && ConfMan.getBool("game_won2");
+	_finalScore[0] = ConfMan.hasKey("final_score") ? ConfMan.getInt("final_score") : 0;
+	_finalScore[1] = ConfMan.hasKey("final_score2") ? ConfMan.getInt("final_score2") : 0;
+
 	// If requested, load a savegame instead of showing the intro
 	if (ConfMan.hasKey("save_slot")) {
 		int saveSlot = ConfMan.getInt("save_slot");
@@ -294,4 +302,15 @@ void XeenEngine::GUIError(const char *msg, ...) {
 	GUIErrorMessage(buffer);
 }
 
+void XeenEngine::saveSettings() {
+	if (_gameWon[0])
+		ConfMan.setBool("game_won", true);
+	if (_gameWon[1])
+		ConfMan.setBool("game_won2", true);
+
+	ConfMan.setInt("final_score", _finalScore[0]);
+	ConfMan.setInt("final_score2", _finalScore[1]);
+	ConfMan.flushToDisk();
+}
+
 } // End of namespace Xeen
diff --git a/engines/xeen/xeen.h b/engines/xeen/xeen.h
index 5031f1f..98ba00b 100644
--- a/engines/xeen/xeen.h
+++ b/engines/xeen/xeen.h
@@ -183,6 +183,8 @@ public:
 	bool _noDirectionSense;
 	bool _startupWindowActive;
 	uint _endingScore;
+	bool _gameWon[2];
+	uint _finalScore[2];
 public:
 	XeenEngine(OSystem *syst, const XeenGameDescription *gameDesc);
 	virtual ~XeenEngine();
@@ -251,6 +253,11 @@ public:
 	static Common::String printK(uint value);
 
 	static Common::String printK2(uint value);
+
+	/**
+	 * Saves engine settings
+	 */
+	void saveSettings();
 };
 
 extern XeenEngine *g_vm;


Commit: f2b574d64762d23a83cc682da0e622be99080688
    https://github.com/scummvm/scummvm/commit/f2b574d64762d23a83cc682da0e622be99080688
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-03-04T22:40:42-05:00

Commit Message:
XEEN: Move all the dialog classes to their own sub-folder

Changed paths:
  A engines/xeen/dialogs/dialogs.cpp
  A engines/xeen/dialogs/dialogs.h
  A engines/xeen/dialogs/dialogs_awards.cpp
  A engines/xeen/dialogs/dialogs_awards.h
  A engines/xeen/dialogs/dialogs_char_info.cpp
  A engines/xeen/dialogs/dialogs_char_info.h
  A engines/xeen/dialogs/dialogs_control_panel.cpp
  A engines/xeen/dialogs/dialogs_control_panel.h
  A engines/xeen/dialogs/dialogs_create_char.cpp
  A engines/xeen/dialogs/dialogs_create_char.h
  A engines/xeen/dialogs/dialogs_difficulty.cpp
  A engines/xeen/dialogs/dialogs_difficulty.h
  A engines/xeen/dialogs/dialogs_dismiss.cpp
  A engines/xeen/dialogs/dialogs_dismiss.h
  A engines/xeen/dialogs/dialogs_exchange.cpp
  A engines/xeen/dialogs/dialogs_exchange.h
  A engines/xeen/dialogs/dialogs_info.cpp
  A engines/xeen/dialogs/dialogs_info.h
  A engines/xeen/dialogs/dialogs_input.cpp
  A engines/xeen/dialogs/dialogs_input.h
  A engines/xeen/dialogs/dialogs_items.cpp
  A engines/xeen/dialogs/dialogs_items.h
  A engines/xeen/dialogs/dialogs_map.cpp
  A engines/xeen/dialogs/dialogs_map.h
  A engines/xeen/dialogs/dialogs_message.cpp
  A engines/xeen/dialogs/dialogs_message.h
  A engines/xeen/dialogs/dialogs_party.cpp
  A engines/xeen/dialogs/dialogs_party.h
  A engines/xeen/dialogs/dialogs_query.cpp
  A engines/xeen/dialogs/dialogs_query.h
  A engines/xeen/dialogs/dialogs_quests.cpp
  A engines/xeen/dialogs/dialogs_quests.h
  A engines/xeen/dialogs/dialogs_quick_fight.cpp
  A engines/xeen/dialogs/dialogs_quick_fight.h
  A engines/xeen/dialogs/dialogs_quick_ref.cpp
  A engines/xeen/dialogs/dialogs_quick_ref.h
  A engines/xeen/dialogs/dialogs_spells.cpp
  A engines/xeen/dialogs/dialogs_spells.h
  A engines/xeen/dialogs/dialogs_whowill.cpp
  A engines/xeen/dialogs/dialogs_whowill.h
  R engines/xeen/dialogs.cpp
  R engines/xeen/dialogs.h
  R engines/xeen/dialogs_awards.cpp
  R engines/xeen/dialogs_awards.h
  R engines/xeen/dialogs_char_info.cpp
  R engines/xeen/dialogs_char_info.h
  R engines/xeen/dialogs_control_panel.cpp
  R engines/xeen/dialogs_control_panel.h
  R engines/xeen/dialogs_create_char.cpp
  R engines/xeen/dialogs_create_char.h
  R engines/xeen/dialogs_difficulty.cpp
  R engines/xeen/dialogs_difficulty.h
  R engines/xeen/dialogs_dismiss.cpp
  R engines/xeen/dialogs_dismiss.h
  R engines/xeen/dialogs_exchange.cpp
  R engines/xeen/dialogs_exchange.h
  R engines/xeen/dialogs_info.cpp
  R engines/xeen/dialogs_info.h
  R engines/xeen/dialogs_input.cpp
  R engines/xeen/dialogs_input.h
  R engines/xeen/dialogs_items.cpp
  R engines/xeen/dialogs_items.h
  R engines/xeen/dialogs_map.cpp
  R engines/xeen/dialogs_map.h
  R engines/xeen/dialogs_message.cpp
  R engines/xeen/dialogs_message.h
  R engines/xeen/dialogs_party.cpp
  R engines/xeen/dialogs_party.h
  R engines/xeen/dialogs_query.cpp
  R engines/xeen/dialogs_query.h
  R engines/xeen/dialogs_quests.cpp
  R engines/xeen/dialogs_quests.h
  R engines/xeen/dialogs_quick_fight.cpp
  R engines/xeen/dialogs_quick_fight.h
  R engines/xeen/dialogs_quick_ref.cpp
  R engines/xeen/dialogs_quick_ref.h
  R engines/xeen/dialogs_spells.cpp
  R engines/xeen/dialogs_spells.h
  R engines/xeen/dialogs_whowill.cpp
  R engines/xeen/dialogs_whowill.h
    engines/xeen/character.cpp
    engines/xeen/interface.cpp
    engines/xeen/interface.h
    engines/xeen/interface_scene.cpp
    engines/xeen/locations.cpp
    engines/xeen/locations.h
    engines/xeen/module.mk
    engines/xeen/party.cpp
    engines/xeen/party.h
    engines/xeen/scripts.cpp
    engines/xeen/spells.cpp
    engines/xeen/swordsofxeen/swordsofxeen_menu.cpp
    engines/xeen/swordsofxeen/swordsofxeen_menu.h
    engines/xeen/worldofxeen/worldofxeen_menu.cpp
    engines/xeen/worldofxeen/worldofxeen_menu.h
    engines/xeen/xeen.h


diff --git a/engines/xeen/character.cpp b/engines/xeen/character.cpp
index 69fbc16..c6ebde8 100644
--- a/engines/xeen/character.cpp
+++ b/engines/xeen/character.cpp
@@ -21,8 +21,8 @@
  */
 
 #include "xeen/character.h"
-#include "xeen/dialogs_query.h"
-#include "xeen/dialogs_message.h"
+#include "xeen/dialogs/dialogs_query.h"
+#include "xeen/dialogs/dialogs_message.h"
 #include "xeen/resources.h"
 #include "xeen/xeen.h"
 
diff --git a/engines/xeen/dialogs.cpp b/engines/xeen/dialogs.cpp
deleted file mode 100644
index 4ca69ec..0000000
--- a/engines/xeen/dialogs.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "common/scummsys.h"
-#include "xeen/dialogs.h"
-#include "xeen/events.h"
-#include "xeen/resources.h"
-#include "xeen/screen.h"
-#include "xeen/xeen.h"
-
-namespace Xeen {
-
-void ButtonContainer::saveButtons() {
-	_savedButtons.push(_buttons);
-	clearButtons();
-}
-
-/*
- * Clears the current list of defined buttons
- */
-void ButtonContainer::clearButtons() {
-	_buttons.clear();
-}
-
-void ButtonContainer::restoreButtons() {
-	_buttons = _savedButtons.pop();
-}
-
-void ButtonContainer::addButton(const Common::Rect &bounds, int val,
-		SpriteResource *sprites) {
-	_buttons.push_back(UIButton(bounds, val, _buttons.size() * 2, sprites, sprites != nullptr));
-}
-
-void ButtonContainer::addButton(const Common::Rect &bounds, int val,
-		int frameNum, SpriteResource *sprites) {
-	_buttons.push_back(UIButton(bounds, val, frameNum, sprites, sprites != nullptr));
-}
-
-void ButtonContainer::addPartyButtons(XeenEngine *vm) {
-	for (uint idx = 0; idx < MAX_ACTIVE_PARTY; ++idx) {
-		addButton(Common::Rect(Res.CHAR_FACES_X[idx], 150, Res.CHAR_FACES_X[idx] + 32, 182),
-			Common::KEYCODE_F1 + idx);
-	}
-}
-
-bool ButtonContainer::checkEvents(XeenEngine *vm) {
-	EventsManager &events = *vm->_events;
-	Party &party = *vm->_party;
-	Windows &windows = *_vm->_windows;
-	_buttonValue = 0;
-
-	if (events._leftButton) {
-		Common::Point pt = events._mousePos;
-
-		// Check for party member glyphs being clicked
-		Common::Rect r(0, 0, 32, 32);
-		for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
-			r.moveTo(Res.CHAR_FACES_X[idx], 150);
-			if (r.contains(pt)) {
-				_buttonValue = Common::KEYCODE_F1 + idx;
-				break;
-			}
-		}
-
-		// Check whether any button is selected
-		for (uint i = 0; i < _buttons.size(); ++i) {
-			if (_buttons[i]._bounds.contains(pt)) {
-				events.debounceMouse();
-
-				_buttonValue = _buttons[i]._value;
-				break;
-			}
-		}
-
-		if (!_buttonValue && Common::Rect(8, 8, 224, 135).contains(pt)) {
-			_buttonValue = 1;
-			return true;
-		}
-	} else if (events.isKeyPending()) {
-		Common::KeyState keyState;
-		events.getKey(keyState);
-
-		_buttonValue = keyState.keycode;
-		if (_buttonValue == Common::KEYCODE_KP8)
-			_buttonValue = Common::KEYCODE_UP;
-		else if (_buttonValue == Common::KEYCODE_KP2)
-			_buttonValue = Common::KEYCODE_DOWN;
-		else if (_buttonValue == Common::KEYCODE_KP_ENTER)
-			_buttonValue = Common::KEYCODE_RETURN;
-
-		_buttonValue |= (keyState.flags & ~Common::KBD_STICKY) << 16;
-	}
-
-	if (_buttonValue) {
-		// Check for a button matching the selected _buttonValue
-		Window &win = windows[39];
-		for (uint btnIndex = 0; btnIndex < _buttons.size(); ++btnIndex) {
-			UIButton &btn = _buttons[btnIndex];
-			if (btn._draw && btn._value == _buttonValue) {
-				// Found the correct button
-				// Draw button depressed
-				btn._sprites->draw(0, btn._frameNum + 1,
-					Common::Point(btn._bounds.left, btn._bounds.top));
-				win.setBounds(btn._bounds);
-				win.update();
-
-				// Slight delay
-				events.updateGameCounter();
-				events.wait(2);
-
-				// Redraw button in it's original non-depressed form
-				btn._sprites->draw(0, btn._frameNum,
-					Common::Point(btn._bounds.left, btn._bounds.top));
-				win.setBounds(btn._bounds);
-				win.update();
-				break;
-			}
-		}
-
-		return true;
-	}
-
-	return false;
-}
-
-void ButtonContainer::drawButtons(XSurface *surface) {
-	for (uint btnIndex = 0; btnIndex < _buttons.size(); ++btnIndex) {
-		UIButton &btn = _buttons[btnIndex];
-		if (btn._draw) {
-			btn._sprites->draw(*surface, btn._frameNum,
-				Common::Point(btn._bounds.left, btn._bounds.top));
-		}
-	}
-}
-
-bool ButtonContainer::doScroll(bool rollUp, bool fadeIn) {
-	if (_vm->_files->_isDarkCc) {
-		return Cutscenes::doScroll(rollUp, fadeIn);
-	} else {
-		saveButtons();
-		clearButtons();
-		bool result = Cutscenes::doScroll(rollUp, fadeIn);
-		restoreButtons();
-		return result;
-	}
-}
-
-void ButtonContainer::loadStrings(const Common::String &name) {
-	File f(name);
-	_textStrings.clear();
-	while (f.pos() < f.size())
-		_textStrings.push_back(f.readString());
-	f.close();
-}
-
-void ButtonContainer::loadStrings(const Common::String &name, int ccMode) {
-	File f(name, ccMode);
-	_textStrings.clear();
-	while (f.pos() < f.size())
-		_textStrings.push_back(f.readString());
-	f.close();
-}
-
-/*------------------------------------------------------------------------*/
-
-void SettingsBaseDialog::showContents(SpriteResource &title1, bool waitFlag) {
-	_vm->_events->pollEventsAndWait();
-	checkEvents(_vm);
-}
-
-/*------------------------------------------------------------------------*/
-
-void CreditsScreen::show(XeenEngine *vm) {
-	CreditsScreen *dlg = new CreditsScreen(vm);
-	
-	switch (vm->getGameID()) {
-	case GType_Clouds:
-		dlg->execute(Res.CLOUDS_CREDITS);
-		break;
-	case GType_Swords:
-		dlg->execute(Res.SWORDS_CREDITS1);
-		dlg->execute(Res.SWORDS_CREDITS2);
-		break;
-	default:
-		dlg->execute(Res.DARK_SIDE_CREDITS);
-		break;
-	}
-	
-	delete dlg;
-}
-
-void CreditsScreen::execute(const char *content) {
-	Screen &screen = *_vm->_screen;
-	Windows &windows = *_vm->_windows;
-	EventsManager &events = *_vm->_events;
-
-	// Handle drawing the credits screen
-	doScroll(true, false);
-	windows[GAME_WINDOW].close();
-
-	screen.loadBackground("marb.raw");
-	windows[0].writeString(content);
-	doScroll(false, false);
-
-	events.setCursor(0);
-	windows[0].update();
-	clearButtons();
-
-	// Wait for keypress
-	while (!events.isKeyMousePressed())
-		events.pollEventsAndWait();
-
-	doScroll(true, false);
-}
-
-/*------------------------------------------------------------------------*/
-
-PleaseWait::PleaseWait(bool isOops) {
-	_msg = isOops ? Res.OOPS : Res.PLEASE_WAIT;
-}
-
-PleaseWait::~PleaseWait() {
-	Windows &windows = *g_vm->_windows;
-	windows[9].close();
-}
-
-void PleaseWait::show() {
-	Windows &windows = *g_vm->_windows;
-	Window &w = windows[9];
-
-	if (g_vm->_mode != MODE_0) {
-		w.open();
-		w.writeString(_msg);
-		w.update();
-	}
-}
-
-} // End of namespace Xeen
diff --git a/engines/xeen/dialogs.h b/engines/xeen/dialogs.h
deleted file mode 100644
index cabc921..0000000
--- a/engines/xeen/dialogs.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef XEEN_DIALOGS_H
-#define XEEN_DIALOGS_H
-
-#include "common/array.h"
-#include "common/stack.h"
-#include "common/rect.h"
-#include "xeen/cutscenes.h"
-#include "xeen/sprites.h"
-#include "xeen/xsurface.h"
-
-namespace Xeen {
-
-class XeenEngine;
-
-class UIButton {
-public:
-	Common::Rect _bounds;
-	SpriteResource *_sprites;
-	int _value;
-	uint _frameNum;
-	bool _draw;
-
-	UIButton(const Common::Rect &bounds, int value, uint frameNum, SpriteResource *sprites, bool draw) :
-		_bounds(bounds), _value(value), _frameNum(frameNum),
-		_sprites(sprites), _draw(draw) {}
-
-	UIButton() : _value(0), _frameNum(0), _sprites(nullptr), _draw(false) {}
-};
-
-class ButtonContainer : public Cutscenes {
-private:
-	Common::Stack< Common::Array<UIButton> > _savedButtons;
-protected:
-	Common::Array<UIButton> _buttons;
-	Common::StringArray _textStrings;
-	int _buttonValue;
-
-	bool checkEvents(XeenEngine *vm);
-
-	/**
-	 * Draws the scroll in the background
-	 * @param rollUp	If true, rolls up the scroll. If false, unrolls.
-	 * @param fadeIn	If true, does an initial fade in
-	 * @returns		True if key or mouse pressed
-	 */
-	virtual bool doScroll(bool rollUp, bool fadeIn);
-
-	/**
-	 * Load a set of text strings from the given resource
-	 * @param name		Name of resource containing strings
-	 */
-	void loadStrings(const Common::String &name);
-
-	/**
-	 * Load a set of text strings from the given resource
-	 * @param name		Name of resource containing strings
-	 * @param ccMode	Optional cc file number to explicitly use
-	 */
-	void loadStrings(const Common::String &name, int ccMode);
-public:
-	ButtonContainer(XeenEngine *vm) : Cutscenes(vm), _buttonValue(0) {}
-
-	/**
-	 * Saves the current list of buttons
-	 */
-	void saveButtons();
-
-	void clearButtons();
-
-	void restoreButtons();
-
-	void addButton(const Common::Rect &bounds, int val,
-		SpriteResource *sprites = nullptr);
-	void addButton(const Common::Rect &bounds, int val,
-		int frameNum, SpriteResource *sprites = nullptr);
-
-	void addPartyButtons(XeenEngine *vm);
-
-	/**
-	 * Draws the buttons onto the passed surface
-	 */
-	void drawButtons(XSurface *surface);
-};
-
-class SettingsBaseDialog : public ButtonContainer {
-protected:
-	virtual void showContents(SpriteResource &title1, bool mode);
-public:
-	SettingsBaseDialog(XeenEngine *vm) : ButtonContainer(vm) {}
-
-	virtual ~SettingsBaseDialog() {}
-};
-
-class CreditsScreen: public ButtonContainer {
-private:
-	CreditsScreen(XeenEngine *vm) : ButtonContainer(vm) {}
-
-	void execute(const char *content);
-public:
-	static void show(XeenEngine *vm);
-};
-
-class PleaseWait {
-private:
-	Common::String _msg;
-public:
-	PleaseWait(bool isOops = false);
-	~PleaseWait();
-
-	void show();
-};
-
-} // End of namespace Xeen
-
-#endif /* XEEN_DIALOGS_H */
diff --git a/engines/xeen/dialogs/dialogs.cpp b/engines/xeen/dialogs/dialogs.cpp
new file mode 100644
index 0000000..c9b5658
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs.cpp
@@ -0,0 +1,257 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/events.h"
+#include "xeen/resources.h"
+#include "xeen/screen.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void ButtonContainer::saveButtons() {
+	_savedButtons.push(_buttons);
+	clearButtons();
+}
+
+/*
+ * Clears the current list of defined buttons
+ */
+void ButtonContainer::clearButtons() {
+	_buttons.clear();
+}
+
+void ButtonContainer::restoreButtons() {
+	_buttons = _savedButtons.pop();
+}
+
+void ButtonContainer::addButton(const Common::Rect &bounds, int val,
+		SpriteResource *sprites) {
+	_buttons.push_back(UIButton(bounds, val, _buttons.size() * 2, sprites, sprites != nullptr));
+}
+
+void ButtonContainer::addButton(const Common::Rect &bounds, int val,
+		int frameNum, SpriteResource *sprites) {
+	_buttons.push_back(UIButton(bounds, val, frameNum, sprites, sprites != nullptr));
+}
+
+void ButtonContainer::addPartyButtons(XeenEngine *vm) {
+	for (uint idx = 0; idx < MAX_ACTIVE_PARTY; ++idx) {
+		addButton(Common::Rect(Res.CHAR_FACES_X[idx], 150, Res.CHAR_FACES_X[idx] + 32, 182),
+			Common::KEYCODE_F1 + idx);
+	}
+}
+
+bool ButtonContainer::checkEvents(XeenEngine *vm) {
+	EventsManager &events = *vm->_events;
+	Party &party = *vm->_party;
+	Windows &windows = *_vm->_windows;
+	_buttonValue = 0;
+
+	if (events._leftButton) {
+		Common::Point pt = events._mousePos;
+
+		// Check for party member glyphs being clicked
+		Common::Rect r(0, 0, 32, 32);
+		for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
+			r.moveTo(Res.CHAR_FACES_X[idx], 150);
+			if (r.contains(pt)) {
+				_buttonValue = Common::KEYCODE_F1 + idx;
+				break;
+			}
+		}
+
+		// Check whether any button is selected
+		for (uint i = 0; i < _buttons.size(); ++i) {
+			if (_buttons[i]._bounds.contains(pt)) {
+				events.debounceMouse();
+
+				_buttonValue = _buttons[i]._value;
+				break;
+			}
+		}
+
+		if (!_buttonValue && Common::Rect(8, 8, 224, 135).contains(pt)) {
+			_buttonValue = 1;
+			return true;
+		}
+	} else if (events.isKeyPending()) {
+		Common::KeyState keyState;
+		events.getKey(keyState);
+
+		_buttonValue = keyState.keycode;
+		if (_buttonValue == Common::KEYCODE_KP8)
+			_buttonValue = Common::KEYCODE_UP;
+		else if (_buttonValue == Common::KEYCODE_KP2)
+			_buttonValue = Common::KEYCODE_DOWN;
+		else if (_buttonValue == Common::KEYCODE_KP_ENTER)
+			_buttonValue = Common::KEYCODE_RETURN;
+
+		_buttonValue |= (keyState.flags & ~Common::KBD_STICKY) << 16;
+	}
+
+	if (_buttonValue) {
+		// Check for a button matching the selected _buttonValue
+		Window &win = windows[39];
+		for (uint btnIndex = 0; btnIndex < _buttons.size(); ++btnIndex) {
+			UIButton &btn = _buttons[btnIndex];
+			if (btn._draw && btn._value == _buttonValue) {
+				// Found the correct button
+				// Draw button depressed
+				btn._sprites->draw(0, btn._frameNum + 1,
+					Common::Point(btn._bounds.left, btn._bounds.top));
+				win.setBounds(btn._bounds);
+				win.update();
+
+				// Slight delay
+				events.updateGameCounter();
+				events.wait(2);
+
+				// Redraw button in it's original non-depressed form
+				btn._sprites->draw(0, btn._frameNum,
+					Common::Point(btn._bounds.left, btn._bounds.top));
+				win.setBounds(btn._bounds);
+				win.update();
+				break;
+			}
+		}
+
+		return true;
+	}
+
+	return false;
+}
+
+void ButtonContainer::drawButtons(XSurface *surface) {
+	for (uint btnIndex = 0; btnIndex < _buttons.size(); ++btnIndex) {
+		UIButton &btn = _buttons[btnIndex];
+		if (btn._draw) {
+			btn._sprites->draw(*surface, btn._frameNum,
+				Common::Point(btn._bounds.left, btn._bounds.top));
+		}
+	}
+}
+
+bool ButtonContainer::doScroll(bool rollUp, bool fadeIn) {
+	if (_vm->_files->_isDarkCc) {
+		return Cutscenes::doScroll(rollUp, fadeIn);
+	} else {
+		saveButtons();
+		clearButtons();
+		bool result = Cutscenes::doScroll(rollUp, fadeIn);
+		restoreButtons();
+		return result;
+	}
+}
+
+void ButtonContainer::loadStrings(const Common::String &name) {
+	File f(name);
+	_textStrings.clear();
+	while (f.pos() < f.size())
+		_textStrings.push_back(f.readString());
+	f.close();
+}
+
+void ButtonContainer::loadStrings(const Common::String &name, int ccMode) {
+	File f(name, ccMode);
+	_textStrings.clear();
+	while (f.pos() < f.size())
+		_textStrings.push_back(f.readString());
+	f.close();
+}
+
+/*------------------------------------------------------------------------*/
+
+void SettingsBaseDialog::showContents(SpriteResource &title1, bool waitFlag) {
+	_vm->_events->pollEventsAndWait();
+	checkEvents(_vm);
+}
+
+/*------------------------------------------------------------------------*/
+
+void CreditsScreen::show(XeenEngine *vm) {
+	CreditsScreen *dlg = new CreditsScreen(vm);
+	
+	switch (vm->getGameID()) {
+	case GType_Clouds:
+		dlg->execute(Res.CLOUDS_CREDITS);
+		break;
+	case GType_Swords:
+		dlg->execute(Res.SWORDS_CREDITS1);
+		dlg->execute(Res.SWORDS_CREDITS2);
+		break;
+	default:
+		dlg->execute(Res.DARK_SIDE_CREDITS);
+		break;
+	}
+	
+	delete dlg;
+}
+
+void CreditsScreen::execute(const char *content) {
+	Screen &screen = *_vm->_screen;
+	Windows &windows = *_vm->_windows;
+	EventsManager &events = *_vm->_events;
+
+	// Handle drawing the credits screen
+	doScroll(true, false);
+	windows[GAME_WINDOW].close();
+
+	screen.loadBackground("marb.raw");
+	windows[0].writeString(content);
+	doScroll(false, false);
+
+	events.setCursor(0);
+	windows[0].update();
+	clearButtons();
+
+	// Wait for keypress
+	while (!events.isKeyMousePressed())
+		events.pollEventsAndWait();
+
+	doScroll(true, false);
+}
+
+/*------------------------------------------------------------------------*/
+
+PleaseWait::PleaseWait(bool isOops) {
+	_msg = isOops ? Res.OOPS : Res.PLEASE_WAIT;
+}
+
+PleaseWait::~PleaseWait() {
+	Windows &windows = *g_vm->_windows;
+	windows[9].close();
+}
+
+void PleaseWait::show() {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[9];
+
+	if (g_vm->_mode != MODE_0) {
+		w.open();
+		w.writeString(_msg);
+		w.update();
+	}
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs.h b/engines/xeen/dialogs/dialogs.h
new file mode 100644
index 0000000..cabc921
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs.h
@@ -0,0 +1,137 @@
+/* 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 XEEN_DIALOGS_H
+#define XEEN_DIALOGS_H
+
+#include "common/array.h"
+#include "common/stack.h"
+#include "common/rect.h"
+#include "xeen/cutscenes.h"
+#include "xeen/sprites.h"
+#include "xeen/xsurface.h"
+
+namespace Xeen {
+
+class XeenEngine;
+
+class UIButton {
+public:
+	Common::Rect _bounds;
+	SpriteResource *_sprites;
+	int _value;
+	uint _frameNum;
+	bool _draw;
+
+	UIButton(const Common::Rect &bounds, int value, uint frameNum, SpriteResource *sprites, bool draw) :
+		_bounds(bounds), _value(value), _frameNum(frameNum),
+		_sprites(sprites), _draw(draw) {}
+
+	UIButton() : _value(0), _frameNum(0), _sprites(nullptr), _draw(false) {}
+};
+
+class ButtonContainer : public Cutscenes {
+private:
+	Common::Stack< Common::Array<UIButton> > _savedButtons;
+protected:
+	Common::Array<UIButton> _buttons;
+	Common::StringArray _textStrings;
+	int _buttonValue;
+
+	bool checkEvents(XeenEngine *vm);
+
+	/**
+	 * Draws the scroll in the background
+	 * @param rollUp	If true, rolls up the scroll. If false, unrolls.
+	 * @param fadeIn	If true, does an initial fade in
+	 * @returns		True if key or mouse pressed
+	 */
+	virtual bool doScroll(bool rollUp, bool fadeIn);
+
+	/**
+	 * Load a set of text strings from the given resource
+	 * @param name		Name of resource containing strings
+	 */
+	void loadStrings(const Common::String &name);
+
+	/**
+	 * Load a set of text strings from the given resource
+	 * @param name		Name of resource containing strings
+	 * @param ccMode	Optional cc file number to explicitly use
+	 */
+	void loadStrings(const Common::String &name, int ccMode);
+public:
+	ButtonContainer(XeenEngine *vm) : Cutscenes(vm), _buttonValue(0) {}
+
+	/**
+	 * Saves the current list of buttons
+	 */
+	void saveButtons();
+
+	void clearButtons();
+
+	void restoreButtons();
+
+	void addButton(const Common::Rect &bounds, int val,
+		SpriteResource *sprites = nullptr);
+	void addButton(const Common::Rect &bounds, int val,
+		int frameNum, SpriteResource *sprites = nullptr);
+
+	void addPartyButtons(XeenEngine *vm);
+
+	/**
+	 * Draws the buttons onto the passed surface
+	 */
+	void drawButtons(XSurface *surface);
+};
+
+class SettingsBaseDialog : public ButtonContainer {
+protected:
+	virtual void showContents(SpriteResource &title1, bool mode);
+public:
+	SettingsBaseDialog(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	virtual ~SettingsBaseDialog() {}
+};
+
+class CreditsScreen: public ButtonContainer {
+private:
+	CreditsScreen(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute(const char *content);
+public:
+	static void show(XeenEngine *vm);
+};
+
+class PleaseWait {
+private:
+	Common::String _msg;
+public:
+	PleaseWait(bool isOops = false);
+	~PleaseWait();
+
+	void show();
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_H */
diff --git a/engines/xeen/dialogs/dialogs_awards.cpp b/engines/xeen/dialogs/dialogs_awards.cpp
new file mode 100644
index 0000000..8e8bfcf
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_awards.cpp
@@ -0,0 +1,131 @@
+/* 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 "xeen/dialogs/dialogs_awards.h"
+#include "xeen/party.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void Awards::show(XeenEngine *vm, const Character *ch) {
+	Awards *dlg = new Awards(vm);
+	dlg->execute(ch);
+	delete dlg;
+}
+
+void Awards::execute(const Character *ch) {
+	EventsManager &events = *g_vm->_events;
+	Windows &windows = *g_vm->_windows;
+	Common::StringArray awards;
+	int numAwards;
+	Mode oldMode = g_vm->_mode;
+	int topIndex = 0;
+
+	loadStrings("award.bin", 1);
+	addButtons();
+
+	// Open the window and draw contents
+	bool win29Open = windows[29]._enabled;
+	if (!win29Open) {
+		windows[29].open();
+		windows[30].open();
+	}
+
+	windows[29].writeString(Res.AWARDS_TEXT);
+	drawButtons(&windows[0]);
+
+	while (!_vm->shouldExit()) {
+		// Build up a list of awards the character has
+		awards.clear();
+		awards.resize(AWARDS_TOTAL);
+		numAwards = 0;
+
+		for (int awardNum = 0; awardNum < AWARDS_TOTAL; ++awardNum) {
+			if (ch->hasAward(awardNum)) {
+				if (awardNum == 9) {
+					// # Warzone Wins
+					awards[numAwards] = Common::String::format(_textStrings[9].c_str(), 28);
+				} else if (awardNum == 17) {
+					// Legendary Race
+					awards[numAwards] = Common::String::format(_textStrings[17].c_str(),
+						Res.RACE_NAMES[ch->_race]);
+				} else {
+					awards[numAwards] = _textStrings[awardNum];
+				}
+				++numAwards;
+			}
+		}
+
+		// If no awards, add in a message indicating so
+		if (numAwards == 0) {
+			awards[1] = Res.NO_AWARDS;
+		}
+
+		Common::String msg = Common::String::format(Res.AWARDS_FOR,
+			ch->_name.c_str(), Res.CLASS_NAMES[ch->_class],
+			awards[topIndex].c_str(),
+			awards[topIndex + 1].c_str(),
+			awards[topIndex + 2].c_str(),
+			awards[topIndex + 3].c_str(),
+			awards[topIndex + 4].c_str(),
+			awards[topIndex + 5].c_str(),
+			awards[topIndex + 6].c_str(),
+			awards[topIndex + 7].c_str(),
+			awards[topIndex + 8].c_str()
+		);
+		windows[30].writeString(msg);
+		windows[24].update();
+
+		// Wait for keypress
+		do {
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+		} while (!g_vm->shouldExit() && !_buttonValue);
+
+		if (_buttonValue == Common::KEYCODE_ESCAPE) {
+			break;
+		} else if (_buttonValue == Common::KEYCODE_u) {
+			topIndex = MAX(topIndex - 1, 0);
+		} else if (_buttonValue == Common::KEYCODE_d) {
+			if ((++topIndex + 9) > numAwards)
+				--topIndex;
+		}
+	}
+
+	// Close the window
+	if (win29Open) {
+		windows[30].close();
+		windows[29].close();
+	}
+
+	g_vm->_mode = oldMode;
+}
+
+void Awards::addButtons() {
+	_iconSprites.load("award.icn");
+	addButton(Common::Rect(216, 109, 240, 129), Common::KEYCODE_u, &_iconSprites);
+	addButton(Common::Rect(250, 109, 274, 129), Common::KEYCODE_d, &_iconSprites);
+	addButton(Common::Rect(284, 109, 308, 129), Common::KEYCODE_ESCAPE, &_iconSprites);
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_awards.h b/engines/xeen/dialogs/dialogs_awards.h
new file mode 100644
index 0000000..2ca6817
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_awards.h
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_AWARDS_H
+#define XEEN_DIALOGS_AWARDS_H
+
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/character.h"
+
+namespace Xeen {
+
+class Awards : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+private:
+	Awards(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	/**
+	 * Executes the dialog
+	 */
+	void execute(const Character *ch);
+
+	/**
+	 * Add buttons for the dialog
+	 */
+	void addButtons();
+public:
+	static void show(XeenEngine *vm, const Character *ch);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_AWARDS_H */
diff --git a/engines/xeen/dialogs/dialogs_char_info.cpp b/engines/xeen/dialogs/dialogs_char_info.cpp
new file mode 100644
index 0000000..0ae64ed
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_char_info.cpp
@@ -0,0 +1,571 @@
+/* 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 "xeen/dialogs/dialogs_awards.h"
+#include "xeen/dialogs/dialogs_char_info.h"
+#include "xeen/dialogs/dialogs_exchange.h"
+#include "xeen/dialogs/dialogs_items.h"
+#include "xeen/dialogs/dialogs_quick_ref.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void CharacterInfo::show(XeenEngine *vm, int charIndex) {
+	CharacterInfo *dlg = new CharacterInfo(vm);
+	dlg->execute(charIndex);
+	delete dlg;
+}
+
+void CharacterInfo::execute(int charIndex) {
+	Combat &combat = *_vm->_combat;
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+
+	bool redrawFlag = true;
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = MODE_CHARACTER_INFO;
+	loadDrawStructs();
+	addButtons();
+
+	Character *c = (oldMode != MODE_COMBAT) ? &party._activeParty[charIndex] : combat._combatParty[charIndex];
+	intf.highlightChar(charIndex);
+	Window &w = windows[24];
+	w.open();
+
+	do {
+		if (redrawFlag) {
+			Common::String charDetails = loadCharacterDetails(*c);
+			w.writeString(Common::String::format(Res.CHARACTER_TEMPLATE, charDetails.c_str()));
+			w.drawList(_drawList, 24);
+			w.update();
+			redrawFlag = false;
+		}
+
+		// Wait for keypress, showing a blinking cursor
+		events.updateGameCounter();
+		bool cursorFlag = false;
+		_buttonValue = 0;
+		while (!_vm->shouldExit() && !_buttonValue) {
+			events.pollEventsAndWait();
+			if (events.timeElapsed() > 4) {
+				cursorFlag = !cursorFlag;
+				events.updateGameCounter();
+			}
+
+			showCursor(cursorFlag);
+			w.update();
+			checkEvents(_vm);
+		}
+		events.clearEvents();
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_F1:
+		case Common::KEYCODE_F2:
+		case Common::KEYCODE_F3:
+		case Common::KEYCODE_F4:
+		case Common::KEYCODE_F5:
+		case Common::KEYCODE_F6:
+			_buttonValue -= Common::KEYCODE_F1;
+			if (_buttonValue < (int)(oldMode == MODE_COMBAT ? combat._combatParty.size() : party._activeParty.size())) {
+				charIndex = _buttonValue;
+				c = (oldMode != MODE_COMBAT) ? &party._activeParty[charIndex] : combat._combatParty[charIndex];
+			} else {
+				_vm->_mode = MODE_CHARACTER_INFO;
+			}
+
+			intf.highlightChar(_buttonValue);
+			redrawFlag = true;
+			break;
+
+		case Common::KEYCODE_UP:
+		case Common::KEYCODE_KP8:
+			if (_cursorCell > 0) {
+				showCursor(false);
+				--_cursorCell;
+				showCursor(true);
+			}
+			w.update();
+			break;
+
+		case Common::KEYCODE_DOWN:
+		case Common::KEYCODE_KP2:
+			if (_cursorCell < 20) {
+				showCursor(false);
+				++_cursorCell;
+				showCursor(true);
+			}
+			w.update();
+			break;
+
+		case Common::KEYCODE_LEFT:
+		case Common::KEYCODE_KP4:
+			if (_cursorCell >= 5) {
+				showCursor(false);
+				_cursorCell -= 5;
+				showCursor(true);
+			}
+			w.update();
+			break;
+
+		case Common::KEYCODE_RIGHT:
+		case Common::KEYCODE_KP6:
+			if (_cursorCell <= 15) {
+				showCursor(false);
+				_cursorCell += 5;
+				showCursor(true);
+			}
+			w.update();
+			break;
+
+		case Common::KEYCODE_RETURN:
+		case Common::KEYCODE_KP_ENTER:
+			_buttonValue = _cursorCell + Common::KEYCODE_a;
+			// Deliberate fall-through
+
+		case 1001:
+		case 1002:
+		case 1003:
+		case 1004:
+		case 1005:
+		case 1006:
+		case 1007:
+		case 1008:
+		case 1009:
+		case 1010:
+		case 1011:
+		case 1012:
+		case 1013:
+		case 1014:
+		case 1015:
+		case 1016:
+		case 1017:
+		case 1018:
+		case 1019:
+		case 1020: {
+			showCursor(false);
+			_cursorCell = _buttonValue - 1001;
+			showCursor(true);
+			w.update();
+
+			bool result = expandStat(_cursorCell, *c);
+			_vm->_mode = MODE_COMBAT;
+			if (result)
+				redrawFlag = true;
+			break;
+		}
+
+		case Common::KEYCODE_e:
+			if (oldMode == MODE_COMBAT) {
+				ErrorScroll::show(_vm, Res.EXCHANGING_IN_COMBAT, WT_FREEZE_WAIT);
+			} else {
+				_vm->_mode = oldMode;
+				ExchangeDialog::show(_vm, c, charIndex);
+				_vm->_mode = MODE_CHARACTER_INFO;
+				redrawFlag = true;
+			}
+			break;
+
+		case Common::KEYCODE_i:
+			_vm->_mode = oldMode;
+			_vm->_combat->_itemFlag = _vm->_mode == MODE_COMBAT;
+			c = ItemsDialog::show(_vm, c, ITEMMODE_CHAR_INFO);
+
+			if (!c) {
+				party._stepped = true;
+				goto exit;
+			}
+
+			_vm->_mode = MODE_CHARACTER_INFO;
+			break;
+
+		case Common::KEYCODE_q:
+			QuickReferenceDialog::show(_vm);
+			redrawFlag = true;
+			break;
+
+		case Common::KEYCODE_ESCAPE:
+			goto exit;
+		}
+	} while (!_vm->shouldExit());
+exit:
+	w.close();
+	intf.unhighlightChar();
+	_vm->_mode = oldMode;
+	_vm->_combat->_itemFlag = false;
+}
+
+void CharacterInfo::loadDrawStructs() {
+	_drawList[0] = DrawStruct(0, 2, 16);
+	_drawList[1] = DrawStruct(2, 2, 39);
+	_drawList[2] = DrawStruct(4, 2, 62);
+	_drawList[3] = DrawStruct(6, 2, 85);
+	_drawList[4] = DrawStruct(8, 2, 108);
+	_drawList[5] = DrawStruct(10, 53, 16);
+	_drawList[6] = DrawStruct(12, 53, 39);
+	_drawList[7] = DrawStruct(14, 53, 62);
+	_drawList[8] = DrawStruct(16, 53, 85);
+	_drawList[9] = DrawStruct(18, 53, 108);
+	_drawList[10] = DrawStruct(20, 104, 16);
+	_drawList[11] = DrawStruct(22, 104, 39);
+	_drawList[12] = DrawStruct(24, 104, 62);
+	_drawList[13] = DrawStruct(26, 104, 85);
+	_drawList[14] = DrawStruct(28, 104, 108);
+	_drawList[15] = DrawStruct(30, 169, 16);
+	_drawList[16] = DrawStruct(32, 169, 39);
+	_drawList[17] = DrawStruct(34, 169, 62);
+	_drawList[18] = DrawStruct(36, 169, 85);
+	_drawList[19] = DrawStruct(38, 169, 108);
+	_drawList[20] = DrawStruct(40, 277, 3);
+	_drawList[21] = DrawStruct(42, 277, 35);
+	_drawList[22] = DrawStruct(44, 277, 67);
+	_drawList[23] = DrawStruct(46, 277, 99);
+
+	_iconSprites.load("view.icn");
+	for (int idx = 0; idx < 24; ++idx)
+		_drawList[idx]._sprites = &_iconSprites;
+}
+
+void CharacterInfo::addButtons() {
+	addButton(Common::Rect(10, 24, 34, 44), 1001, &_iconSprites);
+	addButton(Common::Rect(10, 47, 34, 67), 1002, &_iconSprites);
+	addButton(Common::Rect(10, 70, 34, 90), 1003, &_iconSprites);
+	addButton(Common::Rect(10, 93, 34, 113), 1004, &_iconSprites);
+	addButton(Common::Rect(10, 116, 34, 136), 1005, &_iconSprites);
+	addButton(Common::Rect(61, 24, 85, 44), 1006, &_iconSprites);
+	addButton(Common::Rect(61, 47, 85, 67), 1007, &_iconSprites);
+	addButton(Common::Rect(61, 70, 85, 90), 1008, &_iconSprites);
+	addButton(Common::Rect(61, 93, 85, 113), 1009, &_iconSprites);
+	addButton(Common::Rect(61, 116, 85, 136), 1010, &_iconSprites);
+	addButton(Common::Rect(112, 24, 136, 44), 1011, &_iconSprites);
+	addButton(Common::Rect(112, 47, 136, 67), 1012, &_iconSprites);
+	addButton(Common::Rect(112, 70, 136, 90), 1013, &_iconSprites);
+	addButton(Common::Rect(112, 93, 136, 113), 1014, &_iconSprites);
+	addButton(Common::Rect(112, 116, 136, 136), 1015, &_iconSprites);
+	addButton(Common::Rect(177, 24, 201, 44), 1016, &_iconSprites);
+	addButton(Common::Rect(177, 47, 201, 67), 1017, &_iconSprites);
+	addButton(Common::Rect(177, 70, 201, 90), 1018, &_iconSprites);
+	addButton(Common::Rect(177, 93, 201, 113), 1019, &_iconSprites);
+	addButton(Common::Rect(177, 116, 201, 136), 1020, &_iconSprites);
+	addButton(Common::Rect(285, 11, 309, 31), Common::KEYCODE_i, &_iconSprites);
+	addButton(Common::Rect(285, 43, 309, 63), Common::KEYCODE_q, &_iconSprites);
+	addButton(Common::Rect(285, 75, 309, 95), Common::KEYCODE_e, &_iconSprites);
+	addButton(Common::Rect(285, 107, 309, 127), Common::KEYCODE_ESCAPE, &_iconSprites);
+	addPartyButtons(_vm);
+}
+
+Common::String CharacterInfo::loadCharacterDetails(const Character &c) {
+	Condition condition = c.worstCondition();
+	Party &party = *_vm->_party;
+	int foodVal = party._food / party._activeParty.size() / 3;
+
+	int totalResist =
+		c._fireResistence._permanent + c.itemScan(11) + c._fireResistence._temporary +
+		c._coldResistence._permanent + c.itemScan(13) + c._coldResistence._temporary +
+		c._electricityResistence._permanent + c.itemScan(12) + c._electricityResistence._temporary +
+		c._poisonResistence._permanent + c.itemScan(14) + c._poisonResistence._temporary +
+		c._energyResistence._permanent + c.itemScan(15) + c._energyResistence._temporary +
+		c._magicResistence._permanent + c.itemScan(16) + c._magicResistence._temporary;
+
+	return Common::String::format(Res.CHARACTER_DETAILS,
+		Res.PARTY_GOLD, c._name.c_str(), Res.SEX_NAMES[c._sex],
+		Res.RACE_NAMES[c._race], Res.CLASS_NAMES[c._class],
+		c.statColor(c.getStat(MIGHT), c.getStat(MIGHT, true)), c.getStat(MIGHT),
+		c.statColor(c.getStat(ACCURACY), c.getStat(ACCURACY, true)), c.getStat(ACCURACY),
+		c.statColor(c._currentHp, c.getMaxHP()), c._currentHp,
+		c.getCurrentExperience(),
+		c.statColor(c.getStat(INTELLECT), c.getStat(INTELLECT, true)), c.getStat(INTELLECT),
+		c.statColor(c.getStat(LUCK), c.getStat(LUCK, true)), c.getStat(LUCK),
+		c.statColor(c._currentSp, c.getMaxSP()), c._currentSp,
+		party._gold,
+		c.statColor(c.getStat(PERSONALITY), c.getStat(PERSONALITY, true)), c.getStat(PERSONALITY),
+		c.statColor(c.getAge(), c.getAge(true)), c.getAge(),
+		totalResist,
+		party._gems,
+		c.statColor(c.getStat(ENDURANCE), c.getStat(ENDURANCE, true)), c.getStat(ENDURANCE),
+		c.statColor(c.getCurrentLevel(), c._level._permanent), c.getCurrentLevel(),
+		c.getNumSkills(),
+		foodVal, (foodVal == 1) ? ' ' : 's',
+		c.statColor(c.getStat(SPEED), c.getStat(SPEED, true)), c.getStat(SPEED),
+		c.statColor(c.getArmorClass(), c.getArmorClass(true)), c.getArmorClass(),
+		c.getNumAwards(),
+		Res.CONDITION_COLORS[condition], Res.CONDITION_NAMES[condition],
+		condition == NO_CONDITION && party._blessed ? Res.PLUS_14 : "",
+		condition == NO_CONDITION && party._powerShield ? Res.PLUS_14 : "",
+		condition == NO_CONDITION && party._holyBonus ? Res.PLUS_14 : "",
+		condition == NO_CONDITION && party._heroism ? Res.PLUS_14 : ""
+	);
+}
+
+void CharacterInfo::showCursor(bool flag) {
+	const int CURSOR_X[5] = { 9, 60, 111, 176, 0 };
+	const int CURSOR_Y[5] = { 23, 46, 69, 92, 115 };
+
+	if (_cursorCell < 20) {
+		_iconSprites.draw(0, flag ? 49 : 48,
+			Common::Point(CURSOR_X[_cursorCell / 5], CURSOR_Y[_cursorCell % 5]));
+	}
+}
+
+bool CharacterInfo::expandStat(int attrib, const Character &c) {
+	const int STAT_POS[2][20] = {
+		{
+			61, 61, 61, 61, 61, 112, 112, 112, 112, 112,
+			177, 177, 177, 177, 177, 34, 34, 34, 34, 34
+		}, {
+			24, 47, 70, 93, 116, 24, 47, 70, 93, 116,
+			24, 47, 70, 93, 116, 24, 47, 70, 93, 116
+		}
+	};
+	assert(attrib < 20);
+	Common::Rect bounds(STAT_POS[0][attrib], STAT_POS[1][attrib],
+		STAT_POS[0][attrib] + 143, STAT_POS[1][attrib] + 52);
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	uint stat1, stat2;
+	uint idx;
+	Common::String msg;
+
+	switch (attrib) {
+	case 0:
+	case 1:
+	case 2:
+	case 3:
+	case 4:
+	case 5:
+	case 6:
+		// Basic attributes
+		stat1 = c.getStat((Attribute)attrib, false);
+		stat2 = c.getStat((Attribute)attrib, true);
+		idx = 0;
+		while (Res.STAT_VALUES[idx] <= (int)stat1)
+			++idx;
+
+		msg = Common::String::format(Res.CURRENT_MAXIMUM_RATING_TEXT, Res.STAT_NAMES[attrib],
+			stat1, stat2, Res.RATING_TEXT[idx]);
+		break;
+
+	case 7:
+		// Age
+		stat1 = c.getAge(false);
+		stat2 = c.getAge(true);
+		msg = Common::String::format(Res.AGE_TEXT, Res.STAT_NAMES[attrib],
+			stat1, stat2, c._birthDay, c._birthYear);
+		break;
+
+	case 8: {
+		// Level
+		const int CLASS_ATTACK_GAINS[10] = { 5, 6, 6, 7, 8, 6, 5, 4, 7, 6 };
+		idx = c.getCurrentLevel() / CLASS_ATTACK_GAINS[c._class] + 1;
+
+		msg = Common::String::format(Res.LEVEL_TEXT, Res.STAT_NAMES[attrib],
+			c.getCurrentLevel(), c._level._permanent,
+			idx, idx > 1 ? "s" : "",
+			c._level._permanent);
+		break;
+	}
+
+	case 9:
+		// Armor Class
+		stat1 = c.getArmorClass(false);
+		stat2 = c.getArmorClass(true);
+		msg = Common::String::format(Res.CURRENT_MAXIMUM_TEXT, Res.STAT_NAMES[attrib],
+			stat1, stat2);
+		bounds.setHeight(42);
+		break;
+
+	case 10:
+		// Hit Points
+		stat1 = c._currentHp;
+		stat2 = c.getMaxHP();
+		msg = Common::String::format(Res.CURRENT_MAXIMUM_TEXT, Res.STAT_NAMES[attrib],
+			stat1, stat2);
+		bounds.setHeight(42);
+		break;
+
+	case 11:
+		// Spell Points
+		stat1 = c._currentSp;
+		stat2 = c.getMaxSP();
+		msg = Common::String::format(Res.CURRENT_MAXIMUM_TEXT, Res.STAT_NAMES[attrib],
+			stat1, stat2);
+		bounds.setHeight(42);
+		break;
+
+	case 12:
+		// Resistences
+		msg = Common::String::format(Res.RESISTENCES_TEXT, Res.STAT_NAMES[attrib],
+			c._fireResistence._permanent + c.itemScan(11) + c._fireResistence._temporary,
+			c._coldResistence._permanent + c.itemScan(13) + c._coldResistence._temporary,
+			c._electricityResistence._permanent + c.itemScan(12) + c._electricityResistence._temporary,
+			c._poisonResistence._permanent + c.itemScan(14) + c._poisonResistence._temporary,
+			c._energyResistence._permanent + c.itemScan(15) + c._energyResistence._temporary,
+			c._magicResistence._permanent + c.itemScan(16) + c._magicResistence._temporary);
+		bounds.setHeight(80);
+		break;
+
+	case 13: {
+		// Skills
+		Common::String lines[20];
+		int numLines = c.getNumSkills();
+		if (numLines > 0) {
+			for (int skill = THIEVERY; skill <= DANGER_SENSE; ++skill) {
+				if (c._skills[skill]) {
+					if (skill == THIEVERY) {
+						lines[0] = Common::String::format("\n\t020%s%u",
+							Res.SKILL_NAMES[THIEVERY], c.getThievery());
+					} else {
+						lines[skill] = Common::String::format("\n\t020%s", Res.SKILL_NAMES[skill]);
+					}
+				}
+			}
+		} else {
+			lines[0] = Res.NONE;
+			numLines = 1;
+		}
+
+		msg = Common::String::format("\x2\x3""c%s\x3l%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+			Res.STAT_NAMES[attrib], lines[0].c_str(), lines[1].c_str(),
+			lines[2].c_str(), lines[3].c_str(), lines[4].c_str(), lines[5].c_str(),
+			lines[17].c_str(), lines[6].c_str(), lines[7].c_str(), lines[8].c_str(),
+			lines[9].c_str(), lines[10].c_str(), lines[11].c_str(), lines[12].c_str(),
+			lines[13].c_str(), lines[16].c_str(), lines[14].c_str(), lines[15].c_str());
+
+		bounds.top -= (numLines / 2) * 8;
+		bounds.setHeight(numLines * 9 + 26);
+		if (bounds.bottom >= SCREEN_HEIGHT)
+			bounds.moveTo(bounds.left, SCREEN_HEIGHT - bounds.height() - 1);
+		break;
+	}
+
+	case 14:
+		// Awards
+		Awards::show(_vm, &c);
+		return false;
+
+	case 15:
+		// Experience
+		stat1 = c.getCurrentExperience();
+		stat2 = c.experienceToNextLevel();
+		msg = Common::String::format(Res.EXPERIENCE_TEXT,
+			Res.STAT_NAMES[attrib], stat1,
+			stat2 == 0 ? Res.ELIGIBLE : Common::String::format("%d", stat2).c_str()
+		);
+		bounds.setHeight(43);
+		break;
+
+	case 16:
+		// Gold
+		msg = Common::String::format(Res.IN_PARTY_IN_BANK, Res.CONSUMABLE_NAMES[0],
+			party._gold, party._bankGold);
+		bounds.setHeight(43);
+		break;
+
+	case 17:
+		// Gems
+		msg = Common::String::format(Res.IN_PARTY_IN_BANK, Res.CONSUMABLE_NAMES[1],
+			party._gems, party._bankGems);
+		bounds.setHeight(43);
+		break;
+
+	case 18: {
+		// Food
+		int food = (party._food / party._activeParty.size()) / 3;
+		msg = Common::String::format(Res.FOOD_TEXT, Res.CONSUMABLE_NAMES[2],
+			party._food, food, food != 1 ? "s" : "");
+		break;
+	}
+
+	case 19: {
+		// Conditions
+		Common::String lines[20];
+		int total = 0;
+		for (int condition = CURSED; condition <= ERADICATED; ++condition) {
+			if (c._conditions[condition]) {
+				if (condition >= UNCONSCIOUS) {
+					lines[condition] = Common::String::format("\n\t020%s",
+						Res.CONDITION_NAMES[condition]);
+				} else {
+					lines[condition] = Common::String::format("\n\t020%s\t095-%d",
+						Res.CONDITION_NAMES[condition], c._conditions[condition]);
+				}
+
+				++total;
+			}
+		}
+
+		Condition condition = c.worstCondition();
+		if (condition == NO_CONDITION) {
+			lines[0] = Common::String::format("\n\t020%s", Res.GOOD);
+			++total;
+		}
+
+		if (party._blessed)
+			lines[16] = Common::String::format(Res.BLESSED, party._blessed);
+		if (party._powerShield)
+			lines[17] = Common::String::format(Res.POWER_SHIELD, party._powerShield);
+		if (party._holyBonus)
+			lines[18] = Common::String::format(Res.HOLY_BONUS, party._holyBonus);
+		if (party._heroism)
+			lines[19] = Common::String::format(Res.HEROISM, party._heroism);
+
+		msg = Common::String::format("\x2\x3""c%s\x3l%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\x1",
+			Res.CONSUMABLE_NAMES[3], lines[0].c_str(), lines[1].c_str(),
+			lines[2].c_str(), lines[3].c_str(), lines[4].c_str(),
+			lines[5].c_str(), lines[6].c_str(), lines[7].c_str(),
+			lines[8].c_str(), lines[9].c_str(), lines[10].c_str(),
+			lines[11].c_str(), lines[12].c_str(), lines[13].c_str(),
+			lines[14].c_str(), lines[15].c_str(), lines[16].c_str(),
+			lines[17].c_str(), lines[18].c_str(), lines[19].c_str()
+		);
+
+		bounds.top -= ((total - 1) / 2) * 8;
+		bounds.setHeight(total * 9 + 26);
+		if (bounds.bottom >= SCREEN_HEIGHT)
+			bounds.moveTo(bounds.left, SCREEN_HEIGHT - bounds.height() - 1);
+		break;
+	}
+
+	default:
+		break;
+	}
+
+	// Write the data for the stat display
+	Window &w = windows[28];
+	w.setBounds(bounds);
+	w.open();
+	w.writeString(msg);
+	w.update();
+
+	// Wait for a user key/click
+	EventsManager &events = *_vm->_events;
+	while (!_vm->shouldExit() && !events.isKeyMousePressed())
+		events.pollEventsAndWait();
+	events.clearEvents();
+
+	w.close();
+	return false;
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_char_info.h b/engines/xeen/dialogs/dialogs_char_info.h
new file mode 100644
index 0000000..6dc7eaa
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_char_info.h
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_CHAR_INFO_H
+#define XEEN_DIALOGS_CHAR_INFO_H
+
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/party.h"
+#include "xeen/window.h"
+
+namespace Xeen {
+
+class CharacterInfo : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+	DrawStruct _drawList[24];
+	int _cursorCell;
+
+	CharacterInfo(XeenEngine *vm) : ButtonContainer(vm), _cursorCell(0) {}
+
+	void execute(int charIndex);
+
+	/**
+	 * Load the draw structure list with frame numbers and positions
+	 */
+	void loadDrawStructs();
+
+	/**
+	 * Set up the button list for the dialog
+	 */
+	void addButtons();
+
+	/**
+	 * Return a string containing the details of the character
+	 */
+	Common::String loadCharacterDetails(const Character &c);
+
+	/**
+	 * Cursor display handling
+	 */
+	void showCursor(bool flag);
+
+	bool expandStat(int attrib, const Character &c);
+public:
+	static void show(XeenEngine *vm, int charIndex);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_CHAR_INFO_H */
diff --git a/engines/xeen/dialogs/dialogs_control_panel.cpp b/engines/xeen/dialogs/dialogs_control_panel.cpp
new file mode 100644
index 0000000..9c933b3
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_control_panel.cpp
@@ -0,0 +1,220 @@
+/* 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 "xeen/dialogs/dialogs_control_panel.h"
+#include "xeen/dialogs/dialogs_query.h"
+#include "xeen/party.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+int ControlPanel::show(XeenEngine *vm) {
+	ControlPanel *dlg = new ControlPanel(vm);
+	int result = dlg->execute();
+	delete dlg;
+
+	return result;
+}
+
+int ControlPanel::execute() {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Map &map = *_vm->_map;
+	Party &party = *_vm->_party;
+	SavesManager &saves = *_vm->_saves;
+	Sound &sound = *_vm->_sound;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[23];
+	Window &w3 = windows[3];
+
+	loadButtons();
+
+	int result = 0, debugCtr = 0;
+	w.open();
+
+	do {
+		Common::String btnText = getButtonText();
+		Common::String text = Common::String::format(Res.CONTROL_PANEL_TEXT, btnText.c_str());
+
+		drawButtons(&w);
+		w.writeString(text);
+		w.writeString("\xB""000\t000\x1");
+		w.update();
+
+		do {
+			events.updateGameCounter();
+			intf.draw3d(false, false);
+			w.writeString("\r");
+			drawButtons(&w);
+			w.writeString(text);
+			w.writeString("\v000\t000");
+			w.frame();
+
+			if (_debugFlag)
+				w.writeString(getTimeText());
+
+			w3.update();
+			w.update();
+
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+			if (_vm->shouldExit())
+				return 0;
+		} while (!_buttonValue && !events.timeElapsed());
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_q:
+			if (Confirm::show(g_vm, Res.CONFIRM_QUIT)) {
+				g_vm->_gameMode = GMODE_QUIT;
+				result = 1;
+			}
+			break;
+
+		case Common::KEYCODE_w:
+			if (Confirm::show(g_vm, Res.MR_WIZARD)) {
+				w.close();
+				if (!windows[2]._enabled) {
+					sound.playFX(51);
+
+					if (g_vm->getGameID() == GType_WorldOfXeen) {
+						map._loadDarkSide = false;
+						map.load(28);
+						party._mazeDirection = DIR_EAST;
+					} else {
+						map._loadDarkSide = true;
+						map.load(29);
+						party._mazeDirection = DIR_SOUTH;
+					}
+					party.moveToRunLocation();
+				}
+
+				party._gems = 0;
+				result = 2;
+			}
+			break;
+
+		case Common::KEYCODE_l:
+			if (_vm->_mode == MODE_COMBAT) {
+				ErrorScroll::show(_vm, Res.NO_LOADING_IN_COMBAT);
+			} else {
+				// Close dialog and show loading dialog
+				result = 3;
+			}
+			break;
+
+		case Common::KEYCODE_s:
+			if (_vm->_mode == MODE_COMBAT) {
+				ErrorScroll::show(_vm, Res.NO_SAVING_IN_COMBAT);
+			} else {
+				// Close dialog and show saving dialog
+				result = 4;
+			}
+			break;
+
+		case Common::KEYCODE_e:
+			sound.setEffectsOn(!sound._soundOn);
+			break;
+
+		case Common::KEYCODE_m:
+			sound.setMusicOn(!sound._musicOn);
+			break;
+
+		case Common::KEYCODE_ESCAPE:
+			result = 1;
+			break;
+
+		// Goober cheat sequence
+		case Common::KEYCODE_g:
+			debugCtr = 1;
+			break;
+		case Common::KEYCODE_o:
+			debugCtr = (debugCtr == 1 || debugCtr == 2) ? 2 : 0;
+			break;
+		case Common::KEYCODE_b:
+			debugCtr = (debugCtr == 2) ? 3 : 0;
+			break;
+		case Common::KEYCODE_r:
+			if (debugCtr == 3)
+				_debugFlag = true;
+			else
+				debugCtr = 0;
+			break;
+
+		default:
+			break;
+		}
+	} while (!result);
+
+	w.close();
+	intf.drawParty(true);
+
+	if (result == 3) {
+		saves.loadGame();
+	} else if (result == 4) {
+		saves.saveGame();
+	}
+
+	return result;
+}
+
+void ControlPanel::loadButtons() {
+	_iconSprites.load("cpanel.icn");
+
+	addButton(Common::Rect(214, 56, 244, 69), Common::KEYCODE_e, 0, &_iconSprites);
+	addButton(Common::Rect(214, 75, 244, 88), Common::KEYCODE_m, 0, &_iconSprites);
+	addButton(Common::Rect(135, 56, 165, 69), Common::KEYCODE_l, 0, &_iconSprites);
+	addButton(Common::Rect(135, 75, 165, 88), Common::KEYCODE_s, 0, &_iconSprites);
+
+	// For ScummVM we've merged both Save and Save As into a single
+	// save item, so we don't need this one
+	addButton(Common::Rect(), 0);
+
+	addButton(Common::Rect(135, 94, 165, 107), Common::KEYCODE_q, 0, &_iconSprites);
+	addButton(Common::Rect(175, 113, 205, 126), Common::KEYCODE_w, 0, &_iconSprites);
+}
+
+Common::String ControlPanel::getButtonText() {
+	Sound &sound = *g_vm->_sound;
+	_btnSoundText = sound._soundOn ? Res.ON : Res.OFF;
+	_btnMusicText = sound._musicOn ? Res.ON : Res.OFF;
+
+	return Common::String::format(Res.CONTROL_PANEL_BUTTONS,
+		_btnSoundText.c_str(), _btnMusicText.c_str());
+}
+
+Common::String ControlPanel::getTimeText() const {
+	TimeDate td;
+	g_system->getTimeAndDate(td);
+	Common::String timeStr = Common::String::format("%d:%.2d:%.2d%c",
+		td.tm_hour == 0 || td.tm_hour == 12 ? 12 : (td.tm_hour % 12),
+		td.tm_min, td.tm_sec, (td.tm_hour >= 12) ? 'p' : 'c');
+
+	uint32 playtime = g_vm->_events->playTime() / GAME_FRAME_RATE;
+	Common::String playtimeStr = Common::String::format("%d:%.2d:%.2d",
+		playtime / 3600, (playtime / 60) % 60, playtime % 60);
+	return Common::String::format(
+		"\x2\x3l\xB""000\t000\x4""160%s\x3r\xB""000\t000%s\x1",
+		timeStr.c_str(), playtimeStr.c_str());
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_control_panel.h b/engines/xeen/dialogs/dialogs_control_panel.h
new file mode 100644
index 0000000..5181825
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_control_panel.h
@@ -0,0 +1,66 @@
+/* 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 XEEN_DIALOGS_CONTROL_PANEL_H
+#define XEEN_DIALOGS_CONTROL_PANEL_H
+
+#include "xeen/dialogs/dialogs.h"
+
+namespace Xeen {
+
+class ControlPanel : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+	Common::String _btnSoundText, _btnMusicText;
+	bool _debugFlag;
+private:
+	ControlPanel(XeenEngine *vm) : ButtonContainer(vm), _debugFlag(false) {}
+
+	/**
+	 * Inner handler for showing the dialog
+	 */
+	int execute();
+
+	/**
+	 * Loads the buttons for the dialog
+	 */
+	void loadButtons();
+
+	/**
+	 * Gets the text for the dialog buttons
+	 */
+	Common::String getButtonText();
+
+	/**
+	 * Gets the current time
+	 */
+	Common::String getTimeText() const;
+public:
+	/**
+	 * Show the control panel
+	 */
+	static int show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_CONTROL_PANEL_H */
diff --git a/engines/xeen/dialogs/dialogs_create_char.cpp b/engines/xeen/dialogs/dialogs_create_char.cpp
new file mode 100644
index 0000000..577ae53
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_create_char.cpp
@@ -0,0 +1,648 @@
+/* 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 "xeen/dialogs/dialogs_create_char.h"
+#include "xeen/dialogs/dialogs_input.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void CreateCharacterDialog::show(XeenEngine *vm) {
+	CreateCharacterDialog *dlg = new CreateCharacterDialog(vm);
+	dlg->execute();
+	delete dlg;
+}
+
+CreateCharacterDialog::CreateCharacterDialog(XeenEngine *vm) : ButtonContainer(vm) {
+	Common::fill(&_attribs[0], &_attribs[TOTAL_ATTRIBUTES], 0);
+	Common::fill(&_allowedClasses[0], &_allowedClasses[TOTAL_CLASSES], false);
+	_dicePos[0] = Common::Point(20, 17);
+	_dicePos[1] = Common::Point(112, 35);
+	_dicePos[2] = Common::Point(61, 50);
+	_diceFrame[0] = 0;
+	_diceFrame[1] = 2;
+	_diceFrame[2] = 4;
+	_diceInc[0] = Common::Point(10, -10);
+	_diceInc[1] = Common::Point(-10, -10);
+	_diceInc[2] = Common::Point(-10, 10);
+
+	_dice.load("dice.vga");
+	_diceSize = _dice.getFrameSize(0);
+
+	loadButtons();
+}
+
+void CreateCharacterDialog::execute() {
+	EventsManager &events = *_vm->_events;
+	Party &party = *_vm->_party;
+	Screen &screen = *_vm->_screen;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[0];
+	Common::Array<int> freeCharList;
+	int classId = -1;
+	int selectedClass = 0;
+	bool hasFadedIn = false;
+	bool restartFlag = true;
+	Race race = HUMAN;
+	Sex sex = MALE;
+	Common::String msg, details;
+	int charIndex = 0;
+
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = MODE_4;
+
+	// Load the background
+	screen.loadBackground("create.raw");
+	events.setCursor(0);
+
+	while (!_vm->shouldExit()) {
+		if (restartFlag) {
+			// Build up list of roster slot indexes that are free
+			freeCharList.clear();
+			for (uint idx = 0; idx < XEEN_TOTAL_CHARACTERS; ++idx) {
+				if (party._roster[idx]._name.empty())
+					freeCharList.push_back(idx);
+			}
+			charIndex = 0;
+
+			if (freeCharList.size() == XEEN_TOTAL_CHARACTERS)
+				break;
+
+			// Get and race and sex for the given character
+			race = (Race)((freeCharList[charIndex] / 4) % 5);
+			sex = (Sex)(freeCharList[charIndex] & 1);
+
+			// Randomly determine attributes, and which classes they allow
+			rollAttributes();
+
+			// Get the display of the rolled character details
+			selectedClass = newCharDetails(race, sex, classId, selectedClass, details);
+			msg = Common::String::format(Res.CREATE_CHAR_DETAILS,
+				details.c_str());
+
+			// Draw the icons and the currently selected headshot
+			drawIcons();
+			party._roster[freeCharList[charIndex]]._faceSprites->draw(
+				w, 0, Common::Point(27, 102));
+
+			// Render all on-screen text
+			w.writeString(msg);
+			w.update();
+
+			// Draw the arrow for the selected class, if applicable
+			if (selectedClass != -1)
+				printSelectionArrow(selectedClass);
+
+			// Draw the dice
+			drawDice();
+			if (!hasFadedIn) {
+				screen.fadeIn();
+				hasFadedIn = true;
+			}
+
+			restartFlag = false;
+		}
+
+		// Animate the dice until a user action occurs
+		_buttonValue = 0;
+		while (!_vm->shouldExit() && !_buttonValue)
+			drawDice();
+
+		// Handling for different actions
+		if (_buttonValue == Common::KEYCODE_ESCAPE)
+			break;
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_UP:
+			if (charIndex == 0)
+				continue;
+
+			--charIndex;
+			race = (Race)((freeCharList[charIndex] / 4) % 5);
+			sex = (Sex)(freeCharList[charIndex] & 1);
+			break;
+
+		case Common::KEYCODE_DOWN:
+			if (++charIndex == (int)freeCharList.size()) {
+				--charIndex;
+				continue;
+			} else {
+				race = (Race)((freeCharList[charIndex] / 4) % 5);
+				sex = (Sex)(freeCharList[charIndex] & 1);
+			}
+			break;
+
+		case Common::KEYCODE_PAGEUP:
+			for (int tempClass = selectedClass - 1; tempClass >= 0; --tempClass) {
+				if (_allowedClasses[tempClass]) {
+					selectedClass = tempClass;
+					break;
+				}
+			}
+
+			printSelectionArrow(selectedClass);
+			continue;
+
+		case Common::KEYCODE_PAGEDOWN:
+			break;
+
+		case Common::KEYCODE_m:
+		case Common::KEYCODE_i:
+		case Common::KEYCODE_p:
+		case Common::KEYCODE_e:
+		case Common::KEYCODE_s:
+		case Common::KEYCODE_a:
+		case Common::KEYCODE_l:
+			if (swapAttributes(_buttonValue)) {
+				checkClass();
+				classId = -1;
+				selectedClass = newCharDetails(race, sex, classId, selectedClass, msg);
+			}
+			break;
+
+		case 1000:
+		case 1001:
+		case 1002:
+		case 1003:
+		case 1004:
+		case 1005:
+		case 1006:
+		case 1007:
+		case 1008:
+		case 1009:
+			if (_allowedClasses[_buttonValue - 1000]) {
+				selectedClass = classId = _buttonValue - 1000;
+			}
+			break;
+
+		case Common::KEYCODE_c: {
+			_vm->_mode = MODE_FF;
+			bool result = saveCharacter(party._roster[freeCharList[charIndex]],
+				classId, race, sex);
+			_vm->_mode = MODE_4;
+
+			if (result)
+				restartFlag = true;
+			continue;
+		}
+
+		case Common::KEYCODE_RETURN:
+			classId = selectedClass;
+			break;
+
+		case Common::KEYCODE_SPACE:
+		case Common::KEYCODE_r:
+			// Re-roll the attributes
+			rollAttributes();
+			classId = -1;
+			break;
+
+		default:
+			// For all other keypresses, skip the code below the switch
+			// statement, and go to wait for the next key
+			continue;
+		}
+
+		if (_buttonValue != Common::KEYCODE_PAGEDOWN) {
+			selectedClass = newCharDetails(race, sex, classId, selectedClass, msg);
+
+			drawIcons2();
+			party._roster[freeCharList[charIndex]]._faceSprites->draw(w, 0,
+				Common::Point(27, 102));
+
+			w.writeString(msg);
+			w.update();
+
+			if (selectedClass != -1) {
+				printSelectionArrow(selectedClass);
+				continue;
+			}
+		}
+
+		// Move to next available class, or if the code block above resulted in
+		// selectedClass being -1, move to select the first available class
+		for (int tempClass = selectedClass + 1; tempClass <= CLASS_RANGER; ++tempClass) {
+			if (_allowedClasses[tempClass]) {
+				selectedClass = tempClass;
+				break;
+			}
+		}
+
+		printSelectionArrow(selectedClass);
+	} while (!_vm->shouldExit() && _buttonValue != Common::KEYCODE_ESCAPE);
+
+	_vm->_mode = oldMode;
+}
+
+void CreateCharacterDialog::loadButtons() {
+	_icons.load("create.icn");
+
+	// Add buttons
+	addButton(Common::Rect(132, 98, 156, 118), Common::KEYCODE_r, &_icons);
+	addButton(Common::Rect(132, 128, 156, 148), Common::KEYCODE_c, &_icons);
+	addButton(Common::Rect(132, 158, 156, 178), Common::KEYCODE_ESCAPE, &_icons);
+	addButton(Common::Rect(86, 98, 110, 118), Common::KEYCODE_UP, &_icons);
+	addButton(Common::Rect(86, 120, 110, 140), Common::KEYCODE_DOWN, &_icons);
+	addButton(Common::Rect(168, 19, 192, 39), Common::KEYCODE_n, nullptr);
+	addButton(Common::Rect(168, 43, 192, 63), Common::KEYCODE_i, nullptr);
+	addButton(Common::Rect(168, 67, 192, 87), Common::KEYCODE_p, nullptr);
+	addButton(Common::Rect(168, 91, 192, 111), Common::KEYCODE_e, nullptr);
+	addButton(Common::Rect(168, 115, 192, 135), Common::KEYCODE_s, nullptr);
+	addButton(Common::Rect(168, 139, 192, 159), Common::KEYCODE_a, nullptr);
+	addButton(Common::Rect(168, 163, 192, 183), Common::KEYCODE_l, nullptr);
+	addButton(Common::Rect(227, 19, 239, 29), 1000, nullptr);
+	addButton(Common::Rect(227, 30, 239, 40), 1001, nullptr);
+	addButton(Common::Rect(227, 41, 239, 51), 1002, nullptr);
+	addButton(Common::Rect(227, 52, 239, 62), 1003, nullptr);
+	addButton(Common::Rect(227, 63, 239, 73), 1004, nullptr);
+	addButton(Common::Rect(227, 74, 239, 84), 1005, nullptr);
+	addButton(Common::Rect(227, 85, 239, 95), 1006, nullptr);
+	addButton(Common::Rect(227, 96, 239, 106), 1007, nullptr);
+	addButton(Common::Rect(227, 107, 239, 117), 1008, nullptr);
+	addButton(Common::Rect(227, 118, 239, 128), 1009, nullptr);
+}
+
+void CreateCharacterDialog::drawIcons() {
+	// Draw the screen
+	_icons.draw(0, 10, Common::Point(168, 19));
+	_icons.draw(0, 12, Common::Point(168, 43));
+	_icons.draw(0, 14, Common::Point(168, 67));
+	_icons.draw(0, 16, Common::Point(168, 91));
+	_icons.draw(0, 18, Common::Point(168, 115));
+	_icons.draw(0, 20, Common::Point(168, 139));
+	_icons.draw(0, 22, Common::Point(168, 163));
+	for (int idx = 0; idx < 9; ++idx)
+		_icons.draw(0, 24 + idx * 2, Common::Point(227, 19 + 11 * idx));
+
+	for (int idx = 0; idx < 7; ++idx)
+		_icons.draw(0, 50 + idx, Common::Point(195, 31 + 24 * idx));
+
+	_icons.draw(0, 57, Common::Point(62, 148));
+	_icons.draw(0, 58, Common::Point(62, 158));
+	_icons.draw(0, 59, Common::Point(62, 168));
+	_icons.draw(0, 61, Common::Point(220, 19));
+	_icons.draw(0, 64, Common::Point(220, 155));
+	_icons.draw(0, 65, Common::Point(220, 170));
+
+	_icons.draw(0, 0, Common::Point(132, 98));
+	_icons.draw(0, 2, Common::Point(132, 128));
+	_icons.draw(0, 4, Common::Point(132, 158));
+	_icons.draw(0, 6, Common::Point(86, 98));
+	_icons.draw(0, 8, Common::Point(86, 120));
+}
+
+void CreateCharacterDialog::drawIcons2() {
+	for (int idx = 0; idx < 7; ++idx)
+		_icons.draw(0, 10 + idx * 2, Common::Point(168, 19 + idx * 24));
+	for (int idx = 0; idx < 10; ++idx)
+		_icons.draw(0, 24 + idx * 2, Common::Point(227, 19 + idx * 11));
+	for (int idx = 0; idx < 8; ++idx)
+		_icons.draw(0, 50 + idx, Common::Point(195, 31 + idx * 24));
+
+	_icons.draw(0, 57, Common::Point(62, 148));
+	_icons.draw(0, 58, Common::Point(62, 158));
+	_icons.draw(0, 59, Common::Point(62, 168));
+	_icons.draw(0, 61, Common::Point(220, 19));
+	_icons.draw(0, 64, Common::Point(220, 155));
+	_icons.draw(0, 65, Common::Point(220, 170));
+
+	_icons.draw(0, 0, Common::Point(132, 98));
+	_icons.draw(0, 2, Common::Point(132, 128));
+	_icons.draw(0, 4, Common::Point(132, 158));
+	_icons.draw(0, 6, Common::Point(86, 98));
+	_icons.draw(0, 8, Common::Point(86, 120));
+}
+
+void CreateCharacterDialog::rollAttributes() {
+	bool repeat = true;
+	do {
+		// Default all the attributes to zero
+		Common::fill(&_attribs[0], &_attribs[TOTAL_ATTRIBUTES], 0);
+
+		// Assign random amounts to each attribute
+		for (int idx1 = 0; idx1 < 3; ++idx1) {
+			for (int idx2 = 0; idx2 < TOTAL_ATTRIBUTES; ++idx2) {
+				_attribs[idx2] += _vm->getRandomNumber(10, 79) / 10;
+			}
+		}
+
+		// Check which classes are allowed based on the rolled attributes
+		checkClass();
+
+		// Only exit if the attributes allow for at least one class
+		for (int idx = 0; idx < TOTAL_CLASSES; ++idx) {
+			if (_allowedClasses[idx])
+				repeat = false;
+		}
+	} while (repeat);
+}
+
+void CreateCharacterDialog::checkClass() {
+	_allowedClasses[CLASS_KNIGHT] = _attribs[MIGHT] >= 15;
+	_allowedClasses[CLASS_PALADIN] = _attribs[MIGHT] >= 13
+		&& _attribs[PERSONALITY] >= 13 && _attribs[ENDURANCE] >= 13;
+	_allowedClasses[CLASS_ARCHER] = _attribs[INTELLECT] >= 13 && _attribs[ACCURACY] >= 13;
+	_allowedClasses[CLASS_CLERIC] = _attribs[PERSONALITY] >= 13;
+	_allowedClasses[CLASS_SORCERER] = _attribs[INTELLECT] >= 13;
+	_allowedClasses[CLASS_ROBBER] = _attribs[LUCK] >= 13;
+	_allowedClasses[CLASS_NINJA] = _attribs[SPEED] >= 13 && _attribs[ACCURACY] >= 13;
+	_allowedClasses[CLASS_BARBARIAN] = _attribs[ENDURANCE] >= 15;
+	_allowedClasses[CLASS_DRUID] = _attribs[INTELLECT] >= 15 && _attribs[PERSONALITY] >= 15;
+	_allowedClasses[CLASS_RANGER] = _attribs[INTELLECT] >= 12 && _attribs[PERSONALITY] >= 12
+		&& _attribs[ENDURANCE] >= 12 && _attribs[SPEED] >= 12;
+}
+
+int CreateCharacterDialog::newCharDetails(Race race, Sex sex, int classId,
+		int selectedClass, Common::String &msg) {
+	int foundClass = -1;
+	Common::String skillStr, classStr, raceSkillStr;
+
+	// If a selected class is provided, set the default skill for that class
+	if (classId != -1 && Res.NEW_CHAR_SKILLS[classId] != -1) {
+		const char *skillP = Res.SKILL_NAMES[Res.NEW_CHAR_SKILLS[classId]];
+		skillStr = Common::String(skillP, skillP + Res.NEW_CHAR_SKILLS_LEN[classId]);
+	}
+
+	// If a class is provided, set the class name
+	if (classId != -1) {
+		classStr = Common::String::format("\t062\v168%s", Res.CLASS_NAMES[classId]);
+	}
+
+	// Set up default skill for the race, if any
+	if (Res.NEW_CHAR_RACE_SKILLS[race] != -1) {
+		raceSkillStr = Res.SKILL_NAMES[Res.NEW_CHAR_RACE_SKILLS[race]];
+	}
+
+	// Set up color to use for each skill string to be displayed, based
+	// on whether each class is allowed or not for the given attributes
+	int classColors[TOTAL_CLASSES];
+	Common::fill(&classColors[0], &classColors[TOTAL_CLASSES], 0);
+	for (int classNum = CLASS_KNIGHT; classNum <= CLASS_RANGER; ++classNum) {
+		if (_allowedClasses[classNum]) {
+			if (classId == -1 && (foundClass == -1 || foundClass < classNum))
+				foundClass = classNum;
+			classColors[classNum] = 4;
+		}
+	}
+	if (classId != -1)
+		classColors[selectedClass] = 12;
+
+	// Return stats details and character class
+	msg = Common::String::format(Res.NEW_CHAR_STATS, Res.RACE_NAMES[race], Res.SEX_NAMES[sex],
+		_attribs[MIGHT], _attribs[INTELLECT], _attribs[PERSONALITY],
+		_attribs[ENDURANCE], _attribs[SPEED], _attribs[ACCURACY], _attribs[LUCK],
+		classColors[CLASS_KNIGHT], classColors[CLASS_PALADIN],
+		classColors[CLASS_ARCHER], classColors[CLASS_CLERIC],
+		classColors[CLASS_SORCERER], classColors[CLASS_ROBBER],
+		classColors[CLASS_NINJA], classColors[CLASS_BARBARIAN],
+		classColors[CLASS_DRUID], classColors[CLASS_RANGER],
+		skillStr.c_str(), raceSkillStr.c_str(), classStr.c_str()
+	);
+	return classId == -1 ? foundClass : selectedClass;
+}
+
+void CreateCharacterDialog::printSelectionArrow(int selectedClass) {
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[0];
+
+	_icons.draw(0, 61, Common::Point(220, 19));
+	_icons.draw(0, 63, Common::Point(220, selectedClass * 11 + 21));
+	w.update();
+}
+
+void CreateCharacterDialog::drawDice() {
+	EventsManager &events = *_vm->_events;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[32];
+
+	// Draw the dice area background
+	events.updateGameCounter();
+	_dice.draw(w, 7, Common::Point(12, 11));
+
+	// Iterate through each of the three dice
+	for (int diceNum = 0; diceNum < 3; ++diceNum) {
+		_diceFrame[diceNum] = (_diceFrame[diceNum] + 1) % 7;
+		_dicePos[diceNum] += _diceInc[diceNum];
+
+		if (_dicePos[diceNum].x < 13) {
+			_dicePos[diceNum].x = 13;
+			_diceInc[diceNum].x *= -1;
+		} else if (_dicePos[diceNum].x >= (163 - _diceSize.x)) {
+			_dicePos[diceNum].x = 163 - _diceSize.x;
+			_diceInc[diceNum].x *= -1;
+		}
+
+		if (_dicePos[diceNum].y < 12) {
+			_dicePos[diceNum].y = 12;
+			_diceInc[diceNum].y *= -1;
+		} else if (_dicePos[diceNum].y >= (93 - _diceSize.y)) {
+			_dicePos[diceNum].y = 93 - _diceSize.y;
+			_diceInc[diceNum].y *= -1;
+		}
+
+		_dice.draw(w, _diceFrame[diceNum], _dicePos[diceNum]);
+	}
+
+	// Wait for a single frame, checking for any events
+	w.update();
+	events.wait(1);
+	checkEvents(_vm);
+}
+
+int CreateCharacterDialog::getAttribFromKeycode(int keycode) const {
+	switch (keycode) {
+	case Common::KEYCODE_m:
+		return MIGHT;
+	case Common::KEYCODE_i:
+		return INTELLECT;
+	case Common::KEYCODE_p:
+		return PERSONALITY;
+	case Common::KEYCODE_e:
+		return ENDURANCE;
+	case Common::KEYCODE_s:
+		return SPEED;
+	case Common::KEYCODE_a:
+		return ACCURACY;
+	case Common::KEYCODE_l:
+		return LUCK;
+	default:
+		return -1;
+	}
+}
+
+bool CreateCharacterDialog::swapAttributes(int keycode) {
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[0];
+
+	int srcAttrib = getAttribFromKeycode(keycode);
+	assert(srcAttrib >= 0);
+
+	_vm->_mode = MODE_86;
+	_icons.draw(w, srcAttrib * 2 + 11, Common::Point(
+		_buttons[srcAttrib + 5]._bounds.left, _buttons[srcAttrib + 5]._bounds.top));
+	w.update();
+
+	int destAttrib = exchangeAttribute(srcAttrib);
+	if (destAttrib != -1) {
+		_icons.draw(w, destAttrib * 2 + 11, Common::Point(
+			_buttons[destAttrib + 5]._bounds.left,
+			_buttons[destAttrib + 5]._bounds.top));
+
+		SWAP(_attribs[srcAttrib], _attribs[destAttrib]);
+		return true;
+
+	} else {
+		_icons.draw(w, srcAttrib * 2 + 10, Common::Point(
+			_buttons[srcAttrib + 5]._bounds.left,
+			_buttons[srcAttrib + 5]._bounds.top));
+		w.update();
+		_vm->_mode = MODE_SLEEPING;
+		return false;
+	}
+}
+
+int CreateCharacterDialog::exchangeAttribute(int srcAttr) {
+	EventsManager &events = *_vm->_events;
+	Windows &windows = *_vm->_windows;
+	SpriteResource icons;
+	icons.load("create2.icn");
+
+	saveButtons();
+	addButton(Common::Rect(118, 58, 142, 78), Common::KEYCODE_ESCAPE, &_icons);
+	addButton(Common::Rect(168, 19, 192, 39), Common::KEYCODE_m);
+	addButton(Common::Rect(168, 43, 192, 63), Common::KEYCODE_i);
+	addButton(Common::Rect(168, 67, 192, 87), Common::KEYCODE_p);
+	addButton(Common::Rect(168, 91, 192, 111), Common::KEYCODE_e);
+	addButton(Common::Rect(168, 115, 192, 135), Common::KEYCODE_s);
+	addButton(Common::Rect(168, 139, 192, 159), Common::KEYCODE_a);
+	addButton(Common::Rect(168, 163, 192, 183), Common::KEYCODE_l);
+
+	Window &w = windows[26];
+	w.open();
+	w.writeString(Common::String::format(Res.EXCHANGE_ATTR_WITH, Res.STAT_NAMES[srcAttr]));
+	icons.draw(w, 0, Common::Point(118, 58));
+	w.update();
+
+	int result = -1;
+	bool breakFlag = false;
+	while (!_vm->shouldExit() && !breakFlag) {
+		// Wait for an action
+		do {
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+		} while (!_vm->shouldExit() && !_buttonValue);
+		if (_buttonValue == Common::KEYCODE_ESCAPE)
+			break;
+
+		int destAttr = getAttribFromKeycode(_buttonValue);
+		
+		if (destAttr != -1 && srcAttr != destAttr) {
+			result = destAttr;
+			break;
+		}
+	}
+
+	w.close();
+	restoreButtons();
+	_buttonValue = 0;
+	return result;
+}
+
+bool CreateCharacterDialog::saveCharacter(Character &c, int classId, Race race, Sex sex) {
+	if (classId == -1) {
+		ErrorScroll::show(_vm, Res.SELECT_CLASS_BEFORE_SAVING);
+		return false;
+	}
+
+	Map &map = *_vm->_map;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[6];
+	Common::String name;
+	int result;
+	bool isDarkCc = _vm->_files->_isDarkCc;
+
+	// Prompt for a character name
+	w.open();
+	w.writeString(Res.NAME_FOR_NEW_CHARACTER);
+	saveButtons();
+	result = Input::show(_vm, &w, name, 10, 200);
+	restoreButtons();
+	w.close();
+
+	if (!result)
+		// Name aborted, so exit
+		return false;
+
+	// Save new character details
+	c.clear();
+	c._name = name;
+	c._savedMazeId = party._priorMazeId;
+	c._xeenSide = map._loadDarkSide;
+	c._sex = sex;
+	c._race = race;
+	c._class = (CharacterClass)classId;
+	c._level._permanent = isDarkCc ? 5 : 1;
+
+	c._might._permanent = _attribs[MIGHT];
+	c._intellect._permanent = _attribs[INTELLECT];
+	c._personality._permanent = _attribs[PERSONALITY];
+	c._endurance._permanent = _attribs[ENDURANCE];
+	c._speed._permanent = _attribs[SPEED];
+	c._accuracy._permanent = _attribs[ACCURACY];
+	c._luck._permanent = _attribs[LUCK];
+
+	c._magicResistence._permanent = Res.RACE_MAGIC_RESISTENCES[race];
+	c._fireResistence._permanent = Res.RACE_FIRE_RESISTENCES[race];
+	c._electricityResistence._permanent = Res.RACE_ELECTRIC_RESISTENCES[race];
+	c._coldResistence._permanent = Res.RACE_COLD_RESISTENCES[race];
+	c._energyResistence._permanent = Res.RACE_ENERGY_RESISTENCES[race];
+	c._poisonResistence._permanent = Res.RACE_POISON_RESISTENCES[race];
+
+	c._birthYear = party._year - 18;
+	c._birthDay = party._day;
+	c._hasSpells = false;
+	c._currentSpell = -1;
+
+	// Set up any default spells for the character's class
+	for (int idx = 0; idx < 4; ++idx) {
+		if (Res.NEW_CHARACTER_SPELLS[c._class][idx] != -1) {
+			c._hasSpells = true;
+			c._currentSpell = Res.NEW_CHARACTER_SPELLS[c._class][idx];
+			c._spells[c._currentSpell] = true;
+		}
+	}
+
+	int classSkill = Res.NEW_CHAR_SKILLS[c._class];
+	if (classSkill != -1)
+		c._skills[classSkill] = 1;
+
+	int raceSkill = Res.NEW_CHAR_RACE_SKILLS[c._race];
+	if (raceSkill != -1)
+		c._skills[raceSkill] = 1;
+
+	c._currentHp = c.getMaxHP();
+	c._currentSp = c.getMaxSP();
+	return true;
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_create_char.h b/engines/xeen/dialogs/dialogs_create_char.h
new file mode 100644
index 0000000..dc1422e
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_create_char.h
@@ -0,0 +1,124 @@
+/* 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 XEEN_DIALOGS_CREATE_CHAR_H
+#define XEEN_DIALOGS_CREATE_CHAR_H
+
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/character.h"
+
+namespace Xeen {
+
+class CreateCharacterDialog : public ButtonContainer  {
+private:
+	SpriteResource _icons;
+	SpriteResource _dice;
+	Common::Point _diceSize;
+	int _diceFrame[3];
+	Common::Point _dicePos[3];
+	Common::Point _diceInc[3];
+	uint _attribs[TOTAL_ATTRIBUTES];
+	bool _allowedClasses[TOTAL_CLASSES];
+private:
+	/**
+	 * Constructor
+	 */
+	CreateCharacterDialog(XeenEngine *vm);
+
+	/**
+	 * Loads the buttons for the dialog
+	 */
+	void loadButtons();
+
+	/**
+	 * Draws on-screen icons
+	 */
+	void drawIcons();
+
+	/**
+	 * Draws on-screen icons
+	 */
+	void drawIcons2();
+
+	/**
+	 * Animate the dice rolling around
+	 */
+	void drawDice();
+
+	/**
+	 * Executes the dialog
+	 */
+	void execute();
+
+	/**
+	 * Returns the attribute that a given keycode represents
+	 */
+	int getAttribFromKeycode(int keycode) const;
+
+	/**
+	 * Handles the logic for swapping attributes
+	 * @param keycode		Key pressed representing one of the attributes
+	 * @returns		True if swap occurred
+	 */
+	bool swapAttributes(int keycode);
+
+	/**
+	 * Exchanging two attributes for the character being rolled
+	 */
+	int exchangeAttribute(int srcAttr);
+
+	/**
+	 * Set a list of flags for which classes the passed attribute set meet the
+	 * minimum requirements of
+	 */
+	void checkClass();
+
+	/**
+	 * Return details of the generated character
+	 */
+	int newCharDetails(Race race, Sex sex, int classId, int selectedClass, Common::String &msg);
+
+	/**
+	 * Print the selection arrow to indicate the selected class
+	 */
+	void printSelectionArrow(int selectedClass);
+
+	/**
+	 * Saves the rolled character into the roster
+	 */
+	bool saveCharacter(Character &c, int classId, Race race, Sex sex);
+
+	/**
+	 * Roll up some random values for the attributes, and return both them as
+	 * well as a list of classes that the attributes meet the requirements for
+	 */
+	void rollAttributes();
+public:
+	/**
+	 * Shows the Create Character dialog
+	 */
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_CREATE_CHAR_H */
diff --git a/engines/xeen/dialogs/dialogs_difficulty.cpp b/engines/xeen/dialogs/dialogs_difficulty.cpp
new file mode 100644
index 0000000..0b024e1
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_difficulty.cpp
@@ -0,0 +1,75 @@
+/* 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 "xeen/dialogs/dialogs_difficulty.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+int DifficultyDialog::show(XeenEngine *vm) {
+	DifficultyDialog *dlg = new DifficultyDialog(vm);
+	int result = dlg->execute();
+	delete dlg;
+
+	return result;
+}
+
+DifficultyDialog::DifficultyDialog(XeenEngine *vm) : ButtonContainer(vm) {
+	loadButtons();
+}
+
+int DifficultyDialog::execute() {
+	EventsManager &events = *_vm->_events;
+	Windows &windows = *_vm->_windows;
+
+	Window &w = windows[6];
+	w.open();
+	w.writeString(Res.DIFFICULTY_TEXT);
+	drawButtons(&w);
+
+	int result = -1;
+	while (!_vm->shouldExit()) {
+		events.pollEventsAndWait();
+		checkEvents(_vm);
+
+		if (_buttonValue == Common::KEYCODE_a)
+			result = ADVENTURER;
+		else if (_buttonValue == Common::KEYCODE_w)
+			result = WARRIOR;
+		else if (_buttonValue != Common::KEYCODE_ESCAPE)
+			continue;
+
+		break;
+	}
+
+	w.close();
+	return result;
+}
+
+void DifficultyDialog::loadButtons() {
+	_sprites.load("choice.icn");
+	addButton(Common::Rect(68, 167, 158, 187), Common::KEYCODE_a, &_sprites);
+	addButton(Common::Rect(166, 167, 256, 187), Common::KEYCODE_w, &_sprites);
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_difficulty.h b/engines/xeen/dialogs/dialogs_difficulty.h
new file mode 100644
index 0000000..5ff2c93
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_difficulty.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_DIFFICULTY_H
+#define XEEN_DIALOGS_DIFFICULTY_H
+
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/party.h"
+
+namespace Xeen {
+
+class DifficultyDialog : public ButtonContainer {
+private:
+	SpriteResource _sprites;
+
+	/**
+	 * Constructor
+	 */
+	DifficultyDialog(XeenEngine *vm);
+
+	/**
+	 * Shows the dialog
+	 */
+	int execute();
+
+	/**
+	 * Loads buttons for the dialog
+	 */
+	void loadButtons();
+public:
+	/**
+	 * Shows the difficulty selection dialog
+	 * @param vm		Engine reference
+	 * @returns			0=Adventurer, 1=Warrior, -1 exit
+	 */
+	static int show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_DIFFICULTY_H */
diff --git a/engines/xeen/dialogs/dialogs_dismiss.cpp b/engines/xeen/dialogs/dialogs_dismiss.cpp
new file mode 100644
index 0000000..716f8f0
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_dismiss.cpp
@@ -0,0 +1,95 @@
+/* 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 "xeen/dialogs/dialogs_dismiss.h"
+#include "xeen/party.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void Dismiss::show(XeenEngine *vm) {
+	Dismiss *dlg = new Dismiss(vm);
+	dlg->execute();
+	delete dlg;
+}
+
+void Dismiss::execute() {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	loadButtons();
+
+	Window &w = windows[31];
+	w.open();
+	_iconSprites.draw(w, 0, Common::Point(225, 120));
+	w.update();
+
+	bool breakFlag = false;
+	while (!_vm->shouldExit() && !breakFlag) {
+		do {
+			events.updateGameCounter();
+			intf.draw3d(false);
+			w.frame();
+			w.writeString("\r");
+			_iconSprites.draw(w, 0, Common::Point(225, 120));
+			windows[3].update();
+			w.update();
+
+			do {
+				events.pollEventsAndWait();
+				checkEvents(_vm);
+			} while (!_vm->shouldExit() && !_buttonValue && events.timeElapsed() == 0);
+		} while (!_vm->shouldExit() && !_buttonValue);
+
+		if (_buttonValue >= Common::KEYCODE_F1 && _buttonValue <= Common::KEYCODE_F6) {
+			_buttonValue -= Common::KEYCODE_F1;
+
+			if (_buttonValue < (int)party._activeParty.size()) {
+				if (party._activeParty.size() == 1) {
+					w.close();
+					ErrorScroll::show(_vm, Res.CANT_DISMISS_LAST_CHAR, WT_NONFREEZED_WAIT);
+					w.open();
+				} else {
+					// Remove the character from the party
+					party._activeParty.remove_at(_buttonValue);
+					breakFlag = true;
+				}
+				break;
+			}
+		} else if (_buttonValue == Common::KEYCODE_ESCAPE) {
+			breakFlag = true;
+		}
+	}
+}
+
+void Dismiss::loadButtons() {
+	_iconSprites.load("esc.icn");
+	addButton(Common::Rect(225, 120, 249, 140), Common::KEYCODE_ESCAPE, &_iconSprites);
+	addButton(Common::Rect(16, 16, 48, 48), Common::KEYCODE_1);
+	addButton(Common::Rect(117, 16, 149, 48), Common::KEYCODE_2);
+	addButton(Common::Rect(16, 59, 48, 91), Common::KEYCODE_3);
+	addButton(Common::Rect(117, 59, 149, 91), Common::KEYCODE_4);
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_dismiss.h b/engines/xeen/dialogs/dialogs_dismiss.h
new file mode 100644
index 0000000..832f779
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_dismiss.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_DISMISS_H
+#define XEEN_DIALOGS_DISMISS_H
+
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/party.h"
+
+namespace Xeen {
+
+class Dismiss : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+
+	Dismiss(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute();
+
+	void loadButtons();
+public:
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_DISMISS_H */
diff --git a/engines/xeen/dialogs/dialogs_exchange.cpp b/engines/xeen/dialogs/dialogs_exchange.cpp
new file mode 100644
index 0000000..87dde1b
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_exchange.cpp
@@ -0,0 +1,80 @@
+/* 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 "xeen/dialogs/dialogs_exchange.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void ExchangeDialog::show(XeenEngine *vm, Character *&c, int &charIndex) {
+	ExchangeDialog *dlg = new ExchangeDialog(vm);
+	dlg->execute(c, charIndex);
+	delete dlg;
+}
+
+void ExchangeDialog::execute(Character *&c, int &charIndex) {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	loadButtons();
+
+	Window &w = windows[31];
+	w.open();
+	w.writeString(Res.EXCHANGE_WITH_WHOM);
+	_iconSprites.draw(w, 0, Common::Point(225, 120));
+	w.update();
+
+	while (!_vm->shouldExit()) {
+		events.pollEventsAndWait();
+		checkEvents(_vm);
+
+		if (_buttonValue >= Common::KEYCODE_F1 && _buttonValue <= Common::KEYCODE_F6) {
+			_buttonValue -= Common::KEYCODE_F1;
+			if (_buttonValue < (int)party._activeParty.size()) {
+				SWAP(party._activeParty[charIndex], party._activeParty[_buttonValue]);
+
+				charIndex = _buttonValue;
+				c = &party._activeParty[charIndex];
+				break;
+			}
+		} else if (_buttonValue == Common::KEYCODE_ESCAPE) {
+			break;
+		}
+	}
+
+	w.close();
+	intf.drawParty(true);
+	intf.highlightChar(charIndex);
+}
+
+void ExchangeDialog::loadButtons() {
+	_iconSprites.load("esc.icn");
+	addButton(Common::Rect(225, 120, 249, 245), Common::KEYCODE_ESCAPE, &_iconSprites);
+	addButton(Common::Rect(16, 16, 48, 48), Common::KEYCODE_1);
+	addButton(Common::Rect(117, 16, 149, 48), Common::KEYCODE_2);
+	addButton(Common::Rect(16, 59, 48, 91), Common::KEYCODE_3);
+	addButton(Common::Rect(117, 59, 149, 91), Common::KEYCODE_4);
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_exchange.h b/engines/xeen/dialogs/dialogs_exchange.h
new file mode 100644
index 0000000..ff7e214
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_exchange.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_EXCHANGE_H
+#define XEEN_DIALOGS_EXCHANGE_H
+
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/party.h"
+
+namespace Xeen {
+
+class ExchangeDialog : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+
+	ExchangeDialog(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute(Character *&c, int &charIndex);
+
+	void loadButtons();
+public:
+	static void show(XeenEngine *vm, Character *&c, int &charIndex);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_EXCHANGE_H */
diff --git a/engines/xeen/dialogs/dialogs_info.cpp b/engines/xeen/dialogs/dialogs_info.cpp
new file mode 100644
index 0000000..5055853
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_info.cpp
@@ -0,0 +1,129 @@
+/* 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 "xeen/dialogs/dialogs_info.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void InfoDialog::show(XeenEngine *vm) {
+	InfoDialog *dlg = new InfoDialog(vm);
+	dlg->execute();
+	delete dlg;
+}
+
+void InfoDialog::execute() {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+
+	protectionText();
+	Common::String statusText = "";
+	for (uint idx = 0; idx < _lines.size(); ++idx)
+		statusText += _lines[idx];
+
+	Common::String gameName;
+	if (_vm->getGameID() == GType_Swords)
+		gameName = Res.SWORDS_GAME_TEXT;
+	else if (_vm->getGameID() == GType_Clouds)
+		gameName = Res.CLOUDS_GAME_TEXT;
+	else if (_vm->getGameID() == GType_DarkSide)
+		gameName = Res.DARKSIDE_GAME_TEXT;
+	else
+		gameName = Res.WORLD_GAME_TEXT;
+
+	// Form the display message
+	int hour = party._minutes / 60;
+	Common::String details = Common::String::format(Res.GAME_INFORMATION,
+		gameName.c_str(), Res.WEEK_DAY_STRINGS[party._day % 10],
+		(hour > 12) ? hour - 12 : (!hour ? 12 : hour),
+		party._minutes % 60, (hour > 11) ? 'p' : 'a',
+		party._day, party._year, statusText.c_str());
+
+	Window &w = windows[28];
+	w.setBounds(Common::Rect(88, 20, 248, 112 + (_lines.empty() ? 0 : _lines.size() * 9 + 13)));
+	w.open();
+	w.writeString(details);
+
+	do {
+		events.updateGameCounter();
+		intf.draw3d(false, false);
+		w.frame();
+		w.writeString(details);
+		w.update();
+
+		events.wait(1);
+	} while (!_vm->shouldExit() && !events.isKeyMousePressed());
+
+	events.clearEvents();
+	w.close();
+}
+
+void InfoDialog::protectionText() {
+	Party &party = *_vm->_party;
+//	Common::StringArray _lines;
+	const char *const AA_L024 = "\x3l\n\x9""024";
+	const char *const AA_R124 = "\x3r\x9""124";
+
+	if (party._lightCount) {
+		_lines.push_back(Common::String::format(Res.LIGHT_COUNT_TEXT, party._lightCount));
+	}
+
+	if (party._fireResistence) {
+		_lines.push_back(Common::String::format(Res.FIRE_RESISTENCE_TEXT,
+			_lines.size() == 0 ? 10 : 1, AA_L024, AA_R124, party._fireResistence));
+	}
+
+	if (party._electricityResistence) {
+		_lines.push_back(Common::String::format(Res.ELECRICITY_RESISTENCE_TEXT,
+			_lines.size() == 0 ? 10 : 1, AA_L024, AA_R124, party._electricityResistence));
+	}
+
+	if (party._coldResistence) {
+		_lines.push_back(Common::String::format(Res.COLD_RESISTENCE_TEXT,
+			_lines.size() == 0 ? 10 : 1, AA_L024, AA_R124, party._coldResistence));
+	}
+
+	if (party._poisonResistence) {
+		_lines.push_back(Common::String::format(Res.POISON_RESISTENCE_TEXT,
+			_lines.size() == 0 ? 10 : 1, AA_L024, AA_R124, party._poisonResistence));
+	}
+
+	if (party._clairvoyanceActive) {
+		_lines.push_back(Common::String::format(Res.CLAIRVOYANCE_TEXT,
+			_lines.size() == 0 ? 10 : 1, AA_L024, AA_R124));
+	}
+
+	if (party._levitateCount) {
+		_lines.push_back(Common::String::format(Res.LEVITATE_TEXT,
+			_lines.size() == 0 ? 10 : 1, AA_L024, AA_R124));
+	}
+
+	if (party._walkOnWaterActive) {
+		_lines.push_back(Common::String::format(Res.WALK_ON_WATER_TEXT,
+			_lines.size() == 0 ? 10 : 1, AA_L024, AA_R124));
+	}
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_info.h b/engines/xeen/dialogs/dialogs_info.h
new file mode 100644
index 0000000..fdbbc22
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_info.h
@@ -0,0 +1,46 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_INFO_H
+#define XEEN_DIALOGS_INFO_H
+
+#include "common/str-array.h"
+#include "xeen/dialogs/dialogs.h"
+
+namespace Xeen {
+
+class InfoDialog : public ButtonContainer {
+private:
+	Common::StringArray _lines;
+
+	InfoDialog(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute();
+
+	void protectionText();
+public:
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_INFO_H */
diff --git a/engines/xeen/dialogs/dialogs_input.cpp b/engines/xeen/dialogs/dialogs_input.cpp
new file mode 100644
index 0000000..1d05c81
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_input.cpp
@@ -0,0 +1,323 @@
+/* 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 "xeen/dialogs/dialogs_input.h"
+#include "xeen/scripts.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+int Input::show(XeenEngine *vm, Window *window, Common::String &line,
+		uint maxLen, int maxWidth, bool isNumeric) {
+	Input *dlg = new Input(vm, window);
+	int result = dlg->getString(line, maxLen, maxWidth, isNumeric);
+	delete dlg;
+
+	return result;
+}
+
+int Input::getString(Common::String &line, uint maxLen, int maxWidth, bool isNumeric) {
+	_vm->_noDirectionSense = true;
+	Common::String msg = Common::String::format("\x3""l\t000\x4%03d\x3""c", maxWidth);
+	_window->writeString(msg);
+	_window->update();
+
+	while (!_vm->shouldExit()) {
+		Common::KeyState keyState = waitForKey(msg);
+		const Common::KeyCode keyCode = keyState.keycode;
+
+		bool refresh = false;
+		if ((keyCode == Common::KEYCODE_BACKSPACE || keyCode == Common::KEYCODE_DELETE)
+				&& line.size() > 0) {
+			line.deleteLastChar();
+			refresh = true;
+		} else if (line.size() < maxLen && (line.size() > 0 || keyCode != Common::KEYCODE_SPACE)
+				&& ((isNumeric && keyState.ascii >= '0' && keyState.ascii <= '9') ||
+				   (!isNumeric && keyState.ascii >= ' ' && keyState.ascii <= (char)127))) {
+			line += keyState.ascii;
+			refresh = true;
+		} else if (keyCode == Common::KEYCODE_RETURN || keyCode == Common::KEYCODE_KP_ENTER) {
+			break;
+		} else if (keyCode == Common::KEYCODE_ESCAPE) {
+			line = "";
+			break;
+		}
+
+		if (refresh) {
+			msg = Common::String::format("\x3""l\t000\x4%03d\x3""c%s", maxWidth, line.c_str());
+			_window->writeString(msg);
+			_window->update();
+		}
+	}
+
+	_vm->_noDirectionSense = false;
+	return line.size();
+}
+
+Common::KeyState Input::waitForKey(const Common::String &msg) {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Windows &windows = *_vm->_windows;
+
+	bool oldUpDoorText = intf._upDoorText;
+	byte oldTillMove = intf._tillMove;
+	intf._upDoorText = false;
+	intf._tillMove = 0;
+
+	bool flag = !_vm->_startupWindowActive && !windows[25]._enabled
+		&& _vm->_mode != MODE_FF && _vm->_mode != MODE_17;
+
+	Common::KeyState ks;
+	while (!_vm->shouldExit()) {
+		events.updateGameCounter();
+
+		if (flag)
+			intf.draw3d(false);
+		_window->writeString(msg);
+		animateCursor();
+		_window->update();
+
+		if (flag)
+			windows[3].update();
+
+		events.wait(1);
+
+		if (events.isKeyPending()) {
+			events.getKey(ks);
+			break;
+		}
+	}
+
+	_window->writeString("");
+	_window->update();
+
+	intf._tillMove = oldTillMove;
+	intf._upDoorText = oldUpDoorText;
+
+	return ks;
+}
+
+void Input::animateCursor() {
+	// Iterate through each frame
+	_cursorAnimIndex = _cursorAnimIndex ? _cursorAnimIndex - 1 : 5;
+	static const char CURSOR_ANIMATION_IDS[] = { 32, 124, 126, 127, 126, 124 };
+
+	// Form a string for the cursor and write it out
+	Common::Point writePos = _window->_writePos;
+	_window->writeCharacter(CURSOR_ANIMATION_IDS[_cursorAnimIndex]);
+	_window->_writePos = writePos;
+}
+
+/*------------------------------------------------------------------------*/
+
+StringInput::StringInput(XeenEngine *vm): Input(vm, &(*vm->_windows)[6]) {
+}
+
+int StringInput::show(XeenEngine *vm, bool type, const Common::String &msg1,
+		const Common::String &msg2, int opcode) {
+	StringInput *dlg = new StringInput(vm);
+	int result = dlg->execute(type, msg1, msg2, opcode);
+	delete dlg;
+
+	return result;
+}
+
+int StringInput::execute(bool type, const Common::String &expected,
+		const Common::String &title, int opcode) {
+	FileManager &files = *_vm->_files;
+	Interface &intf = *_vm->_interface;
+	Scripts &scripts = *_vm->_scripts;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[6];
+	Sound &sound = *_vm->_sound;
+	int result = 0;
+
+	w.open();
+	w.writeString(Common::String::format("\r\x03""c%s\v024\t000", title.c_str()));
+	w.update();
+
+	Common::String line;
+	if (getString(line, 30, 200, false)) {
+		if (type) {
+			if (line == intf._interfaceText) {
+				result = true;
+			} else if (line == expected) {
+				result = (opcode == 55) ? -1 : 1;
+			}
+		} else {
+			// Load in the mirror list
+			MirrorEntry me;
+			scripts._mirror.clear();
+
+			File f(Common::String::format("%smirr.txt", files._isDarkCc ? "dark" : "xeen"), 1);
+			while (me.synchronize(f))
+				scripts._mirror.push_back(me);
+			f.close();
+
+			// Load in any extended mirror entries
+			Common::File f2;
+			if (f2.open(Common::String::format("%smirr.ext", files._isDarkCc ? "dark" : "xeen"))) {
+				while (me.synchronize(f2))
+					scripts._mirror.push_back(me);
+				f2.close();
+			}
+
+			for (uint idx = 0; idx < scripts._mirror.size(); ++idx) {
+				if (!line.compareToIgnoreCase(scripts._mirror[idx]._name)) {
+					result = idx + 1;
+					sound.playFX(_vm->_files->_isDarkCc ? 35 : 61);
+					break;
+				}
+			}
+		}
+	}
+
+	w.close();
+	return result;
+}
+
+/*------------------------------------------------------------------------*/
+
+NumericInput::NumericInput(XeenEngine *vm, int window) : Input(vm, &(*vm->_windows)[window]) {
+}
+
+int NumericInput::show(XeenEngine *vm, int window, int maxLength, int maxWidth) {
+	NumericInput *dlg = new NumericInput(vm, window);
+	int result = dlg->execute(maxLength, maxWidth);
+	delete dlg;
+
+	return result;
+}
+
+int NumericInput::execute(int maxLength, int maxWidth) {
+	Common::String line;
+
+	if (getString(line, maxLength, maxWidth, true))
+		return atoi(line.c_str());
+	else
+		return 0;
+}
+
+/*------------------------------------------------------------------------*/
+
+int Choose123::show(XeenEngine *vm, int numOptions) {
+	assert(numOptions <= 3);
+	Choose123 *dlg = new Choose123(vm);
+	int result = dlg->execute(numOptions);
+	delete dlg;
+
+	return result;
+}
+
+int Choose123::execute(int numOptions) {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	LocationManager &loc = *_vm->_locations;
+	Windows &windows = *_vm->_windows;
+
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = MODE_DIALOG_123;
+
+	loadButtons(numOptions);
+	_iconSprites.draw(0, 7, Common::Point(232, 74));
+	drawButtons(&windows[0]);
+	windows[34].update();
+
+	int result = -1;
+	while (result == -1) {
+		do {
+			events.updateGameCounter();
+			int delay;
+			if (loc.isActive()) {
+				loc.drawAnim(true);
+				delay = 3;
+			} else {
+				intf.draw3d(true);
+				delay = 1;
+			}
+
+			events.wait(delay);
+			if (_vm->shouldExit())
+				return 0;
+		} while (!_buttonValue);
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_ESCAPE:
+			result = 0;
+			break;
+		case Common::KEYCODE_1:
+		case Common::KEYCODE_2:
+		case Common::KEYCODE_3: {
+			int v = _buttonValue - Common::KEYCODE_1 + 1;
+			if (v <= numOptions)
+				result = v;
+			break;
+		}
+		default:
+			break;
+		}
+	}
+
+	_vm->_mode = oldMode;
+	intf.mainIconsPrint();
+
+	return result;
+}
+
+void Choose123::loadButtons(int numOptions) {
+	_iconSprites.load("choose.icn");
+
+	if (numOptions >= 1)
+		addButton(Common::Rect(235, 75, 259, 95), Common::KEYCODE_1, &_iconSprites);
+	if (numOptions >= 2)
+		addButton(Common::Rect(260, 75, 284, 95), Common::KEYCODE_2, &_iconSprites);
+	if (numOptions >= 3)
+		addButton(Common::Rect(286, 75, 311, 95), Common::KEYCODE_3, &_iconSprites);
+}
+
+/*------------------------------------------------------------------------*/
+
+int HowMuch::show(XeenEngine *vm) {
+	HowMuch *dlg = new HowMuch(vm);
+	int result = dlg->execute();
+	delete dlg;
+
+	return result;
+}
+
+int HowMuch::execute() {
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[6];
+	Common::String num;
+
+	w.open();
+	w.writeString(Res.HOW_MUCH);
+	w.update();
+	int lineSize = Input::show(_vm, &w, num, 8, 70, true);
+	w.close();
+
+	if (!lineSize)
+		return -1;
+	return atoi(num.c_str());
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_input.h b/engines/xeen/dialogs/dialogs_input.h
new file mode 100644
index 0000000..270495f
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_input.h
@@ -0,0 +1,105 @@
+/* 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 XEEN_DIALOGS_STRING_INPUT_H
+#define XEEN_DIALOGS_STRING_INPUT_H
+
+#include "common/keyboard.h"
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/screen.h"
+
+namespace Xeen {
+
+class Input : public ButtonContainer {
+private:
+	/**
+	 * Draws the text input and cursor and waits until the user presses a key
+	 */
+	Common::KeyState waitForKey(const Common::String &msg);
+
+	/**
+	 * Animates the box text cursor
+	 */
+	void animateCursor();
+protected:
+	Window *_window;
+	int _cursorAnimIndex;
+
+	/**
+	 * Allows the user to enter a string
+	 */
+	int getString(Common::String &line, uint maxLen, int maxWidth, bool isNumeric);
+
+	Input(XeenEngine *vm, Window *window) : ButtonContainer(vm),
+		_window(window), _cursorAnimIndex(0) {}
+public:
+	static int show(XeenEngine *vm, Window *window, Common::String &line,
+		uint maxLen, int maxWidth, bool isNumeric = false);
+};
+
+class StringInput : public Input {
+protected:
+	StringInput(XeenEngine *vm);
+
+	int execute(bool type, const Common::String &expected,
+		const Common::String &title, int opcode);
+public:
+	static int show(XeenEngine *vm, bool type, const Common::String &msg1,
+		const Common::String &msg2, int opcode);
+};
+
+class NumericInput : public Input {
+private:
+	NumericInput(XeenEngine *vm, int window);
+
+	int execute(int maxLength, int maxWidth);
+public:
+	static int show(XeenEngine *vm, int window, int maxLength, int maxWidth);
+};
+
+class Choose123 : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+
+	Choose123(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	int execute(int numOptions);
+
+	void loadButtons(int numOptions);
+public:
+	static int show(XeenEngine *vm, int numOptions);
+};
+
+class HowMuch : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+
+	HowMuch(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	int execute();
+public:
+	static int show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_STRING_INPUT_H */
diff --git a/engines/xeen/dialogs/dialogs_items.cpp b/engines/xeen/dialogs/dialogs_items.cpp
new file mode 100644
index 0000000..0ca0fd2
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_items.cpp
@@ -0,0 +1,1066 @@
+/* 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 "xeen/dialogs/dialogs_items.h"
+#include "xeen/dialogs/dialogs_query.h"
+#include "xeen/dialogs/dialogs_quests.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+Character *ItemsDialog::show(XeenEngine *vm, Character *c, ItemsMode mode) {
+	ItemsDialog *dlg = new ItemsDialog(vm);
+	Character *result = dlg->execute(c, mode);
+	delete dlg;
+
+	return result;
+}
+
+Character *ItemsDialog::execute(Character *c, ItemsMode mode) {
+	Combat &combat = *_vm->_combat;
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+
+	Character *startingChar = c;
+	ItemCategory category = mode == ITEMMODE_RECHARGE || mode == ITEMMODE_COMBAT ?
+		CATEGORY_MISC : CATEGORY_WEAPON;
+	int varA = mode == ITEMMODE_COMBAT ? 1 : 0;
+	if (varA != 0)
+		mode = ITEMMODE_CHAR_INFO;
+	bool updateStock = mode == ITEMMODE_BLACKSMITH;
+	int itemIndex = -1;
+	Common::StringArray lines;
+	uint arr[40];
+	int actionIndex = -1;
+
+	events.setCursor(0);
+	loadButtons(mode, c);
+
+	windows[29].open();
+	windows[30].open();
+
+	enum { REDRAW_NONE, REDRAW_TEXT, REDRAW_FULL } redrawFlag = REDRAW_FULL;
+	for (;;) {
+		if (redrawFlag == REDRAW_FULL) {
+			if ((mode != ITEMMODE_CHAR_INFO || category != CATEGORY_MISC) && mode != ITEMMODE_ENCHANT
+					&& mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+				_buttons[4]._bounds.moveTo(148, _buttons[4]._bounds.top);
+				_buttons[9]._draw = false;
+			} else if (mode == ITEMMODE_RECHARGE) {
+				_buttons[4]._value = Common::KEYCODE_r;
+			} else if (mode == ITEMMODE_ENCHANT) {
+				_buttons[4]._value = Common::KEYCODE_e;
+			} else if (mode == ITEMMODE_TO_GOLD) {
+				_buttons[4]._value = Common::KEYCODE_g;
+			} else {
+				_buttons[4]._bounds.moveTo(0, _buttons[4]._bounds.top);
+				_buttons[9]._draw = true;
+				_buttons[9]._value = Common::KEYCODE_u;
+			}
+
+			// Write text for the dialog
+			Common::String msg;
+			if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_8 && mode != ITEMMODE_ENCHANT
+					&& mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+				msg = Common::String::format(Res.ITEMS_DIALOG_TEXT1,
+					Res.BTN_BUY, Res.BTN_SELL, Res.BTN_IDENTIFY, Res.BTN_FIX);
+			} else if (mode != ITEMMODE_ENCHANT  && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+				msg = Common::String::format(Res.ITEMS_DIALOG_TEXT1,
+					category == 3 ? Res.BTN_USE : Res.BTN_EQUIP,
+					Res.BTN_REMOVE, Res.BTN_DISCARD, Res.BTN_QUEST);
+			} else if (mode == ITEMMODE_ENCHANT) {
+				msg = Common::String::format(Res.ITEMS_DIALOG_TEXT2, Res.BTN_ENCHANT);
+			} else if (mode == ITEMMODE_RECHARGE) {
+				msg = Common::String::format(Res.ITEMS_DIALOG_TEXT2, Res.BTN_RECHARGE);
+			} else {
+				msg = Common::String::format(Res.ITEMS_DIALOG_TEXT2, Res.BTN_GOLD);
+			}
+
+			windows[29].writeString(msg);
+			drawButtons(&windows[0]);
+
+			Common::fill(&arr[0], &arr[40], 0);
+			itemIndex = -1;
+		}
+
+		if (redrawFlag == REDRAW_TEXT || redrawFlag == REDRAW_FULL) {
+			lines.clear();
+
+			if (mode == ITEMMODE_CHAR_INFO || category != 3) {
+				_iconSprites.draw(0, 8, Common::Point(148, 109));
+			}
+			if (mode != ITEMMODE_ENCHANT && mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD) {
+				_iconSprites.draw(0, 10, Common::Point(182, 109));
+				_iconSprites.draw(0, 12, Common::Point(216, 109));
+				_iconSprites.draw(0, 14, Common::Point(250, 109));
+			}
+
+			switch (mode) {
+			case ITEMMODE_CHAR_INFO:
+				_iconSprites.draw(0, 9, Common::Point(148, 109));
+				break;
+			case ITEMMODE_BLACKSMITH:
+				_iconSprites.draw(0, 11, Common::Point(182, 109));
+				break;
+			case ITEMMODE_REPAIR:
+				_iconSprites.draw(0, 15, Common::Point(250, 109));
+				break;
+			case ITEMMODE_IDENTIFY:
+				_iconSprites.draw(0, 13, Common::Point(216, 109));
+				break;
+			default:
+				break;
+			}
+
+			for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+				DrawStruct &ds = _itemsDrawList[idx];
+				XeenItem &i = c->_items[category][idx];
+
+				ds._sprites = nullptr;
+				ds._x = 8;
+				ds._y = 18 + idx * 9;
+
+				switch (category) {
+				case CATEGORY_WEAPON:
+				case CATEGORY_ARMOR:
+				case CATEGORY_ACCESSORY:
+					if (i._id) {
+						if (mode == ITEMMODE_CHAR_INFO || mode == ITEMMODE_8
+								|| mode == ITEMMODE_ENCHANT || mode == ITEMMODE_RECHARGE) {
+							lines.push_back(Common::String::format(Res.ITEMS_DIALOG_LINE1,
+								arr[idx], idx + 1,
+								c->_items[category].getFullDescription(idx, arr[idx]).c_str()));
+						} else {
+							lines.push_back(Common::String::format(Res.ITEMS_DIALOG_LINE2,
+								arr[idx], idx + 1,
+								c->_items[category].getFullDescription(idx, arr[idx]).c_str(),
+								calcItemCost(c, idx, mode,
+									mode == ITEMMODE_TO_GOLD ? 1 : startingChar->_skills[MERCHANT],
+									category)
+							));
+						}
+
+						ds._sprites = &_equipSprites;
+						if (c->_weapons.passRestrictions(i._id, true))
+							ds._frame = i._frame;
+						else
+							ds._frame = 14;
+					} else if (ds._sprites == nullptr && idx == 0) {
+						lines.push_back(Res.NO_ITEMS_AVAILABLE);
+					}
+					break;
+
+				case CATEGORY_MISC:
+					if (i._material == 0) {
+						// No item
+						if (idx == 0) {
+							lines.push_back(Res.NO_ITEMS_AVAILABLE);
+						}
+					} else {
+						ItemsMode tempMode = mode;
+						int skill = startingChar->_skills[MERCHANT];
+
+						if (mode == ITEMMODE_CHAR_INFO || mode == ITEMMODE_8
+								|| mode == ITEMMODE_ENCHANT || mode == ITEMMODE_RECHARGE) {
+							tempMode = ITEMMODE_ENCHANT;
+						} else if (mode == ITEMMODE_TO_GOLD) {
+							skill = 1;
+						}
+
+						lines.push_back(Common::String::format(Res.ITEMS_DIALOG_LINE2,
+							arr[idx], idx + 1,
+							c->_items[category].getFullDescription(idx, arr[idx]).c_str(),
+							calcItemCost(c, idx, tempMode, skill, category)
+						));
+					}
+					break;
+
+				default:
+					break;
+				}
+			}
+			while (lines.size() < INV_ITEMS_TOTAL)
+				lines.push_back("");
+
+			// Draw out overall text and the list of items
+			switch (mode) {
+			case ITEMMODE_CHAR_INFO:
+			case ITEMMODE_8:
+				windows[30].writeString(Common::String::format(Res.X_FOR_THE_Y,
+					category == CATEGORY_MISC ? "\x3l" : "\x3c",
+					Res.CATEGORY_NAMES[category], c->_name.c_str(), Res.CLASS_NAMES[c->_class],
+					category == CATEGORY_MISC ? Res.FMT_CHARGES : " ",
+					lines[0].c_str(), lines[1].c_str(), lines[2].c_str(), lines[3].c_str(),
+					lines[4].c_str(), lines[5].c_str(), lines[6].c_str(), lines[7].c_str(),
+					lines[8].c_str()
+				));
+				break;
+
+			case ITEMMODE_BLACKSMITH:
+				windows[30].writeString(Common::String::format(Res.AVAILABLE_GOLD_COST,
+					Res.CATEGORY_NAMES[category], party._gold,
+					lines[0].c_str(), lines[1].c_str(), lines[2].c_str(), lines[3].c_str(),
+					lines[4].c_str(), lines[5].c_str(), lines[6].c_str(), lines[7].c_str(),
+					lines[8].c_str()
+				));
+				break;
+
+			case ITEMMODE_2:
+			case ITEMMODE_RECHARGE:
+			case ITEMMODE_ENCHANT:
+			case ITEMMODE_REPAIR:
+			case ITEMMODE_IDENTIFY:
+			case ITEMMODE_TO_GOLD:
+				windows[30].writeString(Common::String::format(Res.X_FOR_Y,
+					Res.CATEGORY_NAMES[category], startingChar->_name.c_str(),
+					(mode == ITEMMODE_RECHARGE || mode == ITEMMODE_ENCHANT) ? Res.CHARGES : Res.COST,
+					lines[0].c_str(), lines[1].c_str(), lines[2].c_str(), lines[3].c_str(),
+					lines[4].c_str(), lines[5].c_str(), lines[6].c_str(), lines[7].c_str(),
+					lines[8].c_str()
+				));
+				break;
+
+			case ITEMMODE_3:
+			case ITEMMODE_5:
+				windows[30].writeString(Common::String::format(Res.X_FOR_Y_GOLD,
+					Res.CATEGORY_NAMES[category], c->_name.c_str(), party._gold, Res.CHARGES,
+					lines[0].c_str(), lines[1].c_str(), lines[2].c_str(), lines[3].c_str(),
+					lines[4].c_str(), lines[5].c_str(), lines[6].c_str(), lines[7].c_str(),
+					lines[8].c_str()
+					));
+				break;
+
+			default:
+				break;
+			}
+
+			// Draw the glyphs for the items
+			windows[0].drawList(_itemsDrawList, INV_ITEMS_TOTAL);
+			windows[0].update();
+		}
+
+		redrawFlag = REDRAW_NONE;
+
+		if (itemIndex != -1) {
+			switch (mode) {
+			case ITEMMODE_BLACKSMITH:
+				actionIndex = 0;
+				break;
+			case ITEMMODE_2:
+				actionIndex = 1;
+				break;
+			case ITEMMODE_REPAIR:
+				actionIndex = 3;
+				break;
+			case ITEMMODE_IDENTIFY:
+				actionIndex = 2;
+				break;
+			default:
+				break;
+			}
+		}
+
+		// If it's time to do an item action, take care of it
+		if (actionIndex >= 0) {
+			int result = doItemOptions(*c, actionIndex, itemIndex, category, mode);
+			if (result == 1) {
+				// Finish dialog with no selected character
+				c = nullptr;
+				break;
+			} else if (result == 2) {
+				// Close dialogs and finish dialog with original starting character
+				windows[30].close();
+				windows[29].close();
+				c = startingChar;
+				break;
+			}
+
+			// Otherwise, result and continue showing dialog
+			actionIndex = -1;
+		}
+
+		// Wait for a selection
+		_buttonValue = 0;
+		while (!_vm->shouldExit() && !_buttonValue) {
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+		}
+		if (_vm->shouldExit())
+			return nullptr;
+
+		// Handle escaping out of dialog
+		if (_buttonValue == Common::KEYCODE_ESCAPE) {
+			if (mode == ITEMMODE_8)
+				continue;
+			c = startingChar;
+			break;
+		}
+
+		// Handle other selections
+		switch (_buttonValue) {
+		case Common::KEYCODE_F1:
+		case Common::KEYCODE_F2:
+		case Common::KEYCODE_F3:
+		case Common::KEYCODE_F4:
+		case Common::KEYCODE_F5:
+		case Common::KEYCODE_F6:
+			if (!varA && mode != ITEMMODE_3 && mode != ITEMMODE_ENCHANT
+					&& mode != ITEMMODE_RECHARGE && mode != ITEMMODE_TO_GOLD
+					&& party._mazeId != 0) {
+				_buttonValue -= Common::KEYCODE_F1;
+
+				if (_buttonValue < (int)(_vm->_mode == MODE_COMBAT ?
+						combat._combatParty.size() : party._activeParty.size())) {
+					// Character number is valid
+					redrawFlag = REDRAW_TEXT;
+					Character *newChar = _vm->_mode == MODE_COMBAT ?
+						combat._combatParty[_buttonValue] : &party._activeParty[_buttonValue];
+
+					if (mode == ITEMMODE_BLACKSMITH) {
+						_oldCharacter = newChar;
+						startingChar = newChar;
+						c = &_itemsCharacter;
+					} else if (mode != ITEMMODE_2 && mode != ITEMMODE_REPAIR
+							&& mode != ITEMMODE_IDENTIFY && itemIndex != -1) {
+						InventoryItems &destItems = newChar->_items[category];
+						XeenItem &destItem = destItems[INV_ITEMS_TOTAL - 1];
+						InventoryItems &srcItems = c->_items[category];
+						XeenItem &srcItem = srcItems[itemIndex];
+
+						if (srcItem._bonusFlags & ITEMFLAG_CURSED)
+							ErrorScroll::show(_vm, Res.CANNOT_REMOVE_CURSED_ITEM);
+						else if (destItems[INV_ITEMS_TOTAL - 1]._id)
+							ErrorScroll::show(_vm, Common::String::format(
+								Res.CATEGORY_BACKPACK_IS_FULL[category], c->_name.c_str()));
+						else {
+							destItem = srcItem;
+							srcItem.clear();
+							destItem._frame = 0;
+
+							srcItems.sort();
+							destItems.sort();
+						}
+
+						continue;
+					}
+
+					c = newChar;
+					startingChar = newChar;
+					intf.highlightChar(_buttonValue);
+				}
+			}
+			break;
+
+		case Common::KEYCODE_1:
+		case Common::KEYCODE_2:
+		case Common::KEYCODE_3:
+		case Common::KEYCODE_4:
+		case Common::KEYCODE_5:
+		case Common::KEYCODE_6:
+		case Common::KEYCODE_7:
+		case Common::KEYCODE_8:
+		case Common::KEYCODE_9:
+			// Select an item
+			if (mode == ITEMMODE_3)
+				break;
+
+			_buttonValue -= Common::KEYCODE_1;
+			if (_buttonValue != itemIndex) {
+				// Check whether the new selection has an associated item
+				if (!c->_items[category][_buttonValue].empty()) {
+					itemIndex = _buttonValue;
+					Common::fill(&arr[0], &arr[40], 0);
+					arr[itemIndex] = 15;
+				}
+
+				redrawFlag = REDRAW_TEXT;
+			}
+			break;
+
+		case Common::KEYCODE_a:
+			// Armor category
+			category = CATEGORY_ARMOR;
+			redrawFlag = REDRAW_FULL;
+			break;
+
+		case Common::KEYCODE_b:
+			// Buy
+			if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
+					mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
+				mode = ITEMMODE_BLACKSMITH;
+				c = &_itemsCharacter;
+				redrawFlag = REDRAW_FULL;
+			}
+			break;
+
+		case Common::KEYCODE_c:
+			// Accessories category
+			category = CATEGORY_ACCESSORY;
+			redrawFlag = REDRAW_FULL;
+			break;
+
+		case Common::KEYCODE_d:
+			if (mode == ITEMMODE_CHAR_INFO)
+				actionIndex = 3;
+			break;
+
+		case Common::KEYCODE_e:
+			if (mode == ITEMMODE_CHAR_INFO || mode == ITEMMODE_ENCHANT ||
+					mode == ITEMMODE_TO_GOLD) {
+				if (category != CATEGORY_MISC) {
+					actionIndex = mode == ITEMMODE_ENCHANT ? 4 : 0;
+				}
+			}
+			break;
+
+		case Common::KEYCODE_f:
+			if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
+					mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
+				mode = ITEMMODE_REPAIR;
+				c = startingChar;
+				redrawFlag = REDRAW_TEXT;
+			}
+			break;
+
+		case Common::KEYCODE_g:
+			if (mode == ITEMMODE_TO_GOLD)
+				actionIndex = 6;
+			break;
+
+		case Common::KEYCODE_i:
+			if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
+					mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
+				mode = ITEMMODE_IDENTIFY;
+				c = startingChar;
+				redrawFlag = REDRAW_TEXT;
+			}
+			break;
+
+		case Common::KEYCODE_m:
+			// Misc
+			category = CATEGORY_MISC;
+			redrawFlag = REDRAW_TEXT;
+			break;
+
+		case Common::KEYCODE_q:
+			// Quests
+			if (mode == ITEMMODE_CHAR_INFO) {
+				Quests::show(_vm);
+				redrawFlag = REDRAW_FULL;
+			}
+			break;
+
+		case Common::KEYCODE_r:
+			if (mode == ITEMMODE_CHAR_INFO)
+				actionIndex = 1;
+			else if (mode == ITEMMODE_RECHARGE)
+				actionIndex = 5;
+			break;
+
+		case Common::KEYCODE_s:
+			if (mode != ITEMMODE_CHAR_INFO && mode != ITEMMODE_RECHARGE &&
+					mode != ITEMMODE_ENCHANT && mode != ITEMMODE_TO_GOLD) {
+				mode = ITEMMODE_2;
+				c = startingChar;
+				redrawFlag = REDRAW_TEXT;
+			}
+			break;
+
+		case Common::KEYCODE_u:
+			if (mode == ITEMMODE_CHAR_INFO && category == CATEGORY_MISC)
+				actionIndex = 2;
+			break;
+
+		case Common::KEYCODE_w:
+			// Weapons category
+			category = CATEGORY_WEAPON;
+			redrawFlag = REDRAW_TEXT;
+			break;
+		}
+	}
+
+	windows[30].close();
+	windows[29].close();
+
+	intf.drawParty(true);
+	if (updateStock)
+		charData2BlackData();
+
+	return c;
+}
+
+void ItemsDialog::loadButtons(ItemsMode mode, Character *&c) {
+	_iconSprites.load(Common::String::format("%s.icn",
+		(mode == ITEMMODE_CHAR_INFO) ? "items" : "buy"));
+	_equipSprites.load("equip.icn");
+
+	if (mode == ITEMMODE_ENCHANT || mode == ITEMMODE_RECHARGE || mode == ITEMMODE_TO_GOLD) {
+		// Enchant button list
+		addButton(Common::Rect(12, 109, 36, 129), Common::KEYCODE_w, &_iconSprites);
+		addButton(Common::Rect(46, 109, 70, 129), Common::KEYCODE_a, &_iconSprites);
+		addButton(Common::Rect(80, 109, 104, 129), Common::KEYCODE_c, &_iconSprites);
+		addButton(Common::Rect(114, 109, 138, 129), Common::KEYCODE_m, &_iconSprites);
+		addButton(Common::Rect(148, 109, 172, 129), Common::KEYCODE_e, &_iconSprites);
+		addButton(Common::Rect(284, 109, 308, 129), Common::KEYCODE_ESCAPE, &_iconSprites);
+		addButton(Common::Rect(148, 109, 172, 129), Common::KEYCODE_u, &_iconSprites);
+		addButton(Common::Rect(8, 20, 263, 28), Common::KEYCODE_1);
+		addButton(Common::Rect(8, 29, 263, 37), Common::KEYCODE_2);
+		addButton(Common::Rect(8, 38, 263, 46), Common::KEYCODE_3);
+		addButton(Common::Rect(8, 47, 263, 55), Common::KEYCODE_4);
+		addButton(Common::Rect(8, 56, 263, 64), Common::KEYCODE_5);
+		addButton(Common::Rect(8, 65, 263, 73), Common::KEYCODE_6);
+		addButton(Common::Rect(8, 74, 263, 82), Common::KEYCODE_7);
+		addButton(Common::Rect(8, 83, 263, 91), Common::KEYCODE_8);
+		addButton(Common::Rect(8, 92, 263, 100), Common::KEYCODE_9);
+	} else {
+		addButton(Common::Rect(12, 109, 36, 129), Common::KEYCODE_w, &_iconSprites);
+		addButton(Common::Rect(46, 109, 70, 129), Common::KEYCODE_a, &_iconSprites);
+		addButton(Common::Rect(80, 109, 104, 129), Common::KEYCODE_c, &_iconSprites);
+		addButton(Common::Rect(114, 109, 138, 129), Common::KEYCODE_m, &_iconSprites);
+		addButton(Common::Rect(148, 109, 172, 129), Common::KEYCODE_e, &_iconSprites);
+		addButton(Common::Rect(182, 109, 206, 129), Common::KEYCODE_r, &_iconSprites);
+		addButton(Common::Rect(216, 109, 240, 129), Common::KEYCODE_d, &_iconSprites);
+		addButton(Common::Rect(250, 109, 274, 129), Common::KEYCODE_q, &_iconSprites);
+		addButton(Common::Rect(284, 109, 308, 129), Common::KEYCODE_ESCAPE, &_iconSprites);
+		addButton(Common::Rect(8, 20, 263, 28), Common::KEYCODE_1);
+		addButton(Common::Rect(8, 29, 263, 37), Common::KEYCODE_2);
+		addButton(Common::Rect(8, 38, 263, 46), Common::KEYCODE_3);
+		addButton(Common::Rect(8, 47, 263, 55), Common::KEYCODE_4);
+		addButton(Common::Rect(8, 56, 263, 64), Common::KEYCODE_5);
+		addButton(Common::Rect(8, 65, 263, 73), Common::KEYCODE_6);
+		addButton(Common::Rect(8, 74, 263, 82), Common::KEYCODE_7);
+		addButton(Common::Rect(8, 83, 263, 91), Common::KEYCODE_8);
+		addButton(Common::Rect(8, 92, 263, 100), Common::KEYCODE_9);
+		addPartyButtons(_vm);
+	}
+
+	if (mode == ITEMMODE_BLACKSMITH) {
+		_oldCharacter = c;
+		c = &_itemsCharacter;
+		blackData2CharData();
+
+		_buttons[4]._value = Common::KEYCODE_b;
+		_buttons[5]._value = Common::KEYCODE_s;
+		_buttons[6]._value = Common::KEYCODE_i;
+		_buttons[7]._value = Common::KEYCODE_f;
+
+		setEquipmentIcons();
+	} else {
+		_buttons[4]._value = Common::KEYCODE_e;
+		_buttons[5]._value = Common::KEYCODE_r;
+		_buttons[6]._value = Common::KEYCODE_d;
+		_buttons[7]._value = Common::KEYCODE_q;
+	}
+}
+
+void ItemsDialog::blackData2CharData() {
+	Party &party = *_vm->_party;
+	bool isDarkCc = _vm->_files->_isDarkCc;
+	int slotIndex = 0;
+	while (slotIndex < 4 && party._mazeId != (int)Res.BLACKSMITH_MAP_IDS[isDarkCc][slotIndex])
+		++slotIndex;
+	if (slotIndex == 4)
+		slotIndex = 0;
+
+	for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+		_itemsCharacter._weapons[idx] = party._blacksmithWeapons[isDarkCc][idx];
+		_itemsCharacter._armor[idx] = party._blacksmithArmor[isDarkCc][idx];
+		_itemsCharacter._accessories[idx] = party._blacksmithAccessories[isDarkCc][idx];
+		_itemsCharacter._misc[idx] = party._blacksmithMisc[isDarkCc][idx];
+	}
+}
+
+void ItemsDialog::charData2BlackData() {
+	Party &party = *_vm->_party;
+	bool isDarkCc = _vm->_files->_isDarkCc;
+	int slotIndex = 0;
+	while (slotIndex < 4 && party._mazeId != (int)Res.BLACKSMITH_MAP_IDS[isDarkCc][slotIndex])
+		++slotIndex;
+	if (slotIndex == 4)
+		slotIndex = 0;
+
+	for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+		party._blacksmithWeapons[isDarkCc][idx] = _itemsCharacter._weapons[idx];
+		party._blacksmithArmor[isDarkCc][idx] = _itemsCharacter._armor[idx];
+		party._blacksmithAccessories[isDarkCc][idx] = _itemsCharacter._accessories[idx];
+		party._blacksmithMisc[isDarkCc][idx] = _itemsCharacter._misc[idx];
+	}
+}
+
+void ItemsDialog::setEquipmentIcons() {
+	for (int typeIndex = 0; typeIndex < 4; ++typeIndex) {
+		for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+			switch (typeIndex) {
+			case CATEGORY_WEAPON: {
+				XeenItem &i = _itemsCharacter._weapons[idx];
+				if (i._id <= 17)
+					i._frame = 1;
+				else if (i._id <= 29 || i._id > 33)
+					i._frame = 13;
+				else
+					i._frame = 4;
+				break;
+			}
+
+			case CATEGORY_ARMOR: {
+				XeenItem &i = _itemsCharacter._armor[idx];
+				if (i._id <= 7)
+					i._frame = 3;
+				else if (i._id == 9)
+					i._frame = 5;
+				else if (i._id == 10)
+					i._frame = 9;
+				else if (i._id <= 12)
+					i._frame = 10;
+				else
+					i._frame = 6;
+				break;
+			}
+
+			case CATEGORY_ACCESSORY: {
+				XeenItem &i = _itemsCharacter._accessories[idx];
+				if (i._id == 1)
+					i._id = 8;
+				else if (i._id == 2)
+					i._frame = 12;
+				else if (i._id <= 7)
+					i._frame = 7;
+				else
+					i._frame = 11;
+				break;
+			}
+
+			default:
+				break;
+			}
+		}
+	}
+}
+
+int ItemsDialog::calcItemCost(Character *c, int itemIndex, ItemsMode mode,
+		int skillLevel, ItemCategory category) {
+	int amount1 = 0, amount2 = 0, amount3 = 0, amount4 = 0;
+	int result = 0;
+	int level = skillLevel & 0x7f;
+
+	InventoryItems *invGroups[4] = {
+		&c->_weapons, &c->_armor, &c->_accessories, &c->_misc
+	};
+	const int *BASE_COSTS[4] = {
+		Res.WEAPON_BASE_COSTS, Res.ARMOR_BASE_COSTS, Res.ACCESSORY_BASE_COSTS, Res.MISC_BASE_COSTS
+	};
+
+	switch (mode) {
+	case ITEMMODE_BLACKSMITH:
+		level = 0;
+		break;
+	case ITEMMODE_2:
+	case ITEMMODE_TO_GOLD:
+		level = level == 0 ? 1 : 0;
+		break;
+	case ITEMMODE_IDENTIFY:
+		level = 2;
+		break;
+	case ITEMMODE_REPAIR:
+		level = 3;
+		break;
+	default:
+		break;
+	}
+
+	switch (category) {
+	case CATEGORY_WEAPON:
+	case CATEGORY_ARMOR:
+	case CATEGORY_ACCESSORY: {
+		XeenItem &i = (*invGroups[category])[itemIndex];
+		amount1 = (BASE_COSTS[category])[i._id];
+
+		if (i._material > 36 && i._material < 59) {
+			switch (i._material) {
+			case 37:
+				amount1 /= 10;
+				break;
+			case 38:
+				amount1 /= 4;
+				break;
+			case 39:
+				amount1 /= 2;
+				break;
+			case 40:
+				amount1 /= 4;
+				break;
+			default:
+				amount1 *= Res.METAL_BASE_MULTIPLIERS[i._material - 37];
+				break;
+			}
+		}
+
+		if (i._material < 37)
+			amount2 = Res.ELEMENTAL_DAMAGE[i._material] * 100;
+		else if (i._material > 58)
+			amount3 = Res.ELEMENTAL_DAMAGE[i._material - 59 + 7] * 100;
+
+		switch (mode) {
+		case ITEMMODE_BLACKSMITH:
+		case ITEMMODE_2:
+		case ITEMMODE_REPAIR:
+		case ITEMMODE_IDENTIFY:
+		case ITEMMODE_TO_GOLD:
+			result = (amount1 + amount2 + amount3 + amount4) / Res.ITEM_SKILL_DIVISORS[level];
+			if (!result)
+				result = 1;
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+
+	case CATEGORY_MISC: {
+		// Misc
+		XeenItem &i = c->_misc[itemIndex];
+		amount1 = Res.MISC_MATERIAL_COSTS[i._material];
+		amount4 = Res.MISC_BASE_COSTS[i._id];
+
+		switch (mode) {
+		case ITEMMODE_BLACKSMITH:
+		case ITEMMODE_2:
+		case ITEMMODE_REPAIR:
+		case ITEMMODE_IDENTIFY:
+		case ITEMMODE_TO_GOLD:
+			result = (amount1 + amount2 + amount3 + amount4) / Res.ITEM_SKILL_DIVISORS[level];
+			if (!result)
+				result = 1;
+			break;
+		default:
+			break;
+		}
+		break;
+	}
+
+	default:
+		break;
+	}
+
+	return (mode == ITEMMODE_CHAR_INFO) ? 0 : result;
+}
+
+int ItemsDialog::doItemOptions(Character &c, int actionIndex, int itemIndex, ItemCategory category,
+		ItemsMode mode) {
+	Combat &combat = *_vm->_combat;
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Sound &sound = *_vm->_sound;
+	Spells &spells = *_vm->_spells;
+	Windows &windows = *_vm->_windows;
+	bool isDarkCc = _vm->_files->_isDarkCc;
+
+	XeenItem *itemCategories[4] = { &c._weapons[0], &c._armor[0], &c._accessories[0], &c._misc[0] };
+	XeenItem *items = itemCategories[category];
+	if (!items[0]._id)
+		// Inventory is empty
+		return category == CATEGORY_MISC ? 0 : 2;
+
+	Window &w = windows[11];
+	SpriteResource escSprites;
+	if (itemIndex < 0 || itemIndex > 8) {
+		saveButtons();
+
+		escSprites.load("esc.icn");
+		addButton(Common::Rect(235, 111, 259, 131), Common::KEYCODE_ESCAPE, &escSprites);
+		addButton(Common::Rect(8, 20, 263, 28), Common::KEYCODE_1);
+		addButton(Common::Rect(8, 29, 263, 37), Common::KEYCODE_2);
+		addButton(Common::Rect(8, 38, 263, 46), Common::KEYCODE_3);
+		addButton(Common::Rect(8, 47, 263, 55), Common::KEYCODE_4);
+		addButton(Common::Rect(8, 56, 263, 64), Common::KEYCODE_5);
+		addButton(Common::Rect(8, 65, 263, 73), Common::KEYCODE_6);
+		addButton(Common::Rect(8, 74, 263, 82), Common::KEYCODE_7);
+		addButton(Common::Rect(8, 83, 263, 91), Common::KEYCODE_8);
+		addButton(Common::Rect(8, 92, 263, 100), Common::KEYCODE_9);
+
+		w.open();
+		w.writeString(Common::String::format(Res.WHICH_ITEM, Res.ITEM_ACTIONS[actionIndex]));
+		_iconSprites.draw(0, 0, Common::Point(235, 111));
+		w.update();
+
+		while (!_vm->shouldExit()) {
+			while (!_buttonValue) {
+				events.pollEventsAndWait();
+				checkEvents(_vm);
+				if (_vm->shouldExit())
+					return false;
+			}
+
+			if (_buttonValue == Common::KEYCODE_ESCAPE) {
+				itemIndex = -1;
+				break;
+			} else if (_buttonValue >= Common::KEYCODE_1 && _buttonValue <= Common::KEYCODE_9) {
+				// Check whether there's an item at the selected index
+				int selectedIndex = _buttonValue - Common::KEYCODE_1;
+				if (!items[selectedIndex]._id)
+					continue;
+
+				itemIndex = selectedIndex;
+				break;
+			}
+		}
+
+		w.close();
+		restoreButtons();
+	}
+
+	if (itemIndex != -1) {
+		XeenItem &item = c._items[category][itemIndex];
+
+		switch (mode) {
+		case ITEMMODE_CHAR_INFO:
+		case ITEMMODE_8:
+			switch (actionIndex) {
+			case 0:
+				c._items[category].equipItem(itemIndex);
+				break;
+			case 1:
+				c._items[category].removeItem(itemIndex);
+				break;
+			case 2:
+				if (!party._mazeId) {
+					ErrorScroll::show(_vm, Res.WHATS_YOUR_HURRY);
+				} else {
+					XeenItem &i = c._misc[itemIndex];
+
+					Condition condition = c.worstCondition();
+					switch (condition) {
+					case ASLEEP:
+					case PARALYZED:
+					case UNCONSCIOUS:
+					case DEAD:
+					case STONED:
+					case ERADICATED:
+						ErrorScroll::show(_vm, Common::String::format(Res.IN_NO_CONDITION, c._name.c_str()));
+						break;
+					default:
+						if (combat._itemFlag) {
+							ErrorScroll::show(_vm, Res.USE_ITEM_IN_COMBAT);
+						} else if (i._id && (i._bonusFlags & ITEMFLAG_BONUS_MASK)
+								&& !(i._bonusFlags & (ITEMFLAG_BROKEN | ITEMFLAG_CURSED))) {
+							int charges = (i._bonusFlags & ITEMFLAG_BONUS_MASK) - 1;
+							i._bonusFlags = charges;
+							_oldCharacter = &c;
+
+							windows[30].close();
+							windows[29].close();
+							windows[24].close();
+							spells.castItemSpell(i._id);
+
+							if (!charges) {
+								// Ran out of charges, so make item disappear
+								c._items[category][itemIndex].clear();
+								c._items[category].sort();
+							}
+						} else {
+							ErrorScroll::show(_vm, Common::String::format(Res.NO_SPECIAL_ABILITIES,
+								c._items[category].getFullDescription(itemIndex).c_str()
+							));
+						}
+					}
+				}
+				break;
+			case 3:
+				c._items[category].discardItem(itemIndex);
+				break;
+			default:
+				break;
+			}
+			break;
+
+		case ITEMMODE_BLACKSMITH: {
+			InventoryItems &invItems = _oldCharacter->_items[category];
+			if (invItems[INV_ITEMS_TOTAL - 1]._id) {
+				// If the last slot is in use, it means the list is full
+				ErrorScroll::show(_vm, Common::String::format(Res.BACKPACK_IS_FULL,
+					_oldCharacter->_name.c_str()));
+			} else {
+				int cost = calcItemCost(_oldCharacter, itemIndex, mode, 0, category);
+				Common::String desc = c._items[category].getFullDescription(itemIndex);
+				if (Confirm::show(_vm, Common::String::format(Res.BUY_X_FOR_Y_GOLD,
+						desc.c_str(), cost))) {
+					if (party.subtract(CONS_GOLD, cost, WHERE_PARTY, WT_FREEZE_WAIT)) {
+						if (isDarkCc) {
+							sound.stopSound();
+							sound.playSound("choice2.voc");
+						}
+
+						// Add entry to the end of the list
+						_oldCharacter->_items[category][8] = c._items[category][itemIndex];
+						_oldCharacter->_items[category][8]._frame = 0;
+						c._items[category].clear();
+						c._items[category].sort();
+						_oldCharacter->_items[category].sort();
+					}
+				}
+			}
+			return 0;
+		}
+
+		case ITEMMODE_2: {
+			bool noNeed;
+			switch (category) {
+			case CATEGORY_WEAPON:
+				noNeed = (item._bonusFlags & ITEMFLAG_CURSED) || item._id == 34;
+				break;
+			default:
+				noNeed = item._bonusFlags & ITEMFLAG_CURSED;
+				break;
+			}
+
+			if (noNeed) {
+				ErrorScroll::show(_vm, Common::String::format(Res.NO_NEED_OF_THIS,
+					c._items[category].getFullDescription(itemIndex).c_str()));
+			} else {
+				int cost = calcItemCost(&c, itemIndex, mode, c._skills[MERCHANT], category);
+				Common::String desc = c._items[category].getFullDescription(itemIndex);
+				Common::String msg = Common::String::format(Res.SELL_X_FOR_Y_GOLD,
+					desc.c_str(), cost);
+
+				if (Confirm::show(_vm, msg)) {
+					// Remove the sold item and add gold to the party's total
+					item.clear();
+					c._items[category].sort();
+
+					party._gold += cost;
+				}
+			}
+			return 0;
+		}
+
+		case ITEMMODE_RECHARGE:
+			if (category != CATEGORY_MISC || c._misc[itemIndex]._material > 9
+					|| c._misc[itemIndex]._id == 53 || c._misc[itemIndex]._id == 0) {
+				sound.playFX(21);
+				ErrorScroll::show(_vm, Common::String::format(Res.NOT_RECHARGABLE, Res.SPELL_FAILED));
+			} else {
+				int charges = MIN(63, _vm->getRandomNumber(1, 6) +
+					(c._misc[itemIndex]._bonusFlags & ITEMFLAG_BONUS_MASK));
+				sound.playFX(20);
+
+				c._misc[itemIndex]._bonusFlags = (c._misc[itemIndex]._bonusFlags
+					& ~ITEMFLAG_BONUS_MASK) | charges;
+			}
+			return 2;
+
+		case ITEMMODE_ENCHANT: {
+			int amount = _vm->getRandomNumber(1, _oldCharacter->getCurrentLevel() / 5 + 1);
+			amount = MIN(amount, 5);
+			_oldCharacter->_items[category].enchantItem(itemIndex, amount);
+			break;
+		}
+
+		case ITEMMODE_REPAIR:
+			if (!(item._bonusFlags & ITEMFLAG_BROKEN)) {
+				ErrorScroll::show(_vm, Res.ITEM_NOT_BROKEN);
+			} else {
+				int cost = calcItemCost(&c, itemIndex, mode, actionIndex, category);
+				Common::String msg = Common::String::format(Res.FIX_IDENTIFY_GOLD,
+					Res.FIX_IDENTIFY[0],
+					c._items[category].getFullDescription(itemIndex).c_str(),
+					cost);
+
+				if (Confirm::show(_vm, msg) && party.subtract(CONS_GOLD, cost, WHERE_PARTY)) {
+					item._bonusFlags &= ~ITEMFLAG_BROKEN;
+				}
+			}
+			break;
+
+		case ITEMMODE_IDENTIFY: {
+			int cost = calcItemCost(&c, itemIndex, mode, actionIndex, category);
+			Common::String msg = Common::String::format(Res.FIX_IDENTIFY_GOLD,
+				Res.FIX_IDENTIFY[1],
+				c._items[category].getFullDescription(itemIndex).c_str(),
+				cost);
+
+			if (Confirm::show(_vm, msg) && party.subtract(CONS_GOLD, cost, WHERE_PARTY)) {
+				Common::String details = c._items[category].getIdentifiedDetails(itemIndex);
+				Common::String desc = c._items[category].getFullDescription(itemIndex);
+				Common::String str = Common::String::format(Res.IDENTIFY_ITEM_MSG,
+					desc.c_str(), details.c_str());
+
+				Window &win = windows[14];
+				win.open();
+				win.writeString(str);
+				win.update();
+
+				saveButtons();
+				clearButtons();
+
+				while (!_vm->shouldExit() && !events.isKeyMousePressed())
+					events.pollEventsAndWait();
+				events.clearEvents();
+
+				restoreButtons();
+				win.close();
+			}
+			break;
+		}
+
+		case ITEMMODE_TO_GOLD:
+			// Convert item in inventory to gold
+			itemToGold(c, itemIndex, category, mode);
+			return 2;
+
+		default:
+			break;
+		}
+	}
+
+	intf._charsShooting = false;
+	combat.moveMonsters();
+	combat._whosTurn = -1;
+	return true;
+}
+
+void ItemsDialog::itemToGold(Character &c, int itemIndex, ItemCategory category,
+		ItemsMode mode) {
+	XeenItem &item = c._items[category][itemIndex];
+	Party &party = *_vm->_party;
+	Sound &sound = *_vm->_sound;
+
+	if (category == CATEGORY_WEAPON && item._id == 34) {
+		sound.playFX(21);
+		ErrorScroll::show(_vm, Common::String::format("\v012\t000\x03""c%s",
+			Res.SPELL_FAILED));
+	} else if (item._id != 0) {
+		// There is a valid item present
+		// Calculate cost of item and add it to the party's total
+		int cost = calcItemCost(&c, itemIndex, mode, 1, category);
+		party._gold += cost;
+
+		// Remove the item from the inventory
+		item.clear();
+		c._items[category].sort();
+	}
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_items.h b/engines/xeen/dialogs/dialogs_items.h
new file mode 100644
index 0000000..b9af06e
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_items.h
@@ -0,0 +1,89 @@
+/* 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 XEEN_DIALOGS_ITEMS_H
+#define XEEN_DIALOGS_ITEMS_H
+
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/party.h"
+#include "xeen/window.h"
+
+namespace Xeen {
+
+enum ItemsMode {
+	ITEMMODE_CHAR_INFO = 0, ITEMMODE_BLACKSMITH = 1, ITEMMODE_2 = 2, ITEMMODE_3 = 3,
+	ITEMMODE_RECHARGE = 4, ITEMMODE_5 = 5, ITEMMODE_ENCHANT = 6, ITEMMODE_COMBAT = 7, ITEMMODE_8 = 8,
+	ITEMMODE_REPAIR = 9, ITEMMODE_IDENTIFY = 10, ITEMMODE_TO_GOLD = 11
+};
+
+class ItemsDialog : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+	SpriteResource _equipSprites;
+	Character _itemsCharacter;
+	Character *_oldCharacter;
+	DrawStruct _itemsDrawList[INV_ITEMS_TOTAL];
+
+	ItemsDialog(XeenEngine *vm) : ButtonContainer(vm), _oldCharacter(nullptr) {}
+
+	Character *execute(Character *c, ItemsMode mode);
+
+	/**
+	 * Load the buttons for the dialog
+	 */
+	void loadButtons(ItemsMode mode, Character *&c);
+
+	/**
+	 * Loads the temporary _itemsCharacter character with the item set
+	 * the given blacksmith has available, so the user can "view" the
+	 * set as if it were a standard character's inventory
+	 */
+	void blackData2CharData();
+
+	/**
+	 * Saves the inventory from the temporary _itemsCharacter character back into the
+	 * blacksmith storage, so changes in blacksmith inventory remain persistent
+	 */
+	void charData2BlackData();
+
+	/**
+	 * Sets the equipment icon to use for each item for display
+	 */
+	void setEquipmentIcons();
+
+	/**
+	 * Calculate the cost of an item
+	 */
+	int calcItemCost(Character *c, int itemIndex, ItemsMode mode, int skillLevel,
+		ItemCategory category);
+
+	int doItemOptions(Character &c, int actionIndex, int itemIndex,
+		ItemCategory category, ItemsMode mode);
+
+	void itemToGold(Character &c, int itemIndex, ItemCategory category, ItemsMode mode);
+public:
+	static Character *show(XeenEngine *vm, Character *c, ItemsMode mode);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_ITEMS_H */
diff --git a/engines/xeen/dialogs/dialogs_map.cpp b/engines/xeen/dialogs/dialogs_map.cpp
new file mode 100644
index 0000000..b822c71
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_map.cpp
@@ -0,0 +1,461 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "xeen/dialogs/dialogs_map.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+#define MAP_SIZE 16
+#define MAP_DIFF (MAP_SIZE / 2)
+#define MAP_XSTART 80
+#define MAP_YSTART 38
+#define TILE_WIDTH 10
+#define TILE_HEIGHT 8
+
+void MapDialog::show(XeenEngine *vm) {
+	MapDialog *dlg = new MapDialog(vm);
+	dlg->execute();
+	delete dlg;
+}
+
+void MapDialog::execute() {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Map &map = *_vm->_map;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+
+	_pt = party._mazePosition;
+	_globalSprites.load("global.icn");
+
+	if (_pt.x < 8 && map.mazeData()._surroundingMazes._west == 0) {
+		_arrowPt.x = _pt.x * 10 + 4;
+		_pt.x = 7;
+	} else if (_pt.x > 23) {
+		_arrowPt.x = (byte)(_pt.x * 10 + 100);
+		_pt.x = 23;
+	} else if (_pt.x > 8 && map.mazeData()._surroundingMazes._east == 0) {
+		_arrowPt.x = (byte)(_pt.x * 10 + 4);
+		_pt.x = 7;
+	} else {
+		_arrowPt.x = 74;
+	}
+
+	if (_pt.y < 8 && map.mazeData()._surroundingMazes._south == 0) {
+		_arrowPt.y = ((15 - _pt.y) << 3) + 13;
+		_pt.y = 8;
+	} else if (_pt.y > 24) {
+		_arrowPt.y = ((15 - (_pt.y - 16)) << 3) + 13;
+		_pt.y = 24;
+	} else if (_pt.y >= 8 && map.mazeData()._surroundingMazes._north == 0) {
+		_arrowPt.y = ((15 - _pt.y) << 3) + 13;
+		_pt.y = 8;
+	} else {
+		_arrowPt.y = 69;
+	}
+
+	windows[5].open();
+	bool drawFlag = true;
+
+	events.updateGameCounter();
+	do {
+		if (drawFlag)
+			intf.draw3d(false, false);
+		windows[5].writeString("\r");
+
+		if (map._isOutdoors)
+			drawOutdoors();
+		else
+			drawIndoors();
+
+		windows[5].frame();
+		if (!map._isOutdoors) {
+			map._tileSprites.draw(0, 52, Common::Point(76, 30));
+		} else if (_frameEndFlag) {
+			_globalSprites.draw(0, party._mazeDirection + 1,
+				Common::Point(_arrowPt.x + 76, _arrowPt.y + 25));
+		}
+
+		if (events.timeElapsed() > 5) {
+			// Set the flag to make the basic arrow blinking effect
+			_frameEndFlag = !_frameEndFlag;
+			events.updateGameCounter();
+		}
+
+		windows[5].writeString(Common::String::format(Res.MAP_TEXT,
+			map._mazeName.c_str(), party._mazePosition.x,
+			party._mazePosition.y, Res.DIRECTION_TEXT[party._mazeDirection]));
+		windows[5].update();
+		windows[3].update();
+
+		events.ipause5(2);
+		drawFlag = false;
+	} while (!_vm->shouldExit() && !events.isKeyMousePressed());
+
+	events.clearEvents();
+	windows[5].close();
+}
+
+void MapDialog::drawOutdoors() {
+	Map &map = *g_vm->_map;
+	int v, frame;
+
+	// Draw outdoors map
+	for (int yp = MAP_YSTART, mazeY = _pt.y + MAP_DIFF - 1; mazeY >= (_pt.y - MAP_DIFF);
+			--mazeY, yp += TILE_HEIGHT) {
+		for (int xp = MAP_XSTART, mazeX = _pt.x - (MAP_DIFF - 1); mazeX <= (_pt.x + MAP_DIFF);
+				xp += TILE_WIDTH, ++mazeX) {
+			v = map.mazeLookup(Common::Point(mazeX, mazeY), 0);
+			assert(v != INVALID_CELL);
+			frame = map.mazeDataCurrent()._surfaceTypes[v];
+
+			if (map._currentSteppedOn) {
+				map._tileSprites.draw(0, frame, Common::Point(xp, yp));
+			}
+		}
+	}
+
+	for (int yp = MAP_YSTART, mazeY = _pt.y + MAP_DIFF - 1; mazeY >= (_pt.y - MAP_DIFF);
+			--mazeY, yp += TILE_HEIGHT) {
+		for (int xp = MAP_XSTART, mazeX = _pt.x - (MAP_DIFF - 1); mazeX <= (_pt.x + MAP_DIFF);
+				xp += TILE_WIDTH, ++mazeX) {
+			v = map.mazeLookup(Common::Point(mazeX, mazeY), 4);
+			assert(v != INVALID_CELL);
+			frame = map.mazeDataCurrent()._wallTypes[v];
+
+			if (frame && map._currentSteppedOn)
+				map._tileSprites.draw(0, frame + 16, Common::Point(xp, yp));
+		}
+	}
+
+	for (int yp = MAP_YSTART, mazeY = _pt.y + MAP_DIFF - 1; mazeY >= (_pt.y - MAP_DIFF);
+			--mazeY, yp += TILE_HEIGHT) {
+		for (int xp = MAP_XSTART, mazeX = _pt.x - (MAP_DIFF - 1); mazeX <= (_pt.x + MAP_DIFF);
+				xp += TILE_WIDTH, ++mazeX) {
+			frame = map.mazeLookup(Common::Point(mazeX, mazeY), 8, 0xff);
+
+			if (frame && map._currentSteppedOn)
+				map._tileSprites.draw(0, frame + 32, Common::Point(xp, yp));
+		}
+	}
+}
+
+void MapDialog::drawIndoors() {
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+	int v, frame;
+	int frame2 = _animFrame;
+	_animFrame = (_animFrame + 2) % 8;
+
+	// Draw indoors map
+	frame2 = (frame2 + 2) % 8;
+
+	// Draw default ground for all the valid explored areas
+	for (int yp = MAP_YSTART, mazeY = _pt.y + MAP_DIFF - 1; mazeY >= (_pt.y - MAP_DIFF);
+			yp += TILE_HEIGHT, --mazeY) {
+		for (int xp = MAP_XSTART, mazeX = _pt.x - (MAP_DIFF - 1); mazeX <= (_pt.x + MAP_DIFF);
+				xp += TILE_WIDTH, ++mazeX) {
+			v = map.mazeLookup(Common::Point(mazeX, mazeY), 0, 0xffff);
+
+			if (v != INVALID_CELL && map._currentSteppedOn)
+				map._tileSprites.draw(0, 0, Common::Point(xp, yp));
+		}
+	}
+
+	// Draw thinner ground tiles on the left edge of the map
+	for (int yp = MAP_YSTART + 5, mazeY = _pt.y + MAP_DIFF - 1; mazeY >= (_pt.y - MAP_DIFF);
+			yp += TILE_HEIGHT, --mazeY) {
+		v = map.mazeLookup(Common::Point(_pt.x - 8, mazeY), 0, 0xffff);
+
+		if (v != INVALID_CELL && map._currentSurfaceId != 0 && map._currentSteppedOn)
+			map._tileSprites.draw(0, 36 + map.mazeData()._surfaceTypes[
+				map._currentSurfaceId], Common::Point(75, yp));
+	}
+
+	// Draw thin tile portion on top-left corner of map
+	v = map.mazeLookup(Common::Point(_pt.x - 8, _pt.y + 8), 0, 0xffff);
+	if (v != INVALID_CELL && map._currentSurfaceId != 0 && map._currentSteppedOn)
+		map._tileSprites.draw(0, 36 + map.mazeData()._surfaceTypes[
+			map._currentSurfaceId], Common::Point(75, 35));
+
+	// Draw any thin tiles at the very top of the map
+	for (int xp = MAP_XSTART + 5, mazeX = _pt.x - (MAP_DIFF - 1); mazeX <= (_pt.x + MAP_DIFF);
+			xp += TILE_WIDTH, ++mazeX) {
+		v = map.mazeLookup(Common::Point(mazeX, _pt.y + 8), 0, 0xffff);
+
+		if (v != INVALID_CELL && map._currentSurfaceId != 0 && map._currentSteppedOn)
+			map._tileSprites.draw(0, 36 + map.mazeData()._surfaceTypes[
+				map._currentSurfaceId], Common::Point(xp, 35));
+	}
+
+	// Draw the default ground tiles
+	for (int yp = MAP_YSTART + 5, mazeY = _pt.y + MAP_DIFF - 1; mazeY >= (_pt.y - MAP_DIFF);
+			yp += TILE_HEIGHT, --mazeY) {
+		for (int xp = MAP_XSTART + 5, mazeX = _pt.x - (MAP_DIFF - 1); mazeX <= (_pt.x + MAP_DIFF);
+				xp += TILE_WIDTH, ++mazeX) {
+			v = map.mazeLookup(Common::Point(mazeX, mazeY), 0, 0xffff);
+
+			if (v != INVALID_CELL && map._currentSurfaceId && map._currentSteppedOn)
+				map._tileSprites.draw(0, 36 + map.mazeData()._surfaceTypes[
+					map._currentSurfaceId], Common::Point(xp, yp));
+		}
+	}
+
+	// Draw walls on left and top edges of map
+	for (int xp = MAP_XSTART, yp = MAP_YSTART + (MAP_SIZE - 1) * TILE_HEIGHT,
+			mazeX = _pt.x - (MAP_DIFF - 1), mazeY = _pt.y - MAP_DIFF;
+			mazeX < (_pt.x + MAP_DIFF); xp += TILE_WIDTH, yp -= TILE_HEIGHT, ++mazeX, ++mazeY) {
+		// Draw walls on left edge of map
+		v = map.mazeLookup(Common::Point(_pt.x - 8, mazeY), 12);
+
+		switch (v) {
+		case SURFTYPE_DIRT:
+			frame = 18;
+			break;
+		case SURFTYPE_SNOW:
+			frame = 22;
+			break;
+		case SURFTYPE_SWAMP:
+		case SURFTYPE_CLOUD:
+			frame = 16;
+			break;
+		case SURFTYPE_LAVA:
+		case SURFTYPE_DWATER:
+			frame = 2;
+			break;
+		case SURFTYPE_DESERT:
+			frame = 30;
+			break;
+		case SURFTYPE_ROAD:
+			frame = 32;
+			break;
+		case SURFTYPE_TFLR:
+			frame = 20;
+			break;
+		case SURFTYPE_SKY:
+			frame = 28;
+			break;
+		case SURFTYPE_CROAD:
+			frame = 14;
+			break;
+		case SURFTYPE_SEWER:
+			frame = frame2 + 4;
+			break;
+		case SURFTYPE_SCORCH:
+			frame = 24;
+			break;
+		case SURFTYPE_SPACE:
+			frame = 26;
+			break;
+		default:
+			frame = -1;
+			break;
+		}
+
+		if (frame != -1 && map._currentSteppedOn)
+			map._tileSprites.draw(0, frame, Common::Point(70, yp));
+
+		// Draw walls on top edge of map
+		v = map.mazeLookup(Common::Point(mazeX, _pt.y + 8), 0);
+
+		switch (v) {
+		case SURFTYPE_DIRT:
+			frame = 19;
+			break;
+		case SURFTYPE_GRASS:
+			frame = 35;
+			break;
+		case SURFTYPE_SNOW:
+			frame = 23;
+			break;
+		case SURFTYPE_SWAMP:
+		case SURFTYPE_CLOUD:
+			frame = 17;
+			break;
+		case SURFTYPE_LAVA:
+		case SURFTYPE_DWATER:
+			frame = 3;
+			break;
+		case SURFTYPE_DESERT:
+			frame = 31;
+			break;
+		case SURFTYPE_ROAD:
+			frame = 33;
+			break;
+		case SURFTYPE_TFLR:
+			frame = 21;
+			break;
+		case SURFTYPE_SKY:
+			frame = 29;
+			break;
+		case SURFTYPE_CROAD:
+			frame = 15;
+			break;
+		case SURFTYPE_SEWER:
+			frame = frame2 + 5;
+			break;
+		case SURFTYPE_SCORCH:
+			frame = 25;
+			break;
+		case SURFTYPE_SPACE:
+			frame = 27;
+			break;
+		default:
+			frame = -1;
+			break;
+		}
+
+		if (frame != -1 && map._currentSteppedOn)
+			map._tileSprites.draw(0, frame, Common::Point(xp, 30));
+	}
+
+	// Draw the walls for the remaining cells of the minimap
+	for (int yp = MAP_YSTART, mazeY = _pt.y + MAP_DIFF - 1, yCtr = 0; yCtr < MAP_SIZE;
+			yp += TILE_HEIGHT, --mazeY, ++yCtr) {
+		for (int xp = MAP_XSTART, mazeX = _pt.x - (MAP_DIFF - 1), xCtr = 0; xCtr < MAP_SIZE;
+				xp += TILE_WIDTH, ++mazeX, ++xCtr) {
+			// Draw the arrow if at the correct position
+			if ((_arrowPt.x / 10) == xCtr && (14 - (_arrowPt.y / 10)) == yCtr && _frameEndFlag) {
+				_globalSprites.draw(0, party._mazeDirection + 1,
+					Common::Point(_arrowPt.x + 81, _arrowPt.y + 29));
+			}
+
+			v = map.mazeLookup(Common::Point(mazeX, mazeY), 12);
+			switch (v) {
+			case 1:
+				frame = 18;
+				break;
+			case 2:
+				frame = 34;
+				break;
+			case 3:
+				frame = 22;
+				break;
+			case 4:
+			case 13:
+				frame = 16;
+				break;
+			case 5:
+			case 8:
+				frame = 2;
+				break;
+			case 6:
+				frame = 30;
+				break;
+			case 7:
+				frame = 32;
+				break;
+			case 9:
+				frame = 20;
+				break;
+			case 10:
+				frame = 28;
+				break;
+			case 11:
+				frame = 14;
+				break;
+			case 12:
+				frame = frame2 + 4;
+				break;
+			case 14:
+				frame = 24;
+				break;
+			case 15:
+				frame = 26;
+				break;
+			default:
+				frame = -1;
+				break;
+			}
+
+			if (frame != -1 && map._currentSteppedOn)
+				map._tileSprites.draw(0, frame, Common::Point(xp, yp));
+
+			v = map.mazeLookup(Common::Point(mazeX, mazeY), 0);
+			switch (v) {
+			case 1:
+				frame = 19;
+				break;
+			case 2:
+				frame = 35;
+				break;
+			case 3:
+				frame = 23;
+				break;
+			case 4:
+			case 13:
+				frame = 17;
+				break;
+			case 5:
+			case 8:
+				frame = 3;
+				break;
+			case 6:
+				frame = 31;
+				break;
+			case 7:
+				frame = 33;
+				break;
+			case 9:
+				frame = 21;
+				break;
+			case 10:
+				frame = 29;
+				break;
+			case 11:
+				frame = 15;
+				break;
+			case 12:
+				frame = frame2 + 5;
+				break;
+			case 14:
+				frame = 25;
+				break;
+			case 15:
+				frame = 27;
+				break;
+			default:
+				frame = -1;
+				break;
+			}
+
+			if (frame != -1 && map._currentSteppedOn)
+				map._tileSprites.draw(0, frame, Common::Point(xp, yp));
+		}
+	}
+
+	// Draw overlay on cells that haven't been stepped on yet
+	for (int yp = MAP_YSTART, mazeY = _pt.y + MAP_DIFF - 1; mazeY >= (_pt.y - MAP_DIFF);
+			yp += TILE_HEIGHT, --mazeY) {
+		for (int xp = MAP_XSTART, mazeX = _pt.x - (MAP_DIFF - 1); mazeX <= (_pt.x + MAP_DIFF);
+				xp += TILE_WIDTH, ++mazeX) {
+			v = map.mazeLookup(Common::Point(mazeX, mazeY), 0, 0xffff);
+
+			if (v == INVALID_CELL || !map._currentSteppedOn)
+				map._tileSprites.draw(0, 1, Common::Point(xp, yp));
+		}
+	}
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_map.h b/engines/xeen/dialogs/dialogs_map.h
new file mode 100644
index 0000000..5e22e52
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_map.h
@@ -0,0 +1,62 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_MAP_H
+#define XEEN_DIALOGS_MAP_H
+
+#include "xeen/dialogs/dialogs.h"
+
+namespace Xeen {
+
+class XeenEngine;
+
+class MapDialog: public ButtonContainer {
+private:
+	int _animFrame;
+	SpriteResource _globalSprites;
+	Common::Point _pt, _arrowPt;
+	bool _frameEndFlag;
+private:
+	MapDialog(XeenEngine *vm) : ButtonContainer(vm),
+		_animFrame(0), _frameEndFlag(false) {}
+
+	/**
+	 * Draws the map contents when outdoors
+	 */
+	void drawOutdoors();
+
+	/**
+	 * Draws the map contents when indoors
+	 */
+	void drawIndoors();
+
+	/**
+	 * Handles the display of the dialog
+	 */
+	void execute();
+public:
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_AUTOMAP_H */
diff --git a/engines/xeen/dialogs/dialogs_message.cpp b/engines/xeen/dialogs/dialogs_message.cpp
new file mode 100644
index 0000000..df8afea
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_message.cpp
@@ -0,0 +1,123 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "xeen/dialogs/dialogs_message.h"
+#include "xeen/events.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void MessageDialog::show(XeenEngine *vm, const Common::String &msg, MessageWaitType waitType) {
+	MessageDialog *dlg = new MessageDialog(vm);
+	dlg->execute(msg, waitType);
+	delete dlg;
+}
+
+void MessageDialog::execute(const Common::String &msg, MessageWaitType waitType) {
+	EventsManager &events = *_vm->_events;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[6];
+
+	w.open();
+	w.writeString(msg);
+	w.update();
+
+	switch (waitType) {
+	case WT_FREEZE_WAIT:
+		while (!_vm->shouldExit() && !events.isKeyMousePressed())
+			events.pollEventsAndWait();
+
+		events.clearEvents();
+		break;
+
+	case WT_ANIMATED_WAIT:
+		if (windows[11]._enabled || _vm->_mode == MODE_17) {
+			g_vm->_locations->wait();
+			break;
+		}
+		// fall through
+
+	case WT_NONFREEZED_WAIT:
+		do {
+			events.updateGameCounter();
+			_vm->_interface->draw3d(true);
+
+			events.wait(1);
+			if (checkEvents(_vm))
+				break;
+		} while (!_vm->shouldExit() && !_buttonValue);
+		break;
+
+	case WT_LOC_WAIT:
+		g_vm->_locations->wait();
+		break;
+
+	default:
+		break;
+	}
+
+	w.close();
+}
+
+/*------------------------------------------------------------------------*/
+
+void ErrorScroll::show(XeenEngine *vm, const Common::String &msg, MessageWaitType waitType) {
+	Common::String s = Common::String::format("\x3""c\v010\t000%s", msg.c_str());
+	MessageDialog::show(vm, s, waitType);
+}
+
+/*------------------------------------------------------------------------*/
+
+void CantCast::show(XeenEngine *vm, int spellId, int componentNum) {
+	CantCast *dlg = new CantCast(vm);
+	dlg->execute(spellId, componentNum);
+	delete dlg;
+}
+
+void CantCast::execute(int spellId, int componentNum) {
+	EventsManager &events = *_vm->_events;
+	Sound &sound = *_vm->_sound;
+	Spells &spells = *_vm->_spells;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[6];
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = MODE_FF;
+
+	sound.playFX(21);
+	w.open();
+	w.writeString(Common::String::format(Res.NOT_ENOUGH_TO_CAST,
+		Res.SPELL_CAST_COMPONENTS[componentNum - 1],
+		spells._spellNames[spellId].c_str()
+	));
+	w.update();
+
+	do {
+		events.pollEventsAndWait();
+	} while (!_vm->shouldExit() && !events.isKeyMousePressed());
+	events.clearEvents();
+
+	w.close();
+	_vm->_mode = oldMode;
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_message.h b/engines/xeen/dialogs/dialogs_message.h
new file mode 100644
index 0000000..95d9428
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_message.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 XEEN_dialogs_message_H
+#define XEEN_dialogs_message_H
+
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/character.h"
+
+namespace Xeen {
+
+enum MessageWaitType { WT_FREEZE_WAIT = 0, WT_NONFREEZED_WAIT = 1,
+	WT_LOC_WAIT = 2, WT_ANIMATED_WAIT = 3 };
+
+class MessageDialog : public ButtonContainer {
+private:
+	MessageDialog(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute(const Common::String &msg, MessageWaitType waitType);
+public:
+	static void show(XeenEngine *vm, const Common::String &msg,
+		MessageWaitType waitType = WT_FREEZE_WAIT);
+};
+
+class ErrorScroll {
+public:
+	static void show(XeenEngine *vm, const Common::String &msg,
+		MessageWaitType waitType = WT_FREEZE_WAIT);
+};
+
+class CantCast: public ButtonContainer {
+private:
+	CantCast(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute(int spellId, int componentNum);
+public:
+	static void show(XeenEngine *vm, int spellId, int componentNum);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_dialogs_message_H */
diff --git a/engines/xeen/dialogs/dialogs_party.cpp b/engines/xeen/dialogs/dialogs_party.cpp
new file mode 100644
index 0000000..33e138b
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_party.cpp
@@ -0,0 +1,451 @@
+/* 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 "xeen/dialogs/dialogs_char_info.h"
+#include "xeen/dialogs/dialogs_create_char.h"
+#include "xeen/dialogs/dialogs_party.h"
+#include "xeen/dialogs/dialogs_input.h"
+#include "xeen/dialogs/dialogs_query.h"
+#include "xeen/character.h"
+#include "xeen/events.h"
+#include "xeen/party.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+PartyDialog::PartyDialog(XeenEngine *vm) : ButtonContainer(vm),
+		PartyDrawer(vm), _vm(vm) {
+	initDrawStructs();
+}
+
+void PartyDialog::show(XeenEngine *vm) {
+	PartyDialog *dlg = new PartyDialog(vm);
+	dlg->execute();
+	delete dlg;
+}
+
+void PartyDialog::execute() {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Map &map = *_vm->_map;
+	Party &party = *_vm->_party;
+	Screen &screen = *_vm->_screen;
+	Sound &sound = *_vm->_sound;
+	Windows &windows = *_vm->_windows;
+	bool modeFlag = false;
+	int startingChar = 0;
+
+	loadButtons();
+	setupBackground();
+
+	while (!_vm->shouldExit()) {
+		_vm->_mode = MODE_1;
+
+		// Build up a list of available characters in the Roster that are on the
+		// same side of Xeen as the player is currently on
+		_charList.clear();
+		for (int i = 0; i < XEEN_TOTAL_CHARACTERS; ++i) {
+			Character &player = party._roster[i];
+			if (player._name.empty() || player._xeenSide != (map._loadDarkSide ? 1 : 0))
+				continue;
+
+			_charList.push_back(i);
+		}
+
+		Window &w = windows[11];
+		w.open();
+		setupFaces(startingChar, false);
+		w.writeString(Common::String::format(Res.PARTY_DIALOG_TEXT, _partyDetails.c_str()));
+		w.drawList(&_faceDrawStructs[0], 4);
+
+		_uiSprites.draw(w, 0, Common::Point(16, 100));
+		_uiSprites.draw(w, 2, Common::Point(52, 100));
+		_uiSprites.draw(w, 4, Common::Point(87, 100));
+		_uiSprites.draw(w, 6, Common::Point(122, 100));
+		_uiSprites.draw(w, 8, Common::Point(157, 100));
+		_uiSprites.draw(w, 10, Common::Point(192, 100));
+		if (g_vm->getGameID() == GType_Swords)
+			Res._logoSprites.draw(1, 0, Common::Point(232, 9));
+
+		screen.loadPalette("mm4.pal");
+
+		if (modeFlag) {
+			windows[0].update();
+			events.setCursor(0);
+			screen.fadeIn();
+		} else {
+			if (_vm->getGameID() == GType_DarkSide) {
+				screen.fadeOut();
+				windows[0].update();
+			}
+
+			doScroll(false, false);
+			events.setCursor(0);
+
+			if (_vm->getGameID() == GType_DarkSide) {
+				screen.fadeIn();
+			}
+		}
+
+		bool breakFlag = false;
+		while (!_vm->shouldExit() && !breakFlag) {
+			do {
+				events.pollEventsAndWait();
+				checkEvents(_vm);
+			} while (!_vm->shouldExit() && !_buttonValue);
+
+			switch (_buttonValue) {
+			case Common::KEYCODE_ESCAPE:
+			case Common::KEYCODE_SPACE:
+			case Common::KEYCODE_e:
+			case Common::KEYCODE_x:
+				if (party._activeParty.size() == 0) {
+					ErrorScroll::show(_vm, Res.NO_ONE_TO_ADVENTURE_WITH);
+				} else {
+					if (_vm->_mode != MODE_0) {
+						for (int idx = OBSCURITY_NONE; idx >= OBSCURITY_BLACK; --idx) {
+							events.updateGameCounter();
+							intf.obscureScene((Obscurity)idx);
+							w.update();
+
+							while (events.timeElapsed() < 1)
+								events.pollEventsAndWait();
+						}
+					}
+
+					w.close();
+					party._mazeId = party._priorMazeId;
+
+					party.copyPartyToRoster();
+					//_vm->_saves->writeCharFile();
+					return;
+				}
+				break;
+
+			case Common::KEYCODE_F1:
+			case Common::KEYCODE_F2:
+			case Common::KEYCODE_F3:
+			case Common::KEYCODE_F4:
+			case Common::KEYCODE_F5:
+			case Common::KEYCODE_F6:
+				// Show character info
+				_buttonValue -= Common::KEYCODE_F1;
+				if (_buttonValue < (int)party._activeParty.size())
+					CharacterInfo::show(_vm, _buttonValue);
+				break;
+
+			case Common::KEYCODE_1:
+			case Common::KEYCODE_2:
+			case Common::KEYCODE_3:
+			case Common::KEYCODE_4:
+				_buttonValue -= Common::KEYCODE_1 - 7;
+				if ((_buttonValue - 7 + startingChar) < (int)_charList.size()) {
+					// Check if the selected character is already in the party
+					uint idx = 0;
+					for (; idx < party._activeParty.size(); ++idx) {
+						if (_charList[_buttonValue - 7 + startingChar] ==
+							party._activeParty[idx]._rosterId)
+							break;
+					}
+
+					// Only add the character if they're not already in the party
+					if (idx == party._activeParty.size()) {
+						if (party._activeParty.size() == MAX_ACTIVE_PARTY) {
+							sound.playFX(21);
+							ErrorScroll::show(_vm, Res.YOUR_PARTY_IS_FULL);
+						} else {
+							// Add the character to the active party
+							party._activeParty.push_back(party._roster[
+								_charList[_buttonValue - 7 + startingChar]]);
+								startingCharChanged(startingChar);
+						}
+					}
+				}
+				break;
+
+			case Common::KEYCODE_UP:
+			case Common::KEYCODE_KP8:
+				// Up arrow
+				if (startingChar > 0) {
+					startingChar -= 4;
+					startingCharChanged(startingChar);
+				}
+				break;
+
+			case Common::KEYCODE_DOWN:
+			case Common::KEYCODE_KP2:
+				// Down arrow
+				if (startingChar < ((int)_charList.size() - 4)) {
+					startingChar += 4;
+					startingCharChanged(startingChar);
+				}
+				break;
+
+			case Common::KEYCODE_c:
+				// Create
+				if (_charList.size() == XEEN_TOTAL_CHARACTERS) {
+					ErrorScroll::show(_vm, Res.YOUR_ROSTER_IS_FULL);
+				} else {
+					screen.fadeOut();
+					w.close();
+
+					// Show the create character dialog
+					CreateCharacterDialog::show(_vm);
+
+					party.copyPartyToRoster();
+					//_vm->_saves->writeCharFile();
+					screen.fadeOut();
+					modeFlag = true;
+					breakFlag = true;
+				}
+				break;
+
+			case Common::KEYCODE_d:
+				// Delete character
+				if (_charList.size() > 0) {
+					int charButtonValue = selectCharacter(true, startingChar);
+					if (charButtonValue != 0) {
+						int charIndex = charButtonValue - Common::KEYCODE_1 + startingChar;
+						Character &c = party._roster[_charList[charIndex]];
+						if (c.hasSlayerSword()) {
+							ErrorScroll::show(_vm, Res.HAS_SLAYER_SWORD);
+						} else {
+							Common::String msg = Common::String::format(Res.SURE_TO_DELETE_CHAR,
+								c._name.c_str(), Res.CLASS_NAMES[c._class]);
+							if (Confirm::show(_vm, msg)) {
+								// If the character is in the party, remove it
+								for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
+									if (party._activeParty[idx]._rosterId == c._rosterId) {
+										party._activeParty.remove_at(idx);
+										break;
+									}
+								}
+
+								// Empty the character in the roster
+								c.clear();
+
+								// Rebuild the character list
+								_charList.clear();
+								for (int idx = 0; idx < XEEN_TOTAL_CHARACTERS; ++idx) {
+									Character &ch = party._roster[idx];
+									if (!ch._name.empty() && ch._savedMazeId == party._priorMazeId) {
+										_charList.push_back(idx);
+									}
+								}
+
+								startingCharChanged(startingChar);
+							}
+						}
+					}
+				}
+				break;
+
+			case Common::KEYCODE_r:
+				// Remove character
+				if (party._activeParty.size() > 0) {
+					int charButtonValue = selectCharacter(false, startingChar);
+					if (charButtonValue != 0) {
+						party.copyPartyToRoster();
+						party._activeParty.remove_at(charButtonValue - Common::KEYCODE_F1);
+					}
+					startingCharChanged(startingChar);
+				}
+				break;
+
+			default:
+				break;
+			}
+		}
+	}
+}
+
+void PartyDialog::loadButtons() {
+	_uiSprites.load("inn.icn");
+	addButton(Common::Rect(16, 100, 40, 120), Common::KEYCODE_UP, &_uiSprites);
+	addButton(Common::Rect(52, 100, 76, 120), Common::KEYCODE_DOWN, &_uiSprites);
+	addButton(Common::Rect(87, 100, 111, 120), Common::KEYCODE_d, &_uiSprites);
+	addButton(Common::Rect(122, 100, 146, 120), Common::KEYCODE_r, &_uiSprites);
+	addButton(Common::Rect(157, 100, 181, 120), Common::KEYCODE_c, &_uiSprites);
+	addButton(Common::Rect(192, 100, 216, 120), Common::KEYCODE_x, &_uiSprites);
+	addButton(Common::Rect(0, 0, 0, 0), Common::KEYCODE_ESCAPE);
+}
+
+void PartyDialog::initDrawStructs() {
+	_faceDrawStructs[0] = DrawStruct(0, 0, 0);
+	_faceDrawStructs[1] = DrawStruct(0, 101, 0);
+	_faceDrawStructs[2] = DrawStruct(0, 0, 43);
+	_faceDrawStructs[3] = DrawStruct(0, 101, 43);
+}
+
+void PartyDialog::setupBackground() {
+	_vm->_screen->loadBackground("back.raw");
+	_vm->_interface->assembleBorder();
+}
+
+void PartyDialog::setupFaces(int firstDisplayChar, bool updateFlag) {
+	Party &party = *_vm->_party;
+	Common::String charNames[4];
+	Common::String charRaces[4];
+	Common::String charSex[4];
+	Common::String charClasses[4];
+	int posIndex;
+	int charId;
+
+	// Reset the button areas for the display character images
+	while (_buttons.size() > 7)
+		_buttons.remove_at(7);
+	addButton(Common::Rect(16, 16, 48, 48), Common::KEYCODE_1);
+	addButton(Common::Rect(117, 16, 149, 48), Common::KEYCODE_2);
+	addButton(Common::Rect(59, 59, 91, 91), Common::KEYCODE_3);
+	addButton(Common::Rect(117, 59, 151, 91), Common::KEYCODE_4);
+
+
+	for (posIndex = 0; posIndex < 4; ++posIndex) {
+		charId = (firstDisplayChar + posIndex) >= (int)_charList.size() ? -1 :
+			_charList[firstDisplayChar + posIndex];
+		bool isInParty = party.isInParty(charId);
+
+		if (charId == -1) {
+			while ((int)_buttons.size() >(7 + posIndex))
+				_buttons.remove_at(_buttons.size() - 1);
+			break;
+		}
+
+		Common::Rect &b = _buttons[7 + posIndex]._bounds;
+		b.moveTo((posIndex & 1) ? 117 : 16, b.top);
+		Character &ps = party._roster[_charList[firstDisplayChar + posIndex]];
+		charNames[posIndex] = isInParty ? Res.IN_PARTY : ps._name;
+		charRaces[posIndex] = Res.RACE_NAMES[ps._race];
+		charSex[posIndex] = Res.SEX_NAMES[ps._sex];
+		charClasses[posIndex] = Res.CLASS_NAMES[ps._class];
+	}
+
+	drawParty(updateFlag);
+
+	// Set up the sprite set to use for each face
+	for (posIndex = 0; posIndex < 4; ++posIndex) {
+		if ((firstDisplayChar + posIndex) >= (int)_charList.size())
+			_faceDrawStructs[posIndex]._sprites = nullptr;
+		else
+			_faceDrawStructs[posIndex]._sprites = party._roster[
+				_charList[firstDisplayChar + posIndex]]._faceSprites;
+	}
+
+	_partyDetails = Common::String::format(Res.PARTY_DETAILS,
+		charNames[0].c_str(), charRaces[0].c_str(), charSex[0].c_str(), charClasses[0].c_str(),
+		charNames[1].c_str(), charRaces[1].c_str(), charSex[1].c_str(), charClasses[1].c_str(),
+		charNames[2].c_str(), charRaces[2].c_str(), charSex[2].c_str(), charClasses[2].c_str(),
+		charNames[3].c_str(), charRaces[3].c_str(), charSex[3].c_str(), charClasses[3].c_str()
+		);
+}
+
+void PartyDialog::startingCharChanged(int firstDisplayChar) {
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[11];
+
+	setupFaces(firstDisplayChar, true);
+	w.writeString(Common::String::format(Res.PARTY_DIALOG_TEXT, _partyDetails.c_str()));
+	w.drawList(_faceDrawStructs, 4);
+
+	_uiSprites.draw(w, 0, Common::Point(16, 100));
+	_uiSprites.draw(w, 2, Common::Point(52, 100));
+	_uiSprites.draw(w, 4, Common::Point(87, 100));
+	_uiSprites.draw(w, 6, Common::Point(122, 100));
+	_uiSprites.draw(w, 8, Common::Point(157, 100));
+	_uiSprites.draw(w, 10, Common::Point(192, 100));
+
+	w.update();
+}
+
+int PartyDialog::selectCharacter(bool isDelete, int firstDisplayChar) {
+	EventsManager &events = *_vm->_events;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[28];
+
+	SpriteResource iconSprites;
+	iconSprites.load("esc.icn");
+
+	w.setBounds(Common::Rect(50, isDelete ? 112 : 76, 266, isDelete ? 148 : 112));
+	w.open();
+	w.writeString(Common::String::format(Res.REMOVE_OR_DELETE_WHICH,
+		Res.REMOVE_DELETE[isDelete ? 1 : 0]));
+	iconSprites.draw(w, 0, Common::Point(225, isDelete ? 120 : 84));
+	w.update();
+
+	saveButtons();
+	addButton(Common::Rect(225, isDelete ? 120 : 84, 249, isDelete ? 140 : 104),
+		Common::KEYCODE_ESCAPE, &iconSprites);
+	addButton(Common::Rect(16, 16, 48, 48), Common::KEYCODE_1);
+	addButton(Common::Rect(117, 16, 149, 48), Common::KEYCODE_2);
+	addButton(Common::Rect(16, 59, 48, 91), Common::KEYCODE_3);
+	addButton(Common::Rect(117, 59, 149, 91), Common::KEYCODE_4);
+	addPartyButtons(_vm);
+
+	int result = -1, v;
+	while (!_vm->shouldExit() && result == -1) {
+		_buttonValue = 0;
+		while (!_vm->shouldExit() && !_buttonValue) {
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+		}
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_ESCAPE:
+			result = 0;
+			break;
+
+		case Common::KEYCODE_F1:
+		case Common::KEYCODE_F2:
+		case Common::KEYCODE_F3:
+		case Common::KEYCODE_F4:
+		case Common::KEYCODE_F5:
+		case Common::KEYCODE_F6:
+			if (!isDelete) {
+				v = _buttonValue - Common::KEYCODE_F1;
+				if (v < (int)party._activeParty.size())
+					result = _buttonValue;
+			}
+			break;
+
+		case Common::KEYCODE_1:
+		case Common::KEYCODE_2:
+		case Common::KEYCODE_3:
+		case Common::KEYCODE_4:
+			if (isDelete) {
+				v = _buttonValue - Common::KEYCODE_1;
+				if ((firstDisplayChar + v) < (int)_charList.size())
+					result = _buttonValue;
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	w.close();
+	restoreButtons();
+	return result == -1 ? 0 : result;
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_party.h b/engines/xeen/dialogs/dialogs_party.h
new file mode 100644
index 0000000..8f87ca3
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_party.h
@@ -0,0 +1,87 @@
+/* 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 XEEN_DIALOGS_PARTY_H
+#define XEEN_DIALOGS_PARTY_H
+
+#include "common/array.h"
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/interface.h"
+#include "xeen/screen.h"
+#include "xeen/sprites.h"
+
+namespace Xeen {
+
+/**
+ * Shows the Party dialog that's shown when signing into an inn
+ */
+class PartyDialog : public ButtonContainer, public PartyDrawer {
+private:
+	XeenEngine *_vm;
+	SpriteResource _uiSprites;
+	DrawStruct _faceDrawStructs[4];
+	Common::String _partyDetails;
+	Common::Array<int> _charList;
+
+	/**
+	 * Constructor
+	 */
+	PartyDialog(XeenEngine *vm);
+
+	/**
+	 * Executes the dialog
+	 */
+	void execute();
+
+	/**
+	 * Loads buttons for the dialog
+	 */
+	void loadButtons();
+
+	/**
+	 * Initialises a list of elements to draw
+	 */
+	void initDrawStructs();
+
+	/**
+	 * Sets up the background
+	 */
+	void setupBackground();
+
+	/**
+	 * Sets up the faces from the avaialble roster for display in the party dialog
+	 */
+	void setupFaces(int firstDisplayChar, bool updateFlag);
+
+	void startingCharChanged(int firstDisplayChar);
+
+	int selectCharacter(bool isDelete, int firstDisplayChar);
+public:
+	/**
+	 * Show the Party dialog
+	 */
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_PARTY_H */
diff --git a/engines/xeen/dialogs/dialogs_query.cpp b/engines/xeen/dialogs/dialogs_query.cpp
new file mode 100644
index 0000000..79f4682
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_query.cpp
@@ -0,0 +1,158 @@
+/* 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 "xeen/dialogs/dialogs_query.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+bool Confirm::show(XeenEngine *vm, const Common::String &msg, int mode) {
+	Confirm *dlg = new Confirm(vm);
+	bool result = dlg->execute(msg, mode);
+	delete dlg;
+
+	return result;
+}
+
+bool Confirm::execute(const Common::String &msg, int mode) {
+	EventsManager &events = *_vm->_events;
+	Windows &windows = *_vm->_windows;
+	SpriteResource confirmSprites;
+
+	confirmSprites.load("confirm.icn");
+	addButton(Common::Rect(129, 112, 153, 122), Common::KEYCODE_y, &confirmSprites);
+	addButton(Common::Rect(185, 112, 209, 122), Common::KEYCODE_n, &confirmSprites);
+
+	Window &w = windows[mode ? 22 : 21];
+	w.open();
+
+	if (!mode) {
+		confirmSprites.draw(w, 0, Common::Point(129, 112));
+		confirmSprites.draw(w, 2, Common::Point(185, 112));
+		_buttons[0]._bounds.moveTo(129, 112);
+		_buttons[1]._bounds.moveTo(185, 112);
+	} else {
+		if (mode & 0x80) {
+			clearButtons();
+		} else {
+			confirmSprites.draw(w, 0, Common::Point(120, 133));
+			confirmSprites.draw(w, 2, Common::Point(176, 133));
+			_buttons[0]._bounds.moveTo(120, 133);
+			_buttons[1]._bounds.moveTo(176, 133);
+		}
+	}
+
+	w.writeString(msg);
+	w.update();
+
+	events.clearEvents();
+	bool result = false;
+
+	while (!_vm->shouldExit()) {
+		events.pollEvents();
+		checkEvents(_vm);
+
+		if ((mode & 0x80) || _buttonValue == Common::KEYCODE_ESCAPE
+				|| _buttonValue == Common::KEYCODE_n)
+			break;
+
+		if (_buttonValue == Common::KEYCODE_y) {
+			result = true;
+			break;
+		}
+	}
+
+	w.close();
+	return result;
+}
+
+/*------------------------------------------------------------------------*/
+
+bool YesNo::show(XeenEngine *vm, bool type, bool townFlag) {
+	YesNo *dlg = new YesNo(vm);
+	bool result = dlg->execute(type, townFlag);
+	delete dlg;
+
+	return result;
+}
+
+bool YesNo::execute(bool type, bool townFlag) {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Map &map = *_vm->_map;
+	Party &party = *_vm->_party;
+	Resources &res = *_vm->_resources;
+	LocationManager &loc = *_vm->_locations;
+	Windows &windows = *_vm->_windows;
+	SpriteResource confirmSprites;
+	bool result = false;
+
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = oldMode == MODE_7 ? MODE_8 : MODE_7;
+
+	if (!type) {
+		confirmSprites.load("confirm.icn");
+		res._globalSprites.draw(0, 7, Common::Point(232, 74));
+		confirmSprites.draw(0, 0, Common::Point(235, 75));
+		confirmSprites.draw(0, 2, Common::Point(260, 75));
+		windows[34].update();
+
+		addButton(Common::Rect(235, 75, 259, 95), Common::KEYCODE_y, &confirmSprites);
+		addButton(Common::Rect(260, 75, 284, 95), Common::KEYCODE_n, &confirmSprites);
+
+		intf._face1State = map._headData[party._mazePosition.y][party._mazePosition.x]._left;
+		intf._face2State = map._headData[party._mazePosition.y][party._mazePosition.x]._right;
+	}
+
+	while (!_vm->shouldExit()) {
+		events.updateGameCounter();
+
+		if (loc.isActive()) {
+			loc.drawAnim(townFlag);
+			//numFrames = 3;
+		} else {
+			intf.draw3d(true);
+			//numFrames = 1;
+		}
+
+		events.wait(3);
+		checkEvents(_vm);
+		if (!_buttonValue)
+			continue;
+
+		if (type || _buttonValue == Common::KEYCODE_y) {
+			result = true;
+			break;
+		} else if (_buttonValue == Common::KEYCODE_n || _buttonValue == Common::KEYCODE_ESCAPE)
+			break;
+	}
+
+	intf._face1State = intf._face2State = 2;
+	_vm->_mode = oldMode;
+
+	if (!type)
+		intf.mainIconsPrint();
+
+	return result;
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_query.h b/engines/xeen/dialogs/dialogs_query.h
new file mode 100644
index 0000000..911de3d
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_query.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_QUERY_H
+#define XEEN_DIALOGS_QUERY_H
+
+#include "xeen/dialogs/dialogs.h"
+
+namespace Xeen {
+
+class Confirm : public ButtonContainer {
+private:
+	Confirm(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	bool execute(const Common::String &msg, int mode);
+public:
+	static bool show(XeenEngine *vm, const Common::String &msg, int mode = 0);
+};
+
+class YesNo : public ButtonContainer {
+private:
+	YesNo(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	bool execute(bool type, bool townFlag);
+public:
+	static bool show(XeenEngine *vm, bool type, bool townFlag = false);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_QUERY_H */
diff --git a/engines/xeen/dialogs/dialogs_quests.cpp b/engines/xeen/dialogs/dialogs_quests.cpp
new file mode 100644
index 0000000..e4f6227
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_quests.cpp
@@ -0,0 +1,254 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+#include "xeen/dialogs/dialogs_quests.h"
+#include "xeen/events.h"
+#include "xeen/party.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+#define MAX_DIALOG_LINES 128
+
+void Quests::show(XeenEngine *vm) {
+	Quests *dlg = new Quests(vm);
+	dlg->execute();
+	delete dlg;
+}
+
+void Quests::execute() {
+	EventsManager &events = *_vm->_events;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	Mode oldMode = _vm->_mode;
+	int count = 0;
+	bool headerShown = false;
+	int topRow = 0;
+
+	addButtons();
+	loadQuestNotes();
+
+	enum { QUEST_ITEMS, CURRENT_QUESTS, AUTO_NOTES } mode = QUEST_ITEMS;
+	bool windowFlag;
+	if (windows[29]._enabled) {
+		windowFlag = false;
+	} else {
+		windows[29].open();
+		windows[30].open();
+		windowFlag = true;
+	}
+
+	windows[29].writeString(Res.QUESTS_DIALOG_TEXT);
+	drawButtons(&windows[0]);
+
+	while (!_vm->shouldExit()) {
+		Common::String lines[MAX_DIALOG_LINES];
+
+		switch (mode) {
+		case QUEST_ITEMS:
+			for (int idx = 0; idx < TOTAL_QUEST_ITEMS; ++idx)
+				lines[idx] = "\b \b*";
+
+			count = 0;
+			headerShown = false;
+			for (int idx = 0; idx < TOTAL_QUEST_ITEMS; ++idx) {
+				if (party._questItems[idx]) {
+					if (!count && !headerShown && idx < 35) {
+						lines[count++] = Res.CLOUDS_OF_XEEN_LINE;
+					}
+					if (idx >= 35 && !headerShown) {
+						lines[count++] = Res.DARKSIDE_OF_XEEN_LINE;
+						headerShown = true;
+					}
+
+					switch (idx) {
+					case 17:
+					case 26:
+					case 79:
+					case 80:
+					case 81:
+					case 82:
+					case 83:
+					case 84:
+						lines[count++] = Common::String::format("%d %s%c",
+							party._questItems[idx], Res.QUEST_ITEM_NAMES[idx],
+							party._questItems[idx] == 1 ? ' ' : 's');
+						break;
+					default:
+						lines[count++] = Res.QUEST_ITEM_NAMES[idx];
+						break;
+					}
+				}
+			}
+
+			if (count == 0) {
+				windows[30].writeString(Res.NO_QUEST_ITEMS);
+			} else {
+				windows[30].writeString(Common::String::format(Res.QUEST_ITEMS_DATA,
+					lines[topRow].c_str(), lines[topRow + 1].c_str(),
+					lines[topRow + 2].c_str(), lines[topRow + 3].c_str(),
+					lines[topRow + 4].c_str(), lines[topRow + 5].c_str(),
+					lines[topRow + 6].c_str(), lines[topRow + 7].c_str(),
+					lines[topRow + 8].c_str()
+				));
+			}
+			break;
+
+		case CURRENT_QUESTS:
+			for (int idx = 0; idx < TOTAL_QUEST_ITEMS; ++idx)
+				lines[idx] = "";
+
+			count = 0;
+			headerShown = false;
+			for (int idx = 0; idx < TOTAL_QUEST_FLAGS; ++idx) {
+				if (party._questFlags[(idx + 1) / 30][(idx + 1) % 30]) {
+					if (!count && !headerShown && idx < 29) {
+						lines[count++] = Res.CLOUDS_OF_XEEN_LINE;
+					}
+					if (idx > 28 && !headerShown) {
+						lines[count++] = Res.DARKSIDE_OF_XEEN_LINE;
+						headerShown = true;
+					}
+
+					lines[count++] = _questNotes[idx];
+				}
+			}
+
+			if (count == 0)
+				lines[1] = Res.NO_CURRENT_QUESTS;
+
+			windows[30].writeString(Common::String::format(Res.CURRENT_QUESTS_DATA,
+				lines[topRow].c_str(), lines[topRow + 1].c_str(), lines[topRow + 2].c_str()));
+			break;
+
+		case AUTO_NOTES:
+			for (int idx = 0; idx < MAX_DIALOG_LINES; ++idx)
+				lines[idx] = "";
+
+			count = 0;
+			headerShown = false;
+			for (int idx = 0; idx < MAX_DIALOG_LINES; ++idx) {
+				if (party._worldFlags[idx]) {
+					if (!count && !headerShown && idx < 72) {
+						lines[count++] = Res.CLOUDS_OF_XEEN_LINE;
+					}
+					if (idx >= 72 && !headerShown) {
+						lines[count++] = Res.DARKSIDE_OF_XEEN_LINE;
+						headerShown = true;
+					}
+
+					lines[count++] = _questNotes[idx + 56];
+				}
+			}
+
+			if (count == 0)
+				lines[1] = Res.NO_AUTO_NOTES;
+
+			windows[30].writeString(Common::String::format(Res.AUTO_NOTES_DATA,
+				lines[topRow].c_str(), lines[topRow + 1].c_str(),
+				lines[topRow + 2].c_str(), lines[topRow + 3].c_str(),
+				lines[topRow + 4].c_str(), lines[topRow + 5].c_str(),
+				lines[topRow + 6].c_str(), lines[topRow + 7].c_str(),
+				lines[topRow + 8].c_str()
+			));
+			break;
+		}
+
+		windows[30].writeString("\v000\t000");
+		windows[24].update();
+
+		// Key handling
+		_buttonValue = 0;
+		while (!_vm->shouldExit() && !_buttonValue) {
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+		}
+
+		if (_buttonValue == Common::KEYCODE_ESCAPE)
+			break;
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_a:
+			mode = AUTO_NOTES;
+			topRow = 0;
+			break;
+		case Common::KEYCODE_i:
+			mode = QUEST_ITEMS;
+			topRow = 0;
+			break;
+		case Common::KEYCODE_q:
+			mode = CURRENT_QUESTS;
+			topRow = 0;
+			break;
+		case Common::KEYCODE_HOME:
+			topRow = 0;
+			break;
+		case Common::KEYCODE_END:
+			topRow = MAX(count - 1, 0);
+			break;
+		case Common::KEYCODE_PAGEUP:
+			topRow = MAX(topRow - 3, 0);
+			break;
+		case Common::KEYCODE_PAGEDOWN:
+			topRow = CLIP(topRow + 3, 0, MAX(count - 1, 0));
+			break;
+		case Common::KEYCODE_UP:
+		case Common::KEYCODE_KP8:
+			topRow = MAX(topRow - 1, 0);
+			break;
+		case Common::KEYCODE_DOWN:
+		case Common::KEYCODE_KP2:
+			topRow = CLIP(topRow + 1, 0, MAX(count - 1, 0));
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (windowFlag) {
+		windows[30].close();
+		windows[29].close();
+	}
+	_vm->_mode = oldMode;
+}
+
+void Quests::addButtons() {
+	_iconSprites.load("quest.icn");
+
+
+	addButton(Common::Rect(12, 109, 36, 129), Common::KEYCODE_i, &_iconSprites);
+	addButton(Common::Rect(80, 109, 104, 129), Common::KEYCODE_q, &_iconSprites);
+	addButton(Common::Rect(148, 109, 172, 129), Common::KEYCODE_a, &_iconSprites);
+	addButton(Common::Rect(216, 109, 240, 129), Common::KEYCODE_UP, &_iconSprites);
+	addButton(Common::Rect(250, 109, 274, 129), Common::KEYCODE_DOWN, &_iconSprites);
+	addButton(Common::Rect(284, 109, 308, 129), Common::KEYCODE_ESCAPE, &_iconSprites);
+}
+
+void Quests::loadQuestNotes() {
+	File f("qnotes.bin");
+	while (f.pos() < f.size())
+		_questNotes.push_back(f.readString());
+	f.close();
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_quests.h b/engines/xeen/dialogs/dialogs_quests.h
new file mode 100644
index 0000000..a3f1980
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_quests.h
@@ -0,0 +1,49 @@
+/* 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 XEEN_DIALOGS_QUESTS_H
+#define XEEN_DIALOGS_QUESTS_H
+
+#include "common/str-array.h"
+#include "xeen/dialogs/dialogs.h"
+
+namespace Xeen {
+
+class Quests : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+	Common::StringArray _questNotes;
+
+	Quests(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute();
+
+	void addButtons();
+
+	void loadQuestNotes();
+public:
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_QUESTS_H */
diff --git a/engines/xeen/dialogs/dialogs_quick_fight.cpp b/engines/xeen/dialogs/dialogs_quick_fight.cpp
new file mode 100644
index 0000000..63acf55
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_quick_fight.cpp
@@ -0,0 +1,105 @@
+/* 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 "xeen/dialogs/dialogs_quick_fight.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void QuickFight::show(XeenEngine *vm, Character *currentChar) {
+	QuickFight *dlg = new QuickFight(vm, currentChar);
+	dlg->execute();
+	delete dlg;
+}
+
+QuickFight::QuickFight(XeenEngine *vm, Character *currentChar) : ButtonContainer(vm),
+		_currentChar(currentChar) {
+	loadButtons();
+}
+
+void QuickFight::execute() {
+	Combat &combat = *_vm->_combat;
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[10];
+	w.open();
+
+	do {
+		// Draw the dialog text and buttons
+		Common::String msg = Common::String::format(Res.QUICK_FIGHT_TEXT,
+			_currentChar->_name.c_str(),
+			Res.QUICK_FIGHT_OPTIONS[_currentChar->_quickOption]);
+		w.writeString(msg);
+		drawButtons(&w);
+
+		// Wait for selection
+		_buttonValue = 0;
+		events.updateGameCounter();
+		do {
+			intf.draw3d(false, false);
+
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+			if (_vm->shouldExit())
+				return;
+		} while (!_buttonValue && !events.timeElapsed());
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_n:
+		case Common::KEYCODE_t:
+			_currentChar->_quickOption = (QuickAction)(((int)_currentChar->_quickOption + 1) % 4);
+			break;
+
+		case Common::KEYCODE_F1:
+		case Common::KEYCODE_F2:
+		case Common::KEYCODE_F3:
+		case Common::KEYCODE_F4:
+		case Common::KEYCODE_F5:
+		case Common::KEYCODE_F6: {
+			int charIdx = _buttonValue - Common::KEYCODE_F1;
+			if (charIdx < (int)combat._combatParty.size()) {
+				// Highlight new character
+				_currentChar = &party._activeParty[charIdx];
+				intf.highlightChar(charIdx);
+			}
+			break;
+		}
+
+		default:
+			break;
+		}
+	} while (_buttonValue != Common::KEYCODE_RETURN && _buttonValue != Common::KEYCODE_ESCAPE);
+
+	w.close();
+	events.clearEvents();
+}
+
+void QuickFight::loadButtons() {
+	_icons.load("train.icn");
+	addButton(Common::Rect(281, 108, 305, 128), Common::KEYCODE_ESCAPE, &_icons);
+	addButton(Common::Rect(242, 108, 266, 128), Common::KEYCODE_t, &_icons);
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_quick_fight.h b/engines/xeen/dialogs/dialogs_quick_fight.h
new file mode 100644
index 0000000..e3662c9
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_quick_fight.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_QUICK_FIGHT_H
+#define XEEN_DIALOGS_QUICK_FIGHT_H
+
+#include "xeen/character.h"
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/sprites.h"
+
+namespace Xeen {
+
+class QuickFight : public ButtonContainer {
+private:
+	SpriteResource _icons;
+	Character *_currentChar;
+private:
+	/**
+	 * Constructor
+	 */
+	QuickFight(XeenEngine *vm, Character *currentChar);
+
+	/**
+	 * Executes the display of the dialog
+	 */
+	void execute();
+
+	/**
+	 * Load butons for the dialog
+	 */
+	void loadButtons();
+public:
+	/**
+	 * Show the dialog
+	 */
+	static void show(XeenEngine *vm, Character *currentChar);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_QUICK_FIGHT_H */
diff --git a/engines/xeen/dialogs/dialogs_quick_ref.cpp b/engines/xeen/dialogs/dialogs_quick_ref.cpp
new file mode 100644
index 0000000..0c8a63b
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_quick_ref.cpp
@@ -0,0 +1,88 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "xeen/dialogs/dialogs_quick_ref.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void QuickReferenceDialog::show(XeenEngine *vm) {
+	QuickReferenceDialog *dlg = new QuickReferenceDialog(vm);
+	dlg->execute();
+	delete dlg;
+}
+
+void QuickReferenceDialog::execute() {
+	Combat &combat = *_vm->_combat;
+	EventsManager &events = *_vm->_events;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	Common::String lines[8];
+
+	events.setCursor(0);
+
+	for (uint idx = 0; idx < (combat._globalCombat == 2 ? combat._combatParty.size() :
+			party._activeParty.size()); ++idx) {
+		Character &c = combat._globalCombat == 2 ? *combat._combatParty[idx] :
+			party._activeParty[idx];
+		Condition condition = c.worstCondition();
+		lines[idx] = Common::String::format(Res.QUICK_REF_LINE,
+			idx * 10 + 24, idx + 1, c._name.c_str(),
+			Res.CLASS_NAMES[c._class][0], Res.CLASS_NAMES[c._class][1], Res.CLASS_NAMES[c._class][2],
+			c.statColor(c.getCurrentLevel(), c._level._permanent), c._level._permanent,
+			c.statColor(c._currentHp, c.getMaxHP()), c._currentHp,
+			c.statColor(c._currentSp, c.getMaxSP()), c._currentSp,
+			c.statColor(c.getArmorClass(), c.getArmorClass(true)), c.getArmorClass(),
+			Res.CONDITION_COLORS[condition],
+			Res.CONDITION_NAMES[condition][0], Res.CONDITION_NAMES[condition][1],
+			Res.CONDITION_NAMES[condition][2], Res.CONDITION_NAMES[condition][3]
+		);
+	}
+
+	int food = (party._food / party._activeParty.size()) / 3;
+	Common::String msg = Common::String::format(Res.QUICK_REFERENCE,
+		lines[0].c_str(), lines[1].c_str(), lines[2].c_str(),
+		lines[3].c_str(), lines[4].c_str(), lines[5].c_str(),
+		lines[6].c_str(), lines[7].c_str(),
+		party._gold, party._gems,
+		food, food == 1 ? "" : "s"
+	);
+
+	Window &w = windows[24];
+	bool windowOpen = w._enabled;
+	if (!windowOpen)
+		w.open();
+	w.writeString(msg);
+	w.update();
+
+	// Wait for a key/mouse press
+	events.clearEvents();
+	while (!_vm->shouldExit() && !events.isKeyMousePressed())
+		events.pollEventsAndWait();
+	events.clearEvents();
+
+	if (!windowOpen)
+		w.close();
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_quick_ref.h b/engines/xeen/dialogs/dialogs_quick_ref.h
new file mode 100644
index 0000000..4630043
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_quick_ref.h
@@ -0,0 +1,41 @@
+/* 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 XEEN_DIALOGS_QUICK_REF_H
+#define XEEN_DIALOGS_QUICK_REF_H
+
+#include "xeen/dialogs/dialogs.h"
+
+namespace Xeen {
+
+class QuickReferenceDialog : public ButtonContainer {
+private:
+	QuickReferenceDialog(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute();
+public:
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_QUICK_REF_H */
diff --git a/engines/xeen/dialogs/dialogs_spells.cpp b/engines/xeen/dialogs/dialogs_spells.cpp
new file mode 100644
index 0000000..3da5a51
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_spells.cpp
@@ -0,0 +1,1045 @@
+/* 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 "xeen/dialogs/dialogs_spells.h"
+#include "xeen/dialogs/dialogs_input.h"
+#include "xeen/dialogs/dialogs_query.h"
+#include "xeen/resources.h"
+#include "xeen/spells.h"
+#include "xeen/sprites.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+Character *SpellsDialog::show(XeenEngine *vm, ButtonContainer *priorDialog,
+		Character *c, int isCasting) {
+	SpellsDialog *dlg = new SpellsDialog(vm);
+	Character *result = dlg->execute(priorDialog, c, isCasting);
+	delete dlg;
+
+	return result;
+}
+
+Character *SpellsDialog::execute(ButtonContainer *priorDialog, Character *c, int isCasting) {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Sound &sound = *_vm->_sound;
+	Spells &spells = *_vm->_spells;
+	Windows &windows = *_vm->_windows;
+	bool isDarkCc = _vm->_files->_isDarkCc;
+	loadButtons();
+
+	int castingCopy = isCasting;
+	isCasting &= 0x7f;
+	int selection = -1;
+	int topIndex = 0;
+	int newSelection;
+	windows[25].open();
+
+	do {
+		if (!isCasting) {
+			if (!c->guildMember()) {
+				sound.stopSound();
+				intf._overallFrame = 5;
+				sound.playSound(isDarkCc ? "skull1.voc" : "guild11.voc", 1);
+				break;
+			}
+
+			Common::String title = Common::String::format(Res.BUY_SPELLS, c->_name.c_str());
+			Common::String msg = Common::String::format(Res.GUILD_OPTIONS,
+				title.c_str(), XeenEngine::printMil(party._gold).c_str());
+			windows[10].writeString(msg);
+
+			warning("TODO: Sprite draw using previously used button sprites");
+		}
+
+		_spells.clear();
+		const char *errorMsg = setSpellText(c, castingCopy);
+		windows[25].writeString(Common::String::format(Res.SPELLS_FOR,
+			errorMsg == nullptr ? Res.SPELL_LINES_0_TO_9 : "",
+			c->_name.c_str()));
+
+		// Setup and write out spell list
+		const char *names[10];
+		int colors[10];
+		Common::String emptyStr = "";
+		Common::fill(&names[0], &names[10], emptyStr.c_str());
+		Common::fill(&colors[0], &colors[10], 9);
+
+		for (int idx = 0; idx < 10; ++idx) {
+			if ((topIndex + idx) < (int)_spells.size()) {
+				names[idx] = _spells[topIndex + idx]._name.c_str();
+				colors[idx] = _spells[topIndex + idx]._color;
+			}
+		}
+
+		if (selection >= topIndex && selection < (topIndex + 10))
+			colors[selection - topIndex] = 15;
+		if (_spells.size() == 0)
+			names[0] = errorMsg;
+
+		windows[37].writeString(Common::String::format(Res.SPELLS_DIALOG_SPELLS,
+			colors[0], names[0], colors[1], names[1], colors[2], names[2],
+			colors[3], names[3], colors[4], names[4], colors[5], names[5],
+			colors[6], names[6], colors[7], names[7], colors[8], names[8],
+			colors[9], names[9],
+			isCasting ? Res.SPELL_PTS : Res.GOLD,
+			isCasting ? c->_currentSp : party._gold
+		));
+
+		_scrollSprites.draw(0, 4, Common::Point(39, 26));
+		_scrollSprites.draw(0, 0, Common::Point(187, 26));
+		_scrollSprites.draw(0, 2, Common::Point(187, 111));
+		if (isCasting)
+			_scrollSprites.draw(windows[25], 5, Common::Point(132, 123));
+
+		windows[25].update();
+
+		do {
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+		} while (!_vm->shouldExit() && !_buttonValue);
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_F1:
+		case Common::KEYCODE_F2:
+		case Common::KEYCODE_F3:
+		case Common::KEYCODE_F4:
+		case Common::KEYCODE_F5:
+		case Common::KEYCODE_F6:
+			if (_vm->_mode != MODE_COMBAT) {
+				_buttonValue -= Common::KEYCODE_F1;
+				if (_buttonValue < (int)party._activeParty.size()) {
+					c = &party._activeParty[_buttonValue];
+					spells._lastCaster = _buttonValue;
+					intf.highlightChar(_buttonValue);
+
+					if (_vm->_mode == MODE_17) {
+						windows[10].writeString(Common::String::format(Res.GUILD_OPTIONS,
+							XeenEngine::printMil(party._gold).c_str(), Res.GUILD_TEXT, c->_name.c_str()));
+					} else {
+						int category;
+						switch (c->_class) {
+						case CLASS_ARCHER:
+						case CLASS_SORCERER:
+							category = 1;
+							break;
+						case CLASS_DRUID:
+						case CLASS_RANGER:
+							category = 2;
+							break;
+						default:
+							category = 0;
+							break;
+						}
+
+						int spellIndex = (c->_currentSpell == -1) ? 39 : c->_currentSpell;
+						int spellId = Res.SPELLS_ALLOWED[category][spellIndex];
+						windows[10].writeString(Common::String::format(Res.CAST_SPELL_DETAILS,
+							c->_name.c_str(), spells._spellNames[spellId].c_str(),
+							spells.calcSpellPoints(spellId, c->getCurrentLevel()),
+							Res.SPELL_GEM_COST[spellId], c->_currentSp));
+					}
+
+					if (priorDialog != nullptr)
+						priorDialog->drawButtons(&windows[0]);
+					windows[10].update();
+				}
+			}
+			break;
+
+		case Common::KEYCODE_RETURN:
+		case Common::KEYCODE_KP_ENTER:
+		case Common::KEYCODE_s:
+			if (selection != -1)
+				_buttonValue = Common::KEYCODE_ESCAPE;
+			break;
+
+		case Common::KEYCODE_ESCAPE:
+			selection = -1;
+			_buttonValue = Common::KEYCODE_ESCAPE;
+			break;
+
+		case Common::KEYCODE_0:
+		case Common::KEYCODE_1:
+		case Common::KEYCODE_2:
+		case Common::KEYCODE_3:
+		case Common::KEYCODE_4:
+		case Common::KEYCODE_5:
+		case Common::KEYCODE_6:
+		case Common::KEYCODE_7:
+		case Common::KEYCODE_8:
+		case Common::KEYCODE_9:
+			newSelection = topIndex + ((_buttonValue == Common::KEYCODE_0) ? 9 :
+				(_buttonValue - Common::KEYCODE_1));
+
+			if (newSelection < (int)_spells.size()) {
+				int expenseFactor = 0;
+				int category = 0;
+
+				switch (c->_class) {
+				case CLASS_PALADIN:
+					expenseFactor = 1;
+					category = 0;
+					break;
+				case CLASS_ARCHER:
+					expenseFactor = 1;
+					category = 1;
+					break;
+				case CLASS_CLERIC:
+					category = 0;
+					break;
+				case CLASS_SORCERER:
+					category = 1;
+					break;
+				case CLASS_DRUID:
+					category = 2;
+					break;
+				case CLASS_RANGER:
+					expenseFactor = 1;
+					category = 2;
+					break;
+				default:
+					break;
+				}
+
+				int spellIndex = _spells[newSelection]._spellIndex;
+				int spellId = Res.SPELLS_ALLOWED[category][spellIndex];
+				int spellCost = spells.calcSpellCost(spellId, expenseFactor);
+
+				if (isCasting) {
+					selection = newSelection;
+				} else {
+					Common::String spellName = _spells[newSelection]._name;
+					Common::String msg = (castingCopy & 0x80) ?
+						Common::String::format(Res.SPELLS_PRESS_A_KEY, spellName.c_str()) :
+						Common::String::format(Res.SPELLS_PURCHASE, spellName.c_str(), spellCost);
+
+					if (Confirm::show(_vm, msg, castingCopy + 1)) {
+						if (party.subtract(CONS_GOLD, spellCost, WHERE_PARTY, WT_FREEZE_WAIT)) {
+							c->_spells[spellIndex] = true;
+							sound.stopSound();
+							intf._overallFrame = 0;
+							sound.playSound(isDarkCc ? "guild12.voc" : "parrot2.voc", 1);
+						} else {
+							sound.playFX(21);
+						}
+					}
+				}
+			}
+			break;
+
+		case Common::KEYCODE_PAGEUP:
+		case Common::KEYCODE_KP9:
+			topIndex = MAX((int)topIndex - 10, 0);
+			break;
+
+		case Common::KEYCODE_PAGEDOWN:
+		case Common::KEYCODE_KP3:
+			topIndex = MIN(topIndex + 10, (((int)_spells.size() - 1) / 10) * 10);
+			break;
+
+		case Common::KEYCODE_UP:
+		case Common::KEYCODE_KP8:
+			if (topIndex > 0)
+				--topIndex;
+			break;
+
+		case Common::KEYCODE_DOWN:
+		case Common::KEYCODE_KP2:
+			if (topIndex < ((int)_spells.size() - 10))
+				++topIndex;
+			break;
+		}
+	} while (!_vm->shouldExit() && _buttonValue != Common::KEYCODE_ESCAPE);
+
+	windows[25].close();
+
+	if (_vm->shouldExit())
+		selection = -1;
+	if (isCasting && selection != -1)
+		c->_currentSpell = _spells[selection]._spellIndex;
+
+	return c;
+}
+
+void SpellsDialog::loadButtons() {
+	_iconSprites.load("main.icn");
+	_scrollSprites.load("scroll.icn");
+	addButton(Common::Rect(187, 26, 198, 36), Common::KEYCODE_UP, &_scrollSprites);
+	addButton(Common::Rect(187, 111, 198, 121), Common::KEYCODE_DOWN, &_scrollSprites);
+	addButton(Common::Rect(40, 28, 187, 36), Common::KEYCODE_1);
+	addButton(Common::Rect(40, 37, 187, 45), Common::KEYCODE_2);
+	addButton(Common::Rect(40, 46, 187, 54), Common::KEYCODE_3);
+	addButton(Common::Rect(40, 55, 187, 63), Common::KEYCODE_4);
+	addButton(Common::Rect(40, 64, 187, 72), Common::KEYCODE_5);
+	addButton(Common::Rect(40, 73, 187, 81), Common::KEYCODE_6);
+	addButton(Common::Rect(40, 82, 187, 90), Common::KEYCODE_7);
+	addButton(Common::Rect(40, 91, 187, 99), Common::KEYCODE_8);
+	addButton(Common::Rect(40, 100, 187, 108), Common::KEYCODE_9);
+	addButton(Common::Rect(40, 109, 187, 117), Common::KEYCODE_0);
+	addButton(Common::Rect(174, 123, 198, 133), Common::KEYCODE_ESCAPE);
+	addButton(Common::Rect(187, 35, 198, 73), Common::KEYCODE_PAGEUP);
+	addButton(Common::Rect(187, 74, 198, 112), Common::KEYCODE_PAGEDOWN);
+	addButton(Common::Rect(132, 123, 168, 133), Common::KEYCODE_s);
+	addPartyButtons(_vm);
+}
+
+const char *SpellsDialog::setSpellText(Character *c, int isCasting) {
+	Party &party = *_vm->_party;
+	Spells &spells = *_vm->_spells;
+	bool isDarkCc = _vm->_files->_isDarkCc;
+	int expenseFactor = 0;
+	int currLevel = c->getCurrentLevel();
+	int category;
+
+	if ((isCasting & 0x7f) == 0) {
+		switch (c->_class) {
+		case CLASS_PALADIN:
+			expenseFactor = 1;
+			category = 0;
+			break;
+		case CLASS_ARCHER:
+			expenseFactor = 1;
+			category = 1;
+			break;
+		case CLASS_CLERIC:
+			category = 0;
+			break;
+		case CLASS_SORCERER:
+			category = 1;
+			break;
+		case CLASS_DRUID:
+			category = 2;
+			break;
+		case CLASS_RANGER:
+			expenseFactor = 1;
+			category = 2;
+			break;
+		default:
+			category = -1;
+			break;
+		}
+
+		if (category != -1) {
+			if (party._mazeId == 49 || party._mazeId == 37) {
+				for (uint spellId = 0; spellId < 76; ++spellId) {
+					int idx = 0;
+					while (idx < MAX_SPELLS_PER_CLASS && Res.SPELLS_ALLOWED[category][idx] != (int)spellId)
+						++idx;
+
+					// Handling if the spell is appropriate for the character's class
+					if (idx < MAX_SPELLS_PER_CLASS) {
+						if (!c->_spells[idx] || (isCasting & 0x80)) {
+							int cost = spells.calcSpellCost(Res.SPELLS_ALLOWED[category][idx], expenseFactor);
+							_spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u",
+								spells._spellNames[Res.SPELLS_ALLOWED[category][idx]].c_str(), cost),
+								idx, spellId));
+						}
+					}
+				}
+			} else if (isDarkCc) {
+				int groupIndex = (party._mazeId - 29) / 2;
+				for (int spellId = Res.DARK_SPELL_RANGES[groupIndex][0];
+						spellId < Res.DARK_SPELL_RANGES[groupIndex][1]; ++spellId) {
+					int idx = 0;
+					while (idx < 40 && Res.SPELLS_ALLOWED[category][idx] ==
+						Res.DARK_SPELL_OFFSETS[category][spellId]);
+
+					if (idx < 40) {
+						if (!c->_spells[idx] || (isCasting & 0x80)) {
+							int cost = spells.calcSpellCost(Res.SPELLS_ALLOWED[category][idx], expenseFactor);
+							_spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u",
+								spells._spellNames[Res.SPELLS_ALLOWED[category][idx]].c_str(), cost),
+								idx, spellId));
+						}
+					}
+				}
+			} else {
+				for (int spellId = 0; spellId < 20; ++spellId) {
+					int idx = 0;
+					while (Res.CLOUDS_SPELL_OFFSETS[party._mazeId - 29][spellId] !=
+						(int)Res.SPELLS_ALLOWED[category][idx] && idx < 40) ;
+
+					if (idx < 40) {
+						if (!c->_spells[idx] || (isCasting & 0x80)) {
+							int cost = spells.calcSpellCost(Res.SPELLS_ALLOWED[category][idx], expenseFactor);
+							_spells.push_back(SpellEntry(Common::String::format("\x3l%s\x3r\x9""000%u",
+								spells._spellNames[Res.SPELLS_ALLOWED[category][idx]].c_str(), cost),
+								idx, spellId));
+						}
+					}
+				}
+			}
+		}
+
+		if (c->getMaxSP() == 0)
+			return Res.NOT_A_SPELL_CASTER;
+
+	} else if ((isCasting & 0x7f) == 1) {
+		switch (c->_class) {
+		case CLASS_ARCHER:
+		case CLASS_SORCERER:
+			category = 1;
+			break;
+		case CLASS_DRUID:
+		case CLASS_RANGER:
+			category = 2;
+			break;
+		case CLASS_PALADIN:
+		case CLASS_CLERIC:
+		default:
+			category = 0;
+			break;
+		}
+
+		if (c->getMaxSP() == 0) {
+			return Res.NOT_A_SPELL_CASTER;
+		} else {
+			for (int spellIndex = 0; spellIndex < MAX_SPELLS_PER_CLASS; ++spellIndex) {
+				if (c->_spells[spellIndex]) {
+					int spellId = Res.SPELLS_ALLOWED[category][spellIndex];
+					int gemCost = Res.SPELL_GEM_COST[spellId];
+					int spCost = spells.calcSpellPoints(spellId, currLevel);
+
+					Common::String msg = Common::String::format("\x3l%s\x3r\x9""000%u/%u",
+						spells._spellNames[spellId].c_str(), spCost, gemCost);
+					_spells.push_back(SpellEntry(msg, spellIndex, spellId));
+				}
+			}
+		}
+	}
+
+	return nullptr;
+}
+
+/*------------------------------------------------------------------------*/
+
+CastSpell::CastSpell(XeenEngine *vm) : ButtonContainer(vm) {
+	Windows &windows = *_vm->_windows;
+	_oldMode = _vm->_mode;
+	_vm->_mode = MODE_3;
+
+	windows[10].open();
+	loadButtons();
+}
+
+CastSpell::~CastSpell() {
+	Interface &intf = *_vm->_interface;
+	Windows &windows = *_vm->_windows;
+
+	windows[10].close();
+	intf.unhighlightChar();
+
+	_vm->_mode = (Mode)_oldMode;
+}
+
+
+int CastSpell::show(XeenEngine *vm) {
+	Combat &combat = *vm->_combat;
+	Interface &intf = *vm->_interface;
+	Party &party = *vm->_party;
+	Spells &spells = *vm->_spells;
+	int charNum;
+
+	// Get which character is doing the casting
+	if (vm->_mode == MODE_COMBAT) {
+		charNum = combat._whosTurn;
+	} else if (spells._lastCaster >= 0 && spells._lastCaster < (int)party._activeParty.size()) {
+		charNum = spells._lastCaster;
+	} else {
+		for (charNum = (int)party._activeParty.size() - 1; charNum >= 0; --charNum) {
+			if (party._activeParty[charNum]._hasSpells) {
+				spells._lastCaster = charNum;
+				break;
+			}
+		}
+	}
+
+	Character *c = &party._activeParty[charNum];
+	intf.highlightChar(charNum);
+
+	return show(vm, c);
+}
+
+int CastSpell::show(XeenEngine *vm, Character *&c) {
+	Spells &spells = *vm->_spells;
+	CastSpell *dlg = new CastSpell(vm);
+	int spellId;
+	int result = -1;
+
+	do {
+		spellId = dlg->execute(c);
+
+		if (g_vm->shouldExit() || spellId == -1) {
+			result = 0;
+		} else {
+			result = spells.castSpell(c, (MagicSpell)spellId);
+		}
+	} while (result == -1);
+
+	delete dlg;
+	return result;
+}
+
+int CastSpell::execute(Character *&c) {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Spells &spells = *_vm->_spells;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[10];
+
+	int spellId = -1;
+	bool redrawFlag = true;
+	do {
+		if (redrawFlag) {
+			int category = c->getClassCategory();
+			int spellIndex = c->_currentSpell != -1 ? c->_currentSpell : 39;
+			spellId = Res.SPELLS_ALLOWED[category][spellIndex];
+			int gemCost = Res.SPELL_GEM_COST[spellId];
+			int spCost = spells.calcSpellPoints(spellId, c->getCurrentLevel());
+
+			w.writeString(Common::String::format(Res.CAST_SPELL_DETAILS,
+				c->_name.c_str(), spells._spellNames[spellId].c_str(),
+				spCost, gemCost, c->_currentSp));
+			drawButtons(&windows[0]);
+			w.update();
+
+			redrawFlag = false;
+		}
+
+		events.updateGameCounter();
+		intf.draw3d(true);
+
+		// Wait for event or time expiry
+		do {
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+		} while (!_vm->shouldExit() && events.timeElapsed() < 1 && !_buttonValue);
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_F1:
+		case Common::KEYCODE_F2:
+		case Common::KEYCODE_F3:
+		case Common::KEYCODE_F4:
+		case Common::KEYCODE_F5:
+		case Common::KEYCODE_F6:
+			// Only allow changing character if the party is not in combat
+			if (_oldMode != MODE_COMBAT) {
+				_vm->_mode = (Mode)_oldMode;
+				_buttonValue -= Common::KEYCODE_F1;
+
+				if (_buttonValue < (int)party._activeParty.size()) {
+					c = &party._activeParty[_buttonValue];
+					intf.highlightChar(_buttonValue);
+					redrawFlag = true;
+					break;
+				}
+			}
+			break;
+
+		case Common::KEYCODE_ESCAPE:
+			spellId = -1;
+			break;
+
+		case Common::KEYCODE_c:
+			// Cast spell - return the selected spell Id to be cast
+			if (c->_currentSpell != -1 && !c->noActions())
+				_buttonValue = Common::KEYCODE_ESCAPE;
+			break;
+
+		case Common::KEYCODE_n:
+			// Select new spell
+			_vm->_mode = (Mode)_oldMode;
+			c = SpellsDialog::show(_vm, this, c, 1);
+			redrawFlag = true;
+			break;
+
+		default:
+			break;
+		}
+	} while (!_vm->shouldExit() && _buttonValue != Common::KEYCODE_ESCAPE);
+
+	if (_vm->shouldExit())
+		spellId = -1;
+	return spellId;
+}
+
+void CastSpell::loadButtons() {
+	_iconSprites.load("cast.icn");
+	addButton(Common::Rect(234, 108, 259, 128), Common::KEYCODE_c, &_iconSprites);
+	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_n, &_iconSprites);
+	addButton(Common::Rect(288, 108, 312, 128), Common::KEYCODE_ESCAPE, &_iconSprites);
+	addPartyButtons(_vm);
+}
+
+/*------------------------------------------------------------------------*/
+
+Character *SpellOnWho::show(XeenEngine *vm, int spellId) {
+	SpellOnWho *dlg = new SpellOnWho(vm);
+	int result = dlg->execute(spellId);
+	delete dlg;
+
+	if (result == -1)
+		return nullptr;
+
+	Combat &combat = *vm->_combat;
+	Party &party = *vm->_party;
+	return combat._combatMode == 2 ? combat._combatParty[result] :
+		&party._activeParty[result];
+}
+
+int SpellOnWho::execute(int spellId) {
+	Combat &combat = *_vm->_combat;
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Party &party = *_vm->_party;
+	Spells &spells = *_vm->_spells;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[16];
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = MODE_3;
+	int result = 999;
+
+	w.open();
+	w.writeString(Res.ON_WHO);
+	w.update();
+	addPartyButtons(_vm);
+
+	while (result == 999) {
+		do {
+			events.updateGameCounter();
+			intf.draw3d(true);
+
+			do {
+				events.pollEventsAndWait();
+				if (_vm->shouldExit())
+					return -1;
+
+				checkEvents(_vm);
+			} while (!_buttonValue && events.timeElapsed() < 1);
+		} while (!_buttonValue);
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_ESCAPE:
+			result = -1;
+			spells.addSpellCost(*combat._oldCharacter, spellId);
+			break;
+
+		case Common::KEYCODE_F1:
+		case Common::KEYCODE_F2:
+		case Common::KEYCODE_F3:
+		case Common::KEYCODE_F4:
+		case Common::KEYCODE_F5:
+		case Common::KEYCODE_F6:
+			_buttonValue -= Common::KEYCODE_F1;
+			if (_buttonValue < (int)(combat._combatMode == 2 ? combat._combatParty.size() :
+					party._activeParty.size())) {
+				result = _buttonValue;
+			}
+			break;
+		}
+	}
+
+	w.close();
+	_vm->_mode = oldMode;
+	return result;
+}
+
+/*------------------------------------------------------------------------*/
+
+int SelectElement::show(XeenEngine *vm, int spellId) {
+	SelectElement *dlg = new SelectElement(vm);
+	int result = dlg->execute(spellId);
+	delete dlg;
+
+	return result;
+}
+
+int SelectElement::execute(int spellId) {
+	Combat &combat = *_vm->_combat;
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Spells &spells = *_vm->_spells;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[15];
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = MODE_3;
+	int result = 999;
+
+	loadButtons();
+
+	w.open();
+	w.writeString(Res.WHICH_ELEMENT1);
+	drawButtons(&windows[0]);
+	w.update();
+
+	while (result == 999) {
+		do {
+			events.updateGameCounter();
+			intf.draw3d(true);
+			w.frame();
+			w.writeString(Res.WHICH_ELEMENT2);
+			drawButtons(&windows[0]);
+			w.update();
+
+			do {
+				events.pollEventsAndWait();
+				if (_vm->shouldExit())
+					return -1;
+
+				checkEvents(_vm);
+			} while (!_buttonValue && events.timeElapsed() < 1);
+		} while (!_buttonValue);
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_ESCAPE:
+			result = -1;
+			spells.addSpellCost(*combat._oldCharacter, spellId);
+			break;
+
+		case Common::KEYCODE_a:
+			result = DT_POISON;
+			break;
+		case Common::KEYCODE_c:
+			result = DT_COLD;
+			break;
+		case Common::KEYCODE_e:
+			result = DT_ELECTRICAL;
+			break;
+		case Common::KEYCODE_f:
+			result = DT_FIRE;
+			break;
+		default:
+			break;
+		}
+	}
+
+	w.close();
+	_vm->_mode = oldMode;
+	return result;
+}
+
+void SelectElement::loadButtons() {
+	_iconSprites.load("element.icn");
+	addButton(Common::Rect(60, 92, 84, 112), Common::KEYCODE_f, &_iconSprites);
+	addButton(Common::Rect(90, 92, 114, 112), Common::KEYCODE_e, &_iconSprites);
+	addButton(Common::Rect(120, 92, 144, 112), Common::KEYCODE_c, &_iconSprites);
+	addButton(Common::Rect(150, 92, 174, 112), Common::KEYCODE_a, &_iconSprites);
+}
+
+/*------------------------------------------------------------------------*/
+
+void NotWhileEngaged::show(XeenEngine *vm, int spellId) {
+	NotWhileEngaged *dlg = new NotWhileEngaged(vm);
+	dlg->execute(spellId);
+	delete dlg;
+}
+
+void NotWhileEngaged::execute(int spellId) {
+	EventsManager &events = *_vm->_events;
+	Spells &spells = *_vm->_spells;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[6];
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = MODE_3;
+
+	w.open();
+	w.writeString(Common::String::format(Res.CANT_CAST_WHILE_ENGAGED,
+		spells._spellNames[spellId].c_str()));
+	w.update();
+
+	while (!_vm->shouldExit() && !events.isKeyMousePressed())
+		events.pollEventsAndWait();
+	events.clearEvents();
+
+	w.close();
+	_vm->_mode = oldMode;
+}
+
+/*------------------------------------------------------------------------*/
+
+bool LloydsBeacon::show(XeenEngine *vm) {
+	LloydsBeacon *dlg = new LloydsBeacon(vm);
+	bool result = dlg->execute();
+	delete dlg;
+
+	return result;
+}
+
+bool LloydsBeacon::execute() {
+	Combat &combat = *_vm->_combat;
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Map &map = *_vm->_map;
+	Party &party = *_vm->_party;
+	Sound &sound = *_vm->_sound;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[10];
+	bool isDarkCc = _vm->_files->_isDarkCc;
+	Character &c = *combat._oldCharacter;
+
+	loadButtons();
+
+	if (!c._lloydMap) {
+		// No destination previously set, so have a default ready
+		if (isDarkCc) {
+			c._lloydSide = 1;
+			c._lloydPosition = Common::Point(25, 21);
+			c._lloydMap = 29;
+		} else {
+			c._lloydSide = 0;
+			c._lloydPosition = Common::Point(18, 4);
+			c._lloydMap = 28;
+		}
+	}
+
+	// Open up the text file for the destination map and read in it's name
+	File textFile(Common::String::format("%s%c%03d.txt",
+		c._lloydSide == 0 ? "xeen" : "dark",
+		c._lloydMap >= 100 ? 'x' : '0',
+		c._lloydMap));
+	Common::String mapName = textFile.readString();
+	textFile.close();
+
+	// Display the dialog
+	w.open();
+	w.writeString(Common::String::format(Res.LLOYDS_BEACON,
+		mapName.c_str(), c._lloydPosition.x, c._lloydPosition.y));
+	drawButtons(&windows[0]);
+	w.update();
+
+	bool result = true;
+	do {
+		do {
+			events.updateGameCounter();
+			intf.draw3d(true);
+
+			do {
+				events.pollEventsAndWait();
+				if (_vm->shouldExit())
+					return true;
+
+				checkEvents(_vm);
+			} while (!_buttonValue && events.timeElapsed() < 1);
+		} while (!_buttonValue);
+
+		switch (_buttonValue) {
+		case Common::KEYCODE_r:
+			if (!isDarkCc && c._lloydMap >= 75 && c._lloydMap <= 78 && !party._cloudsEnd) {
+				result = false;
+			} else {
+				sound.playFX(51);
+				map._loadDarkSide = isDarkCc;
+				if (c._lloydMap != party._mazeId || c._lloydSide != (isDarkCc ? 1 : 0)) {
+					map.load(c._lloydMap);
+				}
+
+				party._mazePosition = c._lloydPosition;
+			}
+
+			_buttonValue = Common::KEYCODE_ESCAPE;
+			break;
+
+		case Common::KEYCODE_s:
+		case Common::KEYCODE_t:
+			sound.playFX(20);
+			c._lloydMap = party._mazeId;
+			c._lloydPosition = party._mazePosition;
+			c._lloydSide = isDarkCc ? 1 : 0;
+
+			_buttonValue = Common::KEYCODE_ESCAPE;
+			break;
+		}
+	} while (_buttonValue != Common::KEYCODE_ESCAPE);
+
+	w.close();
+	return result;
+}
+
+void LloydsBeacon::loadButtons() {
+	_iconSprites.load("lloyds.icn");
+
+	addButton(Common::Rect(281, 108, 305, 128), Common::KEYCODE_r, &_iconSprites);
+	addButton(Common::Rect(242, 108, 266, 128), Common::KEYCODE_t, &_iconSprites);
+}
+
+/*------------------------------------------------------------------------*/
+
+int Teleport::show(XeenEngine *vm) {
+	Teleport *dlg = new Teleport(vm);
+	int result = dlg->execute();
+	delete dlg;
+
+	return result;
+}
+
+int Teleport::execute() {
+	Map &map = *_vm->_map;
+	Party &party = *_vm->_party;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[6];
+	Common::String num;
+
+	w.open();
+	w.writeString(Common::String::format(Res.HOW_MANY_SQUARES,
+		Res.DIRECTION_TEXT[party._mazeDirection]));
+	w.update();
+	int lineSize = Input::show(_vm, &w, num, 1, 200, true);
+	w.close();
+
+	if (!lineSize)
+		return -1;
+	int numSquares = atoi(num.c_str());
+	Common::Point pt = party._mazePosition;
+	int v;
+
+	switch (party._mazeDirection) {
+	case DIR_NORTH:
+		pt.y += numSquares;
+		break;
+	case DIR_EAST:
+		pt.x += numSquares;
+		break;
+	case DIR_SOUTH:
+		pt.y -= numSquares;
+		break;
+	case DIR_WEST:
+		pt.x -= numSquares;
+		break;
+	default:
+		break;
+	}
+
+	v = map.mazeLookup(pt, map._isOutdoors ? 0xF : 0xFFFF, 0);
+
+	if ((v != (map._isOutdoors ? 0 : INVALID_CELL)) &&
+		(!map._isOutdoors || v == SURFTYPE_DWATER)) {
+		party._mazePosition = pt;
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+/*------------------------------------------------------------------------*/
+
+int TownPortal::show(XeenEngine *vm) {
+	TownPortal *dlg = new TownPortal(vm);
+	int townNumber = dlg->execute();
+	delete dlg;
+
+	return townNumber;
+}
+
+int TownPortal::execute() {
+	Map &map = *_vm->_map;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[20];
+	Common::String townNames[5];
+	Mode oldMode = _vm->_mode;
+	_vm->_mode = MODE_FF;
+
+	// Build up a lsit of the names of the towns on the current side of Xeen
+	for (int idx = 0; idx < 5; ++idx) {
+		File f(Common::String::format("%s%04d.txt",
+			map._sideTownPortal ? "dark" : "xeen",
+			Res.TOWN_MAP_NUMBERS[map._sideTownPortal][idx]));
+		townNames[idx] = f.readString();
+		f.close();
+	}
+
+	w.open();
+	w.writeString(Common::String::format(Res.TOWN_PORTAL,
+		townNames[0].c_str(), townNames[1].c_str(), townNames[2].c_str(),
+		townNames[3].c_str(), townNames[4].c_str()
+	));
+	w.update();
+
+	// Get the town number
+	int townNumber;
+	Common::String num;
+	do {
+		int result = Input::show(_vm, &w, num, 1, 160, true);
+		townNumber = !result ? 0 : atoi(num.c_str());
+	} while (townNumber > 5);
+
+	w.close();
+	_vm->_mode = oldMode;
+
+	return townNumber;
+}
+
+/*------------------------------------------------------------------------*/
+
+void IdentifyMonster::show(XeenEngine *vm) {
+	IdentifyMonster *dlg = new IdentifyMonster(vm);
+	dlg->execute();
+	delete dlg;
+}
+
+void IdentifyMonster::execute() {
+	Combat &combat = *_vm->_combat;
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Map &map = *_vm->_map;
+	Sound &sound = *_vm->_sound;
+	Windows &windows = *_vm->_windows;
+	Window &w = windows[17];
+	Common::String monsterDesc[3];
+
+	for (int monIndex = 0; monIndex < 3; ++monIndex) {
+		if (combat._attackMonsters[monIndex] == -1)
+			continue;
+
+		MazeMonster &monster = map._mobData._monsters[combat._attackMonsters[monIndex]];
+		MonsterStruct &monsterData = *monster._monsterData;
+
+		monsterDesc[monIndex] = Common::String::format(Res.MONSTER_DETAILS,
+			monsterData._name.c_str(),
+			_vm->printK2(monster._hp).c_str(),
+			monsterData._armorClass, monsterData._numberOfAttacks,
+			Res.MONSTER_SPECIAL_ATTACKS[monsterData._specialAttack]
+		);
+	}
+
+	sound.playFX(20);
+	w.open();
+	w.writeString(Common::String::format(Res.IDENTIFY_MONSTERS,
+		monsterDesc[0].c_str(), monsterDesc[1].c_str(), monsterDesc[2].c_str()));
+	w.update();
+
+	do {
+		events.updateGameCounter();
+		intf.draw3d(false);
+		w.frame();
+		windows[3].update();
+
+		events.wait(1, false);
+	} while (!events.isKeyMousePressed());
+
+	w.close();
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_spells.h b/engines/xeen/dialogs/dialogs_spells.h
new file mode 100644
index 0000000..2bcaef4
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_spells.h
@@ -0,0 +1,151 @@
+/* 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 XEEN_DIALOGS_SPELLS_H
+#define XEEN_DIALOGS_SPELLS_H
+
+#include "common/array.h"
+#include "xeen/dialogs/dialogs.h"
+#include "xeen/party.h"
+
+namespace Xeen {
+
+struct SpellEntry {
+	Common::String _name;
+	int _spellIndex;
+	int _spellId;
+	int _color;
+
+	SpellEntry(const Common::String &name, int spellIndex, int spellId) :
+		_name(name), _spellIndex(spellIndex), _spellId(spellId), _color(9) {}
+};
+
+class SpellsDialog : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+	SpriteResource _scrollSprites;
+	Common::Array<SpellEntry> _spells;
+
+	SpellsDialog(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	Character *execute(ButtonContainer *priorDialog, Character *c, int isCasting);
+
+	void loadButtons();
+
+	const char *setSpellText(Character *c, int isCasting);
+public:
+	static Character *show(XeenEngine *vm, ButtonContainer *priorDialog,
+		Character *c, int isCasting);
+};
+
+class CastSpell : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+	int _oldMode;
+private:
+	CastSpell(XeenEngine *vm);
+	~CastSpell();
+
+	int execute(Character *&c);
+
+	void loadButtons();
+public:
+	static int show(XeenEngine *vm);
+	static int show(XeenEngine *vm, Character *&c);
+};
+
+class SpellOnWho : public ButtonContainer {
+private:
+	SpellOnWho(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	int execute(int spellId);
+public:
+	static Character *show(XeenEngine *vm, int spellId);
+};
+
+class SelectElement : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+
+	SelectElement(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	int execute(int spellId);
+
+	void loadButtons();
+public:
+	static int show(XeenEngine *vm, int spellId);
+};
+
+class NotWhileEngaged : public ButtonContainer {
+private:
+	NotWhileEngaged(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute(int spellId);
+public:
+	static void show(XeenEngine *vm, int spellId);
+};
+
+class LloydsBeacon : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+
+	LloydsBeacon(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	bool execute();
+
+	void loadButtons();
+public:
+	static bool show(XeenEngine *vm);
+};
+
+class Teleport : public ButtonContainer {
+private:
+	SpriteResource _iconSprites;
+
+	Teleport(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	int execute();
+public:
+	static int show(XeenEngine *vm);
+};
+
+class TownPortal : public ButtonContainer {
+private:
+	TownPortal(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	int execute();
+public:
+	static int show(XeenEngine *vm);
+};
+
+class IdentifyMonster : public ButtonContainer {
+private:
+	IdentifyMonster(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute();
+public:
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_SPELLS_H */
diff --git a/engines/xeen/dialogs/dialogs_whowill.cpp b/engines/xeen/dialogs/dialogs_whowill.cpp
new file mode 100644
index 0000000..8428042
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_whowill.cpp
@@ -0,0 +1,105 @@
+/* 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 "xeen/dialogs/dialogs_whowill.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+int WhoWill::show(XeenEngine *vm, int message, int action, bool type) {
+	WhoWill *dlg = new WhoWill(vm);
+	int result = dlg->execute(message, action, type);
+	delete dlg;
+
+	return result;
+}
+
+int WhoWill::execute(int message, int action, bool type) {
+	EventsManager &events = *_vm->_events;
+	Interface &intf = *_vm->_interface;
+	Map &map = *_vm->_map;
+	Party &party = *_vm->_party;
+	Scripts &scripts = *_vm->_scripts;
+	LocationManager &loc = *_vm->_locations;
+	Windows &windows = *_vm->_windows;
+	int numFrames;
+
+	if (party._activeParty.size() <= 1)
+		// Unless there's at least two characters, just return the first one
+		return 1;
+
+	windows[38].close();
+	windows[12].close();
+
+	Common::String actionStr = type ? map._events._text[action] : Res.WHO_WILL_ACTIONS[action];
+	Common::String msg = Common::String::format(Res.WHO_WILL, actionStr.c_str(),
+		Res.WHO_ACTIONS[message], party._activeParty.size());
+
+	windows[36].open();
+	windows[36].writeString(msg);
+	windows[36].update();
+
+	intf._face1State = map._headData[party._mazePosition.y][party._mazePosition.x]._left;
+	intf._face2State = map._headData[party._mazePosition.y][party._mazePosition.x]._right;
+
+	while (!_vm->shouldExit()) {
+		events.updateGameCounter();
+
+		if (windows[11]._enabled) {
+			loc.drawAnim(false);
+			windows[36].frame();
+			numFrames = 3;
+		} else {
+			intf.draw3d(false);
+			windows[36].frame();
+			windows[3].update();
+			numFrames = 1;
+		}
+
+		events.wait(numFrames);
+		checkEvents(_vm);
+		if (!_buttonValue)
+			continue;
+
+		if (_buttonValue == 27) {
+			_buttonValue = 0;
+			break;
+		} else if (_buttonValue >= Common::KEYCODE_F1 && _buttonValue <= Common::KEYCODE_F6) {
+			_buttonValue -= Common::KEYCODE_F1 - 1;
+			if (_buttonValue > (int)party._activeParty.size())
+				continue;
+
+			if (party._activeParty[_buttonValue - 1].noActions())
+				continue;
+
+			scripts._whoWill = _buttonValue;
+			break;
+		}
+	}
+
+	intf._face1State = intf._face2State = 2;
+	windows[36].close();
+	return _buttonValue;
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs_whowill.h b/engines/xeen/dialogs/dialogs_whowill.h
new file mode 100644
index 0000000..5303bdb
--- /dev/null
+++ b/engines/xeen/dialogs/dialogs_whowill.h
@@ -0,0 +1,41 @@
+/* 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 XEEN_DIALOGS_WHOWHILL_H
+#define XEEN_DIALOGS_WHOWHILL_H
+
+#include "xeen/dialogs/dialogs.h"
+
+namespace Xeen {
+
+class WhoWill : public ButtonContainer {
+private:
+	WhoWill(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	int execute(int message, int action, bool type);
+public:
+	static int show(XeenEngine *vm, int message, int action, bool type);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_WHOWHILL_H */
diff --git a/engines/xeen/dialogs_awards.cpp b/engines/xeen/dialogs_awards.cpp
deleted file mode 100644
index 242539c..0000000
--- a/engines/xeen/dialogs_awards.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "xeen/dialogs_awards.h"
-#include "xeen/party.h"
-#include "xeen/resources.h"
-#include "xeen/xeen.h"
-
-namespace Xeen {
-
-void Awards::show(XeenEngine *vm, const Character *ch) {
-	Awards *dlg = new Awards(vm);
-	dlg->execute(ch);
-	delete dlg;
-}
-
-void Awards::execute(const Character *ch) {
-	EventsManager &events = *g_vm->_events;
-	Windows &windows = *g_vm->_windows;
-	Common::StringArray awards;
-	int numAwards;
-	Mode oldMode = g_vm->_mode;
-	int topIndex = 0;
-
-	loadStrings("award.bin", 1);
-	addButtons();
-
-	// Open the window and draw contents
-	bool win29Open = windows[29]._enabled;
-	if (!win29Open) {
-		windows[29].open();
-		windows[30].open();
-	}
-
-	windows[29].writeString(Res.AWARDS_TEXT);
-	drawButtons(&windows[0]);
-
-	while (!_vm->shouldExit()) {
-		// Build up a list of awards the character has
-		awards.clear();
-		awards.resize(AWARDS_TOTAL);
-		numAwards = 0;
-
-		for (int awardNum = 0; awardNum < AWARDS_TOTAL; ++awardNum) {
-			if (ch->hasAward(awardNum)) {
-				if (awardNum == 9) {
-					// # Warzone Wins
-					awards[numAwards] = Common::String::format(_textStrings[9].c_str(), 28);
-				} else if (awardNum == 17) {
-					// Legendary Race
-					awards[numAwards] = Common::String::format(_textStrings[17].c_str(),
-						Res.RACE_NAMES[ch->_race]);
-				} else {
-					awards[numAwards] = _textStrings[awardNum];
-				}
-				++numAwards;
-			}
-		}
-
-		// If no awards, add in a message indicating so
-		if (numAwards == 0) {
-			awards[1] = Res.NO_AWARDS;
-		}
-
-		Common::String msg = Common::String::format(Res.AWARDS_FOR,
-			ch->_name.c_str(), Res.CLASS_NAMES[ch->_class],
-			awards[topIndex].c_str(),
-			awards[topIndex + 1].c_str(),
-			awards[topIndex + 2].c_str(),
-			awards[topIndex + 3].c_str(),
-			awards[topIndex + 4].c_str(),
-			awards[topIndex + 5].c_str(),
-			awards[topIndex + 6].c_str(),
-			awards[topIndex + 7].c_str(),
-			awards[topIndex + 8].c_str()
-		);
-		windows[30].writeString(msg);
-		windows[24].update();
-
-		// Wait for keypress
-		do {
-			events.pollEventsAndWait();
-			checkEvents(_vm);
-		} while (!g_vm->shouldExit() && !_buttonValue);
-
-		if (_buttonValue == Common::KEYCODE_ESCAPE) {
-			break;
-		} else if (_buttonValue == Common::KEYCODE_u) {
-			topIndex = MAX(topIndex - 1, 0);
-		} else if (_buttonValue == Common::KEYCODE_d) {
-			if ((++topIndex + 9) > numAwards)
-				--topIndex;
-		}
-	}
-
-	// Close the window
-	if (win29Open) {
-		windows[30].close();
-		windows[29].close();
-	}
-
-	g_vm->_mode = oldMode;
-}
-
-void Awards::addButtons() {
-	_iconSprites.load("award.icn");
-	addButton(Common::Rect(216, 109, 240, 129), Common::KEYCODE_u, &_iconSprites);
-	addButton(Common::Rect(250, 109, 274, 129), Common::KEYCODE_d, &_iconSprites);
-	addButton(Common::Rect(284, 109, 308, 129), Common::KEYCODE_ESCAPE, &_iconSprites);
-}
-
-} // End of namespace Xeen
diff --git a/engines/xeen/dialogs_awards.h b/engines/xeen/dialogs_awards.h
deleted file mode 100644
index 6ce3a05..0000000
--- a/engines/xeen/dialogs_awards.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef XEEN_DIALOGS_AWARDS_H
-#define XEEN_DIALOGS_AWARDS_H
-
-#include "xeen/dialogs.h"
-#include "xeen/character.h"
-
-namespace Xeen {
-
-class Awards : public ButtonContainer {
-private:
-	SpriteResource _iconSprites;
-private:
-	Awards(XeenEngine *vm) : ButtonContainer(vm) {}
-
-	/**
-	 * Executes the dialog
-	 */
-	void execute(const Character *ch);
-
-	/**
-	 * Add buttons for the dialog
-	 */
-	void addButtons();
-public:
-	static void show(XeenEngine *vm, const Character *ch);
-};
-
-} // End of namespace Xeen
-
-#endif /* XEEN_DIALOGS_AWARDS_H */
diff --git a/engines/xeen/dialogs_char_info.cpp b/engines/xeen/dialogs_char_info.cpp
deleted file mode 100644
index 3d9ebfb..0000000
--- a/engines/xeen/dialogs_char_info.cpp
+++ /dev/null
@@ -1,571 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "xeen/dialogs_awards.h"
-#include "xeen/dialogs_char_info.h"
-#include "xeen/dialogs_exchange.h"
-#include "xeen/dialogs_items.h"
-#include "xeen/dialogs_quick_ref.h"
-#include "xeen/resources.h"
-#include "xeen/xeen.h"
-
-namespace Xeen {
-
-void CharacterInfo::show(XeenEngine *vm, int charIndex) {
-	CharacterInfo *dlg = new CharacterInfo(vm);
-	dlg->execute(charIndex);
-	delete dlg;
-}
-
-void CharacterInfo::execute(int charIndex) {
-	Combat &combat = *_vm->_combat;
-	EventsManager &events = *_vm->_events;
-	Interface &intf = *_vm->_interface;
-	Party &party = *_vm->_party;
-	Windows &windows = *_vm->_windows;
-
-	bool redrawFlag = true;
-	Mode oldMode = _vm->_mode;
-	_vm->_mode = MODE_CHARACTER_INFO;
-	loadDrawStructs();
-	addButtons();
-
-	Character *c = (oldMode != MODE_COMBAT) ? &party._activeParty[charIndex] : combat._combatParty[charIndex];
-	intf.highlightChar(charIndex);
-	Window &w = windows[24];
-	w.open();
-
-	do {
-		if (redrawFlag) {
-			Common::String charDetails = loadCharacterDetails(*c);
-			w.writeString(Common::String::format(Res.CHARACTER_TEMPLATE, charDetails.c_str()));
-			w.drawList(_drawList, 24);
-			w.update();
-			redrawFlag = false;
-		}
-
-		// Wait for keypress, showing a blinking cursor
-		events.updateGameCounter();
-		bool cursorFlag = false;
-		_buttonValue = 0;
-		while (!_vm->shouldExit() && !_buttonValue) {
-			events.pollEventsAndWait();
-			if (events.timeElapsed() > 4) {
-				cursorFlag = !cursorFlag;
-				events.updateGameCounter();
-			}
-
-			showCursor(cursorFlag);
-			w.update();
-			checkEvents(_vm);
-		}
-		events.clearEvents();
-
-		switch (_buttonValue) {
-		case Common::KEYCODE_F1:
-		case Common::KEYCODE_F2:
-		case Common::KEYCODE_F3:
-		case Common::KEYCODE_F4:
-		case Common::KEYCODE_F5:
-		case Common::KEYCODE_F6:
-			_buttonValue -= Common::KEYCODE_F1;
-			if (_buttonValue < (int)(oldMode == MODE_COMBAT ? combat._combatParty.size() : party._activeParty.size())) {
-				charIndex = _buttonValue;
-				c = (oldMode != MODE_COMBAT) ? &party._activeParty[charIndex] : combat._combatParty[charIndex];
-			} else {
-				_vm->_mode = MODE_CHARACTER_INFO;
-			}
-
-			intf.highlightChar(_buttonValue);
-			redrawFlag = true;
-			break;
-
-		case Common::KEYCODE_UP:
-		case Common::KEYCODE_KP8:
-			if (_cursorCell > 0) {
-				showCursor(false);
-				--_cursorCell;
-				showCursor(true);
-			}
-			w.update();
-			break;
-
-		case Common::KEYCODE_DOWN:
-		case Common::KEYCODE_KP2:
-			if (_cursorCell < 20) {
-				showCursor(false);
-				++_cursorCell;
-				showCursor(true);
-			}
-			w.update();
-			break;
-
-		case Common::KEYCODE_LEFT:
-		case Common::KEYCODE_KP4:
-			if (_cursorCell >= 5) {
-				showCursor(false);
-				_cursorCell -= 5;
-				showCursor(true);
-			}
-			w.update();
-			break;
-
-		case Common::KEYCODE_RIGHT:
-		case Common::KEYCODE_KP6:
-			if (_cursorCell <= 15) {
-				showCursor(false);
-				_cursorCell += 5;
-				showCursor(true);
-			}
-			w.update();
-			break;
-
-		case Common::KEYCODE_RETURN:
-		case Common::KEYCODE_KP_ENTER:
-			_buttonValue = _cursorCell + Common::KEYCODE_a;
-			// Deliberate fall-through
-
-		case 1001:
-		case 1002:
-		case 1003:
-		case 1004:
-		case 1005:
-		case 1006:
-		case 1007:
-		case 1008:
-		case 1009:
-		case 1010:
-		case 1011:
-		case 1012:
-		case 1013:
-		case 1014:
-		case 1015:
-		case 1016:
-		case 1017:
-		case 1018:
-		case 1019:
-		case 1020: {
-			showCursor(false);
-			_cursorCell = _buttonValue - 1001;
-			showCursor(true);
-			w.update();
-
-			bool result = expandStat(_cursorCell, *c);
-			_vm->_mode = MODE_COMBAT;
-			if (result)
-				redrawFlag = true;
-			break;
-		}
-
-		case Common::KEYCODE_e:
-			if (oldMode == MODE_COMBAT) {
-				ErrorScroll::show(_vm, Res.EXCHANGING_IN_COMBAT, WT_FREEZE_WAIT);
-			} else {
-				_vm->_mode = oldMode;
-				ExchangeDialog::show(_vm, c, charIndex);
-				_vm->_mode = MODE_CHARACTER_INFO;
-				redrawFlag = true;
-			}
-			break;
-
-		case Common::KEYCODE_i:
-			_vm->_mode = oldMode;
-			_vm->_combat->_itemFlag = _vm->_mode == MODE_COMBAT;
-			c = ItemsDialog::show(_vm, c, ITEMMODE_CHAR_INFO);
-
-			if (!c) {
-				party._stepped = true;
-				goto exit;
-			}
-
-			_vm->_mode = MODE_CHARACTER_INFO;
-			break;
-
-		case Common::KEYCODE_q:
-			QuickReferenceDialog::show(_vm);
-			redrawFlag = true;
-			break;
-
-		case Common::KEYCODE_ESCAPE:
-			goto exit;
-		}
-	} while (!_vm->shouldExit());
-exit:
-	w.close();
-	intf.unhighlightChar();
-	_vm->_mode = oldMode;
-	_vm->_combat->_itemFlag = false;
-}
-
-void CharacterInfo::loadDrawStructs() {
-	_drawList[0] = DrawStruct(0, 2, 16);
-	_drawList[1] = DrawStruct(2, 2, 39);
-	_drawList[2] = DrawStruct(4, 2, 62);
-	_drawList[3] = DrawStruct(6, 2, 85);
-	_drawList[4] = DrawStruct(8, 2, 108);
-	_drawList[5] = DrawStruct(10, 53, 16);
-	_drawList[6] = DrawStruct(12, 53, 39);
-	_drawList[7] = DrawStruct(14, 53, 62);
-	_drawList[8] = DrawStruct(16, 53, 85);
-	_drawList[9] = DrawStruct(18, 53, 108);
-	_drawList[10] = DrawStruct(20, 104, 16);
-	_drawList[11] = DrawStruct(22, 104, 39);
-	_drawList[12] = DrawStruct(24, 104, 62);
-	_drawList[13] = DrawStruct(26, 104, 85);
-	_drawList[14] = DrawStruct(28, 104, 108);
-	_drawList[15] = DrawStruct(30, 169, 16);
-	_drawList[16] = DrawStruct(32, 169, 39);
-	_drawList[17] = DrawStruct(34, 169, 62);
-	_drawList[18] = DrawStruct(36, 169, 85);
-	_drawList[19] = DrawStruct(38, 169, 108);
-	_drawList[20] = DrawStruct(40, 277, 3);
-	_drawList[21] = DrawStruct(42, 277, 35);
-	_drawList[22] = DrawStruct(44, 277, 67);
-	_drawList[23] = DrawStruct(46, 277, 99);
-
-	_iconSprites.load("view.icn");
-	for (int idx = 0; idx < 24; ++idx)
-		_drawList[idx]._sprites = &_iconSprites;
-}
-
-void CharacterInfo::addButtons() {
-	addButton(Common::Rect(10, 24, 34, 44), 1001, &_iconSprites);
-	addButton(Common::Rect(10, 47, 34, 67), 1002, &_iconSprites);
-	addButton(Common::Rect(10, 70, 34, 90), 1003, &_iconSprites);
-	addButton(Common::Rect(10, 93, 34, 113), 1004, &_iconSprites);
-	addButton(Common::Rect(10, 116, 34, 136), 1005, &_iconSprites);
-	addButton(Common::Rect(61, 24, 85, 44), 1006, &_iconSprites);
-	addButton(Common::Rect(61, 47, 85, 67), 1007, &_iconSprites);
-	addButton(Common::Rect(61, 70, 85, 90), 1008, &_iconSprites);
-	addButton(Common::Rect(61, 93, 85, 113), 1009, &_iconSprites);
-	addButton(Common::Rect(61, 116, 85, 136), 1010, &_iconSprites);
-	addButton(Common::Rect(112, 24, 136, 44), 1011, &_iconSprites);
-	addButton(Common::Rect(112, 47, 136, 67), 1012, &_iconSprites);
-	addButton(Common::Rect(112, 70, 136, 90), 1013, &_iconSprites);
-	addButton(Common::Rect(112, 93, 136, 113), 1014, &_iconSprites);
-	addButton(Common::Rect(112, 116, 136, 136), 1015, &_iconSprites);
-	addButton(Common::Rect(177, 24, 201, 44), 1016, &_iconSprites);
-	addButton(Common::Rect(177, 47, 201, 67), 1017, &_iconSprites);
-	addButton(Common::Rect(177, 70, 201, 90), 1018, &_iconSprites);
-	addButton(Common::Rect(177, 93, 201, 113), 1019, &_iconSprites);
-	addButton(Common::Rect(177, 116, 201, 136), 1020, &_iconSprites);
-	addButton(Common::Rect(285, 11, 309, 31), Common::KEYCODE_i, &_iconSprites);
-	addButton(Common::Rect(285, 43, 309, 63), Common::KEYCODE_q, &_iconSprites);
-	addButton(Common::Rect(285, 75, 309, 95), Common::KEYCODE_e, &_iconSprites);
-	addButton(Common::Rect(285, 107, 309, 127), Common::KEYCODE_ESCAPE, &_iconSprites);
-	addPartyButtons(_vm);
-}
-
-Common::String CharacterInfo::loadCharacterDetails(const Character &c) {
-	Condition condition = c.worstCondition();
-	Party &party = *_vm->_party;
-	int foodVal = party._food / party._activeParty.size() / 3;
-
-	int totalResist =
-		c._fireResistence._permanent + c.itemScan(11) + c._fireResistence._temporary +
-		c._coldResistence._permanent + c.itemScan(13) + c._coldResistence._temporary +
-		c._electricityResistence._permanent + c.itemScan(12) + c._electricityResistence._temporary +
-		c._poisonResistence._permanent + c.itemScan(14) + c._poisonResistence._temporary +
-		c._energyResistence._permanent + c.itemScan(15) + c._energyResistence._temporary +
-		c._magicResistence._permanent + c.itemScan(16) + c._magicResistence._temporary;
-
-	return Common::String::format(Res.CHARACTER_DETAILS,
-		Res.PARTY_GOLD, c._name.c_str(), Res.SEX_NAMES[c._sex],
-		Res.RACE_NAMES[c._race], Res.CLASS_NAMES[c._class],
-		c.statColor(c.getStat(MIGHT), c.getStat(MIGHT, true)), c.getStat(MIGHT),
-		c.statColor(c.getStat(ACCURACY), c.getStat(ACCURACY, true)), c.getStat(ACCURACY),
-		c.statColor(c._currentHp, c.getMaxHP()), c._currentHp,
-		c.getCurrentExperience(),
-		c.statColor(c.getStat(INTELLECT), c.getStat(INTELLECT, true)), c.getStat(INTELLECT),
-		c.statColor(c.getStat(LUCK), c.getStat(LUCK, true)), c.getStat(LUCK),
-		c.statColor(c._currentSp, c.getMaxSP()), c._currentSp,
-		party._gold,
-		c.statColor(c.getStat(PERSONALITY), c.getStat(PERSONALITY, true)), c.getStat(PERSONALITY),
-		c.statColor(c.getAge(), c.getAge(true)), c.getAge(),
-		totalResist,
-		party._gems,
-		c.statColor(c.getStat(ENDURANCE), c.getStat(ENDURANCE, true)), c.getStat(ENDURANCE),
-		c.statColor(c.getCurrentLevel(), c._level._permanent), c.getCurrentLevel(),
-		c.getNumSkills(),
-		foodVal, (foodVal == 1) ? ' ' : 's',
-		c.statColor(c.getStat(SPEED), c.getStat(SPEED, true)), c.getStat(SPEED),
-		c.statColor(c.getArmorClass(), c.getArmorClass(true)), c.getArmorClass(),
-		c.getNumAwards(),
-		Res.CONDITION_COLORS[condition], Res.CONDITION_NAMES[condition],
-		condition == NO_CONDITION && party._blessed ? Res.PLUS_14 : "",
-		condition == NO_CONDITION && party._powerShield ? Res.PLUS_14 : "",
-		condition == NO_CONDITION && party._holyBonus ? Res.PLUS_14 : "",
-		condition == NO_CONDITION && party._heroism ? Res.PLUS_14 : ""
-	);
-}
-
-void CharacterInfo::showCursor(bool flag) {
-	const int CURSOR_X[5] = { 9, 60, 111, 176, 0 };
-	const int CURSOR_Y[5] = { 23, 46, 69, 92, 115 };
-
-	if (_cursorCell < 20) {
-		_iconSprites.draw(0, flag ? 49 : 48,
-			Common::Point(CURSOR_X[_cursorCell / 5], CURSOR_Y[_cursorCell % 5]));
-	}
-}
-
-bool CharacterInfo::expandStat(int attrib, const Character &c) {
-	const int STAT_POS[2][20] = {
-		{
-			61, 61, 61, 61, 61, 112, 112, 112, 112, 112,
-			177, 177, 177, 177, 177, 34, 34, 34, 34, 34
-		}, {
-			24, 47, 70, 93, 116, 24, 47, 70, 93, 116,
-			24, 47, 70, 93, 116, 24, 47, 70, 93, 116
-		}
-	};
-	assert(attrib < 20);
-	Common::Rect bounds(STAT_POS[0][attrib], STAT_POS[1][attrib],
-		STAT_POS[0][attrib] + 143, STAT_POS[1][attrib] + 52);
-	Party &party = *_vm->_party;
-	Windows &windows = *_vm->_windows;
-	uint stat1, stat2;
-	uint idx;
-	Common::String msg;
-
-	switch (attrib) {
-	case 0:
-	case 1:
-	case 2:
-	case 3:
-	case 4:
-	case 5:
-	case 6:
-		// Basic attributes
-		stat1 = c.getStat((Attribute)attrib, false);
-		stat2 = c.getStat((Attribute)attrib, true);
-		idx = 0;
-		while (Res.STAT_VALUES[idx] <= (int)stat1)
-			++idx;
-
-		msg = Common::String::format(Res.CURRENT_MAXIMUM_RATING_TEXT, Res.STAT_NAMES[attrib],
-			stat1, stat2, Res.RATING_TEXT[idx]);
-		break;
-
-	case 7:
-		// Age
-		stat1 = c.getAge(false);
-		stat2 = c.getAge(true);
-		msg = Common::String::format(Res.AGE_TEXT, Res.STAT_NAMES[attrib],
-			stat1, stat2, c._birthDay, c._birthYear);
-		break;
-
-	case 8: {
-		// Level
-		const int CLASS_ATTACK_GAINS[10] = { 5, 6, 6, 7, 8, 6, 5, 4, 7, 6 };
-		idx = c.getCurrentLevel() / CLASS_ATTACK_GAINS[c._class] + 1;
-
-		msg = Common::String::format(Res.LEVEL_TEXT, Res.STAT_NAMES[attrib],
-			c.getCurrentLevel(), c._level._permanent,
-			idx, idx > 1 ? "s" : "",
-			c._level._permanent);
-		break;
-	}
-
-	case 9:
-		// Armor Class
-		stat1 = c.getArmorClass(false);
-		stat2 = c.getArmorClass(true);
-		msg = Common::String::format(Res.CURRENT_MAXIMUM_TEXT, Res.STAT_NAMES[attrib],
-			stat1, stat2);
-		bounds.setHeight(42);
-		break;
-
-	case 10:
-		// Hit Points
-		stat1 = c._currentHp;
-		stat2 = c.getMaxHP();
-		msg = Common::String::format(Res.CURRENT_MAXIMUM_TEXT, Res.STAT_NAMES[attrib],
-			stat1, stat2);
-		bounds.setHeight(42);
-		break;
-
-	case 11:
-		// Spell Points
-		stat1 = c._currentSp;
-		stat2 = c.getMaxSP();
-		msg = Common::String::format(Res.CURRENT_MAXIMUM_TEXT, Res.STAT_NAMES[attrib],
-			stat1, stat2);
-		bounds.setHeight(42);
-		break;
-
-	case 12:
-		// Resistences
-		msg = Common::String::format(Res.RESISTENCES_TEXT, Res.STAT_NAMES[attrib],
-			c._fireResistence._permanent + c.itemScan(11) + c._fireResistence._temporary,
-			c._coldResistence._permanent + c.itemScan(13) + c._coldResistence._temporary,
-			c._electricityResistence._permanent + c.itemScan(12) + c._electricityResistence._temporary,
-			c._poisonResistence._permanent + c.itemScan(14) + c._poisonResistence._temporary,
-			c._energyResistence._permanent + c.itemScan(15) + c._energyResistence._temporary,
-			c._magicResistence._permanent + c.itemScan(16) + c._magicResistence._temporary);
-		bounds.setHeight(80);
-		break;
-
-	case 13: {
-		// Skills
-		Common::String lines[20];
-		int numLines = c.getNumSkills();
-		if (numLines > 0) {
-			for (int skill = THIEVERY; skill <= DANGER_SENSE; ++skill) {
-				if (c._skills[skill]) {
-					if (skill == THIEVERY) {
-						lines[0] = Common::String::format("\n\t020%s%u",
-							Res.SKILL_NAMES[THIEVERY], c.getThievery());
-					} else {
-						lines[skill] = Common::String::format("\n\t020%s", Res.SKILL_NAMES[skill]);
-					}
-				}
-			}
-		} else {
-			lines[0] = Res.NONE;
-			numLines = 1;
-		}
-
-		msg = Common::String::format("\x2\x3""c%s\x3l%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
-			Res.STAT_NAMES[attrib], lines[0].c_str(), lines[1].c_str(),
-			lines[2].c_str(), lines[3].c_str(), lines[4].c_str(), lines[5].c_str(),
-			lines[17].c_str(), lines[6].c_str(), lines[7].c_str(), lines[8].c_str(),
-			lines[9].c_str(), lines[10].c_str(), lines[11].c_str(), lines[12].c_str(),
-			lines[13].c_str(), lines[16].c_str(), lines[14].c_str(), lines[15].c_str());
-
-		bounds.top -= (numLines / 2) * 8;
-		bounds.setHeight(numLines * 9 + 26);
-		if (bounds.bottom >= SCREEN_HEIGHT)
-			bounds.moveTo(bounds.left, SCREEN_HEIGHT - bounds.height() - 1);
-		break;
-	}
-
-	case 14:
-		// Awards
-		Awards::show(_vm, &c);
-		return false;
-
-	case 15:
-		// Experience
-		stat1 = c.getCurrentExperience();
-		stat2 = c.experienceToNextLevel();
-		msg = Common::String::format(Res.EXPERIENCE_TEXT,
-			Res.STAT_NAMES[attrib], stat1,
-			stat2 == 0 ? Res.ELIGIBLE : Common::String::format("%d", stat2).c_str()
-		);
-		bounds.setHeight(43);
-		break;
-
-	case 16:
-		// Gold
-		msg = Common::String::format(Res.IN_PARTY_IN_BANK, Res.CONSUMABLE_NAMES[0],
-			party._gold, party._bankGold);
-		bounds.setHeight(43);
-		break;
-
-	case 17:
-		// Gems
-		msg = Common::String::format(Res.IN_PARTY_IN_BANK, Res.CONSUMABLE_NAMES[1],
-			party._gems, party._bankGems);
-		bounds.setHeight(43);
-		break;
-
-	case 18: {
-		// Food
-		int food = (party._food / party._activeParty.size()) / 3;
-		msg = Common::String::format(Res.FOOD_TEXT, Res.CONSUMABLE_NAMES[2],
-			party._food, food, food != 1 ? "s" : "");
-		break;
-	}
-
-	case 19: {
-		// Conditions
-		Common::String lines[20];
-		int total = 0;
-		for (int condition = CURSED; condition <= ERADICATED; ++condition) {
-			if (c._conditions[condition]) {
-				if (condition >= UNCONSCIOUS) {
-					lines[condition] = Common::String::format("\n\t020%s",
-						Res.CONDITION_NAMES[condition]);
-				} else {
-					lines[condition] = Common::String::format("\n\t020%s\t095-%d",
-						Res.CONDITION_NAMES[condition], c._conditions[condition]);
-				}
-
-				++total;
-			}
-		}
-
-		Condition condition = c.worstCondition();
-		if (condition == NO_CONDITION) {
-			lines[0] = Common::String::format("\n\t020%s", Res.GOOD);
-			++total;
-		}
-
-		if (party._blessed)
-			lines[16] = Common::String::format(Res.BLESSED, party._blessed);
-		if (party._powerShield)
-			lines[17] = Common::String::format(Res.POWER_SHIELD, party._powerShield);
-		if (party._holyBonus)
-			lines[18] = Common::String::format(Res.HOLY_BONUS, party._holyBonus);
-		if (party._heroism)
-			lines[19] = Common::String::format(Res.HEROISM, party._heroism);
-
-		msg = Common::String::format("\x2\x3""c%s\x3l%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\x1",
-			Res.CONSUMABLE_NAMES[3], lines[0].c_str(), lines[1].c_str(),
-			lines[2].c_str(), lines[3].c_str(), lines[4].c_str(),
-			lines[5].c_str(), lines[6].c_str(), lines[7].c_str(),
-			lines[8].c_str(), lines[9].c_str(), lines[10].c_str(),
-			lines[11].c_str(), lines[12].c_str(), lines[13].c_str(),
-			lines[14].c_str(), lines[15].c_str(), lines[16].c_str(),
-			lines[17].c_str(), lines[18].c_str(), lines[19].c_str()
-		);
-
-		bounds.top -= ((total - 1) / 2) * 8;
-		bounds.setHeight(total * 9 + 26);
-		if (bounds.bottom >= SCREEN_HEIGHT)
-			bounds.moveTo(bounds.left, SCREEN_HEIGHT - bounds.height() - 1);
-		break;
-	}
-
-	default:
-		break;
-	}
-
-	// Write the data for the stat display
-	Window &w = windows[28];
-	w.setBounds(bounds);
-	w.open();
-	w.writeString(msg);
-	w.update();
-
-	// Wait for a user key/click
-	EventsManager &events = *_vm->_events;
-	while (!_vm->shouldExit() && !events.isKeyMousePressed())
-		events.pollEventsAndWait();
-	events.clearEvents();
-
-	w.close();
-	return false;
-}
-
-} // End of namespace Xeen
diff --git a/engines/xeen/dialogs_char_info.h b/engines/xeen/dialogs_char_info.h
deleted file mode 100644
index 5f53870..0000000
--- a/engines/xeen/dialogs_char_info.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef XEEN_DIALOGS_CHAR_INFO_H
-#define XEEN_DIALOGS_CHAR_INFO_H
-
-#include "xeen/dialogs.h"
-#include "xeen/party.h"
-#include "xeen/window.h"
-
-namespace Xeen {
-
-class CharacterInfo : public ButtonContainer {
-private:
-	SpriteResource _iconSprites;
-	DrawStruct _drawList[24];
-	int _cursorCell;
-
-	CharacterInfo(XeenEngine *vm) : ButtonContainer(vm), _cursorCell(0) {}
-
-	void execute(int charIndex);
-
-	/**
-	 * Load the draw structure list with frame numbers and positions
-	 */
-	void loadDrawStructs();
-
-	/**
-	 * Set up the button list for the dialog
-	 */
-	void addButtons();
-
-	/**
-	 * Return a string containing the details of the character
-	 */
-	Common::String loadCharacterDetails(const Character &c);
-
-	/**
-	 * Cursor display handling
-	 */
-	void showCursor(bool flag);
-
-	bool expandStat(int attrib, const Character &c);
-public:
-	static void show(XeenEngine *vm, int charIndex);
-};
-
-} // End of namespace Xeen
-
-#endif /* XEEN_DIALOGS_CHAR_INFO_H */
diff --git a/engines/xeen/dialogs_control_panel.cpp b/engines/xeen/dialogs_control_panel.cpp
deleted file mode 100644
index d2129e4..0000000
--- a/engines/xeen/dialogs_control_panel.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "xeen/dialogs_control_panel.h"
-#include "xeen/dialogs_query.h"
-#include "xeen/party.h"
-#include "xeen/resources.h"
-#include "xeen/xeen.h"
-
-namespace Xeen {
-
-int ControlPanel::show(XeenEngine *vm) {
-	ControlPanel *dlg = new ControlPanel(vm);
-	int result = dlg->execute();
-	delete dlg;
-
-	return result;
-}
-
-int ControlPanel::execute() {
-	EventsManager &events = *_vm->_events;
-	Interface &intf = *_vm->_interface;
-	Map &map = *_vm->_map;
-	Party &party = *_vm->_party;
-	SavesManager &saves = *_vm->_saves;
-	Sound &sound = *_vm->_sound;
-	Windows &windows = *_vm->_windows;
-	Window &w = windows[23];
-	Window &w3 = windows[3];
-
-	loadButtons();
-
-	int result = 0, debugCtr = 0;
-	w.open();
-
-	do {
-		Common::String btnText = getButtonText();
-		Common::String text = Common::String::format(Res.CONTROL_PANEL_TEXT, btnText.c_str());
-
-		drawButtons(&w);
-		w.writeString(text);
-		w.writeString("\xB""000\t000\x1");
-		w.update();
-
-		do {
-			events.updateGameCounter();
-			intf.draw3d(false, false);
-			w.writeString("\r");
-			drawButtons(&w);
-			w.writeString(text);
-			w.writeString("\v000\t000");
-			w.frame();
-
-			if (_debugFlag)
-				w.writeString(getTimeText());
-
-			w3.update();
-			w.update();
-
-			events.pollEventsAndWait();
-			checkEvents(_vm);
-			if (_vm->shouldExit())
-				return 0;
-		} while (!_buttonValue && !events.timeElapsed());
-
-		switch (_buttonValue) {
-		case Common::KEYCODE_q:
-			if (Confirm::show(g_vm, Res.CONFIRM_QUIT)) {
-				g_vm->_gameMode = GMODE_QUIT;
-				result = 1;
-			}
-			break;
-
-		case Common::KEYCODE_w:
-			if (Confirm::show(g_vm, Res.MR_WIZARD)) {
-				w.close();
-				if (!windows[2]._enabled) {
-					sound.playFX(51);
-
-					if (g_vm->getGameID() == GType_WorldOfXeen) {
-						map._loadDarkSide = false;
-						map.load(28);
-						party._mazeDirection = DIR_EAST;
-					} else {
-						map._loadDarkSide = true;
-						map.load(29);
-						party._mazeDirection = DIR_SOUTH;
-					}
-					party.moveToRunLocation();
-				}
-
-				party._gems = 0;
-				result = 2;
-			}
-			break;
-
-		case Common::KEYCODE_l:
-			if (_vm->_mode == MODE_COMBAT) {
-				ErrorScroll::show(_vm, Res.NO_LOADING_IN_COMBAT);
-			} else {
-				// Close dialog and show loading dialog
-				result = 3;
-			}
-			break;
-
-		case Common::KEYCODE_s:
-			if (_vm->_mode == MODE_COMBAT) {
-				ErrorScroll::show(_vm, Res.NO_SAVING_IN_COMBAT);
-			} else {
-				// Close dialog and show saving dialog
-				result = 4;
-			}
-			break;
-
-		case Common::KEYCODE_e:
-			sound.setEffectsOn(!sound._soundOn);
-			break;
-
-		case Common::KEYCODE_m:
-			sound.setMusicOn(!sound._musicOn);
-			break;
-
-		case Common::KEYCODE_ESCAPE:
-			result = 1;
-			break;
-
-		// Goober cheat sequence
-		case Common::KEYCODE_g:
-			debugCtr = 1;
-			break;
-		case Common::KEYCODE_o:
-			debugCtr = (debugCtr == 1 || debugCtr == 2) ? 2 : 0;
-			break;
-		case Common::KEYCODE_b:
-			debugCtr = (debugCtr == 2) ? 3 : 0;
-			break;
-		case Common::KEYCODE_r:
-			if (debugCtr == 3)
-				_debugFlag = true;
-			else
-				debugCtr = 0;
-			break;
-
-		default:
-			break;
-		}
-	} while (!result);
-
-	w.close();
-	intf.drawParty(true);
-
-	if (result == 3) {
-		saves.loadGame();
-	} else if (result == 4) {
-		saves.saveGame();
-	}
-
-	return result;
-}
-
-void ControlPanel::loadButtons() {
-	_iconSprites.load("cpanel.icn");
-
-	addButton(Common::Rect(214, 56, 244, 69), Common::KEYCODE_e, 0, &_iconSprites);
-	addButton(Common::Rect(214, 75, 244, 88), Common::KEYCODE_m, 0, &_iconSprites);
-	addButton(Common::Rect(135, 56, 165, 69), Common::KEYCODE_l, 0, &_iconSprites);
-	addButton(Common::Rect(135, 75, 165, 88), Common::KEYCODE_s, 0, &_iconSprites);
-
-	// For ScummVM we've merged both Save and Save As into a single
-	// save item, so we don't need this one
-	addButton(Common::Rect(), 0);
-
-	addButton(Common::Rect(135, 94, 165, 107), Common::KEYCODE_q, 0, &_iconSprites);
-	addButton(Common::Rect(175, 113, 205, 126), Common::KEYCODE_w, 0, &_iconSprites);
-}
-
-Common::String ControlPanel::getButtonText() {
-	Sound &sound = *g_vm->_sound;
-	_btnSoundText = sound._soundOn ? Res.ON : Res.OFF;
-	_btnMusicText = sound._musicOn ? Res.ON : Res.OFF;
-
-	return Common::String::format(Res.CONTROL_PANEL_BUTTONS,
-		_btnSoundText.c_str(), _btnMusicText.c_str());
-}
-
-Common::String ControlPanel::getTimeText() const {
-	TimeDate td;
-	g_system->getTimeAndDate(td);
-	Common::String timeStr = Common::String::format("%d:%.2d:%.2d%c",
-		td.tm_hour == 0 || td.tm_hour == 12 ? 12 : (td.tm_hour % 12),
-		td.tm_min, td.tm_sec, (td.tm_hour >= 12) ? 'p' : 'c');
-
-	uint32 playtime = g_vm->_events->playTime() / GAME_FRAME_RATE;
-	Common::String playtimeStr = Common::String::format("%d:%.2d:%.2d",
-		playtime / 3600, (playtime / 60) % 60, playtime % 60);
-	return Common::String::format(
-		"\x2\x3l\xB""000\t000\x4""160%s\x3r\xB""000\t000%s\x1",
-		timeStr.c_str(), playtimeStr.c_str());
-}
-
-} // End of namespace Xeen
diff --git a/engines/xeen/dialogs_control_panel.h b/engines/xeen/dialogs_control_panel.h
deleted file mode 100644
index b87e78d..0000000
--- a/engines/xeen/dialogs_control_panel.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef XEEN_DIALOGS_CONTROL_PANEL_H
-#define XEEN_DIALOGS_CONTROL_PANEL_H
-
-#include "xeen/dialogs.h"
-
-namespace Xeen {
-
-class ControlPanel : public ButtonContainer {
-private:
-	SpriteResource _iconSprites;
-	Common::String _btnSoundText, _btnMusicText;
-	bool _debugFlag;
-private:
-	ControlPanel(XeenEngine *vm) : ButtonContainer(vm), _debugFlag(false) {}
-
-	/**
-	 * Inner handler for showing the dialog
-	 */
-	int execute();
-
-	/**
-	 * Loads the buttons for the dialog
-	 */
-	void loadButtons();
-
-	/**
-	 * Gets the text for the dialog buttons
-	 */
-	Common::String getButtonText();
-
-	/**
-	 * Gets the current time
-	 */
-	Common::String getTimeText() const;
-public:
-	/**
-	 * Show the control panel
-	 */
-	static int show(XeenEngine *vm);
-};
-
-} // End of namespace Xeen
-
-#endif /* XEEN_DIALOGS_CONTROL_PANEL_H */
diff --git a/engines/xeen/dialogs_create_char.cpp b/engines/xeen/dialogs_create_char.cpp
deleted file mode 100644
index 73aa4b3..0000000
--- a/engines/xeen/dialogs_create_char.cpp
+++ /dev/null
@@ -1,648 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "xeen/dialogs_create_char.h"
-#include "xeen/dialogs_input.h"
-#include "xeen/xeen.h"
-
-namespace Xeen {
-
-void CreateCharacterDialog::show(XeenEngine *vm) {
-	CreateCharacterDialog *dlg = new CreateCharacterDialog(vm);
-	dlg->execute();
-	delete dlg;
-}
-
-CreateCharacterDialog::CreateCharacterDialog(XeenEngine *vm) : ButtonContainer(vm) {
-	Common::fill(&_attribs[0], &_attribs[TOTAL_ATTRIBUTES], 0);
-	Common::fill(&_allowedClasses[0], &_allowedClasses[TOTAL_CLASSES], false);
-	_dicePos[0] = Common::Point(20, 17);
-	_dicePos[1] = Common::Point(112, 35);
-	_dicePos[2] = Common::Point(61, 50);
-	_diceFrame[0] = 0;
-	_diceFrame[1] = 2;
-	_diceFrame[2] = 4;
-	_diceInc[0] = Common::Point(10, -10);
-	_diceInc[1] = Common::Point(-10, -10);
-	_diceInc[2] = Common::Point(-10, 10);
-
-	_dice.load("dice.vga");
-	_diceSize = _dice.getFrameSize(0);
-
-	loadButtons();
-}
-
-void CreateCharacterDialog::execute() {
-	EventsManager &events = *_vm->_events;
-	Party &party = *_vm->_party;
-	Screen &screen = *_vm->_screen;
-	Windows &windows = *_vm->_windows;
-	Window &w = windows[0];
-	Common::Array<int> freeCharList;
-	int classId = -1;
-	int selectedClass = 0;
-	bool hasFadedIn = false;
-	bool restartFlag = true;
-	Race race = HUMAN;
-	Sex sex = MALE;
-	Common::String msg, details;
-	int charIndex = 0;
-
-	Mode oldMode = _vm->_mode;
-	_vm->_mode = MODE_4;
-
-	// Load the background
-	screen.loadBackground("create.raw");
-	events.setCursor(0);
-
-	while (!_vm->shouldExit()) {
-		if (restartFlag) {
-			// Build up list of roster slot indexes that are free
-			freeCharList.clear();
-			for (uint idx = 0; idx < XEEN_TOTAL_CHARACTERS; ++idx) {
-				if (party._roster[idx]._name.empty())
-					freeCharList.push_back(idx);
-			}
-			charIndex = 0;
-
-			if (freeCharList.size() == XEEN_TOTAL_CHARACTERS)
-				break;
-
-			// Get and race and sex for the given character
-			race = (Race)((freeCharList[charIndex] / 4) % 5);
-			sex = (Sex)(freeCharList[charIndex] & 1);
-
-			// Randomly determine attributes, and which classes they allow
-			rollAttributes();
-
-			// Get the display of the rolled character details
-			selectedClass = newCharDetails(race, sex, classId, selectedClass, details);
-			msg = Common::String::format(Res.CREATE_CHAR_DETAILS,
-				details.c_str());
-
-			// Draw the icons and the currently selected headshot
-			drawIcons();
-			party._roster[freeCharList[charIndex]]._faceSprites->draw(
-				w, 0, Common::Point(27, 102));
-
-			// Render all on-screen text
-			w.writeString(msg);
-			w.update();
-
-			// Draw the arrow for the selected class, if applicable
-			if (selectedClass != -1)
-				printSelectionArrow(selectedClass);
-
-			// Draw the dice
-			drawDice();
-			if (!hasFadedIn) {
-				screen.fadeIn();
-				hasFadedIn = true;
-			}
-
-			restartFlag = false;
-		}
-
-		// Animate the dice until a user action occurs
-		_buttonValue = 0;
-		while (!_vm->shouldExit() && !_buttonValue)
-			drawDice();
-
-		// Handling for different actions
-		if (_buttonValue == Common::KEYCODE_ESCAPE)
-			break;
-
-		switch (_buttonValue) {
-		case Common::KEYCODE_UP:
-			if (charIndex == 0)
-				continue;
-
-			--charIndex;
-			race = (Race)((freeCharList[charIndex] / 4) % 5);
-			sex = (Sex)(freeCharList[charIndex] & 1);
-			break;
-
-		case Common::KEYCODE_DOWN:
-			if (++charIndex == (int)freeCharList.size()) {
-				--charIndex;
-				continue;
-			} else {
-				race = (Race)((freeCharList[charIndex] / 4) % 5);
-				sex = (Sex)(freeCharList[charIndex] & 1);
-			}
-			break;
-
-		case Common::KEYCODE_PAGEUP:
-			for (int tempClass = selectedClass - 1; tempClass >= 0; --tempClass) {
-				if (_allowedClasses[tempClass]) {
-					selectedClass = tempClass;
-					break;
-				}
-			}
-
-			printSelectionArrow(selectedClass);
-			continue;
-
-		case Common::KEYCODE_PAGEDOWN:
-			break;
-
-		case Common::KEYCODE_m:
-		case Common::KEYCODE_i:
-		case Common::KEYCODE_p:
-		case Common::KEYCODE_e:
-		case Common::KEYCODE_s:
-		case Common::KEYCODE_a:
-		case Common::KEYCODE_l:
-			if (swapAttributes(_buttonValue)) {
-				checkClass();
-				classId = -1;
-				selectedClass = newCharDetails(race, sex, classId, selectedClass, msg);
-			}
-			break;
-
-		case 1000:
-		case 1001:
-		case 1002:
-		case 1003:
-		case 1004:
-		case 1005:
-		case 1006:
-		case 1007:
-		case 1008:
-		case 1009:
-			if (_allowedClasses[_buttonValue - 1000]) {
-				selectedClass = classId = _buttonValue - 1000;
-			}
-			break;
-
-		case Common::KEYCODE_c: {
-			_vm->_mode = MODE_FF;
-			bool result = saveCharacter(party._roster[freeCharList[charIndex]],
-				classId, race, sex);
-			_vm->_mode = MODE_4;
-
-			if (result)
-				restartFlag = true;
-			continue;
-		}
-
-		case Common::KEYCODE_RETURN:
-			classId = selectedClass;
-			break;
-
-		case Common::KEYCODE_SPACE:
-		case Common::KEYCODE_r:
-			// Re-roll the attributes
-			rollAttributes();
-			classId = -1;
-			break;
-
-		default:
-			// For all other keypresses, skip the code below the switch
-			// statement, and go to wait for the next key
-			continue;
-		}
-
-		if (_buttonValue != Common::KEYCODE_PAGEDOWN) {
-			selectedClass = newCharDetails(race, sex, classId, selectedClass, msg);
-
-			drawIcons2();
-			party._roster[freeCharList[charIndex]]._faceSprites->draw(w, 0,
-				Common::Point(27, 102));
-
-			w.writeString(msg);
-			w.update();
-
-			if (selectedClass != -1) {
-				printSelectionArrow(selectedClass);
-				continue;
-			}
-		}
-
-		// Move to next available class, or if the code block above resulted in
-		// selectedClass being -1, move to select the first available class
-		for (int tempClass = selectedClass + 1; tempClass <= CLASS_RANGER; ++tempClass) {
-			if (_allowedClasses[tempClass]) {
-				selectedClass = tempClass;
-				break;
-			}
-		}
-
-		printSelectionArrow(selectedClass);
-	} while (!_vm->shouldExit() && _buttonValue != Common::KEYCODE_ESCAPE);
-
-	_vm->_mode = oldMode;
-}
-
-void CreateCharacterDialog::loadButtons() {
-	_icons.load("create.icn");
-
-	// Add buttons
-	addButton(Common::Rect(132, 98, 156, 118), Common::KEYCODE_r, &_icons);
-	addButton(Common::Rect(132, 128, 156, 148), Common::KEYCODE_c, &_icons);
-	addButton(Common::Rect(132, 158, 156, 178), Common::KEYCODE_ESCAPE, &_icons);
-	addButton(Common::Rect(86, 98, 110, 118), Common::KEYCODE_UP, &_icons);
-	addButton(Common::Rect(86, 120, 110, 140), Common::KEYCODE_DOWN, &_icons);
-	addButton(Common::Rect(168, 19, 192, 39), Common::KEYCODE_n, nullptr);
-	addButton(Common::Rect(168, 43, 192, 63), Common::KEYCODE_i, nullptr);
-	addButton(Common::Rect(168, 67, 192, 87), Common::KEYCODE_p, nullptr);
-	addButton(Common::Rect(168, 91, 192, 111), Common::KEYCODE_e, nullptr);
-	addButton(Common::Rect(168, 115, 192, 135), Common::KEYCODE_s, nullptr);
-	addButton(Common::Rect(168, 139, 192, 159), Common::KEYCODE_a, nullptr);
-	addButton(Common::Rect(168, 163, 192, 183), Common::KEYCODE_l, nullptr);
-	addButton(Common::Rect(227, 19, 239, 29), 1000, nullptr);
-	addButton(Common::Rect(227, 30, 239, 40), 1001, nullptr);
-	addButton(Common::Rect(227, 41, 239, 51), 1002, nullptr);
-	addButton(Common::Rect(227, 52, 239, 62), 1003, nullptr);
-	addButton(Common::Rect(227, 63, 239, 73), 1004, nullptr);
-	addButton(Common::Rect(227, 74, 239, 84), 1005, nullptr);
-	addButton(Common::Rect(227, 85, 239, 95), 1006, nullptr);
-	addButton(Common::Rect(227, 96, 239, 106), 1007, nullptr);
-	addButton(Common::Rect(227, 107, 239, 117), 1008, nullptr);
-	addButton(Common::Rect(227, 118, 239, 128), 1009, nullptr);
-}
-
-void CreateCharacterDialog::drawIcons() {
-	// Draw the screen
-	_icons.draw(0, 10, Common::Point(168, 19));
-	_icons.draw(0, 12, Common::Point(168, 43));
-	_icons.draw(0, 14, Common::Point(168, 67));
-	_icons.draw(0, 16, Common::Point(168, 91));
-	_icons.draw(0, 18, Common::Point(168, 115));
-	_icons.draw(0, 20, Common::Point(168, 139));
-	_icons.draw(0, 22, Common::Point(168, 163));
-	for (int idx = 0; idx < 9; ++idx)
-		_icons.draw(0, 24 + idx * 2, Common::Point(227, 19 + 11 * idx));
-
-	for (int idx = 0; idx < 7; ++idx)
-		_icons.draw(0, 50 + idx, Common::Point(195, 31 + 24 * idx));
-
-	_icons.draw(0, 57, Common::Point(62, 148));
-	_icons.draw(0, 58, Common::Point(62, 158));
-	_icons.draw(0, 59, Common::Point(62, 168));
-	_icons.draw(0, 61, Common::Point(220, 19));
-	_icons.draw(0, 64, Common::Point(220, 155));
-	_icons.draw(0, 65, Common::Point(220, 170));
-
-	_icons.draw(0, 0, Common::Point(132, 98));
-	_icons.draw(0, 2, Common::Point(132, 128));
-	_icons.draw(0, 4, Common::Point(132, 158));
-	_icons.draw(0, 6, Common::Point(86, 98));
-	_icons.draw(0, 8, Common::Point(86, 120));
-}
-
-void CreateCharacterDialog::drawIcons2() {
-	for (int idx = 0; idx < 7; ++idx)
-		_icons.draw(0, 10 + idx * 2, Common::Point(168, 19 + idx * 24));
-	for (int idx = 0; idx < 10; ++idx)
-		_icons.draw(0, 24 + idx * 2, Common::Point(227, 19 + idx * 11));
-	for (int idx = 0; idx < 8; ++idx)
-		_icons.draw(0, 50 + idx, Common::Point(195, 31 + idx * 24));
-
-	_icons.draw(0, 57, Common::Point(62, 148));
-	_icons.draw(0, 58, Common::Point(62, 158));
-	_icons.draw(0, 59, Common::Point(62, 168));
-	_icons.draw(0, 61, Common::Point(220, 19));
-	_icons.draw(0, 64, Common::Point(220, 155));
-	_icons.draw(0, 65, Common::Point(220, 170));
-
-	_icons.draw(0, 0, Common::Point(132, 98));
-	_icons.draw(0, 2, Common::Point(132, 128));
-	_icons.draw(0, 4, Common::Point(132, 158));
-	_icons.draw(0, 6, Common::Point(86, 98));
-	_icons.draw(0, 8, Common::Point(86, 120));
-}
-
-void CreateCharacterDialog::rollAttributes() {
-	bool repeat = true;
-	do {
-		// Default all the attributes to zero
-		Common::fill(&_attribs[0], &_attribs[TOTAL_ATTRIBUTES], 0);
-
-		// Assign random amounts to each attribute
-		for (int idx1 = 0; idx1 < 3; ++idx1) {
-			for (int idx2 = 0; idx2 < TOTAL_ATTRIBUTES; ++idx2) {
-				_attribs[idx2] += _vm->getRandomNumber(10, 79) / 10;
-			}
-		}
-
-		// Check which classes are allowed based on the rolled attributes
-		checkClass();
-
-		// Only exit if the attributes allow for at least one class
-		for (int idx = 0; idx < TOTAL_CLASSES; ++idx) {
-			if (_allowedClasses[idx])
-				repeat = false;
-		}
-	} while (repeat);
-}
-
-void CreateCharacterDialog::checkClass() {
-	_allowedClasses[CLASS_KNIGHT] = _attribs[MIGHT] >= 15;
-	_allowedClasses[CLASS_PALADIN] = _attribs[MIGHT] >= 13


Commit: 67d4de1bb818b2cfc628549ba38cc4f00b8236b2
    https://github.com/scummvm/scummvm/commit/67d4de1bb818b2cfc628549ba38cc4f00b8236b2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-03-04T22:40:43-05:00

Commit Message:
XEEN: Move Credits and Please Wait classes into their own files

Changed paths:
  A engines/xeen/dialogs/credits_screen.cpp
  A engines/xeen/dialogs/credits_screen.h
  A engines/xeen/dialogs/please_wait.cpp
  A engines/xeen/dialogs/please_wait.h
    engines/xeen/dialogs/dialogs.cpp
    engines/xeen/dialogs/dialogs.h
    engines/xeen/map.cpp
    engines/xeen/module.mk
    engines/xeen/swordsofxeen/swordsofxeen_menu.cpp
    engines/xeen/worldofxeen/worldofxeen_menu.cpp


diff --git a/engines/xeen/dialogs/credits_screen.cpp b/engines/xeen/dialogs/credits_screen.cpp
new file mode 100644
index 0000000..8fe0387
--- /dev/null
+++ b/engines/xeen/dialogs/credits_screen.cpp
@@ -0,0 +1,72 @@
+/* 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 "xeen/dialogs/credits_screen.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void CreditsScreen::show(XeenEngine *vm) {
+	CreditsScreen *dlg = new CreditsScreen(vm);
+	
+	switch (vm->getGameID()) {
+	case GType_Clouds:
+		dlg->execute(Res.CLOUDS_CREDITS);
+		break;
+	case GType_Swords:
+		dlg->execute(Res.SWORDS_CREDITS1);
+		dlg->execute(Res.SWORDS_CREDITS2);
+		break;
+	default:
+		dlg->execute(Res.DARK_SIDE_CREDITS);
+		break;
+	}
+	
+	delete dlg;
+}
+
+void CreditsScreen::execute(const char *content) {
+	Screen &screen = *_vm->_screen;
+	Windows &windows = *_vm->_windows;
+	EventsManager &events = *_vm->_events;
+
+	// Handle drawing the credits screen
+	doScroll(true, false);
+	windows[GAME_WINDOW].close();
+
+	screen.loadBackground("marb.raw");
+	windows[0].writeString(content);
+	doScroll(false, false);
+
+	events.setCursor(0);
+	windows[0].update();
+	clearButtons();
+
+	// Wait for keypress
+	while (!events.isKeyMousePressed())
+		events.pollEventsAndWait();
+
+	doScroll(true, false);
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/credits_screen.h b/engines/xeen/dialogs/credits_screen.h
new file mode 100644
index 0000000..b52839d
--- /dev/null
+++ b/engines/xeen/dialogs/credits_screen.h
@@ -0,0 +1,41 @@
+/* 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 XEEN_DIALOGS_CREDITS_SCREEN_H
+#define XEEN_DIALOGS_CREDITS_SCREEN_H
+
+#include "xeen/dialogs/dialogs.h"
+
+namespace Xeen {
+
+class CreditsScreen: public ButtonContainer {
+private:
+	CreditsScreen(XeenEngine *vm) : ButtonContainer(vm) {}
+
+	void execute(const char *content);
+public:
+	static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_CREDITS_SCREEN_H */
diff --git a/engines/xeen/dialogs/dialogs.cpp b/engines/xeen/dialogs/dialogs.cpp
index c9b5658..d7a696b 100644
--- a/engines/xeen/dialogs/dialogs.cpp
+++ b/engines/xeen/dialogs/dialogs.cpp
@@ -187,71 +187,4 @@ void SettingsBaseDialog::showContents(SpriteResource &title1, bool waitFlag) {
 	checkEvents(_vm);
 }
 
-/*------------------------------------------------------------------------*/
-
-void CreditsScreen::show(XeenEngine *vm) {
-	CreditsScreen *dlg = new CreditsScreen(vm);
-	
-	switch (vm->getGameID()) {
-	case GType_Clouds:
-		dlg->execute(Res.CLOUDS_CREDITS);
-		break;
-	case GType_Swords:
-		dlg->execute(Res.SWORDS_CREDITS1);
-		dlg->execute(Res.SWORDS_CREDITS2);
-		break;
-	default:
-		dlg->execute(Res.DARK_SIDE_CREDITS);
-		break;
-	}
-	
-	delete dlg;
-}
-
-void CreditsScreen::execute(const char *content) {
-	Screen &screen = *_vm->_screen;
-	Windows &windows = *_vm->_windows;
-	EventsManager &events = *_vm->_events;
-
-	// Handle drawing the credits screen
-	doScroll(true, false);
-	windows[GAME_WINDOW].close();
-
-	screen.loadBackground("marb.raw");
-	windows[0].writeString(content);
-	doScroll(false, false);
-
-	events.setCursor(0);
-	windows[0].update();
-	clearButtons();
-
-	// Wait for keypress
-	while (!events.isKeyMousePressed())
-		events.pollEventsAndWait();
-
-	doScroll(true, false);
-}
-
-/*------------------------------------------------------------------------*/
-
-PleaseWait::PleaseWait(bool isOops) {
-	_msg = isOops ? Res.OOPS : Res.PLEASE_WAIT;
-}
-
-PleaseWait::~PleaseWait() {
-	Windows &windows = *g_vm->_windows;
-	windows[9].close();
-}
-
-void PleaseWait::show() {
-	Windows &windows = *g_vm->_windows;
-	Window &w = windows[9];
-
-	if (g_vm->_mode != MODE_0) {
-		w.open();
-		w.writeString(_msg);
-		w.update();
-	}
-}
-
 } // End of namespace Xeen
diff --git a/engines/xeen/dialogs/dialogs.h b/engines/xeen/dialogs/dialogs.h
index cabc921..9038f75 100644
--- a/engines/xeen/dialogs/dialogs.h
+++ b/engines/xeen/dialogs/dialogs.h
@@ -113,25 +113,6 @@ public:
 	virtual ~SettingsBaseDialog() {}
 };
 
-class CreditsScreen: public ButtonContainer {
-private:
-	CreditsScreen(XeenEngine *vm) : ButtonContainer(vm) {}
-
-	void execute(const char *content);
-public:
-	static void show(XeenEngine *vm);
-};
-
-class PleaseWait {
-private:
-	Common::String _msg;
-public:
-	PleaseWait(bool isOops = false);
-	~PleaseWait();
-
-	void show();
-};
-
 } // End of namespace Xeen
 
 #endif /* XEEN_DIALOGS_H */
diff --git a/engines/xeen/dialogs/please_wait.cpp b/engines/xeen/dialogs/please_wait.cpp
new file mode 100644
index 0000000..749c6a8
--- /dev/null
+++ b/engines/xeen/dialogs/please_wait.cpp
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "xeen/dialogs/please_wait.h"
+#include "xeen/resources.h"
+#include "xeen/window.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+PleaseWait::PleaseWait(bool isOops) {
+	_msg = isOops ? Res.OOPS : Res.PLEASE_WAIT;
+}
+
+PleaseWait::~PleaseWait() {
+	Windows &windows = *g_vm->_windows;
+	windows[9].close();
+}
+
+void PleaseWait::show() {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[9];
+
+	if (g_vm->_mode != MODE_0) {
+		w.open();
+		w.writeString(_msg);
+		w.update();
+	}
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs/please_wait.h b/engines/xeen/dialogs/please_wait.h
new file mode 100644
index 0000000..0432e55
--- /dev/null
+++ b/engines/xeen/dialogs/please_wait.h
@@ -0,0 +1,45 @@
+/* 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 XEEN_DIALOGS_PLEASE_WAIT_H
+#define XEEN_DIALOGS_PLEASE_WAIT_H
+
+#include "xeen/dialogs/dialogs.h"
+
+namespace Xeen {
+
+class PleaseWait {
+private:
+	Common::String _msg;
+public:
+	PleaseWait(bool isOops = false);
+	~PleaseWait();
+
+	/**
+	 * Show the dialog
+	 */
+	void show();
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_PLEASE_WAIT_H */
diff --git a/engines/xeen/map.cpp b/engines/xeen/map.cpp
index d57d258..63068cd 100644
--- a/engines/xeen/map.cpp
+++ b/engines/xeen/map.cpp
@@ -27,6 +27,7 @@
 #include "xeen/saves.h"
 #include "xeen/screen.h"
 #include "xeen/xeen.h"
+#include "xeen/dialogs/please_wait.h"
 
 namespace Xeen {
 
diff --git a/engines/xeen/module.mk b/engines/xeen/module.mk
index a49d5a3..b3e0d9a 100644
--- a/engines/xeen/module.mk
+++ b/engines/xeen/module.mk
@@ -9,11 +9,7 @@ MODULE_OBJS := \
 	worldofxeen/worldofxeen_resources.o \
 	swordsofxeen/swordsofxeen.o \
 	swordsofxeen/swordsofxeen_menu.o \
-	character.o \
-	combat.o \
-	cutscenes.o \
-	debugger.o \
-	detection.o \
+	dialogs/credits_screen.o \
 	dialogs/dialogs.o \
 	dialogs/dialogs_awards.o \
 	dialogs/dialogs_char_info.o \
@@ -34,6 +30,12 @@ MODULE_OBJS := \
 	dialogs/dialogs_quick_ref.o \
 	dialogs/dialogs_spells.o \
 	dialogs/dialogs_whowill.o \
+	dialogs/please_wait.o \
+	character.o \
+	combat.o \
+	cutscenes.o \
+	debugger.o \
+	detection.o \
 	events.o \
 	files.o \
 	font.o \
diff --git a/engines/xeen/swordsofxeen/swordsofxeen_menu.cpp b/engines/xeen/swordsofxeen/swordsofxeen_menu.cpp
index 6eb6a64..14f2083 100644
--- a/engines/xeen/swordsofxeen/swordsofxeen_menu.cpp
+++ b/engines/xeen/swordsofxeen/swordsofxeen_menu.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "xeen/swordsofxeen/swordsofxeen_menu.h"
+#include "xeen/dialogs/credits_screen.h"
 #include "xeen/dialogs/dialogs_difficulty.h"
 #include "xeen/xeen.h"
 
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.cpp b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
index c0aa900..4797309 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
@@ -23,6 +23,7 @@
 #include "common/scummsys.h"
 #include "xeen/worldofxeen/worldofxeen_menu.h"
 #include "xeen/worldofxeen/worldofxeen.h"
+#include "xeen/dialogs/credits_screen.h"
 #include "xeen/dialogs/dialogs_difficulty.h"
 #include "xeen/resources.h"
 


Commit: b6b9714ec02aa4b927ace42cb9699de899494f91
    https://github.com/scummvm/scummvm/commit/b6b9714ec02aa4b927ace42cb9699de899494f91
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-03-04T22:40:43-05:00

Commit Message:
XEEN: Fix scroll effect for Clouds of Xeen main menu

Changed paths:
    engines/xeen/cutscenes.cpp
    engines/xeen/screen.cpp
    engines/xeen/screen.h
    engines/xeen/worldofxeen/worldofxeen_menu.cpp


diff --git a/engines/xeen/cutscenes.cpp b/engines/xeen/cutscenes.cpp
index 05d9fa7..1be9cc3 100644
--- a/engines/xeen/cutscenes.cpp
+++ b/engines/xeen/cutscenes.cpp
@@ -116,99 +116,7 @@ uint Cutscenes::getSpeakingFrame(uint minFrame, uint maxFrame) {
 }
 
 bool Cutscenes::doScroll(bool rollUp, bool fadeIn) {
-	Screen &screen = *_vm->_screen;
-	EventsManager &events = *_vm->_events;
-	const int SCROLL_L[8] = { 29, 23, 15, -5, -11, -23, -49, -71 };
-	const int SCROLL_R[8] = { 165, 171, 198, 218, 228, 245, 264, 281 };
-
-	if (_vm->_files->_isDarkCc) {
-		if (fadeIn)
-			screen.fadeIn(2);
-		return _vm->shouldExit();
-	}
-
-	screen.saveBackground();
-
-	// Load hand sprites
-	SpriteResource *hand[16];
-	for (int i = 0; i < 16; ++i) {
-		Common::String name = Common::String::format("hand%02d.vga", i);
-		hand[i] = new SpriteResource(name);
-	}
-
-	// Load marb sprites
-	SpriteResource *marb[5];
-	for (int i = 0; i < 4; ++i) {
-		Common::String name = Common::String::format("marb%02d.vga", i + 1);
-		marb[i] = new SpriteResource(name);
-	}
-
-	if (rollUp) {
-		for (int i = 22, ctr = 7; i > 0 && !events.isKeyMousePressed()
-				&& !_vm->shouldExit(); --i) {
-			events.updateGameCounter();
-			screen.restoreBackground();
-
-			if (i > 14) {
-				hand[14]->draw(0, 0, Common::Point(SCROLL_L[ctr], 0), SPRFLAG_800);
-				hand[15]->draw(0, 0, Common::Point(SCROLL_R[ctr], 0), SPRFLAG_800);
-				--ctr;
-			} else if (i != 0) {
-				hand[i - 1]->draw(0, 0);
-			}
-
-			if (i <= 20)
-				marb[(i - 1) / 5]->draw(0, (i - 1) % 5);
-			screen.update();
-
-			while (!_vm->shouldExit() && events.timeElapsed() == 0)
-				events.pollEventsAndWait();
-
-			if (i == 0 && fadeIn)
-				screen.fadeIn(2);
-		}
-	} else {
-		for (int i = 0, ctr = 0; i < 22 && !events.isKeyMousePressed()
-				&& !_vm->shouldExit(); ++i) {
-			events.updateGameCounter();
-			screen.restoreBackground();
-
-			if (i < 14) {
-				hand[i]->draw(0, 0);
-			} else {
-				hand[14]->draw(0, 0, Common::Point(SCROLL_L[ctr], 0), SPRFLAG_800);
-				hand[15]->draw(0, 0, Common::Point(SCROLL_R[ctr], 0), SPRFLAG_800);
-				++ctr;
-			}
-
-			if (i < 20) {
-				marb[i / 5]->draw(0, i % 5);
-			}
-			screen.update();
-
-			while (!_vm->shouldExit() && events.timeElapsed() == 0)
-				events.pollEventsAndWait();
-
-			if (i == 0 && fadeIn)
-				screen.fadeIn(2);
-		}
-	}
-
-	if (rollUp) {
-		hand[0]->draw(0, 0);
-		marb[0]->draw(0, 0);
-	} else {
-		screen.restoreBackground();
-	}
-	screen.update();
-
-	// Free resources
-	for (int i = 0; i < 4; ++i)
-		delete marb[i];
-	for (int i = 0; i < 16; ++i)
-		delete hand[i];
-
-	return _vm->shouldExit() || events.isKeyMousePressed();
+	return _vm->_screen->doScroll(rollUp, fadeIn);
 }
 
 } // End of namespace Xeen
diff --git a/engines/xeen/screen.cpp b/engines/xeen/screen.cpp
index 2c92ee1..8dc7ec8 100644
--- a/engines/xeen/screen.cpp
+++ b/engines/xeen/screen.cpp
@@ -163,4 +163,100 @@ void Screen::restoreBackground(int slot) {
 	blitFrom(_savedScreens[slot - 1]);
 }
 
+bool Screen::doScroll(bool rollUp, bool fadeIn) {
+	Screen &screen = *_vm->_screen;
+	EventsManager &events = *_vm->_events;
+	const int SCROLL_L[8] = { 29, 23, 15, -5, -11, -23, -49, -71 };
+	const int SCROLL_R[8] = { 165, 171, 198, 218, 228, 245, 264, 281 };
+
+	if (_vm->_files->_isDarkCc) {
+		if (fadeIn)
+			screen.fadeIn(2);
+		return _vm->shouldExit();
+	}
+
+	screen.saveBackground();
+
+	// Load hand sprites
+	SpriteResource *hand[16];
+	for (int i = 0; i < 16; ++i) {
+		Common::String name = Common::String::format("hand%02d.vga", i);
+		hand[i] = new SpriteResource(name);
+	}
+
+	// Load marb sprites
+	SpriteResource *marb[5];
+	for (int i = 0; i < 4; ++i) {
+		Common::String name = Common::String::format("marb%02d.vga", i + 1);
+		marb[i] = new SpriteResource(name);
+	}
+
+	if (rollUp) {
+		for (int i = 22, ctr = 7; i > 0 && !events.isKeyMousePressed()
+				&& !_vm->shouldExit(); --i) {
+			events.updateGameCounter();
+			screen.restoreBackground();
+
+			if (i > 14) {
+				hand[14]->draw(0, 0, Common::Point(SCROLL_L[ctr], 0), SPRFLAG_800);
+				hand[15]->draw(0, 0, Common::Point(SCROLL_R[ctr], 0), SPRFLAG_800);
+				--ctr;
+			} else if (i != 0) {
+				hand[i - 1]->draw(0, 0);
+			}
+
+			if (i <= 20)
+				marb[(i - 1) / 5]->draw(0, (i - 1) % 5);
+			screen.update();
+
+			while (!_vm->shouldExit() && events.timeElapsed() == 0)
+				events.pollEventsAndWait();
+
+			if (i == 0 && fadeIn)
+				screen.fadeIn(2);
+		}
+	} else {
+		for (int i = 0, ctr = 0; i < 22 && !events.isKeyMousePressed()
+				&& !_vm->shouldExit(); ++i) {
+			events.updateGameCounter();
+			screen.restoreBackground();
+
+			if (i < 14) {
+				hand[i]->draw(0, 0);
+			} else {
+				hand[14]->draw(0, 0, Common::Point(SCROLL_L[ctr], 0), SPRFLAG_800);
+				hand[15]->draw(0, 0, Common::Point(SCROLL_R[ctr], 0), SPRFLAG_800);
+				++ctr;
+			}
+
+			if (i < 20) {
+				marb[i / 5]->draw(0, i % 5);
+			}
+			screen.update();
+
+			while (!_vm->shouldExit() && events.timeElapsed() == 0)
+				events.pollEventsAndWait();
+
+			if (i == 0 && fadeIn)
+				screen.fadeIn(2);
+		}
+	}
+
+	if (rollUp) {
+		hand[0]->draw(0, 0);
+		marb[0]->draw(0, 0);
+	} else {
+		screen.restoreBackground();
+	}
+	screen.update();
+
+	// Free resources
+	for (int i = 0; i < 4; ++i)
+		delete marb[i];
+	for (int i = 0; i < 16; ++i)
+		delete hand[i];
+
+	return _vm->shouldExit() || events.isKeyMousePressed();
+}
+
 } // End of namespace Xeen
diff --git a/engines/xeen/screen.h b/engines/xeen/screen.h
index 5028b50..3e7f23e 100644
--- a/engines/xeen/screen.h
+++ b/engines/xeen/screen.h
@@ -112,6 +112,14 @@ public:
 	 * Restores a previously saved screen
 	 */
 	void restoreBackground(int slot = 1);
+
+	/**
+	 * Draws the scroll in the background
+	 * @param rollUp	If true, rolls up the scroll. If false, unrolls.
+	 * @param fadeIn	If true, does an initial fade in
+	 * @returns		True if key or mouse pressed
+	 */
+	bool doScroll(bool rollUp, bool fadeIn);
 };
 
 } // End of namespace Xeen
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.cpp b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
index 4797309..356bb8c 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
@@ -70,6 +70,7 @@ void MainMenuContainer::draw() {
 
 void MainMenuContainer::execute() {
 	EventsManager &events = *g_vm->_events;
+	Screen &screen = *g_vm->_screen;
 	bool showFlag = false;
 
 	// Show the cursor
@@ -77,6 +78,8 @@ void MainMenuContainer::execute() {
 	events.setCursor(0);
 	events.showCursor();
 
+	screen.doScroll(true, false);
+
 	while (!g_vm->shouldExit() && g_vm->_gameMode == GMODE_NONE) {
 		// Draw the menu
 		draw();
@@ -86,7 +89,7 @@ void MainMenuContainer::execute() {
 		// Fade/scroll in screen if first frame
 		if (!showFlag) {
 			loadBackground();
-			// TODO: doScroll(false, false);
+			screen.doScroll(false, false);
 			showFlag = true;
 		}
 


Commit: badbeda5e2e4bad22a3f15582f1d0d4801682df6
    https://github.com/scummvm/scummvm/commit/badbeda5e2e4bad22a3f15582f1d0d4801682df6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-03-04T22:40:43-05:00

Commit Message:
XEEN: Implemented Dark Side of Xeen menu

Changed paths:
    engines/xeen/dialogs/credits_screen.cpp
    engines/xeen/worldofxeen/worldofxeen_menu.cpp
    engines/xeen/worldofxeen/worldofxeen_menu.h


diff --git a/engines/xeen/dialogs/credits_screen.cpp b/engines/xeen/dialogs/credits_screen.cpp
index 8fe0387..09547ba 100644
--- a/engines/xeen/dialogs/credits_screen.cpp
+++ b/engines/xeen/dialogs/credits_screen.cpp
@@ -63,7 +63,7 @@ void CreditsScreen::execute(const char *content) {
 	clearButtons();
 
 	// Wait for keypress
-	while (!events.isKeyMousePressed())
+	while (!_vm->shouldExit() && !events.isKeyMousePressed())
 		events.pollEventsAndWait();
 
 	doScroll(true, false);
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.cpp b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
index 356bb8c..d1d6814 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
@@ -51,7 +51,8 @@ void MainMenuContainer::show() {
 	delete menu;
 }
 
-MainMenuContainer::MainMenuContainer(const Common::String &spritesName) : _animateCtr(0), _dialog(nullptr) {
+MainMenuContainer::MainMenuContainer(const Common::String &spritesName, uint frameCount) :
+		_frameCount(frameCount), _animateCtr(0), _dialog(nullptr) {
 	_backgroundSprites.load(spritesName);
 }
 
@@ -64,7 +65,7 @@ MainMenuContainer::~MainMenuContainer() {
 
 void MainMenuContainer::draw() {
 	g_vm->_screen->restoreBackground();
-	_animateCtr = (_animateCtr + 1) % 9;
+	_animateCtr = (_animateCtr + 1) % _frameCount;
 	_backgroundSprites.draw(0, _animateCtr);
 }
 
@@ -86,7 +87,7 @@ void MainMenuContainer::execute() {
 		if (_dialog)
 			_dialog->draw();
 
-		// Fade/scroll in screen if first frame
+		// Fade/scroll in screen if first frame showing screen
 		if (!showFlag) {
 			loadBackground();
 			screen.doScroll(false, false);
@@ -101,8 +102,8 @@ void MainMenuContainer::execute() {
 				// There's a dialog active, so let it handle the event
 				_dialog->handleEvents();
 
-				// If dialog was removed as a result of the event, flag screen for re-showing
-				// if the menu screen isn't being left
+				// If dialog was removed as a result of the event, flag screen for re-showing,
+				// such as returning to main menu from the Credits screen
 				if (!_dialog)
 					showFlag = false;
 			} else {
@@ -123,7 +124,7 @@ void MainMenuContainer::execute() {
 
 /*------------------------------------------------------------------------*/
 
-CloudsMainMenuContainer::CloudsMainMenuContainer() : MainMenuContainer("intro.vga") {
+CloudsMainMenuContainer::CloudsMainMenuContainer() : MainMenuContainer("intro.vga", 9) {
 	g_vm->_sound->playSong("inn.m");
 }
 
@@ -140,31 +141,40 @@ void CloudsMainMenuContainer::showMenuDialog() {
 
 /*------------------------------------------------------------------------*/
 
-DarkSideMainMenuContainer::DarkSideMainMenuContainer() : MainMenuContainer("intro.vga") {
-	g_vm->_sound->playSong("inn.m");
+DarkSideMainMenuContainer::DarkSideMainMenuContainer() : MainMenuContainer("title2a.int", 10) {
+	Screen &screen = *g_vm->_screen;
+	Sound &sound = *g_vm->_sound;
+	screen.loadPalette("dark.pal");
+	screen.fadeIn(0x81);
+	sound.playSong("newbrigh.m");
+
+	_background.load("title2.int");
 }
 
 void DarkSideMainMenuContainer::loadBackground() {
 	Screen &screen = *g_vm->_screen;
-	screen.loadPalette("mm4.pal");
-	screen.loadBackground("intro.raw");
+	_background.draw(0, 0, Common::Point(0, 0));
+	_background.draw(0, 1, Common::Point(160, 0));
+
+	screen.loadPalette("dark.pal");
 	screen.saveBackground();
 }
 
 void DarkSideMainMenuContainer::showMenuDialog() {
-	setOwner(new CloudsMenuDialog(this));
+	setOwner(new DarkSideMenuDialog(this));
 }
 
 /*------------------------------------------------------------------------*/
 
-WorldOfXeenMainMenuContainer::WorldOfXeenMainMenuContainer() : MainMenuContainer("intro.vga") {
-	g_vm->_sound->playSong("inn.m");
+WorldOfXeenMainMenuContainer::WorldOfXeenMainMenuContainer() : MainMenuContainer("world.int", 5) {
+	Sound &sound = *g_vm->_sound;
+	sound.playSong("newbrigh.m");
 }
 
 void WorldOfXeenMainMenuContainer::loadBackground() {
 	Screen &screen = *g_vm->_screen;
-	screen.loadPalette("mm4.pal");
-	screen.loadBackground("intro.raw");
+	screen.loadPalette("dark.pal");
+	screen.loadBackground("world.raw");
 	screen.saveBackground();
 }
 
@@ -206,6 +216,10 @@ bool MainMenuDialog::handleEvents() {
 		CreditsScreen::show(g_vm);
 		break;
 
+	case Common::KEYCODE_ESCAPE:
+		// Exit dialog (returning to just the animated background)
+		break;
+
 	default:
 		return false;
 	}
@@ -276,6 +290,139 @@ bool CloudsMenuDialog::handleEvents() {
 
 /*------------------------------------------------------------------------*/
 
+DarkSideMenuDialog::DarkSideMenuDialog(MainMenuContainer *owner) : MainMenuDialog(owner), _firstDraw(true) {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+	w.setBounds(Common::Rect(72, 25, 248, 150));
+	w.open();
+
+	loadButtons();
+}
+
+DarkSideMenuDialog::~DarkSideMenuDialog() {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+	w.close();
+}
+
+void DarkSideMenuDialog::loadButtons() {
+	addButton(Common::Rect(124, 87, 177, 97), Common::KEYCODE_s);
+	addButton(Common::Rect(126, 98, 173, 108), Common::KEYCODE_l);
+	addButton(Common::Rect(91, 110, 209, 120), Common::KEYCODE_c);
+	addButton(Common::Rect(85, 121, 216, 131), Common::KEYCODE_o);
+}
+
+void DarkSideMenuDialog::draw() {
+	Screen &screen = *g_vm->_screen;
+	EventsManager &events = *g_vm->_events;
+	Sound &sound = *g_vm->_sound;
+	Windows &windows = *g_vm->_windows;
+
+	if (!_firstDraw)
+		return;
+
+	SpriteResource kludgeSprites("kludge.int");
+	SpriteResource title2Sprites[8] = {
+		SpriteResource("title2b.int"), SpriteResource("title2c.int"),
+		SpriteResource("title2d.int"), SpriteResource("title2e.int"),
+		SpriteResource("title2f.int"), SpriteResource("title2g.int"),
+		SpriteResource("title2h.int"), SpriteResource("title2i.int"),
+	};
+
+	screen.loadBackground("title2b.raw");
+	kludgeSprites.draw(0, 0, Common::Point(85, 86));
+	screen.saveBackground();
+	sound.playSound("elect.voc");
+
+	for (int i = 0; i < 30 && !g_vm->shouldExit(); ++i) {
+		events.updateGameCounter();
+		screen.restoreBackground();
+		title2Sprites[i / 4].draw(0, i % 4);
+		windows[0].update();
+
+		if (i == 19)
+			sound.stopSound();
+
+		if (events.wait(2))
+			break;
+	}
+
+	events.clearEvents();
+	sound.stopSound();
+
+	screen.restoreBackground();
+	windows[0].update();
+	_firstDraw = false;
+}
+
+bool DarkSideMenuDialog::handleEvents() {
+	if (MainMenuDialog::handleEvents())
+		return true;
+
+	switch (_buttonValue) {
+	case Common::KEYCODE_o:
+		// Show other options dialog
+		// TODO
+		break;
+
+	default:
+		break;
+	}
+
+	return false;
+}
+
+/*------------------------------------------------------------------------*/
+
+WorldMenuDialog::WorldMenuDialog(MainMenuContainer *owner) : MainMenuDialog(owner) {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+	w.setBounds(Common::Rect(72, 25, 248, 175));
+	w.open();
+
+	loadButtons();
+}
+
+WorldMenuDialog::~WorldMenuDialog() {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+	w.close();
+}
+
+void WorldMenuDialog::loadButtons() {
+	_buttonSprites.load("start.icn");
+	addButton(Common::Rect(93, 53, 227, 73), Common::KEYCODE_s, &_buttonSprites);
+	addButton(Common::Rect(93, 78, 227, 98), Common::KEYCODE_l, &_buttonSprites);
+	addButton(Common::Rect(93, 103, 227, 123), Common::KEYCODE_c, &_buttonSprites);
+	addButton(Common::Rect(93, 128, 227, 148), Common::KEYCODE_o, &_buttonSprites);
+}
+
+void WorldMenuDialog::draw() {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+
+	w.frame();
+	w.writeString(Common::String::format(Res.CLOUDS_MAIN_MENU, g_vm->_gameWon[0] ? 117 : 92));
+	drawButtons(&w);
+}
+
+bool WorldMenuDialog::handleEvents() {
+	if (MainMenuDialog::handleEvents())
+		return true;
+
+	switch (_buttonValue) {
+	case Common::KEYCODE_o:
+		// Show other options dialog
+		// TODO
+		break;
+
+	default:
+		break;
+	}
+
+	return false;
+}
+
 
 } // End of namespace WorldOfXeen
 } // End of namespace Xeen
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.h b/engines/xeen/worldofxeen/worldofxeen_menu.h
index 92d770b..1db78b9 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.h
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.h
@@ -33,7 +33,8 @@ class MainMenuDialog;
 
 class MainMenuContainer {
 private:
-	int _animateCtr;
+	uint _animateCtr;
+	uint _frameCount;
 	SpriteResource _backgroundSprites;
 	MainMenuDialog *_dialog;
 protected:
@@ -60,7 +61,7 @@ public:
 	/**
 	 * Constructor
 	 */
-	MainMenuContainer(const Common::String &spritesName);
+	MainMenuContainer(const Common::String &spritesName, uint frameCount);
 
 	/**
 	 * Destructor
@@ -96,6 +97,8 @@ public:
 };
 
 class DarkSideMainMenuContainer : public MainMenuContainer {
+private:
+	SpriteResource _background;
 protected:
 	/**
 	 * Load the background
@@ -206,6 +209,67 @@ public:
 	virtual bool handleEvents();
 };
 
+class DarkSideMenuDialog : public MainMenuDialog {
+private:
+	SpriteResource _buttonSprites;
+	bool _firstDraw;
+private:
+	/**
+	 * Loads buttons for the dialog
+	 */
+	void loadButtons();
+public:
+	/**
+	 * Constructor
+	 */
+	DarkSideMenuDialog(MainMenuContainer *owner);
+
+	/**
+	 * Destructor
+	 */
+	virtual ~DarkSideMenuDialog();
+
+	/**
+	 * Draws the dialog
+	 */
+	virtual void draw();
+
+	/**
+	 * Handles events
+	 */
+	virtual bool handleEvents();
+};
+
+class WorldMenuDialog : public MainMenuDialog {
+private:
+	SpriteResource _buttonSprites;
+private:
+	/**
+	* Loads buttons for the dialog
+	*/
+	void loadButtons();
+public:
+	/**
+	 * Constructor
+	 */
+	WorldMenuDialog(MainMenuContainer *owner);
+
+	/**
+	* Destructor
+	*/
+	virtual ~WorldMenuDialog();
+
+	/**
+	 * Draws the dialog
+	 */
+	virtual void draw();
+
+	/**
+	 * Handles events
+	 */
+	virtual bool handleEvents();
+};
+
 } // End of namespace WorldOfXeen
 } // End of namespace Xeen
 


Commit: 66bd71f6f37b29b2b859052d8ebff7f3c3cc054e
    https://github.com/scummvm/scummvm/commit/66bd71f6f37b29b2b859052d8ebff7f3c3cc054e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-03-04T22:40:43-05:00

Commit Message:
XEEN: Finish World of Xeen main menu

Changed paths:
    engines/xeen/sound.cpp
    engines/xeen/worldofxeen/worldofxeen_menu.cpp


diff --git a/engines/xeen/sound.cpp b/engines/xeen/sound.cpp
index 2fb8807..95aabbe 100644
--- a/engines/xeen/sound.cpp
+++ b/engines/xeen/sound.cpp
@@ -173,8 +173,7 @@ void Sound::playSong(const Common::String &name, int param) {
 	Common::File mf;
 	if (mf.open(name)) {
 		playSong(mf);
-	}
-	else {
+	} else {
 		File f(name, _musicSide);
 		playSong(f);
 	}
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.cpp b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
index d1d6814..7b60a70 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
@@ -146,6 +146,8 @@ DarkSideMainMenuContainer::DarkSideMainMenuContainer() : MainMenuContainer("titl
 	Sound &sound = *g_vm->_sound;
 	screen.loadPalette("dark.pal");
 	screen.fadeIn(0x81);
+
+	sound._musicSide = 1;
 	sound.playSong("newbrigh.m");
 
 	_background.load("title2.int");
@@ -168,6 +170,7 @@ void DarkSideMainMenuContainer::showMenuDialog() {
 
 WorldOfXeenMainMenuContainer::WorldOfXeenMainMenuContainer() : MainMenuContainer("world.int", 5) {
 	Sound &sound = *g_vm->_sound;
+	sound._musicSide = 1;
 	sound.playSong("newbrigh.m");
 }
 
@@ -179,7 +182,7 @@ void WorldOfXeenMainMenuContainer::loadBackground() {
 }
 
 void WorldOfXeenMainMenuContainer::showMenuDialog() {
-	setOwner(new CloudsMenuDialog(this));
+	setOwner(new WorldMenuDialog(this));
 }
 
 /*------------------------------------------------------------------------*/
@@ -402,7 +405,7 @@ void WorldMenuDialog::draw() {
 	Window &w = windows[GAME_WINDOW];
 
 	w.frame();
-	w.writeString(Common::String::format(Res.CLOUDS_MAIN_MENU, g_vm->_gameWon[0] ? 117 : 92));
+	w.writeString(Res.WORLD_MAIN_MENU);
 	drawButtons(&w);
 }
 


Commit: 59fc48501cf395da1bf6cf1887e7f1f81160e64a
    https://github.com/scummvm/scummvm/commit/59fc48501cf395da1bf6cf1887e7f1f81160e64a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-03-04T22:40:43-05:00

Commit Message:
XEEN: Fix game credits text in create_xeen

Changed paths:
    devtools/create_xeen/constants.cpp


diff --git a/devtools/create_xeen/constants.cpp b/devtools/create_xeen/constants.cpp
index 2df74e2..a0cdb18 100644
--- a/devtools/create_xeen/constants.cpp
+++ b/devtools/create_xeen/constants.cpp
@@ -96,41 +96,41 @@ const char *const CLOUDS_CREDITS =
 	"\t190Michael Suarez\x3""c";
 
 const char *const DARK_SIDE_CREDITS =
-	"\013""012\010""000\003""c\014""35Designed and Directed By:\n"
-	"\014""17Jon Van Caneghem\003""l\n"
+	"\v012\t000\x3""c\f35Designed and Directed By:\n"
+	"\f17Jon Van Caneghem\x3""l\n"
 	"\n"
-	"\t025\014""35Programming:\n"
-	"\t035\014""17Mark Caldwell\n"
+	"\t025\f35Programming:\n"
+	"\t035\f17Mark Caldwell\n"
 	"\t035Dave Hathaway\n"
 	"\n"
-	"\t025\014""35Sound System & FX:\n"
-	"\t035\014""17Mike Heilemann\n"
+	"\t025\f35Sound System & FX:\n"
+	"\t035\f17Mike Heilemann\n"
 	"\n"
-	"\t025\014""35Music & Speech:\n"
-	"\t035\014""17Tim Tully\n"
+	"\t025\f35Music & Speech:\n"
+	"\t035\f17Tim Tully\n"
 	"\n"
-	"\t025\014""35Writing:\n"
-	"\t035\014""17Paul Rattner\n"
+	"\t025\f35Writing:\n"
+	"\t035\f17Paul Rattner\n"
 	"\t035Debbie Van Caneghem\n"
-	"\t035Jon Van Caneghem\013""012\n"
+	"\t035Jon Van Caneghem\v012\n"
 	"\n"
 	"\n"
-	"\t180\014""35Graphics:\n"
-	"\t190\014""17Jonathan P. Gwyn\n"
+	"\t180\f35Graphics:\n"
+	"\t190\f17Jonathan P. Gwyn\n"
 	"\t190Bonita Long-Hemsath\n"
 	"\t190Julia Ulano\n"
 	"\t190Ricardo Barrera\n"
 	"\n"
-	"\t180\014""35Testing:\n"
-	"\t190\014""17Benjamin Bent\n"
+	"\t180\f35Testing:\n"
+	"\t190\f17Benjamin Bent\n"
 	"\t190Christian Dailey\n"
 	"\t190Mario Escamilla\n"
 	"\t190Marco Hunter\n"
 	"\t190Robert J. Lupo\n"
 	"\t190Clayton Retzer\n"
-	"\t190David Vela\003""c";
+	"\t190David Vela\x3""c";
 const char *const SWORDS_CREDITS1 =
-	"\v012\x3""c35Published By New World Computing, Inc.\f17\n"
+	"\v012\x3""c\f35Published By New World Computing, Inc.\f17\n"
 	"Developed By CATware, Inc.\x3l\n"
 	"\f01Design and Direction\t180Series Created by\n"
 	"\t020Bill Fawcett\t190John Van Caneghem\n"
@@ -148,7 +148,7 @@ const char *const SWORDS_CREDITS1 =
 	"\t190Julia Ulano\n"
 	"\t190Ricardo Barrera\n";
 const char *const SWORDS_CREDITS2 =
-	"\f05v012\t000\x3l\n"
+	"\f05\v012\t000\x3l\n"
 	"\t100Sound Programming\n"
 	"\t110Todd Hendrix\n"
 	"\n"
@@ -162,16 +162,12 @@ const char *const SWORDS_CREDITS2 =
 	"\t110David Baton\n"
 	"\t110Jack Nalls\n";
 
-const char *const CLOUDS_MAIN_MENU =
+const char *const OPTIONS_MENU =
 	"\r\x1\x3""c\fdMight and Magic Options\n"
-	"Clouds of Xeen\x2\n"
-	"\v%03dCopyright (c) 1992 NWC, Inc.\n"
+	"%s of Xeen\x2\n"
+	"\v%.3dCopyright (c) %d NWC, Inc.\n"
 	"All Rights Reserved\x1";
-const char *const WORLD_MAIN_MENU =
-	"\r\x1\x3""c\fdMight and Magic Options\n"
-	"World of Xeen\x2\n"
-	"\v117Copyright (c) 1993 NWC, Inc.\n"
-	"All Rights Reserved\x01";
+const char *const GAME_NAMES[3] = { "Clouds", "Darkside", "World" };
 
 const char *const THE_PARTY_NEEDS_REST = "\x0B""012The Party needs rest!";
 
@@ -1847,8 +1843,8 @@ void writeConstants(CCArchive &cc) {
 	file.syncString(DARK_SIDE_CREDITS);
 	file.syncString(SWORDS_CREDITS1);
 	file.syncString(SWORDS_CREDITS2);
-	file.syncString(CLOUDS_MAIN_MENU);
-	file.syncString(WORLD_MAIN_MENU);
+	file.syncString(OPTIONS_MENU);
+	file.syncStrings(GAME_NAMES, 3);
 	file.syncString(THE_PARTY_NEEDS_REST);
 	file.syncString(WHO_WILL);
 	file.syncString(HOW_MUCH);


Commit: 546059408f7ff96997a35c9ae77d1122868d5b1d
    https://github.com/scummvm/scummvm/commit/546059408f7ff96997a35c9ae77d1122868d5b1d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-03-04T22:40:43-05:00

Commit Message:
XEEN: Added Other Options dialog for Dark Side and World

Changed paths:
    engines/xeen/resources.cpp
    engines/xeen/resources.h
    engines/xeen/scripts.cpp
    engines/xeen/worldofxeen/worldofxeen_cutscenes.h
    engines/xeen/worldofxeen/worldofxeen_menu.cpp
    engines/xeen/worldofxeen/worldofxeen_menu.h
    engines/xeen/xeen.cpp
    engines/xeen/xeen.h


diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp
index 6ea4252..14c87d6 100644
--- a/engines/xeen/resources.cpp
+++ b/engines/xeen/resources.cpp
@@ -66,8 +66,8 @@ void Resources::loadData() {
 	file.syncString(DARK_SIDE_CREDITS);
 	file.syncString(SWORDS_CREDITS1);
 	file.syncString(SWORDS_CREDITS2);
-	file.syncString(CLOUDS_MAIN_MENU);
-	file.syncString(WORLD_MAIN_MENU);
+	file.syncString(OPTIONS_MENU);
+	file.syncStrings(GAME_NAMES, 3);
 	file.syncString(THE_PARTY_NEEDS_REST);
 	file.syncString(WHO_WILL);
 	file.syncString(HOW_MUCH);
diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h
index b14b9f5..6dff6a7 100644
--- a/engines/xeen/resources.h
+++ b/engines/xeen/resources.h
@@ -120,8 +120,8 @@ public:
 	const char *DARK_SIDE_CREDITS;
 	const char *SWORDS_CREDITS1;
 	const char *SWORDS_CREDITS2;
-	const char *CLOUDS_MAIN_MENU;
-	const char *WORLD_MAIN_MENU;
+	const char *OPTIONS_MENU;
+	const char *GAME_NAMES[3];
 	const char *THE_PARTY_NEEDS_REST;
 	const char *WHO_WILL;
 	const char *HOW_MUCH;
diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp
index a3aa67b..ffe4e2d 100644
--- a/engines/xeen/scripts.cpp
+++ b/engines/xeen/scripts.cpp
@@ -1085,7 +1085,7 @@ bool Scripts::cmdCutsceneEndClouds(ParamsIterator &params) {
 	party._mazePosition = Common::Point(18, 4);
 
 	g_vm->_gameWon[0] = true;
-	g_vm->_finalScore[0] = party.getScore();
+	g_vm->_finalScore = party.getScore();
 	g_vm->saveSettings();
 
 	doCloudsEnding();
@@ -1421,7 +1421,7 @@ bool Scripts::cmdCutsceneEndDarkside(ParamsIterator &params) {
 	party._mazePosition = Common::Point(25, 21);
 
 	g_vm->_gameWon[1] = true;
-	g_vm->_finalScore[1] = party.getScore();
+	g_vm->_finalScore = party.getScore();
 	g_vm->saveSettings();
 
 	doDarkSideEnding();
@@ -1429,6 +1429,12 @@ bool Scripts::cmdCutsceneEndDarkside(ParamsIterator &params) {
 }
 
 bool Scripts::cmdCutsceneEndWorld(ParamsIterator &params) {
+	Party &party = *g_vm->_party;
+
+	g_vm->_gameWon[2] = true;
+	g_vm->_finalScore = party.getScore();
+	g_vm->saveSettings();
+
 	_vm->_saves->_wonWorld = true;
 	_vm->_party->_worldEnd = true;
 
diff --git a/engines/xeen/worldofxeen/worldofxeen_cutscenes.h b/engines/xeen/worldofxeen/worldofxeen_cutscenes.h
index bd78593..6fee060 100644
--- a/engines/xeen/worldofxeen/worldofxeen_cutscenes.h
+++ b/engines/xeen/worldofxeen/worldofxeen_cutscenes.h
@@ -70,14 +70,14 @@ private:
 	 * Part 4 of World of Xeen ending
 	 */
 	void worldEnding4();
-protected:
+public:
+	WorldOfXeenCutscenes(XeenEngine *vm) : _vm(vm), CloudsCutscenes(vm),
+		DarkSideCutscenes(vm), _goober(NON_GOOBER), _finalScore(0) {}
+
 	/**
 	 * Shows the World of Xeen ending sequence
 	 */
 	void showWorldOfXeenEnding(GooberState state, uint score);
-public:
-	WorldOfXeenCutscenes(XeenEngine *vm) : _vm(vm), CloudsCutscenes(vm),
-		DarkSideCutscenes(vm), _goober(NON_GOOBER), _finalScore(0) {}
 };
 
 } // End of namespace WorldOfXeen
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.cpp b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
index 7b60a70..36d6b7c 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.cpp
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.cpp
@@ -264,7 +264,7 @@ void CloudsMenuDialog::draw() {
 	Window &w = windows[GAME_WINDOW];
 	
 	w.frame();
-	w.writeString(Common::String::format(Res.CLOUDS_MAIN_MENU, g_vm->_gameWon[0] ? 117 : 92));
+	w.writeString(Common::String::format(Res.OPTIONS_MENU, Res.GAME_NAMES[0], g_vm->_gameWon[0] ? 117 : 92, 1992));
 	drawButtons(&w);
 }
 
@@ -279,7 +279,8 @@ bool CloudsMenuDialog::handleEvents() {
 			delete this;
 
 			// Show clouds ending
-			WOX_VM.showCloudsEnding(g_vm->_finalScore[0]);
+			WOX_VM._sound->stopAllAudio();
+			WOX_VM.showCloudsEnding(g_vm->_finalScore);
 			return true;
 		}
 		break;
@@ -363,10 +364,16 @@ bool DarkSideMenuDialog::handleEvents() {
 		return true;
 
 	switch (_buttonValue) {
-	case Common::KEYCODE_o:
+	case Common::KEYCODE_o: {
 		// Show other options dialog
-		// TODO
-		break;
+		// Remove this dialog
+		MainMenuContainer *owner = _owner;
+		delete this;
+
+		// Set the new options dialog
+		owner->setOwner(new OtherOptionsDialog(owner));
+		return true;
+	}
 
 	default:
 		break;
@@ -405,7 +412,7 @@ void WorldMenuDialog::draw() {
 	Window &w = windows[GAME_WINDOW];
 
 	w.frame();
-	w.writeString(Res.WORLD_MAIN_MENU);
+	w.writeString(Common::String::format(Res.OPTIONS_MENU, Res.GAME_NAMES[2], 117, 1993));
 	drawButtons(&w);
 }
 
@@ -414,10 +421,16 @@ bool WorldMenuDialog::handleEvents() {
 		return true;
 
 	switch (_buttonValue) {
-	case Common::KEYCODE_o:
+	case Common::KEYCODE_o: {
 		// Show other options dialog
-		// TODO
-		break;
+		// Remove this dialog
+		MainMenuContainer *owner = _owner;
+		delete this;
+
+		// Set the new options dialog
+		owner->setOwner(new OtherOptionsDialog(owner));
+		return true;
+	}
 
 	default:
 		break;
@@ -426,6 +439,135 @@ bool WorldMenuDialog::handleEvents() {
 	return false;
 }
 
+/*------------------------------------------------------------------------*/
+
+OtherOptionsDialog::OtherOptionsDialog(MainMenuContainer *owner) : MenuContainerDialog(owner) {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+
+	int height = (g_vm->getGameID() == GType_WorldOfXeen ? 25 : 0)
+		+ (g_vm->getGameID() == GType_WorldOfXeen && g_vm->_gameWon[0] ? 25 : 0)
+		+ (g_vm->_gameWon[1] ? 25 : 0)
+		+ (g_vm->_gameWon[2] ? 25 : 0)
+		+ 75;
+
+	w.setBounds(Common::Rect(72, 25, 248, 25 + height));
+	w.open();
+
+	loadButtons();
+}
+
+OtherOptionsDialog::~OtherOptionsDialog() {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+	w.close();
+}
+
+void OtherOptionsDialog::loadButtons() {
+	_buttonSprites.load("special.icn");
+	Common::Rect r(93, 53, 227, 73);
+
+	// View Darkside Intro
+	addButton(r, Common::KEYCODE_d, &_buttonSprites);
+	r.translate(0, 25);
+
+	// View Clouds Intro
+	if (g_vm->getGameID() == GType_WorldOfXeen) {
+		addButton(r, Common::KEYCODE_c, &_buttonSprites);
+		r.translate(0, 25);
+	} else {
+		addButton(Common::Rect(), Common::KEYCODE_INVALID);
+	}
+
+	// View Darkside End
+	if (g_vm->_gameWon[1]) {
+		addButton(r, Common::KEYCODE_e, &_buttonSprites);
+		r.translate(0, 25);
+	} else {
+		addButton(Common::Rect(), Common::KEYCODE_INVALID);
+	}
+
+	// View Clouds End
+	if (g_vm->_gameWon[0]) {
+		addButton(r, Common::KEYCODE_v, &_buttonSprites);
+		r.translate(0, 25);
+	} else {
+		addButton(Common::Rect(), Common::KEYCODE_INVALID);
+	}
+
+	// View World End
+	if (g_vm->_gameWon[2]) {
+		addButton(r, Common::KEYCODE_w, &_buttonSprites);
+	} else {
+		addButton(Common::Rect(), Common::KEYCODE_INVALID);
+	}
+}
+
+void OtherOptionsDialog::draw() {
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[GAME_WINDOW];
+
+	w.frame();
+	w.writeString(Common::String::format(Res.OPTIONS_MENU,
+		Res.GAME_NAMES[g_vm->getGameID() == GType_WorldOfXeen ? 2 : 1], 
+		w.getBounds().height() - 33, 1993));
+	drawButtons(&w);
+}
+
+bool OtherOptionsDialog::handleEvents() {
+	Sound &sound = *g_vm->_sound;
+	checkEvents(g_vm);
+
+	switch (_buttonValue) {
+	case Common::KEYCODE_d:
+		delete this;
+		sound.stopAllAudio();
+		WOX_VM.showDarkSideIntro(false);
+		break;
+
+	case Common::KEYCODE_c:
+		if (g_vm->getGameID() == GType_WorldOfXeen) {
+			delete this;
+			sound.stopAllAudio();
+			WOX_VM.showCloudsIntro();
+		}
+		break;
+
+	case Common::KEYCODE_e:
+		if (g_vm->_gameWon[1]) {
+			delete this;
+			sound.stopAllAudio();
+			WOX_VM.showDarkSideEnding(g_vm->_finalScore);
+		}
+		break;
+
+	case Common::KEYCODE_v:
+		if (g_vm->_gameWon[0]) {
+			delete this;
+			sound.stopAllAudio();
+			WOX_VM.showCloudsEnding(g_vm->_finalScore);
+		}
+		break;
+
+	case Common::KEYCODE_w:
+		if (g_vm->_gameWon[2]) {
+			delete this;
+			sound.stopAllAudio();
+			WOX_VM.showWorldOfXeenEnding(NON_GOOBER, g_vm->_finalScore);
+		}
+		break;
+
+	case Common::KEYCODE_ESCAPE:
+		// Exit dialog
+		delete this;
+		break;
+
+	default:
+		return false;
+	}
+
+	return true;
+}
 
 } // End of namespace WorldOfXeen
 } // End of namespace Xeen
diff --git a/engines/xeen/worldofxeen/worldofxeen_menu.h b/engines/xeen/worldofxeen/worldofxeen_menu.h
index 1db78b9..f3cee75 100644
--- a/engines/xeen/worldofxeen/worldofxeen_menu.h
+++ b/engines/xeen/worldofxeen/worldofxeen_menu.h
@@ -29,14 +29,14 @@
 namespace Xeen {
 namespace WorldOfXeen {
 
-class MainMenuDialog;
+class MenuContainerDialog;
 
 class MainMenuContainer {
 private:
 	uint _animateCtr;
 	uint _frameCount;
 	SpriteResource _backgroundSprites;
-	MainMenuDialog *_dialog;
+	MenuContainerDialog *_dialog;
 protected:
 	/**
 	 * Draws the main menu background
@@ -76,7 +76,7 @@ public:
 	/**
 	 * Sets the dialog being displayed in the menu
 	 */
-	void setOwner(MainMenuDialog *dlalog) {
+	void setOwner(MenuContainerDialog *dlalog) {
 		_dialog = dlalog;
 	}
 };
@@ -129,7 +129,7 @@ public:
 };
 
 class MenuContainerDialog : public ButtonContainer {
-private:
+protected:
 	MainMenuContainer *_owner;
 public:
 	/**
@@ -270,6 +270,36 @@ public:
 	virtual bool handleEvents();
 };
 
+class OtherOptionsDialog : public MenuContainerDialog {
+private:
+	SpriteResource _buttonSprites;
+private:
+	/**
+	* Loads buttons for the dialog
+	*/
+	void loadButtons();
+public:
+	/**
+	 * Constructor
+	 */
+	OtherOptionsDialog(MainMenuContainer *owner);
+
+	/**
+	 * Destructor
+	 */
+	virtual ~OtherOptionsDialog();
+
+	/**
+	 * Draws the dialog
+	 */
+	virtual void draw();
+
+	/**
+	 * Handles events
+	 */
+	virtual bool handleEvents();
+};
+
 } // End of namespace WorldOfXeen
 } // End of namespace Xeen
 
diff --git a/engines/xeen/xeen.cpp b/engines/xeen/xeen.cpp
index 6122f4d..c209420 100644
--- a/engines/xeen/xeen.cpp
+++ b/engines/xeen/xeen.cpp
@@ -62,8 +62,8 @@ XeenEngine::XeenEngine(OSystem *syst, const XeenGameDescription *gameDesc)
 	_mode = MODE_0;
 	_endingScore = 0;
 	_loadSaveSlot = -1;
-	_gameWon[0] = _gameWon[1] = false;
-	_finalScore[0] = _finalScore[1] = 0;
+	_gameWon[0] = _gameWon[1] = _gameWon[2] = false;
+	_finalScore = 0;
 	g_vm = this;
 }
 
@@ -116,8 +116,8 @@ bool XeenEngine::initialize() {
 	// Load settings
 	_gameWon[0] = ConfMan.hasKey("game_won") && ConfMan.getBool("game_won");
 	_gameWon[1] = ConfMan.hasKey("game_won2") && ConfMan.getBool("game_won2");
-	_finalScore[0] = ConfMan.hasKey("final_score") ? ConfMan.getInt("final_score") : 0;
-	_finalScore[1] = ConfMan.hasKey("final_score2") ? ConfMan.getInt("final_score2") : 0;
+	_gameWon[2] = ConfMan.hasKey("game_won3") && ConfMan.getBool("game_won3");
+	_finalScore = ConfMan.hasKey("final_score") ? ConfMan.getInt("final_score") : 0;
 
 	// If requested, load a savegame instead of showing the intro
 	if (ConfMan.hasKey("save_slot")) {
@@ -307,9 +307,10 @@ void XeenEngine::saveSettings() {
 		ConfMan.setBool("game_won", true);
 	if (_gameWon[1])
 		ConfMan.setBool("game_won2", true);
+	if (_gameWon[2])
+		ConfMan.setBool("game_won3", true);
 
-	ConfMan.setInt("final_score", _finalScore[0]);
-	ConfMan.setInt("final_score2", _finalScore[1]);
+	ConfMan.setInt("final_score", _finalScore);
 	ConfMan.flushToDisk();
 }
 
diff --git a/engines/xeen/xeen.h b/engines/xeen/xeen.h
index 62b3a7e..d26ffde 100644
--- a/engines/xeen/xeen.h
+++ b/engines/xeen/xeen.h
@@ -183,8 +183,8 @@ public:
 	bool _noDirectionSense;
 	bool _startupWindowActive;
 	uint _endingScore;
-	bool _gameWon[2];
-	uint _finalScore[2];
+	bool _gameWon[3];
+	uint _finalScore;
 public:
 	XeenEngine(OSystem *syst, const XeenGameDescription *gameDesc);
 	virtual ~XeenEngine();


Commit: d48275970aa78866349f20f44bacdc0aff83e57b
    https://github.com/scummvm/scummvm/commit/d48275970aa78866349f20f44bacdc0aff83e57b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-03-04T22:43:20-05:00

Commit Message:
XEEN: Regenerate xeen.ccs and remove accidentally committed dark.cc

Changed paths:
  R dists/engine-data/dark.cc
    dists/engine-data/xeen.ccs


diff --git a/dists/engine-data/dark.cc b/dists/engine-data/dark.cc
deleted file mode 100644
index 875ed74..0000000
Binary files a/dists/engine-data/dark.cc and /dev/null differ
diff --git a/dists/engine-data/xeen.ccs b/dists/engine-data/xeen.ccs
index 46d09c3..6a1e106 100644
Binary files a/dists/engine-data/xeen.ccs and b/dists/engine-data/xeen.ccs differ





More information about the Scummvm-git-logs mailing list