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

dreammaster dreammaster at scummvm.org
Wed Dec 13 02:30:03 CET 2017


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

Summary:
a5590a3755 XEEN: Create CutsceneLocation base class for cutscene locations
b612bc3c23 XEEN: Rename Town to LocationManager, added Locations namespace


Commit: a5590a3755ca5a6ec7a52266384f908d1b4405f0
    https://github.com/scummvm/scummvm/commit/a5590a3755ca5a6ec7a52266384f908d1b4405f0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2017-12-12T20:08:51-05:00

Commit Message:
XEEN: Create CutsceneLocation base class for cutscene locations

Changed paths:
    engines/xeen/town.cpp
    engines/xeen/town.h


diff --git a/engines/xeen/town.cpp b/engines/xeen/town.cpp
index 34d19da..4a635c7 100644
--- a/engines/xeen/town.cpp
+++ b/engines/xeen/town.cpp
@@ -30,7 +30,7 @@
 
 namespace Xeen {
 
-TownLocation::TownLocation(TownAction action) : ButtonContainer(g_vm),
+BaseLocation::BaseLocation(TownAction action) : ButtonContainer(g_vm),
 		_townActionId(action), _isDarkCc(g_vm->_files->_isDarkCc),
 		_vocName("hello1.voc") {
 	_townMaxId = (action >= SPHINX) ? 0 : Res.TOWN_MAXES[_isDarkCc][action];
@@ -44,10 +44,9 @@ TownLocation::TownLocation(TownAction action) : ButtonContainer(g_vm),
 	_farewellTime = 0;
 	_drawCtr1 = _drawCtr2 = 0;
 	_townPos = Common::Point(8, 8);
-	_animCtr = 0;
 }
 
-TownLocation::~TownLocation() {
+BaseLocation::~BaseLocation() {
 	Interface &intf = *g_vm->_interface;
 
 	for (uint idx = 0; idx < _townSprites.size(); ++idx)
@@ -55,7 +54,7 @@ TownLocation::~TownLocation() {
 	intf.mainIconsPrint();
 }
 
-int TownLocation::show() {
+int BaseLocation::show() {
 	Map &map = *g_vm->_map;
 	Party &party = *g_vm->_party;
 	Sound &sound = *g_vm->_sound;
@@ -110,7 +109,7 @@ int TownLocation::show() {
 	return result;
 }
 
-void TownLocation::drawBackground() {
+void BaseLocation::drawBackground() {
 	Interface &intf = *g_vm->_interface;
 
 	intf._face1UIFrame = intf._face2UIFrame = 0;
@@ -120,7 +119,7 @@ void TownLocation::drawBackground() {
 	_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
 }
 
-void TownLocation::drawWindow() {
+void BaseLocation::drawWindow() {
 	Interface &intf = *g_vm->_interface;
 	Party &party = *g_vm->_party;
 	Windows &windows = *g_vm->_windows;
@@ -138,7 +137,7 @@ void TownLocation::drawWindow() {
 	intf.highlightChar(0);
 }
 
-void TownLocation::drawAnim(bool flag) {
+void BaseLocation::drawAnim(bool flag) {
 	Interface &intf = *g_vm->_interface;
 	Sound &sound = *g_vm->_sound;
 	Windows &windows = *g_vm->_windows;
@@ -273,7 +272,7 @@ void TownLocation::drawAnim(bool flag) {
 		_animFrame = 2;
 }
 
-int TownLocation::wait() {
+int BaseLocation::wait() {
 	EventsManager &events = *g_vm->_events;
 	Windows &windows = *g_vm->_windows;
 
@@ -291,13 +290,9 @@ int TownLocation::wait() {
 	return _buttonValue;
 }
 
-void TownLocation::animUpdate() {
-	// TODO
-}
-
 /*------------------------------------------------------------------------*/
 
-BankLocation::BankLocation() : TownLocation(BANK) {
+BankLocation::BankLocation() : BaseLocation(BANK) {
 	_icons1.load("bank.icn");
 	_icons2.load("bank2.icn");
 	addButton(Common::Rect(234, 108, 259, 128), Common::KEYCODE_d, &_icons1);
@@ -440,7 +435,7 @@ void BankLocation::depositWithdrawl(PartyBank whereId) {
 
 /*------------------------------------------------------------------------*/
 
-BlacksmithLocation::BlacksmithLocation() : TownLocation(BLACKSMITH) {
+BlacksmithLocation::BlacksmithLocation() : BaseLocation(BLACKSMITH) {
 	_icons1.load("esc.icn");
 	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_ESCAPE, &_icons1);
 	addButton(Common::Rect(234, 54, 308, 62), 0);
@@ -487,7 +482,7 @@ void BlacksmithLocation::farewell() {
 
 /*------------------------------------------------------------------------*/
 
-GuildLocation::GuildLocation() : TownLocation(GUILD) {
+GuildLocation::GuildLocation() : BaseLocation(GUILD) {
 	loadStrings("spldesc.bin");
 	_icons1.load("esc.icn");
 	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_ESCAPE, &_icons1);
@@ -540,7 +535,7 @@ Character *GuildLocation::doOptions(Character *c) {
 
 /*------------------------------------------------------------------------*/
 
-TavernLocation::TavernLocation() : TownLocation(TAVERN) {
+TavernLocation::TavernLocation() : BaseLocation(TAVERN) {
 	_v21 = 0;
 	_v22 = 0;
 	_v23 = 0;
@@ -781,7 +776,7 @@ void TavernLocation::farewell() {
 
 /*------------------------------------------------------------------------*/
 
-TempleLocation::TempleLocation() : TownLocation(TEMPLE) {
+TempleLocation::TempleLocation() : BaseLocation(TEMPLE) {
 	_currentCharLevel = 0;
 	_donation = 0;
 	_healCost = 0;
@@ -966,7 +961,7 @@ Character *TempleLocation::doOptions(Character *c) {
 
 /*------------------------------------------------------------------------*/
 
-TrainingLocation::TrainingLocation() : TownLocation(TRAINING) {
+TrainingLocation::TrainingLocation() : BaseLocation(TRAINING) {
 	Common::fill(&_charsTrained[0], &_charsTrained[6], 0);
 	_maxLevel = 0;
 	_experienceToNextLevel = 0;
@@ -1106,19 +1101,41 @@ Character *TrainingLocation::doOptions(Character *c) {
 
 /*------------------------------------------------------------------------*/
 
-ArenaLocation::ArenaLocation() : TownLocation(ARENA) {
+ArenaLocation::ArenaLocation() : BaseLocation(ARENA) {
+	// TODO
+}
+
+/*------------------------------------------------------------------------*/
+
+CutsceneLocation::CutsceneLocation(TownAction action) : BaseLocation(action),
+		_animCtr(0), _mazeFlag(false) {
+	Party &party = *g_vm->_party;
+	_mazeId = party._mazeId;
+	_mazePos = party._mazePosition;
+	_mazeDir = party._mazeDirection;
+}
+
+void CutsceneLocation::cutsceneAnimUpdate() {
 	// TODO
 }
 
+void CutsceneLocation::setNewLocation() {
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+	map.load(_mazeId);
+	party._mazePosition = _mazePos;
+	party._mazeDirection = _mazeDir;
+}
+
 /*------------------------------------------------------------------------*/
 
-ReaperLocation::ReaperLocation() : TownLocation(REAPER) {
+ReaperCutscene::ReaperCutscene() : CutsceneLocation(REAPER) {
 	// TODO
 }
 
 /*------------------------------------------------------------------------*/
 
-GolemLocation::GolemLocation() : TownLocation(GOLEM) {
+GolemCutscene::GolemCutscene() : CutsceneLocation(GOLEM) {
 	// TODO
 }
 
@@ -1148,15 +1165,13 @@ const int16 DWARF2_Y[2][16] = {
 	{ 0, 12, 25, 37, 50, 62, 75, 87, 100, 112, 125, 137, 150, 162, 175, 186 }
 };
 
-DwarfLocation::DwarfLocation(bool isDwarf) : TownLocation(NO_ACTION) {
+DwarfCutscene::DwarfCutscene(bool isDwarf) : CutsceneLocation(NO_ACTION) {
 	_townMaxId = Res.TOWN_MAXES[_isDarkCc][isDwarf ? DWARF1 : DWARF2];
-	loadStrings("special.bin");
 }
 
-int DwarfLocation::show() {
+int DwarfCutscene::show() {
 	EventsManager &events = *g_vm->_events;
 	Interface &intf = *g_vm->_interface;
-	Party &party = *g_vm->_party;
 	Screen &screen = *g_vm->_screen;
 	Sound &sound = *g_vm->_sound;
 	Windows &windows = *g_vm->_windows;
@@ -1165,7 +1180,7 @@ int DwarfLocation::show() {
 	SpriteResource sprites2(_isDarkCc ? "town2.zom" : "dwarf2.vga");
 	SpriteResource sprites3(_isDarkCc ? "town3.zom" : "dwarf3.vga");
 	SpriteResource boxSprites("box.vga");
-	bool mazeFlag = setNewLocation();
+	getNewLocation();
 
 	// Save the screen contents
 	Graphics::ManagedSurface savedBg;
@@ -1208,13 +1223,13 @@ int DwarfLocation::show() {
 			if (_isDarkCc) {
 				sprites2.draw(0, 0);
 				sprites3.draw(0, 0);
-				animUpdate();
+				cutsceneAnimUpdate();
 
 				events.timeMark5();
 				while (!g_vm->shouldQuit() && events.timeElapsed5() < 7)
 					events.pollEventsAndWait();
 
-				sound.playSound(mazeFlag ? "ok2.voc" : "back2.voc");
+				sound.playSound(_mazeFlag ? "ok2.voc" : "back2.voc");
 			} else {
 				sound.playSound("dwarf11.voc");
 			}
@@ -1229,7 +1244,7 @@ int DwarfLocation::show() {
 		do {
 			sprites2.draw(0, 0);
 			sprites3.draw(0, g_vm->getRandomNumber(_isDarkCc ? 8 : 9));
-			animUpdate();
+			cutsceneAnimUpdate();
 
 			events.timeMark5();
 			while (!g_vm->shouldQuit() && events.timeElapsed5() < 2)
@@ -1245,6 +1260,8 @@ int DwarfLocation::show() {
 		sprites3.draw(0, 1);
 	windows[0].update();
 
+	setNewLocation();
+
 	// Restore game screen
 	sound.setMusicVolume(95);
 	screen.loadBackground("back.raw");
@@ -1255,54 +1272,48 @@ int DwarfLocation::show() {
 	return 0;
 }
 
-bool DwarfLocation::setNewLocation() {
-	Map &map = *g_vm->_map;
+void DwarfCutscene::getNewLocation() {
 	Party &party = *g_vm->_party;
-	Common::Point mazePos;
-	Direction mazeDir = DIR_NORTH;
-	int mazeId = 0;
-	bool mazeFlag = false;
 
-	// Set 
 	if (_isDarkCc) {
 		switch (party._mazeId) {
 		case 4:
 			if (party._questItems[35]) {
-				mazeId = 29;
-				mazePos = Common::Point(15, 31);
-				mazeDir = DIR_SOUTH;
+				_mazeId = 29;
+				_mazePos = Common::Point(15, 31);
+				_mazeDir = DIR_SOUTH;
 			}
 			break;
 
 		case 6:
 			if (party._questItems[38]) {
-				mazeId = 35;
-				mazePos = Common::Point(15, 8);
-				mazeDir = DIR_WEST;
+				_mazeId = 35;
+				_mazePos = Common::Point(15, 8);
+				_mazeDir = DIR_WEST;
 			}
 			break;
 
 		case 19:
 			if (party._questItems[36]) {
-				mazeId = 31;
-				mazePos = Common::Point(31, 16);
-				mazeDir = DIR_WEST;
+				_mazeId = 31;
+				_mazePos = Common::Point(31, 16);
+				_mazeDir = DIR_WEST;
 			}
 			break;
 
 		case 22:
 			if (party._questItems[37]) {
-				mazeId = 33;
-				mazePos = Common::Point(0, 3);
-				mazeDir = DIR_EAST;
+				_mazeId = 33;
+				_mazePos = Common::Point(0, 3);
+				_mazeDir = DIR_EAST;
 			}
 			break;
 
 		case 98:
 			if (party._questItems[39]) {
-				mazeId = 37;
-				mazePos = Common::Point(7, 0);
-				mazeDir = DIR_NORTH;
+				_mazeId = 37;
+				_mazePos = Common::Point(7, 0);
+				_mazeDir = DIR_NORTH;
 			}
 			break;
 
@@ -1310,41 +1321,36 @@ bool DwarfLocation::setNewLocation() {
 			break;
 		}
 
-		mazeFlag = mazeId != 0;
-		if (!mazeFlag) {
-			mazeId = party._mazeId;
-			mazePos = party._mazePosition;
-			mazeDir = party._mazeDirection;
-		}
+		_mazeFlag = _mazeId != 0;
 	} else {
 		switch (party._mazeId) {
 		case 14:
-			mazeId = 37;
-			mazePos = Common::Point(1, 4);
-			mazeDir = DIR_EAST;
+			_mazeId = 37;
+			_mazePos = Common::Point(1, 4);
+			_mazeDir = DIR_EAST;
 			break;
 
 		case 18:
 			if (party._mazePosition.x == 9) {
-				mazeId = 35;
-				mazePos = Common::Point(1, 12);
-				mazeDir = DIR_EAST;
+				_mazeId = 35;
+				_mazePos = Common::Point(1, 12);
+				_mazeDir = DIR_EAST;
 			} else {
-				mazeId = 36;
-				mazePos = Common::Point(7, 1);
-				mazeDir = DIR_NORTH;
+				_mazeId = 36;
+				_mazePos = Common::Point(7, 1);
+				_mazeDir = DIR_NORTH;
 			}
 			break;
 
 		case 23:
 			if (party._mazePosition.x == 5) {
-				mazeId = 33;
-				mazePos = Common::Point(7, 1);
-				mazeDir = DIR_NORTH;
+				_mazeId = 33;
+				_mazePos = Common::Point(7, 1);
+				_mazeDir = DIR_NORTH;
 			} else {
-				mazeId = 34;
-				mazePos = Common::Point(7, 30);
-				mazeDir = DIR_SOUTH;
+				_mazeId = 34;
+				_mazePos = Common::Point(7, 30);
+				_mazeDir = DIR_SOUTH;
 			}
 			break;
 
@@ -1352,22 +1358,57 @@ bool DwarfLocation::setNewLocation() {
 			break;
 		}
 	}
-
-	map.load(mazeId);
-	party._mazePosition = mazePos;
-	party._mazeDirection = mazeDir;
-	return mazeFlag;
 }
 
 /*------------------------------------------------------------------------*/
 
-SphinxLocation::SphinxLocation() : TownLocation(SPHINX) {
+SphinxCutscene::SphinxCutscene() : CutsceneLocation(SPHINX) {
+	SpriteResource sprites1("sphinx.vga");
+	_boxSprites.load("box.vga");
+
+
 	// TODO
 }
 
+void SphinxCutscene::getNewLocation() {
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+
+	switch (party._mazeId) {
+	case 2:
+		if (party._questItems[51]) {
+			map._loadDarkSide = true;
+			_mazeId = 125;
+			_mazePos = Common::Point(7, 6);
+			_mazeDir = DIR_NORTH;
+			_mazeFlag = true;
+		}
+		break;
+
+	case 5:
+		if (party._questItems[4]) {
+			_mazeId = 82;
+			_mazePos = Common::Point(7, 5);
+			_mazeDir = DIR_NORTH;
+			_mazeFlag = true;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	if (!_mazeFlag) {
+		_mazeId = party._mazeId;
+		_mazePos = party._mazePosition;
+		_mazeDir = party._mazeDirection;
+	}
+}
+
+
 /*------------------------------------------------------------------------*/
 
-PyramidLocation::PyramidLocation() : TownLocation(PYRAMID) {
+PyramidLocation::PyramidLocation() : BaseLocation(PYRAMID) {
 }
 
 int PyramidLocation::show() {
@@ -1450,19 +1491,19 @@ int Town::townAction(TownAction actionId) {
 		_location = new ArenaLocation();
 		break;
 	case REAPER:
-		_location = new ReaperLocation();
+		_location = new ReaperCutscene();
 		break;
 	case GOLEM:
-		_location = new GolemLocation();
+		_location = new GolemCutscene();
 		break;
 	case DWARF1:
-		_location = new DwarfLocation(true);
+		_location = new DwarfCutscene(true);
 		break;
 	case DWARF2:
-		_location = new DwarfLocation(false);
+		_location = new DwarfCutscene(false);
 		break;
 	case SPHINX:
-		_location = new SphinxLocation();
+		_location = new SphinxCutscene();
 		break;
 	case PYRAMID:
 		_location = new PyramidLocation();
diff --git a/engines/xeen/town.h b/engines/xeen/town.h
index b4b70fa..925bac9 100644
--- a/engines/xeen/town.h
+++ b/engines/xeen/town.h
@@ -40,7 +40,7 @@ enum TownAction {
 class XeenEngine;
 class TownMessage;
 
-class TownLocation : public ButtonContainer {
+class BaseLocation : public ButtonContainer {
 protected:
 	TownAction _townActionId;
 	Common::Array<SpriteResource> _townSprites;
@@ -53,7 +53,6 @@ protected:
 	int _drawFrameIndex;
 	uint _farewellTime;
 	int _drawCtr1, _drawCtr2;
-	int _animCtr;
 protected:
 	/**
 	 * Draw the window
@@ -66,11 +65,6 @@ protected:
 	int wait();
 
 	/**
-	 * Handles animation updates for Sphinx, Golem, Repear, and Dwarf events
-	 */
-	void animUpdate();
-
-	/**
 	 * Generates the display text for the location, for a given character
 	 */
 	virtual Common::String createLocationText(Character &ch) { return ""; }
@@ -90,8 +84,8 @@ protected:
 	 */
 	virtual void farewell() {}
 public:
-	TownLocation(TownAction action);
-	virtual ~TownLocation();
+	BaseLocation(TownAction action);
+	virtual ~BaseLocation();
 
 	/**
 	 * Show the town location
@@ -104,7 +98,7 @@ public:
 	void drawAnim(bool flag);
 };
 
-class BankLocation : public TownLocation {
+class BankLocation : public BaseLocation {
 private:
 	/**
 	 * Handles deposits or withdrawls fro the bank
@@ -130,7 +124,7 @@ public:
 	virtual ~BankLocation() {}
 };
 
-class BlacksmithLocation : public TownLocation {
+class BlacksmithLocation : public BaseLocation {
 protected:
 	/**
 	* Generates the display text for the location, for a given character
@@ -151,7 +145,7 @@ public:
 	virtual ~BlacksmithLocation() {}
 };
 
-class GuildLocation : public TownLocation {
+class GuildLocation : public BaseLocation {
 protected:
 	/**
 	 * Generates the display text for the location, for a given character
@@ -167,7 +161,7 @@ public:
 	virtual ~GuildLocation() {}
 };
 
-class TavernLocation : public TownLocation {
+class TavernLocation : public BaseLocation {
 private:
 	int _v21;
 	uint _v22;
@@ -193,7 +187,7 @@ public:
 	virtual ~TavernLocation() {}
 };
 
-class TempleLocation : public TownLocation {
+class TempleLocation : public BaseLocation {
 private:
 	int _currentCharLevel;
 	int _donation;
@@ -219,7 +213,7 @@ public:
 	virtual ~TempleLocation() {}
 };
 
-class TrainingLocation : public TownLocation {
+class TrainingLocation : public BaseLocation {
 private:
 	int _charIndex;
 	bool _charsTrained[MAX_ACTIVE_PARTY];
@@ -240,33 +234,55 @@ public:
 	virtual ~TrainingLocation() {}
 };
 
-class ArenaLocation : public TownLocation {
+class ArenaLocation : public BaseLocation {
 public:
 	ArenaLocation();
 	virtual ~ArenaLocation() {}
 };
 
-class ReaperLocation : public TownLocation {
+class CutsceneLocation : public BaseLocation {
+protected:
+	int _animCtr;
+	SpriteResource _boxSprites;
+	int _mazeId;
+	Direction _mazeDir;
+	Common::Point _mazePos;
+	bool _mazeFlag;
+protected:
+	/**
+	* Handles cutscene animation update
+	*/
+	void cutsceneAnimUpdate();
+
+	/**
+	 * Sets the new location
+	 */
+	void setNewLocation();
+public:
+	CutsceneLocation(TownAction action);
+};
+
+class ReaperCutscene : public CutsceneLocation {
 public:
-	ReaperLocation();
-	virtual ~ReaperLocation() {}
+	ReaperCutscene();
+	virtual ~ReaperCutscene() {}
 };
 
-class GolemLocation : public TownLocation {
+class GolemCutscene : public CutsceneLocation {
 public:
-	GolemLocation();
-	virtual ~GolemLocation() {}
+	GolemCutscene();
+	virtual ~GolemCutscene() {}
 };
 
-class DwarfLocation : public TownLocation {
+class DwarfCutscene : public CutsceneLocation {
 private:
 	/**
-	 * Set the new location
+	 * Get the new location
 	 */
-	bool setNewLocation();
+	void getNewLocation();
 public:
-	DwarfLocation(bool isDwarf1);
-	virtual ~DwarfLocation() {}
+	DwarfCutscene(bool isDwarf1);
+	virtual ~DwarfCutscene() {}
 
 	/**
 	 * Show the town location
@@ -274,13 +290,18 @@ public:
 	virtual int show();
 };
 
-class SphinxLocation : public TownLocation {
+class SphinxCutscene : public CutsceneLocation {
+private:
+	/**
+	 * Get the new location
+	 */
+	void getNewLocation();
 public:
-	SphinxLocation();
-	virtual ~SphinxLocation() {}
+	SphinxCutscene();
+	virtual ~SphinxCutscene() {}
 };
 
-class PyramidLocation : public TownLocation {
+class PyramidLocation : public BaseLocation {
 public:
 	PyramidLocation();
 	virtual ~PyramidLocation() {}
@@ -293,7 +314,7 @@ public:
 
 class Town {
 private:
-	TownLocation *_location;
+	BaseLocation *_location;
 private:
 	int townWait();
 
@@ -327,11 +348,11 @@ public:
 	void drawAnim(bool flag);
 };
 
-class TownMessage : public TownLocation {
+class TownMessage : public BaseLocation {
 private:
 	SpriteResource _iconSprites;
 
-	TownMessage() : TownLocation(NO_ACTION) {}
+	TownMessage() : BaseLocation(NO_ACTION) {}
 
 	bool execute(int portrait, const Common::String &name,
 		const Common::String &text, int confirm);


Commit: b612bc3c23d9ffc6a57eedd684f1d6b10dc3c6ab
    https://github.com/scummvm/scummvm/commit/b612bc3c23d9ffc6a57eedd684f1d6b10dc3c6ab
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2017-12-12T20:29:47-05:00

Commit Message:
XEEN: Rename Town to LocationManager, added Locations namespace

Changed paths:
  A engines/xeen/locations.cpp
  A engines/xeen/locations.h
  R engines/xeen/town.cpp
  R engines/xeen/town.h
    engines/xeen/dialogs_input.cpp
    engines/xeen/dialogs_query.cpp
    engines/xeen/dialogs_whowill.cpp
    engines/xeen/module.mk
    engines/xeen/scripts.cpp
    engines/xeen/xeen.cpp
    engines/xeen/xeen.h


diff --git a/engines/xeen/dialogs_input.cpp b/engines/xeen/dialogs_input.cpp
index 2f4a174..a0573d2 100644
--- a/engines/xeen/dialogs_input.cpp
+++ b/engines/xeen/dialogs_input.cpp
@@ -225,7 +225,7 @@ int Choose123::show(XeenEngine *vm, int numOptions) {
 int Choose123::execute(int numOptions) {
 	EventsManager &events = *_vm->_events;
 	Interface &intf = *_vm->_interface;
-	Town &town = *_vm->_town;
+	LocationManager &loc = *_vm->_locations;
 	Windows &windows = *_vm->_windows;
 
 	Mode oldMode = _vm->_mode;
@@ -241,8 +241,8 @@ int Choose123::execute(int numOptions) {
 		do {
 			events.updateGameCounter();
 			int delay;
-			if (town.isActive()) {
-				town.drawAnim(true);
+			if (loc.isActive()) {
+				loc.drawAnim(true);
 				delay = 3;
 			} else {
 				intf.draw3d(true);
diff --git a/engines/xeen/dialogs_query.cpp b/engines/xeen/dialogs_query.cpp
index 7dd35a1..fd46693 100644
--- a/engines/xeen/dialogs_query.cpp
+++ b/engines/xeen/dialogs_query.cpp
@@ -102,7 +102,7 @@ bool YesNo::execute(bool type, bool townFlag) {
 	Map &map = *_vm->_map;
 	Party &party = *_vm->_party;
 	Resources &res = *_vm->_resources;
-	Town &town = *_vm->_town;
+	LocationManager &loc = *_vm->_locations;
 	Windows &windows = *_vm->_windows;
 	SpriteResource confirmSprites;
 	bool result = false;
@@ -127,8 +127,8 @@ bool YesNo::execute(bool type, bool townFlag) {
 	while (!_vm->shouldQuit()) {
 		events.updateGameCounter();
 
-		if (town.isActive()) {
-			town.drawAnim(townFlag);
+		if (loc.isActive()) {
+			loc.drawAnim(townFlag);
 			//numFrames = 3;
 		} else {
 			intf.draw3d(true);
diff --git a/engines/xeen/dialogs_whowill.cpp b/engines/xeen/dialogs_whowill.cpp
index 36451dc..a2be4e3 100644
--- a/engines/xeen/dialogs_whowill.cpp
+++ b/engines/xeen/dialogs_whowill.cpp
@@ -40,7 +40,7 @@ int WhoWill::execute(int message, int action, bool type) {
 	Map &map = *_vm->_map;
 	Party &party = *_vm->_party;
 	Scripts &scripts = *_vm->_scripts;
-	Town &town = *_vm->_town;
+	LocationManager &loc = *_vm->_locations;
 	Windows &windows = *_vm->_windows;
 	int numFrames;
 
@@ -66,7 +66,7 @@ int WhoWill::execute(int message, int action, bool type) {
 		events.updateGameCounter();
 
 		if (windows[11]._enabled) {
-			town.drawAnim(false);
+			loc.drawAnim(false);
 			windows[36].frame();
 			numFrames = 3;
 		} else {
diff --git a/engines/xeen/locations.cpp b/engines/xeen/locations.cpp
new file mode 100644
index 0000000..cc2320a
--- /dev/null
+++ b/engines/xeen/locations.cpp
@@ -0,0 +1,1661 @@
+/* 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/locations.h"
+#include "xeen/dialogs_input.h"
+#include "xeen/dialogs_items.h"
+#include "xeen/dialogs_query.h"
+#include "xeen/dialogs_spells.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+namespace Locations {
+
+BaseLocation::BaseLocation(LocationAction action) : ButtonContainer(g_vm),
+		_LocationActionId(action), _isDarkCc(g_vm->_files->_isDarkCc),
+		_vocName("hello1.voc") {
+	_townMaxId = (action >= SPHINX) ? 0 : Res.TOWN_MAXES[_isDarkCc][action];
+	if (action < NO_ACTION) {
+		_songName = Res.TOWN_ACTION_MUSIC[_isDarkCc][action];
+		_townSprites.resize(Res.TOWN_ACTION_FILES[_isDarkCc][action]);
+	}
+
+	_animFrame = 0;
+	_drawFrameIndex = 0;
+	_farewellTime = 0;
+	_drawCtr1 = _drawCtr2 = 0;
+	_townPos = Common::Point(8, 8);
+}
+
+BaseLocation::~BaseLocation() {
+	Interface &intf = *g_vm->_interface;
+
+	for (uint idx = 0; idx < _townSprites.size(); ++idx)
+		_townSprites[idx].clear();
+	intf.mainIconsPrint();
+}
+
+int BaseLocation::show() {
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+	Sound &sound = *g_vm->_sound;
+	Windows &windows = *g_vm->_windows;
+
+	// Play the appropriate music
+	sound.stopSound();
+	sound.playSong(_songName, 223);
+
+	// Load the needed sprite sets for the location
+	for (uint idx = 0; idx < _townSprites.size(); ++idx) {
+		Common::String shapesName = Common::String::format("%s%d.twn",
+			Res.TOWN_ACTION_SHAPES[_LocationActionId], idx + 1);
+		_townSprites[idx].load(shapesName);
+	}
+
+	Character *charP = &party._activeParty[0];
+
+	// Draw the background and the text window
+	drawBackground();
+	drawWindow();
+	drawAnim(true);
+
+	// Play the welcome speech
+	sound.playSound(_vocName, 1);
+
+	do {
+		wait();
+		charP = doOptions(charP);
+		if (_vm->shouldQuit())
+			return 0;
+
+		Common::String msg = createLocationText(*charP);
+		windows[10].writeString(msg);
+		drawButtons(&windows[0]);
+	} while (_buttonValue != Common::KEYCODE_ESCAPE);
+
+	// Handle any farewell message
+	farewell();
+
+	int result;
+	if (party._mazeId != 0) {
+		map.load(party._mazeId);
+		_farewellTime += 1440;
+		party.addTime(_farewellTime);
+		result = 0;
+	} else {
+		_vm->_saves->saveChars();
+		result = 2;
+	}
+
+	return result;
+}
+
+void BaseLocation::drawBackground() {
+	Interface &intf = *g_vm->_interface;
+
+	intf._face1UIFrame = intf._face2UIFrame = 0;
+	intf._dangerSenseUIFrame = 0;
+	intf._spotDoorsUIFrame = 0;
+	intf._levitateUIFrame = 0;
+	_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
+}
+
+void BaseLocation::drawWindow() {
+	Interface &intf = *g_vm->_interface;
+	Party &party = *g_vm->_party;
+	Windows &windows = *g_vm->_windows;
+
+	Character *charP = &party._activeParty[0];
+	Common::String title = createLocationText(*charP);
+
+	// Open up the window and write the string
+	intf.assembleBorder();
+	windows[10].open();
+	windows[10].writeString(title);
+	drawButtons(&windows[0]);
+
+	windows[0].update();
+	intf.highlightChar(0);
+}
+
+void BaseLocation::drawAnim(bool flag) {
+	Interface &intf = *g_vm->_interface;
+	Sound &sound = *g_vm->_sound;
+	Windows &windows = *g_vm->_windows;
+
+	// TODO: Figure out a clean way to split method into individual location classes
+	if (_LocationActionId == BLACKSMITH) {
+		if (sound.isPlaying()) {
+			if (_isDarkCc) {
+				_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
+				_townSprites[2].draw(0, _vm->getRandomNumber(11) == 1 ? 9 : 10,
+					Common::Point(34, 33));
+				_townSprites[2].draw(0, _vm->getRandomNumber(5) + 3,
+					Common::Point(34, 54));
+			}
+		} else {
+			_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
+			if (_isDarkCc) {
+				_townSprites[2].draw(0, _vm->getRandomNumber(11) == 1 ? 9 : 10,
+					Common::Point(34, 33));
+			}
+		}
+	} else if (!_isDarkCc || _LocationActionId != TRAINING) {
+		if (!_townSprites[_drawFrameIndex / 8].empty())
+			_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
+	}
+
+	switch (_LocationActionId) {
+	case BANK:
+		if (sound.isPlaying() || (_isDarkCc && _animFrame)) {
+			if (_isDarkCc) {
+				if (sound.isPlaying() || _animFrame == 1) {
+					_townSprites[4].draw(0, _vm->getRandomNumber(13, 18),
+						Common::Point(8, 30));
+				} else if (_animFrame > 1) {
+					_townSprites[4].draw(0, 13 - _animFrame++,
+						Common::Point(8, 30));
+					if (_animFrame > 14)
+						_animFrame = 0;
+				}
+			} else {
+				_townSprites[2].draw(0, _vm->getRandomNumber(7, 11), Common::Point(8, 8));
+			}
+		}
+		break;
+
+	case GUILD:
+		if (sound.isPlaying()) {
+			if (_isDarkCc) {
+				if (_animFrame) {
+					_animFrame ^= 1;
+					_townSprites[6].draw(0, _animFrame, Common::Point(8, 106));
+				} else {
+					_townSprites[6].draw(0, _vm->getRandomNumber(3), Common::Point(16, 48));
+				}
+			}
+		}
+		break;
+
+	case TAVERN:
+		if (sound.isPlaying() && _isDarkCc) {
+			_townSprites[4].draw(0, _vm->getRandomNumber(7), Common::Point(153, 49));
+		}
+		break;
+
+	case TEMPLE:
+		if (sound.isPlaying()) {
+			_townSprites[3].draw(0, _vm->getRandomNumber(2, 4), Common::Point(8, 8));
+
+		}
+		break;
+
+	case TRAINING:
+		if (sound.isPlaying()) {
+			if (_isDarkCc) {
+				_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
+			}
+		} else {
+			if (_isDarkCc) {
+				_townSprites[0].draw(0, ++_animFrame % 8, Common::Point(8, 8));
+				_townSprites[5].draw(0, _vm->getRandomNumber(5), Common::Point(61, 74));
+			} else {
+				_townSprites[1].draw(0, _vm->getRandomNumber(8, 12), Common::Point(8, 8));
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	if (flag) {
+		intf._face1UIFrame = 0;
+		intf._face2UIFrame = 0;
+		intf._dangerSenseUIFrame = 0;
+		intf._spotDoorsUIFrame = 0;
+		intf._levitateUIFrame = 0;
+
+		intf.assembleBorder();
+	}
+
+	if (windows[11]._enabled) {
+		_drawCtr1 = (_drawCtr1 + 1) % 2;
+		if (!_drawCtr1 || !_drawCtr2) {
+			_drawFrameIndex = 0;
+			_drawCtr2 = 0;
+		} else {
+			_drawFrameIndex = _vm->getRandomNumber(3);
+		}
+	} else {
+		_drawFrameIndex = (_drawFrameIndex + 1) % _townMaxId;
+	}
+
+	if (_isDarkCc) {
+		if (_LocationActionId == BLACKSMITH && (_drawFrameIndex == 4 || _drawFrameIndex == 13))
+			sound.playFX(45);
+
+		if (_LocationActionId == TRAINING && _drawFrameIndex == 23) {
+			sound.playSound("spit1.voc");
+		}
+	} else {
+		if (_townMaxId == 32 && _drawFrameIndex == 0)
+			_drawFrameIndex = 17;
+		if (_townMaxId == 26 && _drawFrameIndex == 0)
+			_drawFrameIndex = 20;
+		if (_LocationActionId == BLACKSMITH && (_drawFrameIndex == 3 || _drawFrameIndex == 9))
+			sound.playFX(45);
+	}
+
+	windows[3].update();
+
+	if (_LocationActionId == BANK)
+		_animFrame = 2;
+}
+
+int BaseLocation::wait() {
+	EventsManager &events = *g_vm->_events;
+	Windows &windows = *g_vm->_windows;
+
+	_buttonValue = 0;
+	while (!_vm->shouldQuit() && !_buttonValue) {
+		events.updateGameCounter();
+		while (!_vm->shouldQuit() && !_buttonValue && events.timeElapsed() < 3) {
+			events.pollEventsAndWait();
+			checkEvents(_vm);
+		}
+		if (!_buttonValue)
+			drawAnim(!windows[11]._enabled);
+	}
+
+	return _buttonValue;
+}
+
+/*------------------------------------------------------------------------*/
+
+BankLocation::BankLocation() : BaseLocation(BANK) {
+	_icons1.load("bank.icn");
+	_icons2.load("bank2.icn");
+	addButton(Common::Rect(234, 108, 259, 128), Common::KEYCODE_d, &_icons1);
+	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_w, &_icons1);
+	addButton(Common::Rect(288, 108, 312, 128), Common::KEYCODE_ESCAPE, &_icons1);
+	_animFrame = 1;
+
+	_vocName = _isDarkCc ? "bank1.voc" : "banker.voc";
+}
+
+Common::String BankLocation::createLocationText(Character &ch) {
+	Party &party = *g_vm->_party;
+	return Common::String::format(Res.BANK_TEXT,
+		XeenEngine::printMil(party._bankGold).c_str(),
+		XeenEngine::printMil(party._bankGems).c_str(),
+		XeenEngine::printMil(party._gold).c_str(),
+		XeenEngine::printMil(party._gems).c_str());
+}
+
+void BankLocation::drawBackground() {
+	if (_isDarkCc) {
+		_townSprites[4].draw(0, _vm->getRandomNumber(13, 18),
+			Common::Point(8, 30));
+	}
+}
+
+Character *BankLocation::doOptions(Character *c) {
+	if (_buttonValue == Common::KEYCODE_d)
+		_buttonValue = (int)WHERE_PARTY;
+	else if (_buttonValue == Common::KEYCODE_w)
+		_buttonValue = (int)WHERE_BANK;
+	else
+		return c;
+
+	depositWithdrawl((PartyBank)_buttonValue);
+	return c;
+}
+
+void BankLocation::depositWithdrawl(PartyBank whereId) {
+	Party &party = *g_vm->_party;
+	Sound &sound = *g_vm->_sound;
+	Windows &windows = *g_vm->_windows;
+	int gold, gems;
+
+	if (whereId == WHERE_BANK) {
+		gold = party._bankGold;
+		gems = party._bankGems;
+	} else {
+		gold = party._gold;
+		gems = party._gems;
+	}
+
+	for (uint idx = 0; idx < _buttons.size(); ++idx)
+		_buttons[idx]._sprites = &_icons2;
+	_buttons[0]._value = Common::KEYCODE_o;
+	_buttons[1]._value = Common::KEYCODE_e;
+	_buttons[2]._value = Common::KEYCODE_ESCAPE;
+
+	Common::String msg = Common::String::format(Res.GOLD_GEMS,
+		Res.DEPOSIT_WITHDRAWL[whereId],
+		XeenEngine::printMil(gold).c_str(),
+		XeenEngine::printMil(gems).c_str());
+
+	windows[35].open();
+	windows[35].writeString(msg);
+	drawButtons(&windows[35]);
+	windows[35].update();
+
+	sound.stopSound();
+	File voc("coina.voc");
+	ConsumableType consType = CONS_GOLD;
+
+	do {
+		switch (wait()) {
+		case Common::KEYCODE_o:
+			consType = CONS_GOLD;
+			break;
+		case Common::KEYCODE_e:
+			consType = CONS_GEMS;
+			break;
+		case Common::KEYCODE_ESCAPE:
+			break;
+		default:
+			continue;
+		}
+
+		if ((whereId == WHERE_BANK && !party._bankGems && consType == CONS_GEMS) ||
+			(whereId == WHERE_BANK && !party._bankGold && consType == CONS_GOLD) ||
+			(whereId == WHERE_PARTY && !party._gems && consType == CONS_GEMS) ||
+			(whereId == WHERE_PARTY && !party._gold && consType == CONS_GOLD)) {
+			party.notEnough(consType, whereId, WHERE_BANK, WT_2);
+		} else {
+			windows[35].writeString(Res.AMOUNT);
+			int amount = NumericInput::show(_vm, 35, 10, 77);
+
+			if (amount) {
+				if (consType == CONS_GEMS) {
+					if (party.subtract(CONS_GEMS, amount, whereId, WT_2)) {
+						if (whereId == WHERE_BANK) {
+							party._gems += amount;
+						} else {
+							party._bankGems += amount;
+						}
+					}
+				} else {
+					if (party.subtract(CONS_GOLD, amount, whereId, WT_2)) {
+						if (whereId == WHERE_BANK) {
+							party._gold += amount;
+						} else {
+							party._bankGold += amount;
+						}
+					}
+				}
+			}
+
+			if (whereId == WHERE_BANK) {
+				gold = party._bankGold;
+				gems = party._bankGems;
+			}
+			else {
+				gold = party._gold;
+				gems = party._gems;
+			}
+
+			sound.playSound(voc);
+			msg = Common::String::format(Res.GOLD_GEMS_2, Res.DEPOSIT_WITHDRAWL[whereId],
+				XeenEngine::printMil(gold).c_str(), XeenEngine::printMil(gems).c_str());
+			windows[35].writeString(msg);
+			windows[35].update();
+		}
+		// TODO
+	} while (!g_vm->shouldQuit() && _buttonValue != Common::KEYCODE_ESCAPE);
+
+	for (uint idx = 0; idx < _buttons.size(); ++idx)
+		_buttons[idx]._sprites = &_icons1;
+	_buttons[0]._value = Common::KEYCODE_d;
+	_buttons[1]._value = Common::KEYCODE_w;
+	_buttons[2]._value = Common::KEYCODE_ESCAPE;
+}
+
+/*------------------------------------------------------------------------*/
+
+BlacksmithLocation::BlacksmithLocation() : BaseLocation(BLACKSMITH) {
+	_icons1.load("esc.icn");
+	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_ESCAPE, &_icons1);
+	addButton(Common::Rect(234, 54, 308, 62), 0);
+	addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_b);
+	addButton(Common::Rect(234, 74, 308, 82), 0);
+	addButton(Common::Rect(234, 84, 308, 92), 0);
+
+	_vocName = _isDarkCc ? "see2.voc" : "whaddayo.voc";
+}
+
+Common::String BlacksmithLocation::createLocationText(Character &ch) {
+	Party &party = *g_vm->_party;
+	return Common::String::format(Res.BLACKSMITH_TEXT,
+		ch._name.c_str(), XeenEngine::printMil(party._gold).c_str());
+}
+
+Character *BlacksmithLocation::doOptions(Character *c) {
+	Interface &intf = *g_vm->_interface;
+	Party &party = *g_vm->_party;
+
+	if (_buttonValue >= Common::KEYCODE_F1 && _buttonValue <= Common::KEYCODE_F6) {
+		// Switch character
+		_buttonValue -= Common::KEYCODE_F1;
+		if (_buttonValue < (int)party._activeParty.size()) {
+			c = &party._activeParty[_buttonValue];
+			intf.highlightChar(_buttonValue);
+		}
+	} else if (_buttonValue == Common::KEYCODE_b) {
+		c = ItemsDialog::show(_vm, c, ITEMMODE_BLACKSMITH);
+		_buttonValue = 0;
+	}
+
+	return c;
+}
+
+void BlacksmithLocation::farewell() {
+	Sound &sound = *g_vm->_sound;
+
+	if (_isDarkCc) {
+		sound.stopSound();
+		sound.playSound("come1.voc", 1);
+	}
+}
+
+/*------------------------------------------------------------------------*/
+
+GuildLocation::GuildLocation() : BaseLocation(GUILD) {
+	loadStrings("spldesc.bin");
+	_icons1.load("esc.icn");
+	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_ESCAPE, &_icons1);
+	addButton(Common::Rect(234, 54, 308, 62), 0);
+	addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_b);
+	addButton(Common::Rect(234, 74, 308, 82), Common::KEYCODE_s);
+	addButton(Common::Rect(234, 84, 308, 92), 0);
+	g_vm->_mode = MODE_17;
+
+	_vocName = _isDarkCc ? "parrot1.voc" : "guild10.voc";
+}
+
+Common::String GuildLocation::createLocationText(Character &ch) {
+	return !ch.guildMember() ? Res.GUILD_NOT_MEMBER_TEXT :
+		Common::String::format(Res.GUILD_TEXT, ch._name.c_str());
+}
+
+Character *GuildLocation::doOptions(Character *c) {
+	Interface &intf = *g_vm->_interface;
+	Party &party = *g_vm->_party;
+	Sound &sound = *g_vm->_sound;
+
+	if (_buttonValue >= Common::KEYCODE_F1 && _buttonValue <= Common::KEYCODE_F6) {
+		// Switch character
+		_buttonValue -= Common::KEYCODE_F1;
+		if (_buttonValue < (int)party._activeParty.size()) {
+			c = &party._activeParty[_buttonValue];
+			intf.highlightChar(_buttonValue);
+
+			if (!c->guildMember()) {
+				sound.stopSound();
+				_animFrame = 5;
+				sound.playSound(_isDarkCc ? "skull1.voc" : "guild11.voc", 1);
+			}
+		}
+	} else if (_buttonValue == Common::KEYCODE_s) {
+		if (c->guildMember())
+			c = SpellsDialog::show(_vm, nullptr, c, 0x80);
+		_buttonValue = 0;
+	} else if (_buttonValue == Common::KEYCODE_c) {
+		if (!c->noActions()) {
+			if (c->guildMember())
+				c = SpellsDialog::show(_vm, nullptr, c, 0);
+			_buttonValue = 0;
+		}
+	}
+
+	return c;
+}
+
+/*------------------------------------------------------------------------*/
+
+TavernLocation::TavernLocation() : BaseLocation(TAVERN) {
+	_v21 = 0;
+	_v22 = 0;
+	_v23 = 0;
+	_v24 = 0;
+
+	loadStrings("tavern.bin");
+	_icons1.load("tavern.icn");
+	addButton(Common::Rect(281, 108, 305, 128), Common::KEYCODE_ESCAPE, &_icons1);
+	addButton(Common::Rect(242, 108, 266, 128), Common::KEYCODE_s, &_icons1);
+	addButton(Common::Rect(234, 54, 308, 62), Common::KEYCODE_d);
+	addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_f);
+	addButton(Common::Rect(234, 74, 308, 82), Common::KEYCODE_t);
+	addButton(Common::Rect(234, 84, 308, 92), Common::KEYCODE_r);
+	g_vm->_mode = MODE_17;
+
+	_vocName = _isDarkCc ? "hello1.voc" : "hello.voc";
+}
+
+Common::String TavernLocation::createLocationText(Character &ch) {
+	Party &party = *g_vm->_party;
+	return Common::String::format(Res.TAVERN_TEXT, ch._name.c_str(),
+		Res.FOOD_AND_DRINK, XeenEngine::printMil(party._gold).c_str());
+}
+
+Character *TavernLocation::doOptions(Character *c) {
+	Interface &intf = *g_vm->_interface;
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+	Sound &sound = *g_vm->_sound;
+	Windows &windows = *g_vm->_windows;
+	int idx = 0;
+
+	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:
+		// Switch character
+		_buttonValue -= Common::KEYCODE_F1;
+		if (_buttonValue < (int)party._activeParty.size()) {
+			c = &party._activeParty[_buttonValue];
+			intf.highlightChar(_buttonValue);
+			_v21 = 0;
+		}
+		break;
+
+	case Common::KEYCODE_d:
+		// Drink
+		if (!c->noActions()) {
+			if (party.subtract(CONS_GOLD, 1, WHERE_PARTY, WT_2)) {
+				sound.stopSound();
+				sound.playSound("gulp.voc");
+				_v21 = 1;
+
+				windows[10].writeString(Common::String::format(Res.TAVERN_TEXT,
+					c->_name.c_str(), Res.GOOD_STUFF,
+					XeenEngine::printMil(party._gold).c_str()));
+				drawButtons(&windows[0]);
+				windows[10].update();
+
+				if (_vm->getRandomNumber(100) < 26) {
+					++c->_conditions[DRUNK];
+					intf.drawParty(true);
+					sound.playFX(28);
+				}
+
+				wait();
+			}
+		}
+		break;
+
+	case Common::KEYCODE_f: {
+		// Food
+		if (party._mazeId == (_isDarkCc ? 29 : 28)) {
+			_v22 = party._activeParty.size() * 15;
+			_v23 = 10;
+			idx = 0;
+		} else if (_isDarkCc && party._mazeId == 31) {
+			_v22 = party._activeParty.size() * 60;
+			_v23 = 100;
+			idx = 1;
+		} else if (!_isDarkCc && party._mazeId == 30) {
+			_v22 = party._activeParty.size() * 50;
+			_v23 = 50;
+			idx = 1;
+		} else if (_isDarkCc) {
+			_v22 = party._activeParty.size() * 120;
+			_v23 = 250;
+			idx = 2;
+		} else if (party._mazeId == 49) {
+			_v22 = party._activeParty.size() * 120;
+			_v23 = 100;
+			idx = 2;
+		} else {
+			_v22 = party._activeParty.size() * 15;
+			_v23 = 10;
+			idx = 0;
+		}
+
+		Common::String msg = _textStrings[(_isDarkCc ? 60 : 75) + idx];
+		windows[10].close();
+		windows[12].open();
+		windows[12].writeString(msg);
+		windows[12].update();
+
+		if (YesNo::show(_vm, false, true)) {
+			if (party._food >= _v22) {
+				ErrorScroll::show(_vm, Res.FOOD_PACKS_FULL, WT_2);
+			} else if (party.subtract(CONS_GOLD, _v23, WHERE_PARTY, WT_2)) {
+				party._food = _v22;
+				sound.stopSound();
+				sound.playSound(_isDarkCc ? "thanks2.voc" : "thankyou.voc", 1);
+			}
+		}
+
+		windows[12].close();
+		windows[10].open();
+		_buttonValue = 0;
+		break;
+	}
+
+	case Common::KEYCODE_r: {
+		// Rumors
+		if (party._mazeId == (_isDarkCc ? 29 : 28)) {
+			idx = 0;
+		} else if (party._mazeId == (_isDarkCc ? 31 : 30)) {
+			idx = 10;
+		} else if (_isDarkCc || party._mazeId == 49) {
+			idx = 20;
+		}
+
+		Common::String msg = Common::String::format("\x03""c\x0B""012%s",
+			_textStrings[(party._day % 10) + idx].c_str());
+		Window &w = windows[12];
+		w.open();
+		w.writeString(msg);
+		w.update();
+
+		wait();
+		w.close();
+		break;
+	}
+
+	case Common::KEYCODE_s: {
+		// Sign In
+		idx = _isDarkCc ? (party._mazeId - 29) >> 1 : party._mazeId - 28;
+		assert(idx >= 0);
+		party._mazePosition.x = Res.TAVERN_EXIT_LIST[_isDarkCc ? 1 : 0][_LocationActionId][idx][0];
+		party._mazePosition.y = Res.TAVERN_EXIT_LIST[_isDarkCc ? 1 : 0][_LocationActionId][idx][1];
+
+		if (!_isDarkCc || party._mazeId == 29)
+			party._mazeDirection = DIR_WEST;
+		else if (party._mazeId == 31)
+			party._mazeDirection = DIR_EAST;
+		else
+			party._mazeDirection = DIR_SOUTH;
+
+		party._priorMazeId = party._mazeId;
+		for (idx = 0; idx < (int)party._activeParty.size(); ++idx) {
+			party._activeParty[idx]._savedMazeId = party._mazeId;
+			party._activeParty[idx]._xeenSide = map._loadDarkSide;
+		}
+
+		party.addTime(1440);
+		party._mazeId = 0;
+		_vm->_quitMode = 2;
+		break;
+	}
+
+	case Common::KEYCODE_t:
+		if (!c->noActions()) {
+			if (!_v21) {
+				windows[10].writeString(Common::String::format(Res.TAVERN_TEXT,
+					c->_name.c_str(), Res.HAVE_A_DRINK,
+					XeenEngine::printMil(party._gold).c_str()));
+				drawButtons(&windows[0]);
+				windows[10].update();
+				wait();
+			} else {
+				_v21 = 0;
+				if (c->_conditions[DRUNK]) {
+					windows[10].writeString(Common::String::format(Res.TAVERN_TEXT,
+						c->_name.c_str(), Res.YOURE_DRUNK,
+						XeenEngine::printMil(party._gold).c_str()));
+					drawButtons(&windows[0]);
+					windows[10].update();
+					wait();
+				} else if (party.subtract(CONS_GOLD, 1, WHERE_PARTY, WT_2)) {
+					sound.stopSound();
+					sound.playSound(_isDarkCc ? "thanks2.voc" : "thankyou.voc", 1);
+
+					if (party._mazeId == (_isDarkCc ? 29 : 28)) {
+						_v24 = 30;
+					} else if (_isDarkCc && party._mazeId == 31) {
+						_v24 = 40;
+					} else if (!_isDarkCc && party._mazeId == 45) {
+						_v24 = 45;
+					} else if (!_isDarkCc && party._mazeId == 49) {
+						_v24 = 60;
+					} else if (_isDarkCc) {
+						_v24 = 50;
+					}
+
+					Common::String msg = _textStrings[map.mazeData()._tavernTips + _v24];
+					map.mazeData()._tavernTips = (map.mazeData()._tavernTips + 1) /
+						(_isDarkCc ? 10 : 15);
+
+					Window &w = windows[12];
+					w.open();
+					w.writeString(Common::String::format("\x03""c\x0B""012%s", msg.c_str()));
+					w.update();
+					wait();
+					w.close();
+				}
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return c;
+}
+
+void TavernLocation::farewell() {
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+	Sound &sound = *g_vm->_sound;
+
+	sound.stopSound();
+	sound.playSound(_isDarkCc ? "gdluck1.voc" : "goodbye.voc", 1);
+
+	map.mazeData()._mazeNumber = party._mazeId;
+}
+
+/*------------------------------------------------------------------------*/
+
+TempleLocation::TempleLocation() : BaseLocation(TEMPLE) {
+	_currentCharLevel = 0;
+	_donation = 0;
+	_healCost = 0;
+	_uncurseCost = 0;
+	_dayOfWeek = 0;
+	_v10 = _v11 = 0;
+	_v12 = _v13 = 0;
+	_v14 = 0;
+	_flag1 = false;
+	_v5 = _v6 = 0;
+
+	_icons1.load("esc.icn");
+	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_ESCAPE, &_icons1);
+	addButton(Common::Rect(234, 54, 308, 62), Common::KEYCODE_h);
+	addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_d);
+	addButton(Common::Rect(234, 74, 308, 82), Common::KEYCODE_u);
+	addButton(Common::Rect(234, 84, 308, 92), 0);
+
+	_vocName = _isDarkCc ? "help2.voc" : "maywe2.voc";
+}
+
+Common::String TempleLocation::createLocationText(Character &ch) {
+	Party &party = *g_vm->_party;
+
+	if (party._mazeId == (_isDarkCc ? 29 : 28)) {
+		_v10 = _v11 = _v12 = _v13 = 0;
+		_v14 = 10;
+	} else if (party._mazeId == (_isDarkCc ? 31 : 30)) {
+		_v13 = 10;
+		_v12 = 50;
+		_v11 = 500;
+		_v10 = 100;
+		_v14 = 25;
+	} else if (party._mazeId == (_isDarkCc ? 37 : 73)) {
+		_v13 = 20;
+		_v12 = 100;
+		_v11 = 1000;
+		_v10 = 200;
+		_v14 = 50;
+	} else if (_isDarkCc || party._mazeId == 49) {
+		_v13 = 100;
+		_v12 = 500;
+		_v11 = 5000;
+		_v10 = 300;
+		_v14 = 100;
+	}
+
+	_currentCharLevel = ch.getCurrentLevel();
+	if (ch._currentHp < ch.getMaxHP()) {
+		_healCost = _currentCharLevel * 10 + _v13;
+	}
+
+	for (int attrib = HEART_BROKEN; attrib <= UNCONSCIOUS; ++attrib) {
+		if (ch._conditions[attrib])
+			_healCost += _currentCharLevel * 10;
+	}
+
+	_v6 = 0;
+	if (ch._conditions[DEAD]) {
+		_v6 += (_currentCharLevel * 100) + (ch._conditions[DEAD] * 50) + _v12;
+	}
+	if (ch._conditions[STONED]) {
+		_v6 += (_currentCharLevel * 100) + (ch._conditions[STONED] * 50) + _v12;
+	}
+	if (ch._conditions[ERADICATED]) {
+		_v5 = (_currentCharLevel * 1000) + (ch._conditions[ERADICATED] * 500) + _v11;
+	}
+
+	for (int idx = 0; idx < 9; ++idx) {
+		_uncurseCost |= ch._weapons[idx]._bonusFlags & 0x40;
+		_uncurseCost |= ch._armor[idx]._bonusFlags & 0x40;
+		_uncurseCost |= ch._accessories[idx]._bonusFlags & 0x40;
+		_uncurseCost |= ch._misc[idx]._bonusFlags & 0x40;
+	}
+
+	if (_uncurseCost || ch._conditions[CURSED])
+		_v5 = (_currentCharLevel * 20) + _v10;
+
+	_donation = _flag1 ? 0 : _v14;
+	_healCost += _v6 + _v5;
+
+	return Common::String::format(Res.TEMPLE_TEXT, ch._name.c_str(),
+		_healCost, _donation, XeenEngine::printK(_uncurseCost).c_str(),
+		XeenEngine::printMil(party._gold).c_str());
+}
+
+Character *TempleLocation::doOptions(Character *c) {
+	Interface &intf = *g_vm->_interface;
+	Party &party = *g_vm->_party;
+	Sound &sound = *g_vm->_sound;
+
+	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:
+		// Switch character
+		_buttonValue -= Common::KEYCODE_F1;
+		if (_buttonValue < (int)party._activeParty.size()) {
+			c = &party._activeParty[_buttonValue];
+			intf.highlightChar(_buttonValue);
+			_dayOfWeek = 0;
+		}
+		break;
+
+	case Common::KEYCODE_d:
+		if (_donation && party.subtract(CONS_GOLD, _donation, WHERE_PARTY, WT_2)) {
+			sound.stopSound();
+			sound.playSound("coina.voc", 1);
+			_dayOfWeek = (_dayOfWeek + 1) / 10;
+
+			if (_dayOfWeek == (party._day / 10)) {
+				party._clairvoyanceActive = true;
+				party._lightCount = 1;
+
+				int amt = _dayOfWeek ? _dayOfWeek : 10;
+				party._heroism = amt;
+				party._holyBonus = amt;
+				party._powerShield = amt;
+				party._blessed = amt;
+
+				intf.drawParty(true);
+				sound.stopSound();
+				sound.playSound("ahh.voc");
+				_flag1 = true;
+				_donation = 0;
+			}
+		}
+		break;
+
+	case Common::KEYCODE_h:
+		if (_healCost && party.subtract(CONS_GOLD, _healCost, WHERE_PARTY, WT_2)) {
+			c->_magicResistence._temporary = 0;
+			c->_energyResistence._temporary = 0;
+			c->_poisonResistence._temporary = 0;
+			c->_electricityResistence._temporary = 0;
+			c->_coldResistence._temporary = 0;
+			c->_fireResistence._temporary = 0;
+			c->_ACTemp = 0;
+			c->_level._temporary = 0;
+			c->_luck._temporary = 0;
+			c->_accuracy._temporary = 0;
+			c->_speed._temporary = 0;
+			c->_endurance._temporary = 0;
+			c->_personality._temporary = 0;
+			c->_intellect._temporary = 0;
+			c->_might._temporary = 0;
+			c->_currentHp = c->getMaxHP();
+			Common::fill(&c->_conditions[HEART_BROKEN], &c->_conditions[NO_CONDITION], 0);
+
+			_farewellTime = 1440;
+			intf.drawParty(true);
+			sound.stopSound();
+			sound.playSound("ahh.voc", 1);
+		}
+		break;
+
+	case Common::KEYCODE_u:
+		if (_uncurseCost && party.subtract(CONS_GOLD, _uncurseCost, WHERE_PARTY, WT_2)) {
+			for (int idx = 0; idx < 9; ++idx) {
+				c->_weapons[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
+				c->_armor[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
+				c->_accessories[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
+				c->_misc[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
+			}
+
+			_farewellTime = 1440;
+			intf.drawParty(true);
+			sound.stopSound();
+			sound.playSound("ahh.voc", 1);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return c;
+}
+
+/*------------------------------------------------------------------------*/
+
+TrainingLocation::TrainingLocation() : BaseLocation(TRAINING) {
+	Common::fill(&_charsTrained[0], &_charsTrained[6], 0);
+	_maxLevel = 0;
+	_experienceToNextLevel = 0;
+	_charIndex = 0;
+
+	_icons1.load("train.icn");
+	addButton(Common::Rect(281, 108, 305, 128), Common::KEYCODE_ESCAPE, &_icons1);
+	addButton(Common::Rect(242, 108, 266, 128), Common::KEYCODE_t, &_icons1);
+
+	_vocName = _isDarkCc ? "training.voc" : "youtrn1.voc";
+}
+
+Common::String TrainingLocation::createLocationText(Character &ch) {
+	Party &party = *g_vm->_party;
+	if (_isDarkCc) {
+		switch (party._mazeId) {
+		case 29:
+			// Castleview
+			_maxLevel = 30;
+			break;
+		case 31:
+			// Sandcaster
+			_maxLevel = 50;
+			break;
+		case 37:
+			// Olympus
+			_maxLevel = 200;
+			break;
+		default:
+			// Kalindra's Castle
+			_maxLevel = 100;
+			break;
+		}
+	} else {
+		switch (party._mazeId) {
+		case 28:
+			// Vertigo
+			_maxLevel = 10;
+			break;
+		case 30:
+			// Rivercity
+			_maxLevel = 15;
+			break;
+		default:
+			// Newcastle
+			_maxLevel = 20;
+			break;
+		}
+	}
+
+	_experienceToNextLevel = ch.experienceToNextLevel();
+
+	Common::String msg;
+	if (_experienceToNextLevel && ch._level._permanent < _maxLevel) {
+		// Need more experience
+		int nextLevel = ch._level._permanent + 1;
+		msg = Common::String::format(Res.EXPERIENCE_FOR_LEVEL,
+			ch._name.c_str(), _experienceToNextLevel, nextLevel);
+	} else if (ch._level._permanent >= _maxLevel) {
+		// At maximum level
+		_experienceToNextLevel = 1;
+		msg = Common::String::format(Res.LEARNED_ALL, ch._name.c_str());
+	} else {
+		// Eligble for level increase
+		msg = Common::String::format(Res.ELIGIBLE_FOR_LEVEL,
+			ch._name.c_str(), ch._level._permanent + 1);
+	}
+
+	return Common::String::format(Res.TRAINING_TEXT, msg.c_str(),
+		XeenEngine::printMil(party._gold).c_str());
+}
+
+Character *TrainingLocation::doOptions(Character *c) {
+	Interface &intf = *g_vm->_interface;
+	Party &party = *g_vm->_party;
+	Sound &sound = *g_vm->_sound;
+
+	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:
+		// Switch character
+		_buttonValue -= Common::KEYCODE_F1;
+		if (_buttonValue < (int)party._activeParty.size()) {
+			_charIndex = _buttonValue;
+			c = &party._activeParty[_buttonValue];
+			intf.highlightChar(_buttonValue);
+		}
+		break;
+
+	case Common::KEYCODE_t:
+		if (_experienceToNextLevel) {
+			sound.stopSound();
+			_drawFrameIndex = 0;
+
+			Common::String name;
+			if (c->_level._permanent >= _maxLevel) {
+				name = _isDarkCc ? "gtlost.voc" : "trainin1.voc";
+			} else {
+				name = _isDarkCc ? "gtlost.voc" : "trainin0.voc";
+			}
+
+			sound.playSound(name);
+
+		} else if (!c->noActions()) {
+			if (party.subtract(CONS_GOLD, (c->_level._permanent * c->_level._permanent) * 10, WHERE_PARTY, WT_2)) {
+				_drawFrameIndex = 0;
+				sound.stopSound();
+				sound.playSound(_isDarkCc ? "prtygd.voc" : "trainin2.voc", 1);
+
+				c->_experience -=  c->nextExperienceLevel() -
+					(c->getCurrentExperience() - c->_experience);
+				c->_level._permanent++;
+
+				if (!_charsTrained[_charIndex]) {
+					party.addTime(1440);
+					_charsTrained[_charIndex] = true;
+				}
+
+				party.resetTemps();
+				c->_currentHp = c->getMaxHP();
+				c->_currentSp = c->getMaxSP();
+				intf.drawParty(true);
+			}
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return c;
+}
+
+/*------------------------------------------------------------------------*/
+
+ArenaLocation::ArenaLocation() : BaseLocation(ARENA) {
+	// TODO
+}
+
+/*------------------------------------------------------------------------*/
+
+CutsceneLocation::CutsceneLocation(LocationAction action) : BaseLocation(action),
+		_animCtr(0), _mazeFlag(false) {
+	Party &party = *g_vm->_party;
+	_mazeId = party._mazeId;
+	_mazePos = party._mazePosition;
+	_mazeDir = party._mazeDirection;
+}
+
+void CutsceneLocation::cutsceneAnimUpdate() {
+	// TODO
+}
+
+void CutsceneLocation::setNewLocation() {
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+	map.load(_mazeId);
+	party._mazePosition = _mazePos;
+	party._mazeDirection = _mazeDir;
+}
+
+/*------------------------------------------------------------------------*/
+
+ReaperCutscene::ReaperCutscene() : CutsceneLocation(REAPER) {
+	// TODO
+}
+
+/*------------------------------------------------------------------------*/
+
+GolemCutscene::GolemCutscene() : CutsceneLocation(GOLEM) {
+	// TODO
+}
+
+/*------------------------------------------------------------------------*/
+
+const int16 DWARF_X0[2][13] = {
+	{  0, -5, -7, -8, -11, -9, -3, 1, 6, 10, 15, 18, 23 },
+	{ 0, 4, 6, 8, 11, 12, 15, 17, 19, 22, 25, 0, 0 }
+};
+const int DWARF_X1[2][13] = {
+	{ 160, 145, 133, 122, 109, 101, 97, 91, 86, 80, 75, 68, 63 },
+	{ 160, 154, 146, 138, 131, 122, 115, 107, 99, 92, 85, 0, 0 }
+};
+const int DWARF_X2[13] = {
+	0, -1, -4, -7, -9, -13, -15, -18, -21, -23, -25, 0, 0
+};
+const int16 DWARF_Y[2][13] = {
+	{ 0, 0, 4, 9, 13, 15, 20, 24, 30, 37, 45, 51, 58 },
+	{ 0, 12, 25, 36, 38, 40, 41, 42, 44, 45, 50, 0, 0 }
+};
+const int16 DWARF2_X[2][16] = {
+	{ 0, -2, -4, -6, -8, -10, -12, -14, -16, -18, -20, -20, -20, -20, -20, -20 },
+	{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150 }
+};
+const int16 DWARF2_Y[2][16] = {
+	{ 0, 12, 25, 37, 50, 62, 75, 87, 100, 112, 125, 137, 150, 162, 175, 187 },
+	{ 0, 12, 25, 37, 50, 62, 75, 87, 100, 112, 125, 137, 150, 162, 175, 186 }
+};
+
+DwarfCutscene::DwarfCutscene(bool isDwarf) : CutsceneLocation(NO_ACTION) {
+	_townMaxId = Res.TOWN_MAXES[_isDarkCc][isDwarf ? DWARF1 : DWARF2];
+}
+
+int DwarfCutscene::show() {
+	EventsManager &events = *g_vm->_events;
+	Interface &intf = *g_vm->_interface;
+	Screen &screen = *g_vm->_screen;
+	Sound &sound = *g_vm->_sound;
+	Windows &windows = *g_vm->_windows;
+
+	SpriteResource sprites1(_isDarkCc ? "town1.zom" : "dwarf1.vga");
+	SpriteResource sprites2(_isDarkCc ? "town2.zom" : "dwarf2.vga");
+	SpriteResource sprites3(_isDarkCc ? "town3.zom" : "dwarf3.vga");
+	SpriteResource boxSprites("box.vga");
+	getNewLocation();
+
+	// Save the screen contents
+	Graphics::ManagedSurface savedBg;
+	savedBg.copyFrom(screen);
+
+	for (int idx = 0; idx < (_isDarkCc ? 10 : 12); ++idx) {
+		screen.copyFrom(savedBg);
+		sprites1.draw(0, 0,
+			Common::Point(DWARF_X0[_isDarkCc][idx], DWARF_Y[_isDarkCc][idx]));
+		sprites1.draw(0, 1,
+			Common::Point(DWARF_X1[_isDarkCc][idx], DWARF_Y[_isDarkCc][idx]));
+		if (_isDarkCc)
+			sprites1.draw(0, 2,
+				Common::Point(DWARF_X2[idx], DWARF_Y[_isDarkCc][idx]));
+
+		windows[0].update();
+		events.wait(1);
+	}
+
+	savedBg.copyFrom(screen);
+	for (int idx = 15; idx >= 0; --idx) {
+		screen.copyFrom(savedBg);
+		sprites2.draw(0, 0, Common::Point(DWARF2_X[_isDarkCc][idx], DWARF2_Y[_isDarkCc][idx]));
+		windows[0].update();
+		events.wait(1);
+	}
+
+	sound.setMusicVolume(48);
+	screen.copyFrom(savedBg);
+	sprites2.draw(0, 0);
+	windows[0].update();
+
+	for (int idx = 0; idx < (_isDarkCc ? 2 : 3); ++idx) {
+		switch (idx) {
+		case 0:
+			sound.playSound(_isDarkCc ? "pass2.voc" : "dwarf10.voc");
+			break;
+
+		case 1:
+			if (_isDarkCc) {
+				sprites2.draw(0, 0);
+				sprites3.draw(0, 0);
+				cutsceneAnimUpdate();
+
+				events.timeMark5();
+				while (!g_vm->shouldQuit() && events.timeElapsed5() < 7)
+					events.pollEventsAndWait();
+
+				sound.playSound(_mazeFlag ? "ok2.voc" : "back2.voc");
+			} else {
+				sound.playSound("dwarf11.voc");
+			}
+			break;
+
+		case 2:
+			sound.playSound("dwarf12.voc");
+			break;
+		}
+
+		events.updateGameCounter();
+		do {
+			sprites2.draw(0, 0);
+			sprites3.draw(0, g_vm->getRandomNumber(_isDarkCc ? 8 : 9));
+			cutsceneAnimUpdate();
+
+			events.timeMark5();
+			while (!g_vm->shouldQuit() && events.timeElapsed5() < 2)
+				events.pollEventsAndWait();
+		} while (!g_vm->shouldQuit() && (sound.isPlaying() || _animCtr));
+
+		while (!g_vm->shouldQuit() && events.timeElapsed() < 3)
+			events.pollEventsAndWait();
+	}
+
+	sprites2.draw(0, 0);
+	if (!_isDarkCc)
+		sprites3.draw(0, 1);
+	windows[0].update();
+
+	setNewLocation();
+
+	// Restore game screen
+	sound.setMusicVolume(95);
+	screen.loadBackground("back.raw");
+	intf.drawParty(false);
+	intf.draw3d(false, false);
+
+	events.clearEvents();
+	return 0;
+}
+
+void DwarfCutscene::getNewLocation() {
+	Party &party = *g_vm->_party;
+
+	if (_isDarkCc) {
+		switch (party._mazeId) {
+		case 4:
+			if (party._questItems[35]) {
+				_mazeId = 29;
+				_mazePos = Common::Point(15, 31);
+				_mazeDir = DIR_SOUTH;
+			}
+			break;
+
+		case 6:
+			if (party._questItems[38]) {
+				_mazeId = 35;
+				_mazePos = Common::Point(15, 8);
+				_mazeDir = DIR_WEST;
+			}
+			break;
+
+		case 19:
+			if (party._questItems[36]) {
+				_mazeId = 31;
+				_mazePos = Common::Point(31, 16);
+				_mazeDir = DIR_WEST;
+			}
+			break;
+
+		case 22:
+			if (party._questItems[37]) {
+				_mazeId = 33;
+				_mazePos = Common::Point(0, 3);
+				_mazeDir = DIR_EAST;
+			}
+			break;
+
+		case 98:
+			if (party._questItems[39]) {
+				_mazeId = 37;
+				_mazePos = Common::Point(7, 0);
+				_mazeDir = DIR_NORTH;
+			}
+			break;
+
+		default:
+			break;
+		}
+
+		_mazeFlag = _mazeId != 0;
+	} else {
+		switch (party._mazeId) {
+		case 14:
+			_mazeId = 37;
+			_mazePos = Common::Point(1, 4);
+			_mazeDir = DIR_EAST;
+			break;
+
+		case 18:
+			if (party._mazePosition.x == 9) {
+				_mazeId = 35;
+				_mazePos = Common::Point(1, 12);
+				_mazeDir = DIR_EAST;
+			} else {
+				_mazeId = 36;
+				_mazePos = Common::Point(7, 1);
+				_mazeDir = DIR_NORTH;
+			}
+			break;
+
+		case 23:
+			if (party._mazePosition.x == 5) {
+				_mazeId = 33;
+				_mazePos = Common::Point(7, 1);
+				_mazeDir = DIR_NORTH;
+			} else {
+				_mazeId = 34;
+				_mazePos = Common::Point(7, 30);
+				_mazeDir = DIR_SOUTH;
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+/*------------------------------------------------------------------------*/
+
+SphinxCutscene::SphinxCutscene() : CutsceneLocation(SPHINX) {
+	SpriteResource sprites1("sphinx.vga");
+	_boxSprites.load("box.vga");
+
+
+	// TODO
+}
+
+void SphinxCutscene::getNewLocation() {
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+
+	switch (party._mazeId) {
+	case 2:
+		if (party._questItems[51]) {
+			map._loadDarkSide = true;
+			_mazeId = 125;
+			_mazePos = Common::Point(7, 6);
+			_mazeDir = DIR_NORTH;
+			_mazeFlag = true;
+		}
+		break;
+
+	case 5:
+		if (party._questItems[4]) {
+			_mazeId = 82;
+			_mazePos = Common::Point(7, 5);
+			_mazeDir = DIR_NORTH;
+			_mazeFlag = true;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	if (!_mazeFlag) {
+		_mazeId = party._mazeId;
+		_mazePos = party._mazePosition;
+		_mazeDir = party._mazeDirection;
+	}
+}
+
+
+/*------------------------------------------------------------------------*/
+
+PyramidLocation::PyramidLocation() : BaseLocation(PYRAMID) {
+}
+
+int PyramidLocation::show() {
+	EventsManager &events = *g_vm->_events;
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+	Windows &windows = *g_vm->_windows;
+	int mapId;
+	Direction dir = DIR_NORTH;
+	Common::Point pt;
+
+	if (g_vm->getGameID() == GType_WorldOfXeen) {
+		if (_isDarkCc) {
+			if (party._mazeId == 52) {
+				mapId = 49;
+				pt = Common::Point(7, 14);
+				dir = DIR_SOUTH;
+			} else {
+				mapId = 23;
+				pt = Common::Point(8, 10);
+			}
+		} else {
+			if (party._mazeId == 49) {
+				mapId = 52;
+				pt = Common::Point(2, 2);
+			} else {
+				mapId = 29;
+				pt = Common::Point(25, 21);
+			}
+		}
+
+		// Load the destination map and set position and direction
+		map._loadDarkSide = !_isDarkCc;
+		map.load(mapId);
+		party._mazePosition = pt;
+		party._mazeDirection = dir;
+	} else {
+		// Playing Clouds or Dark Side on it's own, so can't switch sides
+		Window &win = windows[12];
+		Common::String msg = Common::String::format(Res.MOONS_NOT_ALIGNED,
+			_isDarkCc ? "Clouds" : "Darkside");
+		win.open();
+		win.writeString(msg);
+		win.update();
+
+		events.waitForPressAnimated();
+		win.close();
+	}
+
+	return 0;
+}
+
+} // End of namespace Locations
+
+/*------------------------------------------------------------------------*/
+
+LocationManager::LocationManager() : _location(nullptr) {
+}
+
+int LocationManager::doAction(LocationAction actionId) {
+	// Create the desired location
+	switch (actionId) {
+	case BANK:
+		_location = new Locations::BankLocation();
+		break;
+	case BLACKSMITH:
+		_location = new Locations::BlacksmithLocation();
+		break;
+	case GUILD:
+		_location = new Locations::GuildLocation();
+		break;
+	case TAVERN:
+		_location = new Locations::TavernLocation();
+		break;
+	case TEMPLE:
+		_location = new Locations::TempleLocation();
+		break;
+	case TRAINING:
+		_location = new Locations::TrainingLocation();
+		break;
+	case ARENA:
+		_location = new Locations::ArenaLocation();
+		break;
+	case REAPER:
+		_location = new Locations::ReaperCutscene();
+		break;
+	case GOLEM:
+		_location = new Locations::GolemCutscene();
+		break;
+	case DWARF1:
+		_location = new Locations::DwarfCutscene(true);
+		break;
+	case DWARF2:
+		_location = new Locations::DwarfCutscene(false);
+		break;
+	case SPHINX:
+		_location = new Locations::SphinxCutscene();
+		break;
+	case PYRAMID:
+		_location = new Locations::PyramidLocation();
+		break;
+	default:
+		return 0;
+	}
+
+	// Show the location
+	int result = _location->show();
+	delete _location;
+	_location = nullptr;
+
+	return result;
+}
+
+bool LocationManager::isActive() const {
+	return _location != nullptr;
+}
+
+void LocationManager::drawAnim(bool flag) {
+	if (_location)
+		_location->drawAnim(flag);
+}
+
+/*------------------------------------------------------------------------*/
+
+bool LocationMessage::show(int portrait, const Common::String &name,
+		const Common::String &text, int confirm) {
+	LocationMessage *dlg = new LocationMessage();
+	bool result = dlg->execute(portrait, name, text, confirm);
+	delete dlg;
+
+	return result;
+}
+
+bool LocationMessage::execute(int portrait, const Common::String &name, const Common::String &text,
+		int confirm) {
+	EventsManager &events = *g_vm->_events;
+	Interface &intf = *g_vm->_interface;
+	Map &map = *g_vm->_map;
+	Party &party = *g_vm->_party;
+	Resources &res = *g_vm->_resources;
+	Windows &windows = *g_vm->_windows;
+	Window &w = windows[11];
+
+	_townMaxId = 4;
+	_drawFrameIndex = 0;
+	_townPos = Common::Point(23, 22);
+
+	if (!confirm)
+		loadButtons();
+
+	_townSprites.resize(2);
+	_townSprites[0].load(Common::String::format("face%02d.fac", portrait));
+	_townSprites[1].load("frame.fac");
+
+	if (!w._enabled)
+		w.open();
+
+	int result = -1;
+	Common::String msgText = text;
+	do {
+		Common::String msg = Common::String::format("\r\v014\x03""c\t125%s\t000\v054%s",
+			name.c_str(), msgText.c_str());
+
+		// Count the number of words
+		const char *msgEnd = w.writeString(msg);
+		int wordCount = 0;
+
+		for (const char *msgP = msg.c_str(); msgP != msgEnd && *msgP; ++msgP) {
+			if (*msgP == ' ')
+				++wordCount;
+		}
+
+		_drawCtr2 = wordCount * 2;	// Set timeout
+		_townSprites[1].draw(0, 0, Common::Point(16, 16));
+		_townSprites[0].draw(0, _drawFrameIndex, Common::Point(23, 22));
+		w.update();
+
+		if (!msgEnd && !confirm) {
+			res._globalSprites.draw(0, 7, Common::Point(232, 74));
+			res._globalSprites.draw(0, 0, Common::Point(235, 75));
+			res._globalSprites.draw(0, 2, Common::Point(260, 75));
+			windows[34].update();
+
+			intf._face1State = map._headData[party._mazePosition.y][party._mazePosition.x]._left;
+			intf._face2State = map._headData[party._mazePosition.y][party._mazePosition.x]._right;
+		}
+
+		if (confirm == 2) {
+			intf._face1State = intf._face2State = 2;
+			return false;
+		}
+
+		do {
+			events.clearEvents();
+			events.updateGameCounter();
+			if (msgEnd)
+				clearButtons();
+
+			do {
+				events.pollEventsAndWait();
+				checkEvents(_vm);
+
+				if (_vm->shouldQuit())
+					return false;
+
+				while (events.timeElapsed() >= 3) {
+					drawAnim(false);
+					events.updateGameCounter();
+				}
+			} while (!_buttonValue);
+
+			if (msgEnd)
+				// Another screen of text remaining
+				break;
+
+			if (confirm || _buttonValue == Common::KEYCODE_ESCAPE ||
+					_buttonValue == Common::KEYCODE_n)
+				result = 0;
+			else if (_buttonValue == Common::KEYCODE_y)
+				result = 1;
+		} while (result == -1);
+
+		if (msgEnd) {
+			// Text remaining, so cut off already displayed page's
+			msgText = Common::String(msgEnd);
+			_drawCtr2 = wordCount;
+			continue;
+		}
+	} while (result == -1);
+
+	intf._face1State = intf._face2State = 2;
+	if (!confirm)
+		intf.mainIconsPrint();
+
+	_townSprites[0].clear();
+	_townSprites[1].clear();
+	events.clearEvents();
+	return result == 1;
+}
+
+void LocationMessage::loadButtons() {
+	_iconSprites.load("confirm.icn");
+
+	addButton(Common::Rect(235, 75, 259, 95), Common::KEYCODE_y, &_iconSprites);
+	addButton(Common::Rect(260, 75, 284, 95), Common::KEYCODE_n, &_iconSprites);
+	addButton(Common::Rect(), Common::KEYCODE_ESCAPE);
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/locations.h b/engines/xeen/locations.h
new file mode 100644
index 0000000..e0f4838
--- /dev/null
+++ b/engines/xeen/locations.h
@@ -0,0 +1,371 @@
+/* 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_LOCATIONS_H
+#define XEEN_LOCATIONS_H
+
+#include "common/scummsys.h"
+#include "common/str-array.h"
+#include "xeen/dialogs.h"
+#include "xeen/dialogs_error.h"
+#include "xeen/party.h"
+
+namespace Xeen {
+
+enum LocationAction {
+	BANK = 0, BLACKSMITH = 1, GUILD = 2, TAVERN = 3, TEMPLE = 4,
+	TRAINING = 5, ARENA = 6, NO_ACTION = 7, REAPER = 8, GOLEM = 9,
+	DWARF1 = 10, SPHINX = 11, PYRAMID = 12, DWARF2 = 13
+};
+
+class XeenEngine;
+
+namespace Locations {
+
+class BaseLocation : public ButtonContainer {
+protected:
+	LocationAction _LocationActionId;
+	Common::Array<SpriteResource> _townSprites;
+	SpriteResource _icons1, _icons2;
+	int _townMaxId;
+	const bool &_isDarkCc;
+	int _animFrame;
+	Common::String _vocName, _songName;
+	Common::Point _townPos;
+	int _drawFrameIndex;
+	uint _farewellTime;
+	int _drawCtr1, _drawCtr2;
+protected:
+	/**
+	 * Draw the window
+	 */
+	void drawWindow();
+
+	/**
+	 * Waits for a brief pause, checking for any key or mouse events
+	 */
+	int wait();
+
+	/**
+	 * Generates the display text for the location, for a given character
+	 */
+	virtual Common::String createLocationText(Character &ch) { return ""; }
+
+	/**
+	 * Draw the visual background
+	 */
+	virtual void drawBackground();
+
+	/**
+	 * Handles options for the particular location
+	 */
+	virtual Character *doOptions(Character *c) { return c; }
+
+	/**
+	 * Handle any farewell
+	 */
+	virtual void farewell() {}
+public:
+	BaseLocation(LocationAction action);
+	virtual ~BaseLocation();
+
+	/**
+	 * Show the town location
+	 */
+	virtual int show();
+
+	/**
+	 * Draws the animated parts
+	 */
+	void drawAnim(bool flag);
+};
+
+class BankLocation : public BaseLocation {
+private:
+	/**
+	 * Handles deposits or withdrawls fro the bank
+	 */
+	void depositWithdrawl(PartyBank whereId);
+protected:
+	/**
+	 * Generates the display text for the location, for a given character
+	 */
+	virtual Common::String createLocationText(Character &ch);
+
+	/**
+	 * Draw the visual background
+	 */
+	virtual void drawBackground();
+
+	/**
+	 * Handles options for the particular location
+	 */
+	virtual Character *doOptions(Character *c);
+public:
+	BankLocation();
+	virtual ~BankLocation() {}
+};
+
+class BlacksmithLocation : public BaseLocation {
+protected:
+	/**
+	* Generates the display text for the location, for a given character
+	*/
+	virtual Common::String createLocationText(Character &ch);
+
+	/**
+	 * Handle any farewell
+	 */
+	virtual void farewell();
+
+	/**
+	 * Handles options for the particular location
+	 */
+	virtual Character *doOptions(Character *c);
+public:
+	BlacksmithLocation();
+	virtual ~BlacksmithLocation() {}
+};
+
+class GuildLocation : public BaseLocation {
+protected:
+	/**
+	 * Generates the display text for the location, for a given character
+	 */
+	virtual Common::String createLocationText(Character &ch);
+
+	/**
+	 * Handles options for the particular location
+	 */
+	virtual Character *doOptions(Character *c);
+public:
+	GuildLocation();
+	virtual ~GuildLocation() {}
+};
+
+class TavernLocation : public BaseLocation {
+private:
+	int _v21;
+	uint _v22;
+	int _v23;
+	int _v24;
+protected:
+	/**
+	* Generates the display text for the location, for a given character
+	*/
+	virtual Common::String createLocationText(Character &ch);
+
+	/**
+	 * Handle any farewell
+	 */
+	virtual void farewell();
+
+	/**
+	 * Handles options for the particular location
+	 */
+	virtual Character *doOptions(Character *c);
+public:
+	TavernLocation();
+	virtual ~TavernLocation() {}
+};
+
+class TempleLocation : public BaseLocation {
+private:
+	int _currentCharLevel;
+	int _donation;
+	int _healCost;
+	int _uncurseCost;
+	int _dayOfWeek;
+	int _v10, _v11, _v12;
+	int _v13, _v14;
+	bool _flag1;
+	int _v5, _v6;
+protected:
+	/**
+	* Generates the display text for the location, for a given character
+	*/
+	virtual Common::String createLocationText(Character &ch);
+
+	/**
+	 * Handles options for the particular location
+	 */
+	virtual Character *doOptions(Character *c);
+public:
+	TempleLocation();
+	virtual ~TempleLocation() {}
+};
+
+class TrainingLocation : public BaseLocation {
+private:
+	int _charIndex;
+	bool _charsTrained[MAX_ACTIVE_PARTY];
+	uint _experienceToNextLevel;
+	uint _maxLevel;
+protected:
+	/**
+	 * Generates the display text for the location, for a given character
+	 */
+	virtual Common::String createLocationText(Character &ch);
+
+	/**
+	 * Handles options for the particular location
+	 */
+	virtual Character *doOptions(Character *c);
+public:
+	TrainingLocation();
+	virtual ~TrainingLocation() {}
+};
+
+class ArenaLocation : public BaseLocation {
+public:
+	ArenaLocation();
+	virtual ~ArenaLocation() {}
+};
+
+class CutsceneLocation : public BaseLocation {
+protected:
+	int _animCtr;
+	SpriteResource _boxSprites;
+	int _mazeId;
+	Direction _mazeDir;
+	Common::Point _mazePos;
+	bool _mazeFlag;
+protected:
+	/**
+	* Handles cutscene animation update
+	*/
+	void cutsceneAnimUpdate();
+
+	/**
+	 * Sets the new location
+	 */
+	void setNewLocation();
+public:
+	CutsceneLocation(LocationAction action);
+};
+
+class ReaperCutscene : public CutsceneLocation {
+public:
+	ReaperCutscene();
+	virtual ~ReaperCutscene() {}
+};
+
+class GolemCutscene : public CutsceneLocation {
+public:
+	GolemCutscene();
+	virtual ~GolemCutscene() {}
+};
+
+class DwarfCutscene : public CutsceneLocation {
+private:
+	/**
+	 * Get the new location
+	 */
+	void getNewLocation();
+public:
+	DwarfCutscene(bool isDwarf1);
+	virtual ~DwarfCutscene() {}
+
+	/**
+	 * Show the town location
+	 */
+	virtual int show();
+};
+
+class SphinxCutscene : public CutsceneLocation {
+private:
+	/**
+	 * Get the new location
+	 */
+	void getNewLocation();
+public:
+	SphinxCutscene();
+	virtual ~SphinxCutscene() {}
+};
+
+class PyramidLocation : public BaseLocation {
+public:
+	PyramidLocation();
+	virtual ~PyramidLocation() {}
+
+	/**
+	 * Show the town location
+	 */
+	virtual int show();
+};
+
+} // End of namespace Locations
+
+class LocationMessage : public Locations::BaseLocation {
+private:
+	SpriteResource _iconSprites;
+
+	LocationMessage() : Locations::BaseLocation(NO_ACTION) {}
+
+	bool execute(int portrait, const Common::String &name,
+		const Common::String &text, int confirm);
+
+	void loadButtons();
+public:
+	static bool show(int portrait, const Common::String &name,
+		const Common::String &text, int confirm);
+};
+
+class LocationManager {
+private:
+	Locations::BaseLocation *_location;
+private:
+	int townWait();
+
+	Character *doBankOptions(Character *c);
+
+	Character *doBlacksmithOptions(Character *c);
+
+	Character *doGuildOptions(Character *c);
+
+	Character *doTavernOptions(Character *c);
+
+	Character *doTempleOptions(Character *c);
+
+	Character *doTrainingOptions(Character *c);
+public:
+	LocationManager();
+
+	/**
+	* Show a given location, and return any result
+	*/
+	int doAction(LocationAction actionId);
+
+	/**
+	* Returns true if a town location (bank, blacksmith, etc.) is currently active
+	*/
+	bool isActive() const;
+
+	/**
+	* Draws a currently active town location's animation
+	*/
+	void drawAnim(bool flag);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_LOCATIONS_H */
diff --git a/engines/xeen/module.mk b/engines/xeen/module.mk
index 7656f4c..2e11e19 100644
--- a/engines/xeen/module.mk
+++ b/engines/xeen/module.mk
@@ -35,6 +35,7 @@ MODULE_OBJS := \
 	interface.o \
 	interface_minimap.o \
 	interface_scene.o \
+	locations.o \
 	map.o \
 	music.o \
 	party.o \
@@ -45,7 +46,6 @@ MODULE_OBJS := \
 	sound.o \
 	spells.o \
 	sprites.o \
-	town.o \
 	window.o \
 	xeen.o \
 	xsurface.o
diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp
index e630893..cfdd9b7 100644
--- a/engines/xeen/scripts.cpp
+++ b/engines/xeen/scripts.cpp
@@ -442,7 +442,7 @@ bool Scripts::cmdNPC(ParamsIterator &params) {
 	int confirm = params.readByte();
 	int lineNum = params.readByte();
 
-	if (TownMessage::show(portrait, _message, map._events._text[textNum],
+	if (LocationMessage::show(portrait, _message, map._events._text[textNum],
 			confirm)) {
 		_lineNum = lineNum;
 		return false;
@@ -839,7 +839,7 @@ bool Scripts::cmdSpawn(ParamsIterator &params) {
 }
 
 bool Scripts::cmdDoTownEvent(ParamsIterator &params) {
-	_scriptResult = _vm->_town->townAction((TownAction)params.readByte());
+	_scriptResult = _vm->_locations->doAction((LocationAction)params.readByte());
 	_vm->_party->_stepped = true;
 	_refreshIcons = true;
 
diff --git a/engines/xeen/town.cpp b/engines/xeen/town.cpp
deleted file mode 100644
index 4a635c7..0000000
--- a/engines/xeen/town.cpp
+++ /dev/null
@@ -1,1658 +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/town.h"
-#include "xeen/dialogs_input.h"
-#include "xeen/dialogs_items.h"
-#include "xeen/dialogs_query.h"
-#include "xeen/dialogs_spells.h"
-#include "xeen/resources.h"
-#include "xeen/xeen.h"
-
-namespace Xeen {
-
-BaseLocation::BaseLocation(TownAction action) : ButtonContainer(g_vm),
-		_townActionId(action), _isDarkCc(g_vm->_files->_isDarkCc),
-		_vocName("hello1.voc") {
-	_townMaxId = (action >= SPHINX) ? 0 : Res.TOWN_MAXES[_isDarkCc][action];
-	if (action < NO_ACTION) {
-		_songName = Res.TOWN_ACTION_MUSIC[_isDarkCc][action];
-		_townSprites.resize(Res.TOWN_ACTION_FILES[_isDarkCc][action]);
-	}
-
-	_animFrame = 0;
-	_drawFrameIndex = 0;
-	_farewellTime = 0;
-	_drawCtr1 = _drawCtr2 = 0;
-	_townPos = Common::Point(8, 8);
-}
-
-BaseLocation::~BaseLocation() {
-	Interface &intf = *g_vm->_interface;
-
-	for (uint idx = 0; idx < _townSprites.size(); ++idx)
-		_townSprites[idx].clear();
-	intf.mainIconsPrint();
-}
-
-int BaseLocation::show() {
-	Map &map = *g_vm->_map;
-	Party &party = *g_vm->_party;
-	Sound &sound = *g_vm->_sound;
-	Windows &windows = *g_vm->_windows;
-
-	// Play the appropriate music
-	sound.stopSound();
-	sound.playSong(_songName, 223);
-
-	// Load the needed sprite sets for the location
-	for (uint idx = 0; idx < _townSprites.size(); ++idx) {
-		Common::String shapesName = Common::String::format("%s%d.twn",
-			Res.TOWN_ACTION_SHAPES[_townActionId], idx + 1);
-		_townSprites[idx].load(shapesName);
-	}
-
-	Character *charP = &party._activeParty[0];
-
-	// Draw the background and the text window
-	drawBackground();
-	drawWindow();
-	drawAnim(true);
-
-	// Play the welcome speech
-	sound.playSound(_vocName, 1);
-
-	do {
-		wait();
-		charP = doOptions(charP);
-		if (_vm->shouldQuit())
-			return 0;
-
-		Common::String msg = createLocationText(*charP);
-		windows[10].writeString(msg);
-		drawButtons(&windows[0]);
-	} while (_buttonValue != Common::KEYCODE_ESCAPE);
-
-	// Handle any farewell message
-	farewell();
-
-	int result;
-	if (party._mazeId != 0) {
-		map.load(party._mazeId);
-		_farewellTime += 1440;
-		party.addTime(_farewellTime);
-		result = 0;
-	} else {
-		_vm->_saves->saveChars();
-		result = 2;
-	}
-
-	return result;
-}
-
-void BaseLocation::drawBackground() {
-	Interface &intf = *g_vm->_interface;
-
-	intf._face1UIFrame = intf._face2UIFrame = 0;
-	intf._dangerSenseUIFrame = 0;
-	intf._spotDoorsUIFrame = 0;
-	intf._levitateUIFrame = 0;
-	_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
-}
-
-void BaseLocation::drawWindow() {
-	Interface &intf = *g_vm->_interface;
-	Party &party = *g_vm->_party;
-	Windows &windows = *g_vm->_windows;
-
-	Character *charP = &party._activeParty[0];
-	Common::String title = createLocationText(*charP);
-
-	// Open up the window and write the string
-	intf.assembleBorder();
-	windows[10].open();
-	windows[10].writeString(title);
-	drawButtons(&windows[0]);
-
-	windows[0].update();
-	intf.highlightChar(0);
-}
-
-void BaseLocation::drawAnim(bool flag) {
-	Interface &intf = *g_vm->_interface;
-	Sound &sound = *g_vm->_sound;
-	Windows &windows = *g_vm->_windows;
-
-	// TODO: Figure out a clean way to split method into individual location classes
-	if (_townActionId == BLACKSMITH) {
-		if (sound.isPlaying()) {
-			if (_isDarkCc) {
-				_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
-				_townSprites[2].draw(0, _vm->getRandomNumber(11) == 1 ? 9 : 10,
-					Common::Point(34, 33));
-				_townSprites[2].draw(0, _vm->getRandomNumber(5) + 3,
-					Common::Point(34, 54));
-			}
-		} else {
-			_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
-			if (_isDarkCc) {
-				_townSprites[2].draw(0, _vm->getRandomNumber(11) == 1 ? 9 : 10,
-					Common::Point(34, 33));
-			}
-		}
-	} else if (!_isDarkCc || _townActionId != TRAINING) {
-		if (!_townSprites[_drawFrameIndex / 8].empty())
-			_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
-	}
-
-	switch (_townActionId) {
-	case BANK:
-		if (sound.isPlaying() || (_isDarkCc && _animFrame)) {
-			if (_isDarkCc) {
-				if (sound.isPlaying() || _animFrame == 1) {
-					_townSprites[4].draw(0, _vm->getRandomNumber(13, 18),
-						Common::Point(8, 30));
-				} else if (_animFrame > 1) {
-					_townSprites[4].draw(0, 13 - _animFrame++,
-						Common::Point(8, 30));
-					if (_animFrame > 14)
-						_animFrame = 0;
-				}
-			} else {
-				_townSprites[2].draw(0, _vm->getRandomNumber(7, 11), Common::Point(8, 8));
-			}
-		}
-		break;
-
-	case GUILD:
-		if (sound.isPlaying()) {
-			if (_isDarkCc) {
-				if (_animFrame) {
-					_animFrame ^= 1;
-					_townSprites[6].draw(0, _animFrame, Common::Point(8, 106));
-				} else {
-					_townSprites[6].draw(0, _vm->getRandomNumber(3), Common::Point(16, 48));
-				}
-			}
-		}
-		break;
-
-	case TAVERN:
-		if (sound.isPlaying() && _isDarkCc) {
-			_townSprites[4].draw(0, _vm->getRandomNumber(7), Common::Point(153, 49));
-		}
-		break;
-
-	case TEMPLE:
-		if (sound.isPlaying()) {
-			_townSprites[3].draw(0, _vm->getRandomNumber(2, 4), Common::Point(8, 8));
-
-		}
-		break;
-
-	case TRAINING:
-		if (sound.isPlaying()) {
-			if (_isDarkCc) {
-				_townSprites[_drawFrameIndex / 8].draw(0, _drawFrameIndex % 8, _townPos);
-			}
-		} else {
-			if (_isDarkCc) {
-				_townSprites[0].draw(0, ++_animFrame % 8, Common::Point(8, 8));
-				_townSprites[5].draw(0, _vm->getRandomNumber(5), Common::Point(61, 74));
-			} else {
-				_townSprites[1].draw(0, _vm->getRandomNumber(8, 12), Common::Point(8, 8));
-			}
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	if (flag) {
-		intf._face1UIFrame = 0;
-		intf._face2UIFrame = 0;
-		intf._dangerSenseUIFrame = 0;
-		intf._spotDoorsUIFrame = 0;
-		intf._levitateUIFrame = 0;
-
-		intf.assembleBorder();
-	}
-
-	if (windows[11]._enabled) {
-		_drawCtr1 = (_drawCtr1 + 1) % 2;
-		if (!_drawCtr1 || !_drawCtr2) {
-			_drawFrameIndex = 0;
-			_drawCtr2 = 0;
-		} else {
-			_drawFrameIndex = _vm->getRandomNumber(3);
-		}
-	} else {
-		_drawFrameIndex = (_drawFrameIndex + 1) % _townMaxId;
-	}
-
-	if (_isDarkCc) {
-		if (_townActionId == BLACKSMITH && (_drawFrameIndex == 4 || _drawFrameIndex == 13))
-			sound.playFX(45);
-
-		if (_townActionId == TRAINING && _drawFrameIndex == 23) {
-			sound.playSound("spit1.voc");
-		}
-	} else {
-		if (_townMaxId == 32 && _drawFrameIndex == 0)
-			_drawFrameIndex = 17;
-		if (_townMaxId == 26 && _drawFrameIndex == 0)
-			_drawFrameIndex = 20;
-		if (_townActionId == BLACKSMITH && (_drawFrameIndex == 3 || _drawFrameIndex == 9))
-			sound.playFX(45);
-	}
-
-	windows[3].update();
-
-	if (_townActionId == BANK)
-		_animFrame = 2;
-}
-
-int BaseLocation::wait() {
-	EventsManager &events = *g_vm->_events;
-	Windows &windows = *g_vm->_windows;
-
-	_buttonValue = 0;
-	while (!_vm->shouldQuit() && !_buttonValue) {
-		events.updateGameCounter();
-		while (!_vm->shouldQuit() && !_buttonValue && events.timeElapsed() < 3) {
-			events.pollEventsAndWait();
-			checkEvents(_vm);
-		}
-		if (!_buttonValue)
-			drawAnim(!windows[11]._enabled);
-	}
-
-	return _buttonValue;
-}
-
-/*------------------------------------------------------------------------*/
-
-BankLocation::BankLocation() : BaseLocation(BANK) {
-	_icons1.load("bank.icn");
-	_icons2.load("bank2.icn");
-	addButton(Common::Rect(234, 108, 259, 128), Common::KEYCODE_d, &_icons1);
-	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_w, &_icons1);
-	addButton(Common::Rect(288, 108, 312, 128), Common::KEYCODE_ESCAPE, &_icons1);
-	_animFrame = 1;
-
-	_vocName = _isDarkCc ? "bank1.voc" : "banker.voc";
-}
-
-Common::String BankLocation::createLocationText(Character &ch) {
-	Party &party = *g_vm->_party;
-	return Common::String::format(Res.BANK_TEXT,
-		XeenEngine::printMil(party._bankGold).c_str(),
-		XeenEngine::printMil(party._bankGems).c_str(),
-		XeenEngine::printMil(party._gold).c_str(),
-		XeenEngine::printMil(party._gems).c_str());
-}
-
-void BankLocation::drawBackground() {
-	if (_isDarkCc) {
-		_townSprites[4].draw(0, _vm->getRandomNumber(13, 18),
-			Common::Point(8, 30));
-	}
-}
-
-Character *BankLocation::doOptions(Character *c) {
-	if (_buttonValue == Common::KEYCODE_d)
-		_buttonValue = (int)WHERE_PARTY;
-	else if (_buttonValue == Common::KEYCODE_w)
-		_buttonValue = (int)WHERE_BANK;
-	else
-		return c;
-
-	depositWithdrawl((PartyBank)_buttonValue);
-	return c;
-}
-
-void BankLocation::depositWithdrawl(PartyBank whereId) {
-	Party &party = *g_vm->_party;
-	Sound &sound = *g_vm->_sound;
-	Windows &windows = *g_vm->_windows;
-	int gold, gems;
-
-	if (whereId == WHERE_BANK) {
-		gold = party._bankGold;
-		gems = party._bankGems;
-	} else {
-		gold = party._gold;
-		gems = party._gems;
-	}
-
-	for (uint idx = 0; idx < _buttons.size(); ++idx)
-		_buttons[idx]._sprites = &_icons2;
-	_buttons[0]._value = Common::KEYCODE_o;
-	_buttons[1]._value = Common::KEYCODE_e;
-	_buttons[2]._value = Common::KEYCODE_ESCAPE;
-
-	Common::String msg = Common::String::format(Res.GOLD_GEMS,
-		Res.DEPOSIT_WITHDRAWL[whereId],
-		XeenEngine::printMil(gold).c_str(),
-		XeenEngine::printMil(gems).c_str());
-
-	windows[35].open();
-	windows[35].writeString(msg);
-	drawButtons(&windows[35]);
-	windows[35].update();
-
-	sound.stopSound();
-	File voc("coina.voc");
-	ConsumableType consType = CONS_GOLD;
-
-	do {
-		switch (wait()) {
-		case Common::KEYCODE_o:
-			consType = CONS_GOLD;
-			break;
-		case Common::KEYCODE_e:
-			consType = CONS_GEMS;
-			break;
-		case Common::KEYCODE_ESCAPE:
-			break;
-		default:
-			continue;
-		}
-
-		if ((whereId == WHERE_BANK && !party._bankGems && consType == CONS_GEMS) ||
-			(whereId == WHERE_BANK && !party._bankGold && consType == CONS_GOLD) ||
-			(whereId == WHERE_PARTY && !party._gems && consType == CONS_GEMS) ||
-			(whereId == WHERE_PARTY && !party._gold && consType == CONS_GOLD)) {
-			party.notEnough(consType, whereId, WHERE_BANK, WT_2);
-		} else {
-			windows[35].writeString(Res.AMOUNT);
-			int amount = NumericInput::show(_vm, 35, 10, 77);
-
-			if (amount) {
-				if (consType == CONS_GEMS) {
-					if (party.subtract(CONS_GEMS, amount, whereId, WT_2)) {
-						if (whereId == WHERE_BANK) {
-							party._gems += amount;
-						} else {
-							party._bankGems += amount;
-						}
-					}
-				} else {
-					if (party.subtract(CONS_GOLD, amount, whereId, WT_2)) {
-						if (whereId == WHERE_BANK) {
-							party._gold += amount;
-						} else {
-							party._bankGold += amount;
-						}
-					}
-				}
-			}
-
-			if (whereId == WHERE_BANK) {
-				gold = party._bankGold;
-				gems = party._bankGems;
-			}
-			else {
-				gold = party._gold;
-				gems = party._gems;
-			}
-
-			sound.playSound(voc);
-			msg = Common::String::format(Res.GOLD_GEMS_2, Res.DEPOSIT_WITHDRAWL[whereId],
-				XeenEngine::printMil(gold).c_str(), XeenEngine::printMil(gems).c_str());
-			windows[35].writeString(msg);
-			windows[35].update();
-		}
-		// TODO
-	} while (!g_vm->shouldQuit() && _buttonValue != Common::KEYCODE_ESCAPE);
-
-	for (uint idx = 0; idx < _buttons.size(); ++idx)
-		_buttons[idx]._sprites = &_icons1;
-	_buttons[0]._value = Common::KEYCODE_d;
-	_buttons[1]._value = Common::KEYCODE_w;
-	_buttons[2]._value = Common::KEYCODE_ESCAPE;
-}
-
-/*------------------------------------------------------------------------*/
-
-BlacksmithLocation::BlacksmithLocation() : BaseLocation(BLACKSMITH) {
-	_icons1.load("esc.icn");
-	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_ESCAPE, &_icons1);
-	addButton(Common::Rect(234, 54, 308, 62), 0);
-	addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_b);
-	addButton(Common::Rect(234, 74, 308, 82), 0);
-	addButton(Common::Rect(234, 84, 308, 92), 0);
-
-	_vocName = _isDarkCc ? "see2.voc" : "whaddayo.voc";
-}
-
-Common::String BlacksmithLocation::createLocationText(Character &ch) {
-	Party &party = *g_vm->_party;
-	return Common::String::format(Res.BLACKSMITH_TEXT,
-		ch._name.c_str(), XeenEngine::printMil(party._gold).c_str());
-}
-
-Character *BlacksmithLocation::doOptions(Character *c) {
-	Interface &intf = *g_vm->_interface;
-	Party &party = *g_vm->_party;
-
-	if (_buttonValue >= Common::KEYCODE_F1 && _buttonValue <= Common::KEYCODE_F6) {
-		// Switch character
-		_buttonValue -= Common::KEYCODE_F1;
-		if (_buttonValue < (int)party._activeParty.size()) {
-			c = &party._activeParty[_buttonValue];
-			intf.highlightChar(_buttonValue);
-		}
-	} else if (_buttonValue == Common::KEYCODE_b) {
-		c = ItemsDialog::show(_vm, c, ITEMMODE_BLACKSMITH);
-		_buttonValue = 0;
-	}
-
-	return c;
-}
-
-void BlacksmithLocation::farewell() {
-	Sound &sound = *g_vm->_sound;
-
-	if (_isDarkCc) {
-		sound.stopSound();
-		sound.playSound("come1.voc", 1);
-	}
-}
-
-/*------------------------------------------------------------------------*/
-
-GuildLocation::GuildLocation() : BaseLocation(GUILD) {
-	loadStrings("spldesc.bin");
-	_icons1.load("esc.icn");
-	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_ESCAPE, &_icons1);
-	addButton(Common::Rect(234, 54, 308, 62), 0);
-	addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_b);
-	addButton(Common::Rect(234, 74, 308, 82), Common::KEYCODE_s);
-	addButton(Common::Rect(234, 84, 308, 92), 0);
-	g_vm->_mode = MODE_17;
-
-	_vocName = _isDarkCc ? "parrot1.voc" : "guild10.voc";
-}
-
-Common::String GuildLocation::createLocationText(Character &ch) {
-	return !ch.guildMember() ? Res.GUILD_NOT_MEMBER_TEXT :
-		Common::String::format(Res.GUILD_TEXT, ch._name.c_str());
-}
-
-Character *GuildLocation::doOptions(Character *c) {
-	Interface &intf = *g_vm->_interface;
-	Party &party = *g_vm->_party;
-	Sound &sound = *g_vm->_sound;
-
-	if (_buttonValue >= Common::KEYCODE_F1 && _buttonValue <= Common::KEYCODE_F6) {
-		// Switch character
-		_buttonValue -= Common::KEYCODE_F1;
-		if (_buttonValue < (int)party._activeParty.size()) {
-			c = &party._activeParty[_buttonValue];
-			intf.highlightChar(_buttonValue);
-
-			if (!c->guildMember()) {
-				sound.stopSound();
-				_animFrame = 5;
-				sound.playSound(_isDarkCc ? "skull1.voc" : "guild11.voc", 1);
-			}
-		}
-	} else if (_buttonValue == Common::KEYCODE_s) {
-		if (c->guildMember())
-			c = SpellsDialog::show(_vm, nullptr, c, 0x80);
-		_buttonValue = 0;
-	} else if (_buttonValue == Common::KEYCODE_c) {
-		if (!c->noActions()) {
-			if (c->guildMember())
-				c = SpellsDialog::show(_vm, nullptr, c, 0);
-			_buttonValue = 0;
-		}
-	}
-
-	return c;
-}
-
-/*------------------------------------------------------------------------*/
-
-TavernLocation::TavernLocation() : BaseLocation(TAVERN) {
-	_v21 = 0;
-	_v22 = 0;
-	_v23 = 0;
-	_v24 = 0;
-
-	loadStrings("tavern.bin");
-	_icons1.load("tavern.icn");
-	addButton(Common::Rect(281, 108, 305, 128), Common::KEYCODE_ESCAPE, &_icons1);
-	addButton(Common::Rect(242, 108, 266, 128), Common::KEYCODE_s, &_icons1);
-	addButton(Common::Rect(234, 54, 308, 62), Common::KEYCODE_d);
-	addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_f);
-	addButton(Common::Rect(234, 74, 308, 82), Common::KEYCODE_t);
-	addButton(Common::Rect(234, 84, 308, 92), Common::KEYCODE_r);
-	g_vm->_mode = MODE_17;
-
-	_vocName = _isDarkCc ? "hello1.voc" : "hello.voc";
-}
-
-Common::String TavernLocation::createLocationText(Character &ch) {
-	Party &party = *g_vm->_party;
-	return Common::String::format(Res.TAVERN_TEXT, ch._name.c_str(),
-		Res.FOOD_AND_DRINK, XeenEngine::printMil(party._gold).c_str());
-}
-
-Character *TavernLocation::doOptions(Character *c) {
-	Interface &intf = *g_vm->_interface;
-	Map &map = *g_vm->_map;
-	Party &party = *g_vm->_party;
-	Sound &sound = *g_vm->_sound;
-	Windows &windows = *g_vm->_windows;
-	int idx = 0;
-
-	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:
-		// Switch character
-		_buttonValue -= Common::KEYCODE_F1;
-		if (_buttonValue < (int)party._activeParty.size()) {
-			c = &party._activeParty[_buttonValue];
-			intf.highlightChar(_buttonValue);
-			_v21 = 0;
-		}
-		break;
-
-	case Common::KEYCODE_d:
-		// Drink
-		if (!c->noActions()) {
-			if (party.subtract(CONS_GOLD, 1, WHERE_PARTY, WT_2)) {
-				sound.stopSound();
-				sound.playSound("gulp.voc");
-				_v21 = 1;
-
-				windows[10].writeString(Common::String::format(Res.TAVERN_TEXT,
-					c->_name.c_str(), Res.GOOD_STUFF,
-					XeenEngine::printMil(party._gold).c_str()));
-				drawButtons(&windows[0]);
-				windows[10].update();
-
-				if (_vm->getRandomNumber(100) < 26) {
-					++c->_conditions[DRUNK];
-					intf.drawParty(true);
-					sound.playFX(28);
-				}
-
-				wait();
-			}
-		}
-		break;
-
-	case Common::KEYCODE_f: {
-		// Food
-		if (party._mazeId == (_isDarkCc ? 29 : 28)) {
-			_v22 = party._activeParty.size() * 15;
-			_v23 = 10;
-			idx = 0;
-		} else if (_isDarkCc && party._mazeId == 31) {
-			_v22 = party._activeParty.size() * 60;
-			_v23 = 100;
-			idx = 1;
-		} else if (!_isDarkCc && party._mazeId == 30) {
-			_v22 = party._activeParty.size() * 50;
-			_v23 = 50;
-			idx = 1;
-		} else if (_isDarkCc) {
-			_v22 = party._activeParty.size() * 120;
-			_v23 = 250;
-			idx = 2;
-		} else if (party._mazeId == 49) {
-			_v22 = party._activeParty.size() * 120;
-			_v23 = 100;
-			idx = 2;
-		} else {
-			_v22 = party._activeParty.size() * 15;
-			_v23 = 10;
-			idx = 0;
-		}
-
-		Common::String msg = _textStrings[(_isDarkCc ? 60 : 75) + idx];
-		windows[10].close();
-		windows[12].open();
-		windows[12].writeString(msg);
-		windows[12].update();
-
-		if (YesNo::show(_vm, false, true)) {
-			if (party._food >= _v22) {
-				ErrorScroll::show(_vm, Res.FOOD_PACKS_FULL, WT_2);
-			} else if (party.subtract(CONS_GOLD, _v23, WHERE_PARTY, WT_2)) {
-				party._food = _v22;
-				sound.stopSound();
-				sound.playSound(_isDarkCc ? "thanks2.voc" : "thankyou.voc", 1);
-			}
-		}
-
-		windows[12].close();
-		windows[10].open();
-		_buttonValue = 0;
-		break;
-	}
-
-	case Common::KEYCODE_r: {
-		// Rumors
-		if (party._mazeId == (_isDarkCc ? 29 : 28)) {
-			idx = 0;
-		} else if (party._mazeId == (_isDarkCc ? 31 : 30)) {
-			idx = 10;
-		} else if (_isDarkCc || party._mazeId == 49) {
-			idx = 20;
-		}
-
-		Common::String msg = Common::String::format("\x03""c\x0B""012%s",
-			_textStrings[(party._day % 10) + idx].c_str());
-		Window &w = windows[12];
-		w.open();
-		w.writeString(msg);
-		w.update();
-
-		wait();
-		w.close();
-		break;
-	}
-
-	case Common::KEYCODE_s: {
-		// Sign In
-		idx = _isDarkCc ? (party._mazeId - 29) >> 1 : party._mazeId - 28;
-		assert(idx >= 0);
-		party._mazePosition.x = Res.TAVERN_EXIT_LIST[_isDarkCc ? 1 : 0][_townActionId][idx][0];
-		party._mazePosition.y = Res.TAVERN_EXIT_LIST[_isDarkCc ? 1 : 0][_townActionId][idx][1];
-
-		if (!_isDarkCc || party._mazeId == 29)
-			party._mazeDirection = DIR_WEST;
-		else if (party._mazeId == 31)
-			party._mazeDirection = DIR_EAST;
-		else
-			party._mazeDirection = DIR_SOUTH;
-
-		party._priorMazeId = party._mazeId;
-		for (idx = 0; idx < (int)party._activeParty.size(); ++idx) {
-			party._activeParty[idx]._savedMazeId = party._mazeId;
-			party._activeParty[idx]._xeenSide = map._loadDarkSide;
-		}
-
-		party.addTime(1440);
-		party._mazeId = 0;
-		_vm->_quitMode = 2;
-		break;
-	}
-
-	case Common::KEYCODE_t:
-		if (!c->noActions()) {
-			if (!_v21) {
-				windows[10].writeString(Common::String::format(Res.TAVERN_TEXT,
-					c->_name.c_str(), Res.HAVE_A_DRINK,
-					XeenEngine::printMil(party._gold).c_str()));
-				drawButtons(&windows[0]);
-				windows[10].update();
-				wait();
-			} else {
-				_v21 = 0;
-				if (c->_conditions[DRUNK]) {
-					windows[10].writeString(Common::String::format(Res.TAVERN_TEXT,
-						c->_name.c_str(), Res.YOURE_DRUNK,
-						XeenEngine::printMil(party._gold).c_str()));
-					drawButtons(&windows[0]);
-					windows[10].update();
-					wait();
-				} else if (party.subtract(CONS_GOLD, 1, WHERE_PARTY, WT_2)) {
-					sound.stopSound();
-					sound.playSound(_isDarkCc ? "thanks2.voc" : "thankyou.voc", 1);
-
-					if (party._mazeId == (_isDarkCc ? 29 : 28)) {
-						_v24 = 30;
-					} else if (_isDarkCc && party._mazeId == 31) {
-						_v24 = 40;
-					} else if (!_isDarkCc && party._mazeId == 45) {
-						_v24 = 45;
-					} else if (!_isDarkCc && party._mazeId == 49) {
-						_v24 = 60;
-					} else if (_isDarkCc) {
-						_v24 = 50;
-					}
-
-					Common::String msg = _textStrings[map.mazeData()._tavernTips + _v24];
-					map.mazeData()._tavernTips = (map.mazeData()._tavernTips + 1) /
-						(_isDarkCc ? 10 : 15);
-
-					Window &w = windows[12];
-					w.open();
-					w.writeString(Common::String::format("\x03""c\x0B""012%s", msg.c_str()));
-					w.update();
-					wait();
-					w.close();
-				}
-			}
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	return c;
-}
-
-void TavernLocation::farewell() {
-	Map &map = *g_vm->_map;
-	Party &party = *g_vm->_party;
-	Sound &sound = *g_vm->_sound;
-
-	sound.stopSound();
-	sound.playSound(_isDarkCc ? "gdluck1.voc" : "goodbye.voc", 1);
-
-	map.mazeData()._mazeNumber = party._mazeId;
-}
-
-/*------------------------------------------------------------------------*/
-
-TempleLocation::TempleLocation() : BaseLocation(TEMPLE) {
-	_currentCharLevel = 0;
-	_donation = 0;
-	_healCost = 0;
-	_uncurseCost = 0;
-	_dayOfWeek = 0;
-	_v10 = _v11 = 0;
-	_v12 = _v13 = 0;
-	_v14 = 0;
-	_flag1 = false;
-	_v5 = _v6 = 0;
-
-	_icons1.load("esc.icn");
-	addButton(Common::Rect(261, 108, 285, 128), Common::KEYCODE_ESCAPE, &_icons1);
-	addButton(Common::Rect(234, 54, 308, 62), Common::KEYCODE_h);
-	addButton(Common::Rect(234, 64, 308, 72), Common::KEYCODE_d);
-	addButton(Common::Rect(234, 74, 308, 82), Common::KEYCODE_u);
-	addButton(Common::Rect(234, 84, 308, 92), 0);
-
-	_vocName = _isDarkCc ? "help2.voc" : "maywe2.voc";
-}
-
-Common::String TempleLocation::createLocationText(Character &ch) {
-	Party &party = *g_vm->_party;
-
-	if (party._mazeId == (_isDarkCc ? 29 : 28)) {
-		_v10 = _v11 = _v12 = _v13 = 0;
-		_v14 = 10;
-	} else if (party._mazeId == (_isDarkCc ? 31 : 30)) {
-		_v13 = 10;
-		_v12 = 50;
-		_v11 = 500;
-		_v10 = 100;
-		_v14 = 25;
-	} else if (party._mazeId == (_isDarkCc ? 37 : 73)) {
-		_v13 = 20;
-		_v12 = 100;
-		_v11 = 1000;
-		_v10 = 200;
-		_v14 = 50;
-	} else if (_isDarkCc || party._mazeId == 49) {
-		_v13 = 100;
-		_v12 = 500;
-		_v11 = 5000;
-		_v10 = 300;
-		_v14 = 100;
-	}
-
-	_currentCharLevel = ch.getCurrentLevel();
-	if (ch._currentHp < ch.getMaxHP()) {
-		_healCost = _currentCharLevel * 10 + _v13;
-	}
-
-	for (int attrib = HEART_BROKEN; attrib <= UNCONSCIOUS; ++attrib) {
-		if (ch._conditions[attrib])
-			_healCost += _currentCharLevel * 10;
-	}
-
-	_v6 = 0;
-	if (ch._conditions[DEAD]) {
-		_v6 += (_currentCharLevel * 100) + (ch._conditions[DEAD] * 50) + _v12;
-	}
-	if (ch._conditions[STONED]) {
-		_v6 += (_currentCharLevel * 100) + (ch._conditions[STONED] * 50) + _v12;
-	}
-	if (ch._conditions[ERADICATED]) {
-		_v5 = (_currentCharLevel * 1000) + (ch._conditions[ERADICATED] * 500) + _v11;
-	}
-
-	for (int idx = 0; idx < 9; ++idx) {
-		_uncurseCost |= ch._weapons[idx]._bonusFlags & 0x40;
-		_uncurseCost |= ch._armor[idx]._bonusFlags & 0x40;
-		_uncurseCost |= ch._accessories[idx]._bonusFlags & 0x40;
-		_uncurseCost |= ch._misc[idx]._bonusFlags & 0x40;
-	}
-
-	if (_uncurseCost || ch._conditions[CURSED])
-		_v5 = (_currentCharLevel * 20) + _v10;
-
-	_donation = _flag1 ? 0 : _v14;
-	_healCost += _v6 + _v5;
-
-	return Common::String::format(Res.TEMPLE_TEXT, ch._name.c_str(),
-		_healCost, _donation, XeenEngine::printK(_uncurseCost).c_str(),
-		XeenEngine::printMil(party._gold).c_str());
-}
-
-Character *TempleLocation::doOptions(Character *c) {
-	Interface &intf = *g_vm->_interface;
-	Party &party = *g_vm->_party;
-	Sound &sound = *g_vm->_sound;
-
-	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:
-		// Switch character
-		_buttonValue -= Common::KEYCODE_F1;
-		if (_buttonValue < (int)party._activeParty.size()) {
-			c = &party._activeParty[_buttonValue];
-			intf.highlightChar(_buttonValue);
-			_dayOfWeek = 0;
-		}
-		break;
-
-	case Common::KEYCODE_d:
-		if (_donation && party.subtract(CONS_GOLD, _donation, WHERE_PARTY, WT_2)) {
-			sound.stopSound();
-			sound.playSound("coina.voc", 1);
-			_dayOfWeek = (_dayOfWeek + 1) / 10;
-
-			if (_dayOfWeek == (party._day / 10)) {
-				party._clairvoyanceActive = true;
-				party._lightCount = 1;
-
-				int amt = _dayOfWeek ? _dayOfWeek : 10;
-				party._heroism = amt;
-				party._holyBonus = amt;
-				party._powerShield = amt;
-				party._blessed = amt;
-
-				intf.drawParty(true);
-				sound.stopSound();
-				sound.playSound("ahh.voc");
-				_flag1 = true;
-				_donation = 0;
-			}
-		}
-		break;
-
-	case Common::KEYCODE_h:
-		if (_healCost && party.subtract(CONS_GOLD, _healCost, WHERE_PARTY, WT_2)) {
-			c->_magicResistence._temporary = 0;
-			c->_energyResistence._temporary = 0;
-			c->_poisonResistence._temporary = 0;
-			c->_electricityResistence._temporary = 0;
-			c->_coldResistence._temporary = 0;
-			c->_fireResistence._temporary = 0;
-			c->_ACTemp = 0;
-			c->_level._temporary = 0;
-			c->_luck._temporary = 0;
-			c->_accuracy._temporary = 0;
-			c->_speed._temporary = 0;
-			c->_endurance._temporary = 0;
-			c->_personality._temporary = 0;
-			c->_intellect._temporary = 0;
-			c->_might._temporary = 0;
-			c->_currentHp = c->getMaxHP();
-			Common::fill(&c->_conditions[HEART_BROKEN], &c->_conditions[NO_CONDITION], 0);
-
-			_farewellTime = 1440;
-			intf.drawParty(true);
-			sound.stopSound();
-			sound.playSound("ahh.voc", 1);
-		}
-		break;
-
-	case Common::KEYCODE_u:
-		if (_uncurseCost && party.subtract(CONS_GOLD, _uncurseCost, WHERE_PARTY, WT_2)) {
-			for (int idx = 0; idx < 9; ++idx) {
-				c->_weapons[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
-				c->_armor[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
-				c->_accessories[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
-				c->_misc[idx]._bonusFlags &= ~ITEMFLAG_CURSED;
-			}
-
-			_farewellTime = 1440;
-			intf.drawParty(true);
-			sound.stopSound();
-			sound.playSound("ahh.voc", 1);
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	return c;
-}
-
-/*------------------------------------------------------------------------*/
-
-TrainingLocation::TrainingLocation() : BaseLocation(TRAINING) {
-	Common::fill(&_charsTrained[0], &_charsTrained[6], 0);
-	_maxLevel = 0;
-	_experienceToNextLevel = 0;
-	_charIndex = 0;
-
-	_icons1.load("train.icn");
-	addButton(Common::Rect(281, 108, 305, 128), Common::KEYCODE_ESCAPE, &_icons1);
-	addButton(Common::Rect(242, 108, 266, 128), Common::KEYCODE_t, &_icons1);
-
-	_vocName = _isDarkCc ? "training.voc" : "youtrn1.voc";
-}
-
-Common::String TrainingLocation::createLocationText(Character &ch) {
-	Party &party = *g_vm->_party;
-	if (_isDarkCc) {
-		switch (party._mazeId) {
-		case 29:
-			// Castleview
-			_maxLevel = 30;
-			break;
-		case 31:
-			// Sandcaster
-			_maxLevel = 50;
-			break;
-		case 37:
-			// Olympus
-			_maxLevel = 200;
-			break;
-		default:
-			// Kalindra's Castle
-			_maxLevel = 100;
-			break;
-		}
-	} else {
-		switch (party._mazeId) {
-		case 28:
-			// Vertigo
-			_maxLevel = 10;
-			break;
-		case 30:
-			// Rivercity
-			_maxLevel = 15;
-			break;
-		default:
-			// Newcastle
-			_maxLevel = 20;
-			break;
-		}
-	}
-
-	_experienceToNextLevel = ch.experienceToNextLevel();
-
-	Common::String msg;
-	if (_experienceToNextLevel && ch._level._permanent < _maxLevel) {
-		// Need more experience
-		int nextLevel = ch._level._permanent + 1;
-		msg = Common::String::format(Res.EXPERIENCE_FOR_LEVEL,
-			ch._name.c_str(), _experienceToNextLevel, nextLevel);
-	} else if (ch._level._permanent >= _maxLevel) {
-		// At maximum level
-		_experienceToNextLevel = 1;
-		msg = Common::String::format(Res.LEARNED_ALL, ch._name.c_str());
-	} else {
-		// Eligble for level increase
-		msg = Common::String::format(Res.ELIGIBLE_FOR_LEVEL,
-			ch._name.c_str(), ch._level._permanent + 1);
-	}
-
-	return Common::String::format(Res.TRAINING_TEXT, msg.c_str(),
-		XeenEngine::printMil(party._gold).c_str());
-}
-
-Character *TrainingLocation::doOptions(Character *c) {
-	Interface &intf = *g_vm->_interface;
-	Party &party = *g_vm->_party;
-	Sound &sound = *g_vm->_sound;
-
-	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:
-		// Switch character
-		_buttonValue -= Common::KEYCODE_F1;
-		if (_buttonValue < (int)party._activeParty.size()) {
-			_charIndex = _buttonValue;
-			c = &party._activeParty[_buttonValue];
-			intf.highlightChar(_buttonValue);
-		}
-		break;
-
-	case Common::KEYCODE_t:
-		if (_experienceToNextLevel) {
-			sound.stopSound();
-			_drawFrameIndex = 0;
-
-			Common::String name;
-			if (c->_level._permanent >= _maxLevel) {
-				name = _isDarkCc ? "gtlost.voc" : "trainin1.voc";
-			} else {
-				name = _isDarkCc ? "gtlost.voc" : "trainin0.voc";
-			}
-
-			sound.playSound(name);
-
-		} else if (!c->noActions()) {
-			if (party.subtract(CONS_GOLD, (c->_level._permanent * c->_level._permanent) * 10, WHERE_PARTY, WT_2)) {
-				_drawFrameIndex = 0;
-				sound.stopSound();
-				sound.playSound(_isDarkCc ? "prtygd.voc" : "trainin2.voc", 1);
-
-				c->_experience -=  c->nextExperienceLevel() -
-					(c->getCurrentExperience() - c->_experience);
-				c->_level._permanent++;
-
-				if (!_charsTrained[_charIndex]) {
-					party.addTime(1440);
-					_charsTrained[_charIndex] = true;
-				}
-
-				party.resetTemps();
-				c->_currentHp = c->getMaxHP();
-				c->_currentSp = c->getMaxSP();
-				intf.drawParty(true);
-			}
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	return c;
-}
-
-/*------------------------------------------------------------------------*/
-
-ArenaLocation::ArenaLocation() : BaseLocation(ARENA) {
-	// TODO
-}
-
-/*------------------------------------------------------------------------*/
-
-CutsceneLocation::CutsceneLocation(TownAction action) : BaseLocation(action),
-		_animCtr(0), _mazeFlag(false) {
-	Party &party = *g_vm->_party;
-	_mazeId = party._mazeId;
-	_mazePos = party._mazePosition;
-	_mazeDir = party._mazeDirection;
-}
-
-void CutsceneLocation::cutsceneAnimUpdate() {
-	// TODO
-}
-
-void CutsceneLocation::setNewLocation() {
-	Map &map = *g_vm->_map;
-	Party &party = *g_vm->_party;
-	map.load(_mazeId);
-	party._mazePosition = _mazePos;
-	party._mazeDirection = _mazeDir;
-}
-
-/*------------------------------------------------------------------------*/
-
-ReaperCutscene::ReaperCutscene() : CutsceneLocation(REAPER) {
-	// TODO
-}
-
-/*------------------------------------------------------------------------*/
-
-GolemCutscene::GolemCutscene() : CutsceneLocation(GOLEM) {
-	// TODO
-}
-
-/*------------------------------------------------------------------------*/
-
-const int16 DWARF_X0[2][13] = {
-	{  0, -5, -7, -8, -11, -9, -3, 1, 6, 10, 15, 18, 23 },
-	{ 0, 4, 6, 8, 11, 12, 15, 17, 19, 22, 25, 0, 0 }
-};
-const int DWARF_X1[2][13] = {
-	{ 160, 145, 133, 122, 109, 101, 97, 91, 86, 80, 75, 68, 63 },
-	{ 160, 154, 146, 138, 131, 122, 115, 107, 99, 92, 85, 0, 0 }
-};
-const int DWARF_X2[13] = {
-	0, -1, -4, -7, -9, -13, -15, -18, -21, -23, -25, 0, 0
-};
-const int16 DWARF_Y[2][13] = {
-	{ 0, 0, 4, 9, 13, 15, 20, 24, 30, 37, 45, 51, 58 },
-	{ 0, 12, 25, 36, 38, 40, 41, 42, 44, 45, 50, 0, 0 }
-};
-const int16 DWARF2_X[2][16] = {
-	{ 0, -2, -4, -6, -8, -10, -12, -14, -16, -18, -20, -20, -20, -20, -20, -20 },
-	{ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150 }
-};
-const int16 DWARF2_Y[2][16] = {
-	{ 0, 12, 25, 37, 50, 62, 75, 87, 100, 112, 125, 137, 150, 162, 175, 187 },
-	{ 0, 12, 25, 37, 50, 62, 75, 87, 100, 112, 125, 137, 150, 162, 175, 186 }
-};
-
-DwarfCutscene::DwarfCutscene(bool isDwarf) : CutsceneLocation(NO_ACTION) {
-	_townMaxId = Res.TOWN_MAXES[_isDarkCc][isDwarf ? DWARF1 : DWARF2];
-}
-
-int DwarfCutscene::show() {
-	EventsManager &events = *g_vm->_events;
-	Interface &intf = *g_vm->_interface;
-	Screen &screen = *g_vm->_screen;
-	Sound &sound = *g_vm->_sound;
-	Windows &windows = *g_vm->_windows;
-
-	SpriteResource sprites1(_isDarkCc ? "town1.zom" : "dwarf1.vga");
-	SpriteResource sprites2(_isDarkCc ? "town2.zom" : "dwarf2.vga");
-	SpriteResource sprites3(_isDarkCc ? "town3.zom" : "dwarf3.vga");
-	SpriteResource boxSprites("box.vga");
-	getNewLocation();
-
-	// Save the screen contents
-	Graphics::ManagedSurface savedBg;
-	savedBg.copyFrom(screen);
-
-	for (int idx = 0; idx < (_isDarkCc ? 10 : 12); ++idx) {
-		screen.copyFrom(savedBg);
-		sprites1.draw(0, 0,
-			Common::Point(DWARF_X0[_isDarkCc][idx], DWARF_Y[_isDarkCc][idx]));
-		sprites1.draw(0, 1,
-			Common::Point(DWARF_X1[_isDarkCc][idx], DWARF_Y[_isDarkCc][idx]));
-		if (_isDarkCc)
-			sprites1.draw(0, 2,
-				Common::Point(DWARF_X2[idx], DWARF_Y[_isDarkCc][idx]));
-
-		windows[0].update();
-		events.wait(1);
-	}
-
-	savedBg.copyFrom(screen);
-	for (int idx = 15; idx >= 0; --idx) {
-		screen.copyFrom(savedBg);
-		sprites2.draw(0, 0, Common::Point(DWARF2_X[_isDarkCc][idx], DWARF2_Y[_isDarkCc][idx]));
-		windows[0].update();
-		events.wait(1);
-	}
-
-	sound.setMusicVolume(48);
-	screen.copyFrom(savedBg);
-	sprites2.draw(0, 0);
-	windows[0].update();
-
-	for (int idx = 0; idx < (_isDarkCc ? 2 : 3); ++idx) {
-		switch (idx) {
-		case 0:
-			sound.playSound(_isDarkCc ? "pass2.voc" : "dwarf10.voc");
-			break;
-
-		case 1:
-			if (_isDarkCc) {
-				sprites2.draw(0, 0);
-				sprites3.draw(0, 0);
-				cutsceneAnimUpdate();
-
-				events.timeMark5();
-				while (!g_vm->shouldQuit() && events.timeElapsed5() < 7)
-					events.pollEventsAndWait();
-
-				sound.playSound(_mazeFlag ? "ok2.voc" : "back2.voc");
-			} else {
-				sound.playSound("dwarf11.voc");
-			}
-			break;
-
-		case 2:
-			sound.playSound("dwarf12.voc");
-			break;
-		}
-
-		events.updateGameCounter();
-		do {
-			sprites2.draw(0, 0);
-			sprites3.draw(0, g_vm->getRandomNumber(_isDarkCc ? 8 : 9));
-			cutsceneAnimUpdate();
-
-			events.timeMark5();
-			while (!g_vm->shouldQuit() && events.timeElapsed5() < 2)
-				events.pollEventsAndWait();
-		} while (!g_vm->shouldQuit() && (sound.isPlaying() || _animCtr));
-
-		while (!g_vm->shouldQuit() && events.timeElapsed() < 3)
-			events.pollEventsAndWait();
-	}
-
-	sprites2.draw(0, 0);
-	if (!_isDarkCc)
-		sprites3.draw(0, 1);
-	windows[0].update();
-
-	setNewLocation();
-
-	// Restore game screen
-	sound.setMusicVolume(95);
-	screen.loadBackground("back.raw");
-	intf.drawParty(false);
-	intf.draw3d(false, false);
-
-	events.clearEvents();
-	return 0;
-}
-
-void DwarfCutscene::getNewLocation() {
-	Party &party = *g_vm->_party;
-
-	if (_isDarkCc) {
-		switch (party._mazeId) {
-		case 4:
-			if (party._questItems[35]) {
-				_mazeId = 29;
-				_mazePos = Common::Point(15, 31);
-				_mazeDir = DIR_SOUTH;
-			}
-			break;
-
-		case 6:
-			if (party._questItems[38]) {
-				_mazeId = 35;
-				_mazePos = Common::Point(15, 8);
-				_mazeDir = DIR_WEST;
-			}
-			break;
-
-		case 19:
-			if (party._questItems[36]) {
-				_mazeId = 31;
-				_mazePos = Common::Point(31, 16);
-				_mazeDir = DIR_WEST;
-			}
-			break;
-
-		case 22:
-			if (party._questItems[37]) {
-				_mazeId = 33;
-				_mazePos = Common::Point(0, 3);
-				_mazeDir = DIR_EAST;
-			}
-			break;
-
-		case 98:
-			if (party._questItems[39]) {
-				_mazeId = 37;
-				_mazePos = Common::Point(7, 0);
-				_mazeDir = DIR_NORTH;
-			}
-			break;
-
-		default:
-			break;
-		}
-
-		_mazeFlag = _mazeId != 0;
-	} else {
-		switch (party._mazeId) {
-		case 14:
-			_mazeId = 37;
-			_mazePos = Common::Point(1, 4);
-			_mazeDir = DIR_EAST;
-			break;
-
-		case 18:
-			if (party._mazePosition.x == 9) {
-				_mazeId = 35;
-				_mazePos = Common::Point(1, 12);
-				_mazeDir = DIR_EAST;
-			} else {
-				_mazeId = 36;
-				_mazePos = Common::Point(7, 1);
-				_mazeDir = DIR_NORTH;
-			}
-			break;
-
-		case 23:
-			if (party._mazePosition.x == 5) {
-				_mazeId = 33;
-				_mazePos = Common::Point(7, 1);
-				_mazeDir = DIR_NORTH;
-			} else {
-				_mazeId = 34;
-				_mazePos = Common::Point(7, 30);
-				_mazeDir = DIR_SOUTH;
-			}
-			break;
-
-		default:
-			break;
-		}
-	}
-}
-
-/*------------------------------------------------------------------------*/
-
-SphinxCutscene::SphinxCutscene() : CutsceneLocation(SPHINX) {
-	SpriteResource sprites1("sphinx.vga");
-	_boxSprites.load("box.vga");
-
-
-	// TODO
-}
-
-void SphinxCutscene::getNewLocation() {
-	Map &map = *g_vm->_map;
-	Party &party = *g_vm->_party;
-
-	switch (party._mazeId) {
-	case 2:
-		if (party._questItems[51]) {
-			map._loadDarkSide = true;
-			_mazeId = 125;
-			_mazePos = Common::Point(7, 6);
-			_mazeDir = DIR_NORTH;
-			_mazeFlag = true;
-		}
-		break;
-
-	case 5:
-		if (party._questItems[4]) {
-			_mazeId = 82;
-			_mazePos = Common::Point(7, 5);
-			_mazeDir = DIR_NORTH;
-			_mazeFlag = true;
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	if (!_mazeFlag) {
-		_mazeId = party._mazeId;
-		_mazePos = party._mazePosition;
-		_mazeDir = party._mazeDirection;
-	}
-}
-
-
-/*------------------------------------------------------------------------*/
-
-PyramidLocation::PyramidLocation() : BaseLocation(PYRAMID) {
-}
-
-int PyramidLocation::show() {
-	EventsManager &events = *g_vm->_events;
-	Map &map = *g_vm->_map;
-	Party &party = *g_vm->_party;
-	Windows &windows = *g_vm->_windows;
-	int mapId;
-	Direction dir = DIR_NORTH;
-	Common::Point pt;
-
-	if (g_vm->getGameID() == GType_WorldOfXeen) {
-		if (_isDarkCc) {
-			if (party._mazeId == 52) {
-				mapId = 49;
-				pt = Common::Point(7, 14);
-				dir = DIR_SOUTH;
-			} else {
-				mapId = 23;
-				pt = Common::Point(8, 10);
-			}
-		} else {
-			if (party._mazeId == 49) {
-				mapId = 52;
-				pt = Common::Point(2, 2);
-			} else {
-				mapId = 29;
-				pt = Common::Point(25, 21);
-			}
-		}
-
-		// Load the destination map and set position and direction
-		map._loadDarkSide = !_isDarkCc;
-		map.load(mapId);
-		party._mazePosition = pt;
-		party._mazeDirection = dir;
-	} else {
-		// Playing Clouds or Dark Side on it's own, so can't switch sides
-		Window &win = windows[12];
-		Common::String msg = Common::String::format(Res.MOONS_NOT_ALIGNED,
-			_isDarkCc ? "Clouds" : "Darkside");
-		win.open();
-		win.writeString(msg);
-		win.update();
-
-		events.waitForPressAnimated();
-		win.close();
-	}
-
-	return 0;
-}
-
-/*------------------------------------------------------------------------*/
-
-Town::Town() : _location(nullptr) {
-}
-
-int Town::townAction(TownAction actionId) {
-	// Create the desired location
-	switch (actionId) {
-	case BANK:
-		_location = new BankLocation();
-		break;
-	case BLACKSMITH:
-		_location = new BlacksmithLocation();
-		break;
-	case GUILD:
-		_location = new GuildLocation();
-		break;
-	case TAVERN:
-		_location = new TavernLocation();
-		break;
-	case TEMPLE:
-		_location = new TempleLocation();
-		break;
-	case TRAINING:
-		_location = new TrainingLocation();
-		break;
-	case ARENA:
-		_location = new ArenaLocation();
-		break;
-	case REAPER:
-		_location = new ReaperCutscene();
-		break;
-	case GOLEM:
-		_location = new GolemCutscene();
-		break;
-	case DWARF1:
-		_location = new DwarfCutscene(true);
-		break;
-	case DWARF2:
-		_location = new DwarfCutscene(false);
-		break;
-	case SPHINX:
-		_location = new SphinxCutscene();
-		break;
-	case PYRAMID:
-		_location = new PyramidLocation();
-		break;
-	default:
-		return 0;
-	}
-
-	// Show the location
-	int result = _location->show();
-	delete _location;
-	_location = nullptr;
-
-	return result;
-}
-
-bool Town::isActive() const {
-	return _location != nullptr;
-}
-
-void Town::drawAnim(bool flag) {
-	if (_location)
-		_location->drawAnim(flag);
-}
-
-/*------------------------------------------------------------------------*/
-
-bool TownMessage::show(int portrait, const Common::String &name,
-		const Common::String &text, int confirm) {
-	TownMessage *dlg = new TownMessage();
-	bool result = dlg->execute(portrait, name, text, confirm);
-	delete dlg;
-
-	return result;
-}
-
-bool TownMessage::execute(int portrait, const Common::String &name, const Common::String &text,
-		int confirm) {
-	EventsManager &events = *g_vm->_events;
-	Interface &intf = *g_vm->_interface;
-	Map &map = *g_vm->_map;
-	Party &party = *g_vm->_party;
-	Resources &res = *g_vm->_resources;
-	Windows &windows = *g_vm->_windows;
-	Window &w = windows[11];
-
-	_townMaxId = 4;
-	_drawFrameIndex = 0;
-	_townPos = Common::Point(23, 22);
-
-	if (!confirm)
-		loadButtons();
-
-	_townSprites.resize(2);
-	_townSprites[0].load(Common::String::format("face%02d.fac", portrait));
-	_townSprites[1].load("frame.fac");
-
-	if (!w._enabled)
-		w.open();
-
-	int result = -1;
-	Common::String msgText = text;
-	do {
-		Common::String msg = Common::String::format("\r\v014\x03""c\t125%s\t000\v054%s",
-			name.c_str(), msgText.c_str());
-
-		// Count the number of words
-		const char *msgEnd = w.writeString(msg);
-		int wordCount = 0;
-
-		for (const char *msgP = msg.c_str(); msgP != msgEnd && *msgP; ++msgP) {
-			if (*msgP == ' ')
-				++wordCount;
-		}
-
-		_drawCtr2 = wordCount * 2;	// Set timeout
-		_townSprites[1].draw(0, 0, Common::Point(16, 16));
-		_townSprites[0].draw(0, _drawFrameIndex, Common::Point(23, 22));
-		w.update();
-
-		if (!msgEnd && !confirm) {
-			res._globalSprites.draw(0, 7, Common::Point(232, 74));
-			res._globalSprites.draw(0, 0, Common::Point(235, 75));
-			res._globalSprites.draw(0, 2, Common::Point(260, 75));
-			windows[34].update();
-
-			intf._face1State = map._headData[party._mazePosition.y][party._mazePosition.x]._left;
-			intf._face2State = map._headData[party._mazePosition.y][party._mazePosition.x]._right;
-		}
-
-		if (confirm == 2) {
-			intf._face1State = intf._face2State = 2;
-			return false;
-		}
-
-		do {
-			events.clearEvents();
-			events.updateGameCounter();
-			if (msgEnd)
-				clearButtons();
-
-			do {
-				events.pollEventsAndWait();
-				checkEvents(_vm);
-
-				if (_vm->shouldQuit())
-					return false;
-
-				while (events.timeElapsed() >= 3) {
-					drawAnim(false);
-					events.updateGameCounter();
-				}
-			} while (!_buttonValue);
-
-			if (msgEnd)
-				// Another screen of text remaining
-				break;
-
-			if (confirm || _buttonValue == Common::KEYCODE_ESCAPE ||
-					_buttonValue == Common::KEYCODE_n)
-				result = 0;
-			else if (_buttonValue == Common::KEYCODE_y)
-				result = 1;
-		} while (result == -1);
-
-		if (msgEnd) {
-			// Text remaining, so cut off already displayed page's
-			msgText = Common::String(msgEnd);
-			_drawCtr2 = wordCount;
-			continue;
-		}
-	} while (result == -1);
-
-	intf._face1State = intf._face2State = 2;
-	if (!confirm)
-		intf.mainIconsPrint();
-
-	_townSprites[0].clear();
-	_townSprites[1].clear();
-	events.clearEvents();
-	return result == 1;
-}
-
-void TownMessage::loadButtons() {
-	_iconSprites.load("confirm.icn");
-
-	addButton(Common::Rect(235, 75, 259, 95), Common::KEYCODE_y, &_iconSprites);
-	addButton(Common::Rect(260, 75, 284, 95), Common::KEYCODE_n, &_iconSprites);
-	addButton(Common::Rect(), Common::KEYCODE_ESCAPE);
-}
-
-} // End of namespace Xeen
diff --git a/engines/xeen/town.h b/engines/xeen/town.h
deleted file mode 100644
index 925bac9..0000000
--- a/engines/xeen/town.h
+++ /dev/null
@@ -1,368 +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_TOWN_H
-#define XEEN_TOWN_H
-
-#include "common/scummsys.h"
-#include "common/str-array.h"
-#include "xeen/dialogs.h"
-#include "xeen/dialogs_error.h"
-#include "xeen/party.h"
-
-namespace Xeen {
-
-enum TownAction {
-	BANK = 0, BLACKSMITH = 1, GUILD = 2, TAVERN = 3, TEMPLE = 4,
-	TRAINING = 5, ARENA = 6, NO_ACTION = 7, REAPER = 8, GOLEM = 9,
-	DWARF1 = 10, SPHINX = 11, PYRAMID = 12, DWARF2 = 13
-};
-
-class XeenEngine;
-class TownMessage;
-
-class BaseLocation : public ButtonContainer {
-protected:
-	TownAction _townActionId;
-	Common::Array<SpriteResource> _townSprites;
-	SpriteResource _icons1, _icons2;
-	int _townMaxId;
-	const bool &_isDarkCc;
-	int _animFrame;
-	Common::String _vocName, _songName;
-	Common::Point _townPos;
-	int _drawFrameIndex;
-	uint _farewellTime;
-	int _drawCtr1, _drawCtr2;
-protected:
-	/**
-	 * Draw the window
-	 */
-	void drawWindow();
-
-	/**
-	 * Waits for a brief pause, checking for any key or mouse events
-	 */
-	int wait();
-
-	/**
-	 * Generates the display text for the location, for a given character
-	 */
-	virtual Common::String createLocationText(Character &ch) { return ""; }
-
-	/**
-	 * Draw the visual background
-	 */
-	virtual void drawBackground();
-
-	/**
-	 * Handles options for the particular location
-	 */
-	virtual Character *doOptions(Character *c) { return c; }
-
-	/**
-	 * Handle any farewell
-	 */
-	virtual void farewell() {}
-public:
-	BaseLocation(TownAction action);
-	virtual ~BaseLocation();
-
-	/**
-	 * Show the town location
-	 */
-	virtual int show();
-
-	/**
-	 * Draws the animated parts
-	 */
-	void drawAnim(bool flag);
-};
-
-class BankLocation : public BaseLocation {
-private:
-	/**
-	 * Handles deposits or withdrawls fro the bank
-	 */
-	void depositWithdrawl(PartyBank whereId);
-protected:
-	/**
-	 * Generates the display text for the location, for a given character
-	 */
-	virtual Common::String createLocationText(Character &ch);
-
-	/**
-	 * Draw the visual background
-	 */
-	virtual void drawBackground();
-
-	/**
-	 * Handles options for the particular location
-	 */
-	virtual Character *doOptions(Character *c);
-public:
-	BankLocation();
-	virtual ~BankLocation() {}
-};
-
-class BlacksmithLocation : public BaseLocation {
-protected:
-	/**
-	* Generates the display text for the location, for a given character
-	*/
-	virtual Common::String createLocationText(Character &ch);
-
-	/**
-	 * Handle any farewell
-	 */
-	virtual void farewell();
-
-	/**
-	 * Handles options for the particular location
-	 */
-	virtual Character *doOptions(Character *c);
-public:
-	BlacksmithLocation();
-	virtual ~BlacksmithLocation() {}
-};
-
-class GuildLocation : public BaseLocation {
-protected:
-	/**
-	 * Generates the display text for the location, for a given character
-	 */
-	virtual Common::String createLocationText(Character &ch);
-
-	/**
-	 * Handles options for the particular location
-	 */
-	virtual Character *doOptions(Character *c);
-public:
-	GuildLocation();
-	virtual ~GuildLocation() {}
-};
-
-class TavernLocation : public BaseLocation {
-private:
-	int _v21;
-	uint _v22;
-	int _v23;
-	int _v24;
-protected:
-	/**
-	* Generates the display text for the location, for a given character
-	*/
-	virtual Common::String createLocationText(Character &ch);
-
-	/**
-	 * Handle any farewell
-	 */
-	virtual void farewell();
-
-	/**
-	 * Handles options for the particular location
-	 */
-	virtual Character *doOptions(Character *c);
-public:
-	TavernLocation();
-	virtual ~TavernLocation() {}
-};
-
-class TempleLocation : public BaseLocation {
-private:
-	int _currentCharLevel;
-	int _donation;
-	int _healCost;
-	int _uncurseCost;
-	int _dayOfWeek;
-	int _v10, _v11, _v12;
-	int _v13, _v14;
-	bool _flag1;
-	int _v5, _v6;
-protected:
-	/**
-	* Generates the display text for the location, for a given character
-	*/
-	virtual Common::String createLocationText(Character &ch);
-
-	/**
-	 * Handles options for the particular location
-	 */
-	virtual Character *doOptions(Character *c);
-public:
-	TempleLocation();
-	virtual ~TempleLocation() {}
-};
-
-class TrainingLocation : public BaseLocation {
-private:
-	int _charIndex;
-	bool _charsTrained[MAX_ACTIVE_PARTY];
-	uint _experienceToNextLevel;
-	uint _maxLevel;
-protected:
-	/**
-	 * Generates the display text for the location, for a given character
-	 */
-	virtual Common::String createLocationText(Character &ch);
-
-	/**
-	 * Handles options for the particular location
-	 */
-	virtual Character *doOptions(Character *c);
-public:
-	TrainingLocation();
-	virtual ~TrainingLocation() {}
-};
-
-class ArenaLocation : public BaseLocation {
-public:
-	ArenaLocation();
-	virtual ~ArenaLocation() {}
-};
-
-class CutsceneLocation : public BaseLocation {
-protected:
-	int _animCtr;
-	SpriteResource _boxSprites;
-	int _mazeId;
-	Direction _mazeDir;
-	Common::Point _mazePos;
-	bool _mazeFlag;
-protected:
-	/**
-	* Handles cutscene animation update
-	*/
-	void cutsceneAnimUpdate();
-
-	/**
-	 * Sets the new location
-	 */
-	void setNewLocation();
-public:
-	CutsceneLocation(TownAction action);
-};
-
-class ReaperCutscene : public CutsceneLocation {
-public:
-	ReaperCutscene();
-	virtual ~ReaperCutscene() {}
-};
-
-class GolemCutscene : public CutsceneLocation {
-public:
-	GolemCutscene();
-	virtual ~GolemCutscene() {}
-};
-
-class DwarfCutscene : public CutsceneLocation {
-private:
-	/**
-	 * Get the new location
-	 */
-	void getNewLocation();
-public:
-	DwarfCutscene(bool isDwarf1);
-	virtual ~DwarfCutscene() {}
-
-	/**
-	 * Show the town location
-	 */
-	virtual int show();
-};
-
-class SphinxCutscene : public CutsceneLocation {
-private:
-	/**
-	 * Get the new location
-	 */
-	void getNewLocation();
-public:
-	SphinxCutscene();
-	virtual ~SphinxCutscene() {}
-};
-
-class PyramidLocation : public BaseLocation {
-public:
-	PyramidLocation();
-	virtual ~PyramidLocation() {}
-
-	/**
-	 * Show the town location
-	 */
-	virtual int show();
-};
-
-class Town {
-private:
-	BaseLocation *_location;
-private:
-	int townWait();
-
-	Character *doBankOptions(Character *c);
-
-	Character *doBlacksmithOptions(Character *c);
-
-	Character *doGuildOptions(Character *c);
-
-	Character *doTavernOptions(Character *c);
-
-	Character *doTempleOptions(Character *c);
-
-	Character *doTrainingOptions(Character *c);
-public:
-	Town();
-
-	/**
-	 * Show a given location, and return any result
-	 */
-	int townAction(TownAction actionId);
-
-	/**
-	 * Returns true if a town location (bank, blacksmith, etc.) is currently active
-	 */
-	bool isActive() const;
-
-	/**
-	 * Draws a currently active town location's animation
-	 */
-	void drawAnim(bool flag);
-};
-
-class TownMessage : public BaseLocation {
-private:
-	SpriteResource _iconSprites;
-
-	TownMessage() : BaseLocation(NO_ACTION) {}
-
-	bool execute(int portrait, const Common::String &name,
-		const Common::String &text, int confirm);
-
-	void loadButtons();
-public:
-	static bool show(int portrait, const Common::String &name,
-		const Common::String &text, int confirm);
-};
-
-} // End of namespace Xeen
-
-#endif /* XEEN_SPELLS_H */
diff --git a/engines/xeen/xeen.cpp b/engines/xeen/xeen.cpp
index ddecc9a..67fb977 100644
--- a/engines/xeen/xeen.cpp
+++ b/engines/xeen/xeen.cpp
@@ -48,6 +48,7 @@ XeenEngine::XeenEngine(OSystem *syst, const XeenGameDescription *gameDesc)
 	_events = nullptr;
 	_files = nullptr;
 	_interface = nullptr;
+	_locations = nullptr;
 	_map = nullptr;
 	_party = nullptr;
 	_resources = nullptr;
@@ -56,7 +57,6 @@ XeenEngine::XeenEngine(OSystem *syst, const XeenGameDescription *gameDesc)
 	_scripts = nullptr;
 	_sound = nullptr;
 	_spells = nullptr;
-	_town = nullptr;
 	_windows = nullptr;
 	_eventData = nullptr;
 	_noDirectionSense = false;
@@ -73,6 +73,7 @@ XeenEngine::~XeenEngine() {
 	delete _debugger;
 	delete _events;
 	delete _interface;
+	delete _locations;
 	delete _map;
 	delete _party;
 	delete _saves;
@@ -80,7 +81,6 @@ XeenEngine::~XeenEngine() {
 	delete _scripts;
 	delete _sound;
 	delete _spells;
-	delete _town;
 	delete _windows;
 	delete _eventData;
 	delete _resources;
@@ -96,6 +96,7 @@ void XeenEngine::initialize() {
 	_debugger = new Debugger(this);
 	_events = new EventsManager(this);
 	_interface = new Interface(this);
+	_locations = new LocationManager();
 	_map = new Map(this);
 	_party = new Party(this);
 	_saves = new SavesManager(this, *_party);
@@ -103,7 +104,6 @@ void XeenEngine::initialize() {
 	_scripts = new Scripts(this);
 	_sound = new Sound(this, _mixer);
 	_spells = new Spells(this);
-	_town = new Town();
 	_windows = new Windows();
 
 	File f("029.obj");
diff --git a/engines/xeen/xeen.h b/engines/xeen/xeen.h
index cc187c9..022ad66 100644
--- a/engines/xeen/xeen.h
+++ b/engines/xeen/xeen.h
@@ -37,6 +37,7 @@
 #include "xeen/events.h"
 #include "xeen/files.h"
 #include "xeen/interface.h"
+#include "xeen/locations.h"
 #include "xeen/map.h"
 #include "xeen/party.h"
 #include "xeen/resources.h"
@@ -45,7 +46,6 @@
 #include "xeen/scripts.h"
 #include "xeen/sound.h"
 #include "xeen/spells.h"
-#include "xeen/town.h"
 #include "xeen/window.h"
 
 /**
@@ -144,6 +144,7 @@ public:
 	EventsManager *_events;
 	FileManager *_files;
 	Interface *_interface;
+	LocationManager *_locations;
 	Map *_map;
 	Party *_party;
 	Resources *_resources;
@@ -152,7 +153,6 @@ public:
 	Scripts *_scripts;
 	Sound *_sound;
 	Spells *_spells;
-	Town *_town;
 	Windows *_windows;
 	Mode _mode;
 	GameEvent _gameEvent;





More information about the Scummvm-git-logs mailing list