/* 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 {

Town::Town(XeenEngine *vm) : ButtonContainer(vm) {
	Common::fill(&_arr1[0], &_arr1[6], 0);
	_townMaxId = 0;
	_townActionId = 0;
	_drawFrameIndex = 0;
	_currentCharLevel = 0;
	_v1 = 0;
	_v2 = 0;
	_donation = 0;
	_healCost = 0;
	_v5 = _v6 = 0;
	_v10 = _v11 = 0;
	_v12 = _v13 = 0;
	_v14 = 0;
	_v20 = 0;
	_v21 = 0;
	_v22 = 0;
	_v23 = 0;
	_v24 = 0;
	_dayOfWeek = 0;
	_uncurseCost = 0;
	_flag1 = false;
	_experienceToNextLevel = 0;
	_drawCtr1 = _drawCtr2 = 0;
}

void Town::loadStrings(const Common::String &name) {
	File f(name);
	_textStrings.clear();
	while (f.pos() < f.size())
		_textStrings.push_back(f.readString());
	f.close();
}

int Town::townAction(int actionId) {
	Interface &intf = *_vm->_interface;
	Map &map = *_vm->_map;
	Party &party = *_vm->_party;
	Screen &screen = *_vm->_screen;
	Sound &sound = *_vm->_sound;
	bool isDarkCc = _vm->_files->_isDarkCc;

	if (actionId == 12) {
		pyramidEvent();
		return 0;
	}

	_townMaxId = Res.TOWN_MAXES[_vm->_files->_isDarkCc][actionId];
	_townActionId = actionId;
	_drawFrameIndex = 0;
	_v1 = 0;
	_townPos = Common::Point(8, 8);
	intf._overallFrame = 0;

	// This area sets up the GUI buttos and startup sample to play for the
	// given town action
	Common::String vocName = "hello1.voc";
	clearButtons();
	_icons1.clear();
	_icons2.clear();

	switch (actionId) {
	case 0:
		// 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);
		intf._overallFrame = 1;

		sound.stopSound();
		vocName = isDarkCc ? "bank1.voc" : "banker.voc";
		break;

	case 1:
		// Blacksmith
		_icons1.load("esc.icn");
		addButton(Common::Rect(261, 100, 285, 120), 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);

		sound.stopSound();
		vocName = isDarkCc ? "see2.voc" : "whaddayo.voc";
		break;

	case 2:
		// Guild
		loadStrings("spldesc.bin");
		_icons1.load("esc.icn");
		addButton(Common::Rect(261, 100, 285, 120), 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);
		_vm->_mode = MODE_17;

		sound.stopSound();
		vocName = isDarkCc ? "parrot1.voc" : "guild10.voc";
		break;

	case 3:
		// Tavern
		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);
		_vm->_mode = MODE_17;

		sound.stopSound();
		vocName = isDarkCc ? "hello1.voc" : "hello.voc";
		break;

	case 4:
		// Temple
		_icons1.load("esc.icn");
		addButton(Common::Rect(261, 100, 285, 120), 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);

		sound.stopSound();
		vocName = isDarkCc ? "help2.voc" : "maywe2.voc";
		break;

	case 5:
		// Training
		Common::fill(&_arr1[0], &_arr1[6], 0);
		_v2 = 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);

		sound.stopSound();
		vocName = isDarkCc ? "training.voc" : "youtrn1.voc";
		break;

	case 6:
		// Arena event
		arenaEvent();
		return false;

	case 8:
		// Reaper event
		reaperEvent();
		return false;

	case 9:
		// Golem event
		golemEvent();
		return false;

	case 10:
	case 13:
		dwarfEvent();
		return false;

	case 11:
		sphinxEvent();
		return false;

	default:
		break;
	}

	sound.playSong(Res.TOWN_ACTION_MUSIC[actionId], 223);

	_townSprites.resize(Res.TOWN_ACTION_FILES[isDarkCc][actionId]);
	for (uint idx = 0; idx < _townSprites.size(); ++idx) {
		Common::String shapesName = Common::String::format("%s%d.twn",
			Res.TOWN_ACTION_SHAPES[actionId], idx + 1);
		_townSprites[idx].load(shapesName);
	}

	Character *charP = &party._activeParty[0];
	Common::String title = createTownText(*charP);
	intf._face1UIFrame = intf._face2UIFrame = 0;
	intf._dangerSenseUIFrame = 0;
	intf._spotDoorsUIFrame = 0;
	intf._levitateUIFrame = 0;

	_townSprites[_drawFrameIndex / 8].draw(screen, _drawFrameIndex % 8, _townPos);
	if (actionId == 0 && isDarkCc) {
		_townSprites[4].draw(screen, _vm->getRandomNumber(13, 18),
			Common::Point(8, 30));
	}

	intf.assembleBorder();

	// Open up the window and write the string
	screen._windows[10].open();
	screen._windows[10].writeString(title);
	drawButtons(&screen);

	screen._windows[0].update();
	intf.highlightChar(0);
	drawTownAnim(1);

	if (actionId == 0)
		intf._overallFrame = 2;

	sound.playSound(vocName, 1);

	do {
		townWait();
		charP = doTownOptions(charP);
		screen._windows[10].writeString(title);
		drawButtons(&screen);
	} while (!_vm->shouldQuit() && _buttonValue != Common::KEYCODE_ESCAPE);

	switch (actionId) {
	case 1:
		// Leave blacksmith
		if (isDarkCc) {
			sound.stopSound();
			sound.playSound("come1.voc", 1);
		}
		break;

	case 3: {
		// Leave Tavern
		sound.stopSound();
		sound.playSound(isDarkCc ? "gdluck1.voc" : "goodbye.voc", 1);

		map.mazeData()._mazeNumber = party._mazeId;
		break;
	}
	default:
		break;
	}

	int result;
	if (party._mazeId != 0) {
		map.load(party._mazeId);
		_v1 += 1440;
		party.addTime(_v1);
		result = 0;
	} else {
		_vm->_saves->saveChars();
		result = 2;
	}

	for (uint idx = 0; idx < _townSprites.size(); ++idx)
		_townSprites[idx].clear();
	intf.mainIconsPrint();
	_buttonValue = 0;

	return result;
}

int Town::townWait() {
	EventsManager &events = *_vm->_events;

	_buttonValue = 0;
	while (!_vm->shouldQuit() && !_buttonValue) {
		events.updateGameCounter();
		while (!_vm->shouldQuit() && !_buttonValue && events.timeElapsed() < 3) {
			events.pollEventsAndWait();
			checkEvents(_vm);
		}
		if (!_buttonValue)
			drawTownAnim(!_vm->_screen->_windows[11]._enabled);
	}

	return _buttonValue;
}

void Town::pyramidEvent() {
	error("TODO: pyramidEvent");
}

void Town::arenaEvent() {
	error("TODO: arenaEvent");
}

void Town::reaperEvent() {
	error("TODO: repearEvent");
}

void Town::golemEvent() {
	error("TODO: golemEvent");
}

void Town::sphinxEvent() {
	error("TODO: sphinxEvent");
}

void Town::dwarfEvent() {
	error("TODO: dwarfEvent");
}

Common::String Town::createTownText(Character &ch) {
	Party &party = *_vm->_party;
	Common::String msg;

	switch (_townActionId) {
	case 0:
		// Bank
		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());
	case 1:
		// Blacksmith
		return Common::String::format(Res.BLACKSMITH_TEXT,
			XeenEngine::printMil(party._gold).c_str());

	case 2:
		// Guild
		return !ch.guildMember() ? Res.GUILD_NOT_MEMBER_TEXT :
			Common::String::format(Res.GUILD_TEXT, ch._name.c_str());

	case 3:
		// Tavern
		return Common::String::format(Res.TAVERN_TEXT, ch._name.c_str(),
			Res.FOOD_AND_DRINK, XeenEngine::printMil(party._gold).c_str());

	case 4:
		// Temple
		_donation = 0;
		_uncurseCost = 0;
		_v5 = 0;
		_v6 = 0;
		_healCost = 0;

		if (party._mazeId == (_vm->_files->_isDarkCc ? 29 : 28)) {
			_v10 = _v11 = _v12 = _v13 = 0;
			_v14 = 10;
		} else if (party._mazeId == (_vm->_files->_isDarkCc ? 31 : 30)) {
			_v13 = 10;
			_v12 = 50;
			_v11 = 500;
			_v10 = 100;
			_v14 = 25;
		} else if (party._mazeId == (_vm->_files->_isDarkCc ? 37 : 73)) {
			_v13 = 20;
			_v12 = 100;
			_v11 = 1000;
			_v10 = 200;
			_v14 = 50;
		} else if (_vm->_files->_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());

	case 5:
		// Training
		if (_vm->_files->_isDarkCc) {
			switch (party._mazeId) {
			case 29:
				_v20 = 30;
				break;
			case 31:
				_v20 = 50;
				break;
			case 37:
				_v20 = 200;
				break;
			default:
				_v20 = 100;
				break;
			}
		} else {
			switch (party._mazeId) {
			case 28:
				_v20 = 10;
				break;
			case 30:
				_v20 = 15;
				break;
			default:
				_v20 = 20;
				break;
			}
		}

		_experienceToNextLevel = ch.experienceToNextLevel();

		if (_experienceToNextLevel >= 0x10000 && ch._level._permanent < _v20) {
			int nextLevel = ch._level._permanent + 1;
			return Common::String::format(Res.EXPERIENCE_FOR_LEVEL,
				ch._name.c_str(), _experienceToNextLevel, nextLevel);
		} else if (ch._level._permanent >= 20) {
			_experienceToNextLevel = 1;
			msg = Common::String::format(Res.LEARNED_ALL, ch._name.c_str());
		} else {
			msg = Common::String::format(Res.ELIGIBLE_FOR_LEVEL,
				ch._name.c_str(), ch._level._permanent + 1);
		}

		return Common::String::format(Res.TRAINING_TEXT,
			XeenEngine::printMil(party._gold).c_str());

	default:
		return "";
	}
}

Character *Town::doTownOptions(Character *c) {
	switch (_townActionId) {
	case 0:
		// Bank
		c = doBankOptions(c);
		break;
	case 1:
		// Blacksmith
		c = doBlacksmithOptions(c);
		break;
	case 2:
		// Guild
		c = doGuildOptions(c);
		break;
	case 3:
		// Tavern
		c = doTavernOptions(c);
		break;
	case 4:
		// Temple
		c = doTempleOptions(c);
	case 5:
		// Training
		c = doTrainingOptions(c);
		break;
	default:
		break;
	}

	return c;
}

Character *Town::doBankOptions(Character *c) {
	if (_buttonValue == Common::KEYCODE_d)
		_buttonValue = 0;
	else if (_buttonValue == Common::KEYCODE_w)
		_buttonValue = 1;
	else
		return c;

	depositWithdrawl(_buttonValue);
	return c;
}

Character *Town::doBlacksmithOptions(Character *c) {
	Interface &intf = *_vm->_interface;
	Party &party = *_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;
}

Character *Town::doGuildOptions(Character *c) {
	Interface &intf = *_vm->_interface;
	Party &party = *_vm->_party;
	Sound &sound = *_vm->_sound;
	bool isDarkCc = _vm->_files->_isDarkCc;

	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();
				intf._overallFrame = 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;
}

Character *Town::doTavernOptions(Character *c) {
	Interface &intf = *_vm->_interface;
	Map &map = *_vm->_map;
	Party &party = *_vm->_party;
	Sound &sound = *_vm->_sound;
	Screen &screen = *_vm->_screen;
	bool isDarkCc = _vm->_files->_isDarkCc;
	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(0, 1, 0, WT_2)) {
				sound.stopSound();
				sound.playSound("gulp.voc");
				_v21 = 1;

				screen._windows[10].writeString(Common::String::format(Res.TAVERN_TEXT,
					c->_name.c_str(), Res.GOOD_STUFF,
					XeenEngine::printMil(party._gold).c_str()));
				drawButtons(&screen._windows[0]);
				screen._windows[10].update();

				if (_vm->getRandomNumber(100) < 26) {
					++c->_conditions[DRUNK];
					intf.drawParty(true);
					sound.playFX(28);
				}

				townWait();
			}
		}
		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];
		screen._windows[10].close();
		screen._windows[12].open();
		screen._windows[12].writeString(msg);
		screen._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(0, _v23, 0, WT_2)) {
				party._food = _v22;
				sound.stopSound();
				sound.playSound(isDarkCc ? "thanks2.voc" : "thankyou.voc", 1);
			}
		}

		screen._windows[12].close();
		screen._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 = screen._windows[12];
		w.open();
		w.writeString(msg);
		w.update();

		townWait();
		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) {
				screen._windows[10].writeString(Common::String::format(Res.TAVERN_TEXT,
					c->_name.c_str(), Res.HAVE_A_DRINK,
					XeenEngine::printMil(party._gold).c_str()));
				drawButtons(&screen);
				screen._windows[10].update();
				townWait();
			} else {
				_v21 = 0;
				if (c->_conditions[DRUNK]) {
					screen._windows[10].writeString(Common::String::format(Res.TAVERN_TEXT,
						c->_name.c_str(), Res.YOURE_DRUNK,
						XeenEngine::printMil(party._gold).c_str()));
					drawButtons(&screen);
					screen._windows[10].update();
					townWait();
				} else if (party.subtract(0, 1, 0, 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 = screen._windows[12];
					w.open();
					w.writeString(Common::String::format("\x03""c\x0B""012%s", msg.c_str()));
					w.update();
					townWait();
					w.close();
				}
			}
		}
		break;

	default:
		break;
	}

	return c;
}

Character *Town::doTempleOptions(Character *c) {
	Interface &intf = *_vm->_interface;
	Party &party = *_vm->_party;
	Sound &sound = *_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(0, _donation, 0, 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(0, _healCost, 0, 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);

			_v1 = 1440;
			intf.drawParty(true);
			sound.stopSound();
			sound.playSound("ahh.voc", 1);
		}
		break;

	case Common::KEYCODE_u:
		if (_uncurseCost && party.subtract(0, _uncurseCost, 0, 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;
			}

			_v1 = 1440;
			intf.drawParty(true);
			sound.stopSound();
			sound.playSound("ahh.voc", 1);
		}
		break;

	default:
		break;
	}

	return c;
}

Character *Town::doTrainingOptions(Character *c) {
	Interface &intf = *_vm->_interface;
	Party &party = *_vm->_party;
	Sound &sound = *_vm->_sound;
	bool isDarkCc = _vm->_files->_isDarkCc;

	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()) {
			_v2 = _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 >= _v20) {
				name = isDarkCc ? "gtlost.voc" : "trainin1.voc";
			} else {
				name = isDarkCc ? "gtlost.voc" : "trainin0.voc";
			}

			sound.playSound(name);

		} else if (!c->noActions()) {
			if (party.subtract(0, (c->_level._permanent * c->_level._permanent) * 10, 0, 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 (!_arr1[_v2]) {
					party.addTime(1440);
					_arr1[_v2] = 1;
				}

				party.resetTemps();
				c->_currentHp = c->getMaxHP();
				c->_currentSp = c->getMaxSP();
				intf.drawParty(true);
			}
		}
		break;

	default:
		break;
	}

	return c;
}

void Town::depositWithdrawl(int choice) {
	Party &party = *_vm->_party;
	Screen &screen = *_vm->_screen;
	Sound &sound = *_vm->_sound;
	int gold, gems;

	if (choice) {
		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[choice],
		XeenEngine::printMil(gold).c_str(),
		XeenEngine::printMil(gems).c_str());

	screen._windows[35].open();
	screen._windows[35].writeString(msg);
	drawButtons(&screen._windows[35]);
	screen._windows[35].update();

	sound.stopSound();
	File voc("coina.voc");
	bool flag = false;

	do {
		switch (townWait()) {
		case Common::KEYCODE_o:
			flag = false;
			break;
		case Common::KEYCODE_e:
			flag = true;
			break;
		case Common::KEYCODE_ESCAPE:
			break;
		default:
			continue;
		}

		if ((choice && !party._bankGems && flag) ||
			(choice && !party._bankGold && !flag) ||
			(!choice && !party._gems && flag) ||
			(!choice && !party._gold && !flag)) {
			party.notEnough(flag, choice, 1, WT_2);
		} else {
			screen._windows[35].writeString(Res.AMOUNT);
			int amount = NumericInput::show(_vm, 35, 10, 77);

			if (amount) {
				if (flag) {
					if (party.subtract(true, amount, choice, WT_2)) {
						if (choice) {
							party._gems += amount;
						} else {
							party._bankGems += amount;
						}
					}
				} else {
					if (party.subtract(false, amount, choice, WT_2)) {
						if (choice) {
							party._gold += amount;
						} else {
							party._bankGold += amount;
						}
					}
				}
			}

			if (choice) {
				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[choice],
				XeenEngine::printMil(gold).c_str(), XeenEngine::printMil(gems).c_str());
			screen._windows[35].writeString(msg);
			screen._windows[35].update();
		}
		// TODO
	} while (!_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;
}

void Town::drawTownAnim(bool flag) {
	Interface &intf = *_vm->_interface;
	Screen &screen = *_vm->_screen;
	Sound &sound = *_vm->_sound;
	bool isDarkCc = _vm->_files->_isDarkCc;

	if (_townActionId == 1) {
		if (sound.isPlaying()) {
			if (isDarkCc) {
				_townSprites[_drawFrameIndex / 8].draw(screen, _drawFrameIndex % 8, _townPos);
				_townSprites[2].draw(screen, _vm->getRandomNumber(11) == 1 ? 9 : 10,
					Common::Point(34, 33));
				_townSprites[2].draw(screen, _vm->getRandomNumber(5) + 3,
					Common::Point(34, 54));
			}
		} else {
			_townSprites[_drawFrameIndex / 8].draw(screen, _drawFrameIndex % 8, _townPos);
			if (isDarkCc) {
				_townSprites[2].draw(screen, _vm->getRandomNumber(11) == 1 ? 9 : 10,
					Common::Point(34, 33));
			}
		}
	} else {
		if (!isDarkCc || _townActionId != 5) {
			if (!_townSprites[_drawFrameIndex / 8].empty())
				_townSprites[_drawFrameIndex / 8].draw(screen, _drawFrameIndex % 8, _townPos);
		}
	}

	switch (_townActionId) {
	case 0:
		if (sound.isPlaying() || (isDarkCc && intf._overallFrame)) {
			if (isDarkCc) {
				if (sound.isPlaying() || intf._overallFrame == 1) {
					_townSprites[4].draw(screen, _vm->getRandomNumber(13, 18),
						Common::Point(8, 30));
				} else if (intf._overallFrame > 1) {
					_townSprites[4].draw(screen, 13 - intf._overallFrame++,
						Common::Point(8, 30));
					if (intf._overallFrame > 14)
						intf._overallFrame = 0;
				}
			} else {
				_townSprites[2].draw(screen, _vm->getRandomNumber(7, 11), Common::Point(8, 8));
			}
		}
		break;

	case 2:
		if (sound.isPlaying()) {
			if (isDarkCc) {
				if (intf._overallFrame) {
					intf._overallFrame ^= 1;
					_townSprites[6].draw(screen, intf._overallFrame, Common::Point(8, 106));
				} else {
					_townSprites[6].draw(screen, _vm->getRandomNumber(3), Common::Point(16, 48));
				}
			}
		}
		break;

	case 3:
		if (sound.isPlaying() && isDarkCc) {
			_townSprites[4].draw(screen, _vm->getRandomNumber(7), Common::Point(153, 49));
		}
		break;
	case 4:
		if (sound.isPlaying()) {
			_townSprites[3].draw(screen, _vm->getRandomNumber(2, 4), Common::Point(8, 8));

		}
		break;

	case 5:
		if (sound.isPlaying()) {
			if (isDarkCc) {
				_townSprites[_drawFrameIndex / 8].draw(screen, _drawFrameIndex % 8, _townPos);
			}
		} else {
			if (isDarkCc) {
				_townSprites[0].draw(screen, ++intf._overallFrame % 8, Common::Point(8, 8));
				_townSprites[5].draw(screen, _vm->getRandomNumber(5), Common::Point(61, 74));
			} else {
				_townSprites[1].draw(screen, _vm->getRandomNumber(8, 12), Common::Point(8, 8));
			}
		}
	}

	if (flag) {
		intf._face1UIFrame = 0;
		intf._face2UIFrame = 0;
		intf._dangerSenseUIFrame = 0;
		intf._spotDoorsUIFrame = 0;
		intf._levitateUIFrame = 0;

		intf.assembleBorder();
	}

	if (screen._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 == 1 && (_drawFrameIndex == 4 || _drawFrameIndex == 13))
			sound.playFX(45);

		if (_townActionId == 5 && _drawFrameIndex == 23) {
			sound.playSound("spit1.voc");
		}
	} else {
		if (_townMaxId == 32 && _drawFrameIndex == 0)
			_drawFrameIndex = 17;
		if (_townMaxId == 26 && _drawFrameIndex == 0)
			_drawFrameIndex = 20;
		if (_townActionId == 1 && (_drawFrameIndex == 3 || _drawFrameIndex == 9))
			sound.playFX(45);
	}

	screen._windows[3].update();
}

bool Town::isActive() const {
	return _townSprites.size() > 0 && !_townSprites[0].empty();
}

void Town::clearSprites() {
	_townSprites.clear();
}

/*------------------------------------------------------------------------*/

bool TownMessage::show(XeenEngine *vm, int portrait, const Common::String &name,
		const Common::String &text, int confirm) {
	TownMessage *dlg = new TownMessage(vm);
	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 = *_vm->_events;
	Interface &intf = *_vm->_interface;
	Screen &screen = *_vm->_screen;
	Town &town = *_vm->_town;
	Window &w = screen._windows[11];

	town._townMaxId = 4;
	town._townActionId = 7;
	town._drawFrameIndex = 0;
	town._townPos = Common::Point(23, 22);

	if (!confirm)
		loadButtons();

	if (town._townSprites[0].empty()) {
		town._townSprites[0].load(Common::String::format("face%02d.fac", portrait));
		town._townSprites[1].load("frame.fac");
	}

	if (!w._enabled)
		w.open();

	int result = -1;
	Common::String msgText = text;
	for (;;) {
		Common::String msg = Common::String::format("\r\v014\x03c\t125%s\t000\v054%s",
			name.c_str(), msgText.c_str());
		const char *msgEnd = w.writeString(msg.c_str());
		int wordCount = 0;

		for (const char *msgP = msg.c_str(); msgP < msgEnd; ++msgP) {
			if (*msgP == ' ')
				++wordCount;
		}

		town._drawCtr2 = wordCount * 2;
		town._townSprites[1].draw(screen, 0, Common::Point(16, 16));
		town._townSprites[0].draw(screen, town._drawFrameIndex, Common::Point(23, 22));
		w.update();

		if (!msgEnd) {
			// Doesn't look like the code here in original can ever be reached
			assert(0);
		}

		if (confirm == 2) {
			intf._face1State = intf._face2State = 2;
			return false;
		}

		do {
			events.clearEvents();
			events.updateGameCounter();
			if (msgEnd)
				clearButtons();

			do {
				events.wait(3);
				checkEvents(_vm);
				if (_vm->shouldQuit())
					return false;

				town.drawTownAnim(false);
				events.updateGameCounter();
			} while (!_buttonValue);

			if (msgEnd)
				break;

			if (!msgEnd) {
				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) {
			msgText = Common::String(msgEnd);
			town._drawCtr2 = wordCount;
			continue;
		}
	} while (result == -1);

	intf._face1State = intf._face2State = 2;
	if (!confirm)
		intf.mainIconsPrint();

	town._townSprites[0].clear();
	town._townSprites[1].clear();
	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