/* 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 */


#ifdef ENABLE_EOB

#include "kyra/engine/eob.h"
#include "kyra/graphics/screen_eob.h"
#include "kyra/graphics/screen_eob_segacd.h"
#include "kyra/gui/gui_eob_segacd.h"
#include "kyra/resource/resource.h"
#include "kyra/resource/resource_segacd.h"

#include "common/system.h"

namespace Kyra {

int EoBEngine::clickedCamp(Button *button) {
	gui_resetAnimations();

	if (_flags.platform == Common::kPlatformSegaCD)
		snd_playSong(11);

	EoBCoreEngine::clickedCamp(button);

	if (_flags.platform != Common::kPlatformSegaCD)
		return button->arg;

	gui_resetAnimations();

	return button->arg;
}

void EoBEngine::gui_drawPlayField(bool refresh) {
	if (_flags.platform != Common::kPlatformSegaCD) {
		EoBCoreEngine::gui_drawPlayField(refresh);
		return;
	}

	_screen->sega_fadeToBlack(_loading ? 0 : 1);
	_screen->sega_selectPalette(6, 1);
	_screen->sega_selectPalette(7, 3);

	// transposeScreenOutputY(8);
	_txt->clearDim(0);
	_screen->sega_getAnimator()->clearSprites();
	_screen->sega_getAnimator()->update();
	SegaRenderer *r = _screen->sega_getRenderer();
	r->fillRectWithTiles(0, 0, 0, 40, 28, 0);
	r->fillRectWithTiles(1, 0, 0, 40, 28, 0);

	uint8 *data = _res->fileData("PLAYFLD", 0);
	for (int i = 0; i < 256; ++i)
		r->loadToVRAM(&data[i << 5], 32, _addrTbl1[i] << 5);
	memcpy(_compassData, data + 0x2000, 0x5000);
	delete[] data;

	const uint16 *pattern = _playFldPattern1;
	uint16 *dst = _playFldPattern2;

	for (int i = 0; i < 1040; ++i) {
		int ix = (*pattern++) - 11;
		*dst++ = (ix < 0) ? 0 : _addrTbl1[ix];
	}

	static const uint16 ps[6] = { 0xCE, 0xE0, 0x2FE, 0x310, 0x52E, 0x540 };

	for (int i = 0; i < 4; ++i) {
		dst = &_playFldPattern2[ps[i] >> 1];
		memset(dst, 0, 8);
		memset(&dst[40], 0, 8);
		memset(&dst[80], 0, 8);
		memset(&dst[120], 0, 8);
	}

	_sres->loadContainer("ITEM");
	Common::SeekableReadStreamEndian *str = _sres->resStreamEndian(7);
	r->loadStreamToVRAM(str, 0x8880, true);
	delete str;
	str = _sres->resStreamEndian(9);
	r->loadStreamToVRAM(str, 0xA4A0, false);
	delete str;
	str = _sres->resStreamEndian(10);
	r->loadStreamToVRAM(str, 0x7920, false);
	delete str;

	gui_setupPlayFieldHelperPages();

	if (refresh && !_sceneDrawPage2)
		drawScene(1);

	_screen->copyRegionToBuffer(0, 173, 0, 6, 120, _shakeBackBuffer1);
	_screen->copyRegionToBuffer(0, 0, 117, 179, 6, _shakeBackBuffer2);

	// Since we're not going to draw the character portrait boxes with the SegaRenderer but rather with our "normal" code, we have to backup
	// some parts of the background between the character portraits. Unlike in the other versions the red splat shapes overlaps with that space.
	for (int i = 0; i < 6; ++i) {
		delete[] _redSplatBG[i];
		_redSplatBG[i] = new uint8[_redSplatShape[2] << 5];
		_screen->copyRegionToBuffer(0, guiSettings()->charBoxCoords.boxX[i & 1] + guiSettings()->charBoxCoords.redSplatOffsetX, guiSettings()->charBoxCoords.boxY[i >> 1] + guiSettings()->charBoxCoords.boxHeight - 1, _redSplatShape[2] << 3, 4, _redSplatBG[i]);
	}
	for (int i = 2; i < 4; ++i) {
		if (_characters[i + 2].flags & 1)
			memcpy(_redSplatBG[i] + _redSplatShape[2] * 24, _redSplatBG[0] + _redSplatShape[2] * 24, _redSplatShape[2] << 3);
	}

	_compassDirection2 = -1;
	gui_drawCompass(false);

	_screen->sega_fadeToNeutral(1);
}

void EoBEngine::gui_setupPlayFieldHelperPages(bool keepText) {
	if (_flags.platform != Common::kPlatformSegaCD) {
		EoBCoreEngine::gui_setupPlayFieldHelperPages();
		return;
	}

	if (!keepText)
		_txt->clearDim(0);

	SegaRenderer *r = _screen->sega_getRenderer();
	r->loadToVRAM(_scrYellow, 4992, 0x3CE0);
	r->fillRectWithTiles(0, 0, 0, 22, 21, 0);
	r->fillRectWithTiles(0, 22, 0, 18, 21, 0);
	r->fillRectWithTiles(1, 0, 0, 40, 26, 0x2000, true, false, _playFldPattern2);
	r->fillRectWithTiles(0, 0, 21, 40, 5, 0x2000, true, false, _textFieldPattern);
	// Nametables for scene window vcn block tiles. We don't need that. We draw the blocks with our "normal" graphics code.
	// r->fillRectWithTiles(1, 0, 0, 22, 15, 0xC14B, true, true);
	// Nametables for scene window shapes tiles. We don't need that, since we're not going to draw any scene shapes with the renderer.
	// r->fillRectWithTiles(0, 0, 1, 22, 14, 0xE295, true, true);
	// Text field tiles
	r->fillRectWithTiles(0, 1, 22, 35, 3, 0x2597, true);
	r->render(0);
	r->fillRectWithTiles(1, 22, 0, 18, 21, 0x6444, true, true, _invPattern);
	r->render(2);
	r->fillRectWithTiles(1, 22, 0, 18, 21, 0x6444, true, true, _statsPattern);
	r->render(Screen_EoB::kSegaRenderPage);
	_screen->copyRegion(184, 1, 176, 168, guiSettings()->charBoxCoords.boxWidth, 24, 0, 2, Screen::CR_NO_P_CHECK);
	_screen->copyRegion(184, 25, 240, 168, guiSettings()->charBoxCoords.boxWidth, guiSettings()->charBoxCoords.boxHeight - 24, 0, 2, Screen::CR_NO_P_CHECK);
}

void EoBEngine::gui_drawWeaponSlotStatus(int x, int y, int status) {
	if (_flags.platform != Common::kPlatformSegaCD) {
		EoBCoreEngine::gui_drawWeaponSlotStatus(x, y, status);
		return;
	}

	if (status < 0) {
		_screen->drawShape(_screen->_curPage, _weaponSlotShapes[status < -2 ? -status - 1 : 3 - status], x - 1, y, 0);
	} else {
		_screen->drawShape(_screen->_curPage, _weaponSlotShapes[0], x - 1, y, 0);
		gui_printInventoryDigits(x + 8, y + 6, status);
	}
}

void EoBEngine::gui_printInventoryDigits(int x, int y, int val) {
	if (_flags.platform != Common::kPlatformSegaCD) {
		EoBCoreEngine::gui_printInventoryDigits(x, y, val);
		return;
	}
	_screen->drawShape(_screen->_curPage, _invSmallDigits[(val < 10) ? 22 + val : (val >= 100 ? 1 : 2 + val / 10)], x, y, 0);
	_screen->drawShape(_screen->_curPage, (val >= 10 && val < 100) ? _invSmallDigits[12 + (val % 10)] : 0, x, y, 0);
}

void EoBEngine::gui_drawCharacterStatsPage() {
	if (_flags.platform != Common::kPlatformSegaCD) {
		EoBCoreEngine::gui_drawCharacterStatsPage();
		return;
	}

	SegaRenderer *r = _screen->sega_getRenderer();
	EoBCharacter *c = &_characters[_updateCharNum];

	memset(_tempPattern, 0, 792);
	for (int i = 0; i < 11; ++i) {
		_tempPattern[5 * 18 + i + 1] = 0x6555 + i;
		_tempPattern[6 * 18 + i + 1] = 0x6565 + i;
	}

	for (int i = 0; i < 4; i++)
		printStatsString(_chargenStatStrings[6 + i], 1, 11 + i);
	printStatsString(_chargenStatStrings[10], 7, 16);

	printStatsString(_chargenClassStrings[c->cClass == 9 ? 27 : (c->cClass == 12 ? 28 : c->cClass)], 2, 7);
	printStatsString(_chargenAlignmentStrings[c->alignment], 2, 8);
	printStatsString(_chargenRaceSexStrings[c->raceSex], 2, 9);

	// FIXME? For now I have kept the exact original layout. If the character has a strengthExt stat there will be
	// no space left between the digits and the right stats row ("DEX" etc.). Maybe I should move that row one tile
	// further to the right? There is space enough left over there.
	printStatsString(getCharStrength(c->strengthCur, c->strengthExtCur).c_str(), c->strengthExtCur ? 4 : 5, 11);
	printStatsString(Common::String::format("%2d", c->intelligenceCur).c_str(), 5, 12);
	printStatsString(Common::String::format("%2d", c->wisdomCur).c_str(), 5, 13);
	printStatsString(Common::String::format("%2d", c->dexterityCur).c_str(), 13, 11);
	printStatsString(Common::String::format("%2d", c->constitutionCur).c_str(), 13, 12);
	printStatsString(Common::String::format("%2d", c->charismaCur).c_str(), 13, 13);
	printStatsString(Common::String::format("%2d", c->armorClass).c_str(), _flags.lang == Common::JA_JPN ? 9 : 5, 14);

	for (int i = 0; i < 3; i++) {
		int t = getCharacterClassType(c->cClass, i);
		if (t == -1)
			continue;
		printStatsString(_chargenClassStrings[t + 21], 1, 17 + i);
		printStatsString(Common::String::format("%2d", c->level[i]).c_str(), 14, 17 + i);
		printStatsString(Common::String::format("%6d", c->experience[i]).c_str(), 7, 17 + i);
	}

	r->fillRectWithTiles(0, 22, 0, 18, 21, 0, true, true, _tempPattern);
	r->render(2, 22, 5, 18, 16);
}

void EoBEngine::gui_displayMap() {
	disableSysTimer(2);

	_screen->sega_fadeToBlack(2);
	Button b;
	clickedSpellbookAbort(&b);
	gui_resetAnimations();
	for (int i = 0; i < 6; i++) {
		if (!testCharacter(i, 1))
			continue;
		_characters[i].damageTaken = 0;
		_characters[i].slotStatus[0] = _characters[i].slotStatus[1] = 0;
		gui_drawCharPortraitWithStats(i);
	}

	SegaRenderer *r = _screen->sega_getRenderer();
	r->fillRectWithTiles(0, 0, 0, 40, 28, 0);
	r->fillRectWithTiles(1, 0, 0, 40, 28, 0);
	_screen->sega_getAnimator()->clearSprites();
	_screen->sega_getAnimator()->update();
	_screen->sega_selectPalette(55, 1);
	_screen->sega_selectPalette(56, 2);

	snd_stopSound();
	_sres->loadContainer("MAP");
	Common::SeekableReadStreamEndian *in = _sres->resStreamEndian(0);
	r->loadStreamToVRAM(in, 0x20);
	delete in;
	in = _sres->resStreamEndian(1);
	r->loadStreamToVRAM(in, 0x80);
	delete in;


	int cs = _screen->setFontStyles(_screen->_currentFont, _flags.lang == Common::JA_JPN ? Font::kStyleNone : Font::kStyleFullWidth);

	_screen->sega_clearTextBuffer(0);
	for (int i = 0; i < 3; ++i)
		drawMapButton(_mapStrings1[i], 0, i << 4);
	_screen->sega_loadTextBufferToVRAM(0, 0x7E20, 1536);
	r->fillRectWithTiles(0, 31, 19, 8, 6, 0x63F1, true);
	_screen->sega_clearTextBuffer(0);

	_screen->sega_clearTextBuffer(0);
	_txt->printShadedText(_mapStrings2[_currentLevel - 1], 0, 0, 0xFF, 0, 64, 16, 0, false);
	_screen->sega_loadTextBufferToVRAM(0, 0x7C20, 512);
	r->fillRectWithTiles(0, 31, 16, 8, 2, 0x63E1, true);

	drawMapPage(_currentLevel);
	r->render(0);
	_screen->sega_fadeToNeutral(3);

	gui_resetButtonList();
	for (int i = 96; i < 99; ++i)
		gui_initButton(i);

	int animState = 0;
	for (int level = _currentLevel; level && !shouldQuit(); ) {
		uint32 del = _system->getMillis() + 16;
		int inputFlag = checkInput(_activeButtons, false, 0);
		removeInputTop();

		drawMapSpots(level, animState < 20 ? 0 : 1);
		bool needupdate = (animState == 0 || animState == 20);
		if (++animState == 40)
			animState = 0;

		int op = (inputFlag & 0x8000) ? (int16)gui_getButton(_activeButtons, inputFlag & 0xFF)->arg : 0;
		if (op) {
			snd_playSoundEffect(0x81);
			level = (op == 2) ? 0 : CLIP(level + op, 1, 12);
			if (level)
				drawMapPage(level);
		}

		if (needupdate) {
			r->render(0);
			_screen->updateScreen();
		}
		delayUntil(del);
	}

	_screen->setFontStyles(_screen->_currentFont, cs);
	_screen->sega_fadeToBlack(3);

	setLevelPalettes(_currentLevel);
	gui_drawPlayField(true);
	gui_drawAllCharPortraitsWithStats();
	gui_setInventoryButtons();
	snd_playLevelScore();

	enableSysTimer(2);
}

void EoBEngine::gui_drawSpellbook() {
	if (_flags.platform != Common::kPlatformSegaCD) {
		EoBCoreEngine::gui_drawSpellbook();
		return;
	}

	SegaRenderer *r = _screen->sega_getRenderer();
	r->fillRectWithTiles(0, 10, 15, 12, 7, 0);
	r->fillRectWithTiles(1, 10, 15, 12, 7, 0x6429);
	memset(_tempPattern, 0, 168);
	uint16 *dst = _tempPattern;

	for (int i = 0; i < 6; ++i) {
		dst[0] = 0x642B + 2 * i + (i == _openBookSpellLevel ? 0 : 12);
		dst[1] = dst[0] + 1;
		dst += 2;
	}

	for (int i = 0; i < 6; ++i) {
		int d = _openBookAvailableSpells[_openBookSpellLevel * 10 + i];
		if (d < 0)
			continue;
		printSpellbookString(&_tempPattern[(i + 1) * 12], _openBookSpellList[d], (i == _openBookSpellSelectedItem) ? 0x6223 : 0x63C9);
	}

	r->fillRectWithTiles(0, 10, 15, 12, 7, 0, true, false, _tempPattern);
	r->render(Screen_EoB::kSegaRenderPage, 10, 15, 12, 7);

	// The original SegaCD version actually doesn't disable the spell book after use but closes it instead.
	if (!_closeSpellbookAfterUse) {
		if (_characters[_openBookChar].disabledSlots & 4) {
			static const uint8 xpos[] = { 0x44, 0x62, 0x80, 0x90 };
			static const uint8 ypos[] = { 0x80, 0x90, 0xA0 };
			for (int yc = 0; yc < 3; yc++) {
				for (int xc = 0; xc < 4; xc++)
					_screen->drawShape(Screen_EoB::kSegaRenderPage, _weaponSlotGrid, xpos[xc], ypos[yc], 0);
			}
		}
	}

	_screen->copyRegion(80, 120, 80, 120, 96, 56, Screen_EoB::kSegaRenderPage, 0, Screen::CR_NO_P_CHECK);
	if (!_loading)
		_screen->updateScreen();
}

void EoBEngine::gui_updateAnimations() {
	if (_flags.platform != Common::kPlatformSegaCD)
		return;

	bool updScreen = false;
	bool redrawCompass = false;

	// Compass
	if (_compassDirection != _compassDirection2) {
		_compassAnimDest = _compassDirection << 2;
		int diff = _compassAnimDest - _compassAnimPhase;
		if (diff < 0)
			diff += 16;
		if (diff) {
			_compassAnimStep = (diff < 8) ? 1 : -1;
			_compassAnimDone = false;
		}
		_compassDirection2 = _compassDirection;
		redrawCompass = true;
	}
	if (_compassAnimDelayCounter) {
		--_compassAnimDelayCounter;
	} else if (!redrawCompass) {
		if (_compassAnimDest != _compassAnimPhase) {
			_compassAnimPhase = (_compassAnimPhase + _compassAnimStep) & 0x0F;
			_compassAnimDelayCounter = 6;
			redrawCompass = true;
		} else if (!_compassAnimDone) {
			if (_compassAnimSwitch) {
				_compassAnimPhase = (_compassAnimPhase + _compassAnimStep) & 0x0F;
				_compassAnimDelayCounter = 6;
				_compassAnimStep = -_compassAnimStep;
				_compassAnimSwitch = false;
			} else {
				_compassAnimDone = _compassAnimSwitch = true;
			}
			redrawCompass = true;
		}
	}
	if (_updateFlags)
		_compassTilesRestore = true;
	else if (_compassTilesRestore) {
		_screen->sega_getRenderer()->fillRectWithTiles(0, 10, 15, 12, 7, 0);
		for (int i = 15; i < 22; ++i)
			_screen->sega_getRenderer()->fillRectWithTiles(1, 10, i, 12, 1, 0x2000, true, true, &_playFldPattern2[i * 40 + 10]);
		_compassTilesRestore = false;
	}
	if (redrawCompass) {
		_screen->sega_getRenderer()->loadToVRAM(_compassData + (_compassAnimPhase & 0x0F) * 0x500, 0x500, 0xEE00);
		_screen->sega_getRenderer()->render(0, 11, 15, 10, 6);
		updScreen = true;
	}

	// Red grid effect
	for (int i = 0; i < 6; ++i) {
		if (!_characters[i].gfxUpdateCountdown)
			continue;
		_characters[i].gfxUpdateCountdown--;
		int cp = _screen->setCurPage(0);

		if (!_currentControlMode && (_characters[i].gfxUpdateCountdown & 1))
			_screen->drawShape(0, _redGrid, 176 + guiSettings()->charBoxCoords.facePosX_1[i & 1], guiSettings()->charBoxCoords.facePosY_1[i >> 1], 0);
		else if (_currentControlMode && _updateCharNum == i && (_characters[i].gfxUpdateCountdown & 1))
			_screen->drawShape(0, _redGrid, guiSettings()->charBoxCoords.facePosX_2[0], guiSettings()->charBoxCoords.facePosY_2[0], 0);
		else
			gui_drawFaceShape(i);

		_screen->setCurPage(cp);
		updScreen = true;
	}

	// Scene shake
	if (_sceneShakeCountdown) {
		--_sceneShakeCountdown;
		_sceneShakeOffsetX = _sceneShakeOffsets[_sceneShakeCountdown << 1];
		_sceneShakeOffsetY = _sceneShakeOffsets[(_sceneShakeCountdown << 1) + 1];
		_screen->fillRect(0, 0, 2, 119, 0, _sceneDrawPage1);
		_screen->fillRect(0, 0, 175, 2, 0, _sceneDrawPage1);
		_screen->copyBlockToPage(_sceneDrawPage1, 173, 0, 6, 120, _shakeBackBuffer1);
		_screen->copyBlockToPage(_sceneDrawPage1, 0, 117, 179, 6, _shakeBackBuffer2);
		if (_updateFlags)
			_screen->copyRegion(64, 120, 64, 120, 112, 3, Screen_EoB::kSegaRenderPage, _sceneDrawPage1);
		_screen->copyBlockToPage(_sceneDrawPage1, _sceneXoffset + _sceneShakeOffsetX, _sceneShakeOffsetY, 176, 120, _sceneWindowBuffer);

		// For whatever reason the original shakes all types of shapes (decorations, doors, etc.) except the monsters and
		// the items lying on the floor. So we do the same. I've added drawing flags to drawSceneShapes() which allow
		// separate drawing passes for the different shape types.
		for (int i = 0; i < 18; i++) {
			_shapeShakeOffsetX = _sceneShakeOffsetX;
			_shapeShakeOffsetY = _sceneShakeOffsetY;
			// All shapes except monsters and items
			drawSceneShapes(i, i + 1, 0xFF & ~0x2A);
			_shapeShakeOffsetX = _shapeShakeOffsetY = 0;
			// Monsters and items
			drawSceneShapes(i, i + 1, 0x2A);
		}
		_screen->copyRegion(0, 0, 0, 0, 179, 123, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK);
		updScreen = true;
	}

	if (updScreen)
		_screen->updateScreen();
}

void EoBEngine::gui_resetAnimations() {
	if (_flags.platform != Common::kPlatformSegaCD)
		return;

	for (int i = 0; i < 6; ++i)
		_characters[i].gfxUpdateCountdown = 1;
	_sceneShakeCountdown = 1;
	_compassAnimDelayCounter = _compassAnimSwitch = 0;
	_compassAnimPhase = _compassAnimDest;
}

void EoBEngine::makeNameShapes(int charId) {
	if (_flags.platform != Common::kPlatformSegaCD)
		return;

	int first = 0;
	int last = 5;
	if (charId != -1)
		first = last = charId;

	int cd = _txt->clearDim(4);
	int cp = _screen->setCurPage(2);
	_screen->sega_getRenderer()->fillRectWithTiles(1, 0, 0, 40, 28, 0x2000);
	_screen->sega_getRenderer()->fillRectWithTiles(0, 0, 0, 30, 28, 0x600A, true);
	_screen->sega_clearTextBuffer(0);
	int cs = _screen->setFontStyles(_screen->_currentFont, Font::kStyleForceOneByte);

	uint8 *in = _res->fileData("FACE", 0);
	for (int i = first; i <= last; ++i) {
		if (!_characters[i].flags)
			continue;
		if (_characters[i].portrait < 0) {
			_screen->sega_getRenderer()->loadToVRAM(in + 27424 - _characters[i].portrait * 224, 224, 0x3F00 + i * 0xE0);
			_screen->sega_getRenderer()->fillRectWithTiles(0, 0, i << 1, 7, 1, 0x61F8 + i * 7, true);
		} else {
			_txt->printShadedText(_characters[i].name, 0, i << 4, 0xFF, 0xCC);
		}
	}
	delete[] in;

	_screen->sega_getRenderer()->render(_screen->_curPage, 0, 0, 8, 12);
	for (int i = first; i <= last; ++i) {
		if (!_characters[i].flags)
			continue;
		delete[] _characters[i].nameShape;
		_characters[i].nameShape = _screen->encodeShape(0, i << 4, 8, 13);
	}

	_screen->clearPage(2);
	_screen->setCurPage(cp);
	_screen->sega_clearTextBuffer(0);
	_screen->setFontStyles(_screen->_currentFont, cs);

	_txt->clearDim(4);
	_txt->clearDim(cd);
}

void EoBEngine::makeFaceShapes(int charId) {
	if (_flags.platform != Common::kPlatformSegaCD) {
		EoBCoreEngine::makeFaceShapes();
		return;
	}

	int first = 0;
	int last = 5;
	if (charId != -1)
		first = last = charId;

	uint8 *in = _res->fileData("FACE", 0);
	for (int i = first; i <= last; i++) {
		EoBCharacter *c = &_characters[i];
		if (!c->flags)
			continue;
		_screen->sega_encodeShapesFromSprites(&c->faceShape, &in[(c->portrait < 0 ? -c->portrait + 43 : c->portrait) << 9], 1, 32, 32, 3);
	}
	delete[] in;
}

void EoBEngine::printStatsString(const char *str, int x, int y) {
	uint16 *dst = &_tempPattern[y * 18 + x];
	for (const uint8 *pos = (const uint8*)str; *pos; ++pos)
		*dst++ = 0x6525 + _charTilesTable[*pos];
}

void EoBEngine::printSpellbookString(uint16 *dst, const char *str, uint16 ntbl) {
	assert(str);
	const uint8 *in = (const uint8*)str;
	for (uint8 c = *in++; c; c = *in++) {
		if (_flags.lang == Common::JA_JPN) {
			if (c > 165 && c < 222)
				*dst = ntbl + c - 166;
			else if (c == 32)
				*dst = ntbl + 82;
			else if (c > 47 && c < 58)
				*dst = ntbl + c + 35;
			else if (c == 47)
				*dst = ntbl + 93;
			else if (c == 165)
				*dst = ntbl + 94;
			else if (c == 43)
				*dst = ntbl + 95;

			if (*in == 222) {
				if (c > 181 && c < 197) {
					*dst = ntbl + c - 121;
					++in;
				} else if (c > 201 && c < 207) {
					*dst = ntbl + c - 126;
					++in;
				} else if (c == 179) {
					*dst = ntbl + c + 81;
					++in;
				}
			} else if (*in == 223 && c > 201 && c < 207) {
				*dst = ntbl + c - 146;
				++in;
			}

		} else {
			if (c > 31 && c < 128)
				*dst = ntbl + c - 32;
		}
		dst++;
	}
}

void EoBEngine::drawMapButton(const char *str, int x, int y) {
	_screen->sega_drawClippedLine(8, 9, x, y, 64, 14, 0x99);
	_screen->sega_drawClippedLine(8, 9, x, y + 1, 63, 13, 0xBB);
	_screen->sega_drawClippedLine(8, 9, x + 1, y + 1, 62, 12, 0xAA);
	_txt->printShadedText(str, x + 14, y + 1, 0xFF, 0xCC, 64, 72, 0, false);
}

void EoBEngine::drawMapPage(int level) {
	_screen->sega_clearTextBuffer(0);
	int cs = _screen->setFontStyles(_screen->_currentFont, (_flags.lang == Common::JA_JPN ? Font::kStyleNone : Font::kStyleFullWidth) | Font::kStyleNarrow1);
	_txt->printShadedText(_mapStrings3[level - 1], 0, 0, 0xCC, 0, 48, 16, 0, false);
	_screen->setFontStyles(_screen->_currentFont, cs);
	_screen->sega_loadTextBufferToVRAM(0, 0x7920, 384);
	SegaRenderer *r = _screen->sega_getRenderer();
	r->fillRectWithTiles(0, 23, 8, 6, 2, 0x63C9, true);

	Common::SeekableReadStreamEndian *in = _sres->resStreamEndian(hasLevelMap(level) ? 2 + level : 2);
	r->loadStreamToVRAM(in, 0x5500, true);
	delete in;
	r->fillRectWithTiles(1, 3, 0, 26, 26, 0x2004, true);
	r->fillRectWithTiles(0, 5, 6, 17, 17, 0x42A8, true);
}

void EoBEngine::drawMapSpots(int level, int animState) {
	SegaAnimator *a = _screen->sega_getAnimator();
	const EoBItem &m = _items[447 + level];
	int curX = _currentBlock & 0x1F;
	int curY = _currentBlock >> 5;
	int mX = m.block & 0x1F;
	int mY = m.block >> 5;

	if (hasLevelMap(level)) {
		if (!animState && level == _currentLevel)
			a->initSprite(0, (curX << 2) + 48, (curY << 2) + 56, 0x6001, 0);
		else
			a->initSprite(0, 0x4000, 0, 0, 0);
		a->initSprite(1, 0x4000, 0, 0, 0);
	} else {
		a->initSprite(0, 0x4000, 0, 0, 0);
		if (level == _currentLevel)
			a->initSprite(0, (curX << 2) + 48, (curY << 2) + 56, animState ? 0x2002 : 0x2001, 0);
		a->initSprite(1, (mX << 2) + 48, (mY << 2) + 56, animState ? 0x2002 : 0x2003, 0);
	}
	a->update();
}

void EoBEngine::drawDialogueButtons() {
	if (_flags.platform != Common::kPlatformSegaCD) {
		KyraRpgEngine::drawDialogueButtons();
		return;
	}

	_screen->sega_clearTextBuffer(0);

	for (int i = 0; i < _dialogueNumButtons; i++) {
		int cs = _screen->setFontStyles(_screen->_currentFont, (_flags.lang == Common::JA_JPN ? Font::kStyleNone : Font::kStyleFullWidth) | Font::kStyleNarrow2);
		if (_screen->getTextWidth(_dialogueButtonString[i]) > 90)
			_screen->setFontStyles(_screen->_currentFont, (_flags.lang == Common::JA_JPN ? Font::kStyleNone : Font::kStyleFullWidth) | Font::kStyleNarrow1);
		_screen->sega_drawClippedLine(38, 6, _dialogueButtonPosX[i], _dialogueButtonPosY[i], 90, 14, 0x99);
		_screen->sega_drawClippedLine(38, 6, _dialogueButtonPosX[i], _dialogueButtonPosY[i] + 1, 89, 13, 0xBB);
		_screen->sega_drawClippedLine(38, 6, _dialogueButtonPosX[i] + 1, _dialogueButtonPosY[i] + 1, 88, 12, 0xAA);
		_txt->printShadedText(_dialogueButtonString[i], _dialogueButtonPosX[i] + (_dialogueButtonWidth >> 1) - MIN<int>(_dialogueButtonWidth, _screen->getTextWidth(_dialogueButtonString[i])) / 2,
			_dialogueButtonPosY[i] + 1, _dialogueHighlightedButton == i ? _dialogueButtonLabelColor1 : _dialogueButtonLabelColor2, 0xEE, 304, 48, 0, false);
		_screen->setFontStyles(_screen->_currentFont, cs);
	}

	_screen->sega_loadTextBufferToVRAM(0, 0xA380, 7296);
	_screen->sega_getRenderer()->render(0);
}

GUI_EoB_SegaCD::GUI_EoB_SegaCD(EoBEngine *vm) : GUI_EoB(vm), _vm(vm), _clickableCharactersNumPages(vm->_textInputCharacterLinesSize) {
	_vm->_sres->loadContainer("ITEM");
	uint8 *cm = _vm->_sres->resData(8, 0);
	uint8 *cmdec = new uint8[47925];
	uint16 decodeSize = READ_LE_UINT16(cm + 2);
	_screen->decodeBIN(cm + 4, cmdec, decodeSize);
	_campMenu = cmdec;
	delete[] cm;

	const EoBMenuButtonDef* df = &_vm->_menuButtonDefs[6];
	_saveLoadCancelButton = new Button();
	_saveLoadCancelButton->index = 7;
	_saveLoadCancelButton->width = df->width;
	_saveLoadCancelButton->height = df->height;
	_saveLoadCancelButton->flags = df->flags;
	_saveLoadCancelButton->extButtonDef = df;
}

GUI_EoB_SegaCD::~GUI_EoB_SegaCD() {
	delete[] _campMenu;
	delete _saveLoadCancelButton;
}

void GUI_EoB_SegaCD::drawCampMenu() {
	_screen->sega_getRenderer()->loadToVRAM(_campMenu, 14784, 0x20);
	_screen->sega_getRenderer()->fillRectWithTiles(0, 0, 0, 22, 21, 0);
	_screen->sega_getRenderer()->fillRectWithTiles(1, 0, 0, 22, 21, 0x4001, true);
	_screen->sega_selectPalette(40, 2, true);
}

void GUI_EoB_SegaCD::initMemorizePrayMenu(int spellType) {
	_screen->sega_getRenderer()->fillRectWithTiles(0, 0, 0, 22, 21, 0);
	_screen->sega_getRenderer()->fillRectWithTiles(0, 1, 8, 20, 2, 0x62AB, true);
	_screen->sega_getRenderer()->fillRectWithTiles(0, 1, 4, 20, 4, 0x6283, true);
	_screen->sega_getRenderer()->memsetVRAM(0x5060, 0, 2560);
	_screen->sega_getRenderer()->memsetVRAM(0x5560, 0, 1280);
	_screen->sega_getRenderer()->loadToVRAM(&_campMenu[0x87C0], 4992, 0x3CE0);
	_screen->sega_clearTextBuffer(0);
	_vm->_txt->printShadedText(_vm->_menuStringsSpells[spellType ? 17 : 14], 0, 2, 0xFF, 0xCC, 160, 16, 0, false);
	_screen->sega_loadTextBufferToVRAM(0, 0x5060, 2560);
	_screen->sega_getRenderer()->render(0, 1, 4, 20, 2);
}

void GUI_EoB_SegaCD::initScribeScrollMenu() {
	_screen->sega_getRenderer()->fillRectWithTiles(0, 0, 0, 22, 21, 0);
	_screen->sega_getRenderer()->fillRectWithTiles(0, 1, 4, 20, 4, 0x6283, true);
	_screen->sega_getRenderer()->loadToVRAM(&_campMenu[0x87C0], 4992, 0x3CE0);
	_screen->sega_clearTextBuffer(0);
	_vm->_txt->printShadedText(getMenuString(48), 0, 3, 0xFF, 0xCC, 160, 16, 0, false);
	_screen->sega_loadTextBufferToVRAM(0, 0x5060, 2560);
	_screen->sega_getRenderer()->render(0, 1, 4, 20, 2);
}

void GUI_EoB_SegaCD::printScribeScrollSpellString(const int16 *menuItems, int id, bool highlight) {
	assert(menuItems);
	uint16 buf[22];
	memset(buf, 0, sizeof(buf));
	_vm->printSpellbookString(&buf[1], _vm->_mageSpellList[menuItems[id]], highlight ? 0x6223 : 0x63C9);
	_screen->sega_getRenderer()->fillRectWithTiles(0, 1, 10 + id, 20, 1, 0,  true, false, buf);
	_screen->sega_getRenderer()->render(0, 1, 10 + id, 20, 1);
}

void GUI_EoB_SegaCD::drawSaveSlotDialog(int x, int y, int id) {
	_screen->sega_getRenderer()->fillRectWithTiles(0, 0, 0, 22, 21, 0);
	_screen->sega_getRenderer()->fillRectWithTiles(0, (x >> 3) + 1, (y >> 3) + (y ? 3 : 4), 20, 2, 0x6283, true);
	_screen->sega_getRenderer()->fillRectWithTiles(0, (x >> 3) + (x ? 5 : 6), (y >> 3) + (y ? 6 : 7), 15, 10, 0x62AB, true);
	_screen->sega_getRenderer()->fillRectWithTiles(0, (x >> 3) + 1, (y >> 3) + 19, 7, 1, 0x6002, true);
	_screen->sega_getRenderer()->loadToVRAM(&_campMenu[0x87C0], 4992, 0x3CE0);
	_screen->sega_getRenderer()->memsetVRAM(0x5560, 0, 4480);
	_screen->sega_clearTextBuffer(0);
	_saveLoadCancelButton->x = ((const EoBMenuButtonDef*)_saveLoadCancelButton->extButtonDef)->x + x - (x ? 8 : 0);
	_saveLoadCancelButton->y = ((const EoBMenuButtonDef*)_saveLoadCancelButton->extButtonDef)->y + y;
	int cs = _screen->setFontStyles(_screen->_currentFont, _vm->gameFlags().lang == Common::JA_JPN ? Font::kStyleNone : Font::kStyleFullWidth);
	_vm->_txt->printShadedText(_vm->_saveLoadStrings[2 + id], 0, 3, 0xFF, 0xCC, 160, 16, 0, false);
	_screen->setFontStyles(_screen->_currentFont, cs);
	_screen->sega_loadTextBufferToVRAM(0, 0x5060, 1280);
	_screen->sega_getRenderer()->render(0, x >> 3, (y >> 3) + 1, 22, 21);
}

bool GUI_EoB_SegaCD::confirmDialogue(int id) {
	_screen->sega_clearTextBuffer(0);

	int cs = _vm->gameFlags().lang == Common::JA_JPN ? Font::kStyleNone : Font::kStyleFullWidth;
	if (id == 47) {
		cs |= Font::kStyleNarrow2;
		_screen->_charSpacing = 1;
	}
	cs = _screen->setFontStyles(_screen->_currentFont, cs);
	_vm->_txt->printShadedText(getMenuString(id), 0, 3, 0xFF, 0xCC, 160, 40, 0, false);
	_screen->_charSpacing = 0;
	_screen->setFontStyles(_screen->_currentFont, cs);

	_screen->sega_loadTextBufferToVRAM(0, 0x5060, 10240);
	_screen->sega_getRenderer()->fillRectWithTiles(0, 1, 0, 20, 20, 0);
	_screen->sega_getRenderer()->fillRectWithTiles(0, 1, 5, 20, 8, 0x6283, true);
	_screen->sega_getRenderer()->render(0, 1, 0, 22, 20);
	_screen->updateScreen();

	Button *buttonList = initMenu(5);

	int newHighlight = 0;
	int lastHighlight = -1;
	bool result = false;

	for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
		if (newHighlight != lastHighlight) {
			if (lastHighlight != -1)
				drawMenuButton(_vm->gui_getButton(buttonList, lastHighlight + 33), false, false, true);
			drawMenuButton(_vm->gui_getButton(buttonList, newHighlight + 33), false, true, true);
			_screen->updateScreen();
			lastHighlight = newHighlight;
		}

		int inputFlag = _vm->checkInput(buttonList, false, 0) & 0x80FF;
		_vm->removeInputTop();

		if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP5] || inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN]) {
			result = lastHighlight == 0;
			inputFlag = 0x8012 + lastHighlight;
			runLoop = false;
		} else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP4] || inputFlag == _vm->_keyMap[Common::KEYCODE_LEFT] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP6] || inputFlag == _vm->_keyMap[Common::KEYCODE_RIGHT]) {
			newHighlight ^= 1;
		} else if (inputFlag == 0x8012) {
			result = true;
			runLoop = false;
		} else if (inputFlag == 0x8013) {
			result = false;
			runLoop = false;
		} else {
			Common::Point p = _vm->getMousePos();
			for (Button *b = buttonList; b; b = b->nextButton) {
				if ((b->arg & 2) && _vm->posWithinRect(p.x, p.y, b->x, b->y, b->x + b->width, b->y + b->height))
					newHighlight = b->index - 18;
			}
		}

		if (!runLoop) {
			Button *b = _vm->gui_getButton(buttonList, lastHighlight + 18);
			drawMenuButton(b, true, true, true);
			_screen->updateScreen();
			_vm->_system->delayMillis(80);
			drawMenuButton(b, false, true, true);
			_screen->updateScreen();
		}
	}

	releaseButtons(buttonList);

	return result;
}

void GUI_EoB_SegaCD::displayTextBox(int id, int textColor, bool wait) {
	_screen->sega_getRenderer()->fillRectWithTiles(0, 0, 0, 22, 20, 0);
	_screen->sega_clearTextBuffer(0);
	int cs = _vm->gameFlags().lang == Common::JA_JPN ? Font::kStyleNone : Font::kStyleFullWidth;
	if (id == 23 || id == 26 || id == 49)
		cs |= Font::kStyleNarrow2;
	cs = _screen->setFontStyles(_screen->_currentFont, cs);
	_vm->_txt->printShadedText(getMenuString(id), 0, 0, textColor, 0xCC, 160, 40, 0, false);
	_screen->sega_loadTextBufferToVRAM(0, 0x5060, 3200);
	_screen->setFontStyles(_screen->_currentFont, cs);
	_screen->sega_getRenderer()->fillRectWithTiles(0, 1, 6, 20, 5, 0x6283, true);
	_screen->sega_getRenderer()->render(0, 0, 1, 22, 19);
	_screen->updateScreen();
	if (!wait)
		return;

	_vm->resetSkipFlag();
	while (!(_vm->shouldQuit() || _vm->skipFlag()))
		_vm->delay(20);
	_vm->resetSkipFlag();
}

void GUI_EoB_SegaCD::drawMenuButton(Button *b, bool clicked, bool highlight, bool noFill) {
	if (!b)
		return;

	const MenuButtonTiles &t = _menuButtonTiles[b->index - 1];
	if (!t.nameTbl)
		return;

	_screen->sega_getRenderer()->loadToVRAM(&_campMenu[(0x1CE + t.srcOffs + (clicked ? 1 : 0) * ((b->width * b->height) >> 6)) << 5], (b->width * b->height) >> 1, t.nameTbl << 5);
	_screen->sega_getRenderer()->fillRectWithTiles(0, b->x >> 3, b->y >> 3, b->width >> 3, b->height >> 3, 0x4000 + t.nameTbl, true);
	_screen->sega_getRenderer()->render(0, b->x >> 3, b->y >> 3, b->width >> 3, b->height >> 3);
}

void GUI_EoB_SegaCD::drawSaveSlotButton(int slot, int redrawBox, bool highlight) {
	if (slot < 0)
		return;

	if (slot == 5) {
		drawMenuButton(_saveLoadCancelButton, redrawBox == 2, false, false);
		return;
	}

	_screen->sega_getRenderer()->fillRectWithTiles(0, (_saveSlotX >> 3) + (_saveSlotX ? 1 : 2), (_saveSlotY >> 3) + (_saveSlotY ? 6 : 7) + (slot << 1), 3, 2, 0x41E7 + slot * 12 + (redrawBox == 2 ? 6 : 0), true);
	_screen->sega_clearTextBuffer(0);
	Common::String s1;
	Common::String s2(slot < 5 ? _saveSlotStringsTemp[slot] : _vm->_saveLoadStrings[0]);

	if (_vm->gameFlags().lang == Common::JA_JPN) {
		if (s2.contains('\r')) {
			// Savegame generated from ingame menu. The first part of the auto-generated save description (character name)
			// is not a 2-byte encoding, but rather a special 1-byte encoding. We cut that part off and print it separately,
			// since we have to notify the glyph renderer of the special encoding.
			uint len = s2.findFirstOf('\r');
			s1 = s2.substr(0, len);
			s2.erase(0, len);
			while (len--)
				s2.insertChar(' ', 0);
		} else {
			// Savegame generated via the GMM save dialog. The Japanese font only has upper case ASCII glyphs, so we have to uppercase the string.
			s2.toUppercase();
		}
	}

	_vm->_txt->printShadedText(s2.c_str(), 0, (slot << 4) + (slot < 5 ? 0 : 2), highlight ? 0x55 : 0xFF, 0xCC, 121, 80, 0, false);
	if (!s1.empty()) {
		int cs = _screen->setFontStyles(_screen->_currentFont, Font::kStyleForceOneByte);
		_vm->_txt->printShadedText(s1.c_str(), 0, (slot << 4) + (slot < 5 ? 0 : 2), highlight ? 0x55 : 0xFF, 0xCC, 121, 80, 0, false);
		_screen->setFontStyles(_screen->_currentFont, cs);
	}

	_screen->sega_loadTextBufferToVRAM(0, 0x5560, 4800);
	_screen->sega_getRenderer()->render(0, (_saveSlotX >> 3) + (_saveSlotX ? 1 : 2), (_saveSlotY >> 3) + (_saveSlotY ? 6 : 7) + (slot << 1), 21, 2);
}

int GUI_EoB_SegaCD::getHighlightSlot() {
	int res = -1;
	Common::Point p = _vm->getMousePos();

	for (int i = 0; i < 5; i++) {
		int y = _saveSlotY + i * 16 + (_saveSlotY ? 48 : 56);
		if (_vm->posWithinRect(p.x, p.y, _saveSlotX + (_saveSlotX ? 8 : 16), y, _saveSlotX + 167, y + 15)) {
			res = i;
			break;
		}
	}

	if (_vm->posWithinRect(p.x, p.y, _saveLoadCancelButton->x, _saveLoadCancelButton->y, _saveLoadCancelButton->x + _saveLoadCancelButton->width - 1, _saveLoadCancelButton->y + _saveLoadCancelButton->height - 1))
		res = 5;

	return res;
}

int GUI_EoB_SegaCD::mapPointToEntry(const Common::Point &p) const {
	if (_vm->posWithinRect(p.x, p.y, 8, 80, 168, 152))
		return (p.y - 80) / 8;

	return -1;
}

void GUI_EoB_SegaCD::memorizePrayMenuPrintString(int spellId, int bookPageIndex, int spellType, bool noFill, bool highLight) {
	if (bookPageIndex < 0)
		return;

	if (spellId) {
		memset(_vm->_tempPattern, 0, 924);
		Common::String s = Common::String::format(_vm->_menuStringsMgc[0], spellType ? _vm->_clericSpellList[spellId] : _vm->_mageSpellList[spellId], _numAssignedSpellsOfType[spellId * 2 - 2]);
		if (_vm->gameFlags().lang == Common::JA_JPN) {
			for (int i = 0; i < 19; ++i) {
				if ((int8)s[i] == -34 || (int8)s[i] == -33)
					s.insertChar(' ', 18);
			}
		}
		_vm->printSpellbookString(_vm->_tempPattern, s.c_str(), highLight ? 0x6223 : 0x63C9);
		_screen->sega_getRenderer()->fillRectWithTiles(0, 1, 10 + bookPageIndex, 20, 1, 0, true, true, _vm->_tempPattern);
	} else {
		_screen->sega_getRenderer()->fillRectWithTiles(0, 1, 10 + bookPageIndex, 20, 1, 0);
	}
	_screen->sega_getRenderer()->render(0, 1, 10 + bookPageIndex, 20, 1);
}

void GUI_EoB_SegaCD::updateOptionsStrings() {
	uint16 ntblInputMode[3] = { 0x34C, 0x360, 0x30C };
	int speed = _vm->_configMouse ? _vm->_mouseSpeed : _vm->_padSpeed;

	SegaRenderer *r = _screen->sega_getRenderer();
	r->loadToVRAM(&_campMenu[(0x1CE + (_vm->_configMouse ? 0x240 : 0x24C)) << 5], 0x180, 0x42E0);
	r->loadToVRAM(&_campMenu[(0x1CE + (_vm->_configMusic ? 0x258 : 0x264)) << 5], 0x180, 0x4460);
	r->loadToVRAM(&_campMenu[(0x1CE + (_vm->_configSounds ? 0x258 : 0x264)) << 5], 0x180, 0x45E0);
	r->loadToVRAM(&_campMenu[(0x1CE + ntblInputMode[_vm->_inputMode]) << 5], 0x280, 0x49A0);
	r->loadToVRAM(&_campMenu[(0x444 + speed * 12) << 5], 0xC0, 0x48E0);

	r->fillRectWithTiles(0, 15, 5, 3, 2, 0x4247, true);
	r->fillRectWithTiles(0, 8, 5, 6, 2, 0x4217, true);
	r->fillRectWithTiles(0, 8, 8, 6, 2, 0x4223, true);
	r->fillRectWithTiles(0, 8, 11, 6, 2, 0x422F, true);
	r->fillRectWithTiles(0, 8, 14, 10, 2, 0x424D, true);
}

void GUI_EoB_SegaCD::restParty_updateRestTime(int hours, bool init) {
	SegaRenderer *r = _screen->sega_getRenderer();
	if (init)
		r->fillRectWithTiles(0, 1, 4, 20, 17, 0);
	_screen->sega_clearTextBuffer(0);

	int cs = _screen->setFontStyles(_screen->_currentFont, Font::kStyleFullWidth);
	_vm->_txt->printShadedText(getMenuString(42), 0, 0, 0xFF, 0xCC, 160, 48, 0, false);
	_vm->_txt->printShadedText(_vm->_menuStringsRest2[3], 0, 16, 0xFF, 0xCC, 160, 48, 0, false);
	_vm->_txt->printShadedText(Common::String::format("%3d", hours).c_str(), _vm->gameFlags().lang == Common::JA_JPN ? 60 : 117, 16, 0xFF, 0xCC, 160, 48, 0, false);
	_screen->setFontStyles(_screen->_currentFont, cs);

	_screen->sega_loadTextBufferToVRAM(0, 0x5060, 5120);
	r->fillRectWithTiles(0, 1, 4, 20, 2, 0x6000);
	r->fillRectWithTiles(0, 1, 6, 20, 6, 0x6283, true);
	r->render(0, 0, 0, 22, 17);
	_screen->updateScreen();
	_vm->delay(160);
}

uint16 GUI_EoB_SegaCD::checkClickableCharactersSelection() {
	Common::Point mousePos = _vm->getMousePos();
	int highlight = -1;

	for (int i = 0; i < 60; ++i) {
		int x = (i % 12) * 12 + 152;
		int y = (i / 12) * 12 + 96;
		if (!_vm->posWithinRect(mousePos.x, mousePos.y, x, y, x + 11, y + 7))
			continue;
		highlight = i;
		break;
	}

	if (highlight == -1) {
		for (int i = 0; i < 3; ++i) {
			int x = 200 + i * 36;
			if (!_vm->posWithinRect(mousePos.x, mousePos.y, x, 164, x + _screen->getTextWidth(_vm->_textInputSelectStrings[i ? i + 2 : _clickableCharactersPage]) - 1, 171))
				continue;
			highlight = 200 + i;
			break;
		}
	}

	if (highlight != _menuCur) {
		printClickableCharacters(_clickableCharactersPage);
		if (highlight != -1)
			printClickableCharacter(highlight, 0x55);
		_screen->sega_getRenderer()->render(0, 18, 10, 20, 14);
		_menuCur = highlight;
	}

	_csjis[0] = _csjis[1] = _csjis[2] = 0;
	int in = 0;
	for (Common::List<KyraEngine_v1::Event>::const_iterator evt = _vm->_eventList.begin(); evt != _vm->_eventList.end(); ++evt) {
		if (evt->event.type == Common::EVENT_LBUTTONDOWN)
			in = 1;
	}

	if (in && highlight != -1) {
		_menuCur = -1;
		switch (highlight) {
		case 200:
			printClickableCharacters((_clickableCharactersPage + 1) % _clickableCharactersNumPages);
			break;
		case 201:
			_keyPressed.keycode = Common::KEYCODE_BACKSPACE;
			break;
		case 202:
			_keyPressed.keycode = Common::KEYCODE_RETURN;
			break;
		default:
			_csjis[0] = fetchClickableCharacter(highlight);
			_csjis[1] = '\x1';
			return 0x89;
		}
	}

	return in;
}

void GUI_EoB_SegaCD::printClickableCharacters(int page) {
	if (_clickableCharactersPage != page) {
		_clickableCharactersPage = page;
		assert(_vm->_wndBackgrnd);
		_screen->sega_loadTextBackground(_vm->_wndBackgrnd, 10240);
	}
	for (int i = 0; i < 60; ++i)
		printClickableCharacter(i, 0xFF);
	for (int i = 200; i < 203; ++i)
		printClickableCharacter(i, 0xFF);
	_screen->sega_getRenderer()->render(0, 18, 10, 20, 14);
}

void GUI_EoB_SegaCD::printClickableCharacter(int id, int col) {
	char ch[3] = "\0\0";

	if (id < 60) {
		ch[0] = fetchClickableCharacter(id);
		_vm->_txt->printShadedText(ch, (id % 12) * 12 + 12, (id / 12) * 12 + 32, col);
	} else if (id >= 200) {
		id -= 200;
		_vm->_txt->printShadedText(_vm->_textInputSelectStrings[id ? id + 2 : _clickableCharactersPage], 60 + id * 36, 100, col);
	}
}

char GUI_EoB_SegaCD::fetchClickableCharacter(int id) const {
	if (id >= 200)
		return (char)id;
	if (id >= 60)
		return 0;

	uint8 c = (uint8)_vm->_textInputCharacterLines[_clickableCharactersPage][id];
	if (_clickableCharactersPage == 1) {
		if (c > 159 && c < 192)
			c -= 32;
		else if (c > 191 && c < 224)
			c += 32;
	}
	return (char)c;
}

const GUI_EoB_SegaCD::MenuButtonTiles GUI_EoB_SegaCD::_menuButtonTiles[40] = {
	{ 0x01e7, 0x0000 },	{ 0x01fb, 0x0028 },	{ 0x020f, 0x0050 }, { 0x0223, 0x0078 },
	{ 0x0237, 0x00a0 }, { 0x0000, 0x0000 },	{ 0x01cf, 0x01c8 },	{ 0x025f, 0x0118 },
	{ 0x024b, 0x00c8 }, { 0x0273, 0x0140 },	{ 0x020b, 0x0198 },	{ 0x01cf, 0x01c8 },
	{ 0x01f3, 0x01e0 }, { 0x01ff, 0x01f8 },	{ 0x0000, 0x0000 },	{ 0x01e7, 0x0210 },
	{ 0x0000, 0x0000 },	{ 0x01CF, 0x0168 }, { 0x01db, 0x0180 }, { 0x01cf, 0x01c8 },
	{ 0x0000, 0x0000 }, { 0x0000, 0x0000 }, { 0x0000, 0x0000 }, { 0x0000, 0x0000 },
	{ 0x0000, 0x0000 },	{ 0x0000, 0x0000 },	{ 0x01db, 0x01b0 }, { 0x01cf, 0x01c8 },
	{ 0x0000, 0x0000 }, { 0x01e7, 0x0270 },	{ 0x01f3, 0x027C }, { 0x01ff, 0x0288 },
	{ 0x020b, 0x0294 },	{ 0x0217, 0x02A0 },	{ 0x024d, 0x030c },	{ 0x0000, 0x0000 },
	{ 0x0000, 0x0000 }, { 0x0000, 0x0000 }, { 0x01CF, 0x01C8 }, { 0x0000, 0x0000 }
};

} // End of namespace Kyra

#endif // ENABLE_EOB
