mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
1096 lines
39 KiB
C++
1096 lines
39 KiB
C++
/* 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
|