diff options
-rw-r--r-- | engines/kyra/gui.h | 7 | ||||
-rw-r--r-- | engines/kyra/gui_lol.cpp | 552 | ||||
-rw-r--r-- | engines/kyra/gui_lol.h | 94 | ||||
-rw-r--r-- | engines/kyra/items_lol.cpp | 16 | ||||
-rw-r--r-- | engines/kyra/kyra_v1.cpp | 32 | ||||
-rw-r--r-- | engines/kyra/lol.cpp | 539 | ||||
-rw-r--r-- | engines/kyra/lol.h | 294 | ||||
-rw-r--r-- | engines/kyra/module.mk | 1 | ||||
-rw-r--r-- | engines/kyra/scene_lol.cpp | 183 | ||||
-rw-r--r-- | engines/kyra/screen_lol.cpp | 76 | ||||
-rw-r--r-- | engines/kyra/screen_lol.h | 9 | ||||
-rw-r--r-- | engines/kyra/script_lol.cpp | 276 | ||||
-rw-r--r-- | engines/kyra/script_tim.cpp | 232 | ||||
-rw-r--r-- | engines/kyra/script_tim.h | 38 | ||||
-rw-r--r-- | engines/kyra/sound.cpp | 23 | ||||
-rw-r--r-- | engines/kyra/sound.h | 8 | ||||
-rw-r--r-- | engines/kyra/staticres.cpp | 9 | ||||
-rw-r--r-- | engines/kyra/text_lol.cpp | 573 | ||||
-rw-r--r-- | engines/kyra/text_lol.h | 104 |
19 files changed, 2716 insertions, 350 deletions
diff --git a/engines/kyra/gui.h b/engines/kyra/gui.h index 2ee764bfbe..1b524b7752 100644 --- a/engines/kyra/gui.h +++ b/engines/kyra/gui.h @@ -158,6 +158,13 @@ public: // utilities for thumbnail creation virtual void createScreenThumbnail(Graphics::Surface &dst) = 0; + + // LOL tim player specific + virtual void drawDialogueBox(int numStr, const char *s1, const char *s2, const char *s3) {} + virtual uint16 processDialogue() { return 0; } + virtual void update() {} + virtual char *getTableString(int id) { return 0; } + protected: KyraEngine_v1 *_vm; Screen *_screen; diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp index 477c7937eb..3e00b32b0d 100644 --- a/engines/kyra/gui_lol.cpp +++ b/engines/kyra/gui_lol.cpp @@ -25,6 +25,7 @@ #include "kyra/lol.h" #include "kyra/screen_lol.h" +#include "kyra/gui_lol.h" namespace Kyra { @@ -35,7 +36,7 @@ void LoLEngine::gui_drawPlayField() { // copy compass shape static const int cx[] = { 112, 152, 224 }; _screen->copyRegion(cx[_lang], 32, 288, 0, 32, 32, 2, 2, Screen::CR_NO_P_CHECK); - _updateUnk2 = -1; + _compassDirection = -1; } if (_screen->_drawGuiFlag & 0x1000) @@ -51,28 +52,27 @@ void LoLEngine::gui_drawPlayField() { } if (_screen->_drawGuiFlag & 0x800) - turnOnLamp(); + resetLampStatus(); - //mouseDimUnk() gui_drawScene(2); gui_drawAllCharPortraitsWithStats(); gui_drawInventory(); gui_drawMoneyBox(_screen->_curPage); + _screen->setCurPage(cp); _screen->hideMouse(); _screen->copyPage(2, 0); - //mouseDimUnk _screen->showMouse(); } void LoLEngine::gui_drawScene(int pageNum) { - if (/*_charFlagUnk == 1 && */_weaponsDisabled == false && _unkDrawLevelBool && _vcnBlocks) + if (!(_updateFlags & 1) && _weaponsDisabled == false && _unkDrawLevelBool && _vcnBlocks) drawScene(pageNum); } void LoLEngine::gui_drawInventory() { - if (!_unkInventFlag || !_updateCharV6) { + if (!_hideControls || !_hideInventory) { for (int i = 0; i < 9; i++) gui_drawInventoryItem(i); } @@ -89,8 +89,8 @@ void LoLEngine::gui_drawInventoryItem(int index) { _screen->hideMouse(); _screen->drawShape(_screen->_curPage, _gameShapes[4], x, 179, 0, flag); - if (_inventoryItemIndex[index]) - _screen->drawShape(_screen->_curPage, getItemIconShapePtr(_inventoryItemIndex[index]), x + 1, 180, 0, 0); + if (_inventory[index]) + _screen->drawShape(_screen->_curPage, getItemIconShapePtr(_inventory[index]), x + 1, 180, 0, 0); _screen->showMouse(); } @@ -134,13 +134,13 @@ void LoLEngine::gui_drawAllCharPortraitsWithStats() { } void LoLEngine::gui_drawCharPortraitWithStats(int charNum) { - if (!(_characters[charNum].flags & 1) || _charFlagUnk & 2) + if (!(_characters[charNum].flags & 1) || _updateFlags & 2) return; Screen::FontId tmpFid = _screen->setFont(Screen::FID_6_FNT); int cp = _screen->setCurPage(6); - gui_drawPortraitBox(0, 0, 66, 34, 1, 1, -1); + gui_drawBox(0, 0, 66, 34, 1, 1, -1); gui_drawCharFaceShape(0, 0, 1, _screen->_curPage); gui_drawLiveMagicBar(33, 32, _characters[charNum].magicPointsCur, 0, _characters[charNum].magicPointsMax, 5, 32, 162, 1, 0); @@ -165,22 +165,22 @@ void LoLEngine::gui_drawCharPortraitWithStats(int charNum) { _screen->drawGridBox(44, (spellLevels << 3) + 1, 22, 32 - (spellLevels << 3), 1); } else { // magic submenu closed - int shapeNum = -1; - /*if (_characters[charNum].items[0]) { - int u8 = _itemProperties[_itemsInPlay[_characters[charNum].items[0]].itemPropertyIndex].unk8 & 0xff; - if (u8 > shapeNum) - shapeNum = u8; - }*/ - - shapeNum = _gameShapeMap[_itemProperties[_itemsInPlay[_characters[charNum].items[0]].itemPropertyIndex].shpIndex]; - if (shapeNum == 0x5a) { // draw raceClassSex specific hand shape - shapeNum = _characters[charNum].raceClassSex - 1; - if (shapeNum < 0) - shapeNum = 0; - shapeNum += 68; + int handIndex = 0; + if (_characters[charNum].items[0]) { + if (_itemProperties[_itemsInPlay[_characters[charNum].items[0]].itemPropertyIndex].unk8 != -1) + handIndex = _itemsInPlay[_characters[charNum].items[0]].itemPropertyIndex; + } + + handIndex = _gameShapeMap[_itemProperties[handIndex].shpIndex << 1]; + if (handIndex == 0x5a) { // draw raceClassSex specific hand shape + handIndex = _characters[charNum].raceClassSex - 1; + if (handIndex < 0) + handIndex = 0; + handIndex += 68; } + // draw hand/weapon - _screen->drawShape(_screen->_curPage, _gameShapes[shapeNum], 44, 0, 0, 0); + _screen->drawShape(_screen->_curPage, _gameShapes[handIndex], 44, 0, 0, 0); // draw magic symbol _screen->drawShape(_screen->_curPage, _gameShapes[72 + _characters[charNum].field_41], 44, 17, 0, 0); @@ -189,7 +189,7 @@ void LoLEngine::gui_drawCharPortraitWithStats(int charNum) { } uint16 f = _characters[charNum].flags & 0x314C; - if ((f == 0 && (f != 4 || _characters[charNum].weaponHit == 0)) || _weaponsDisabled) + if ((f == 0 && _weaponsDisabled) || (f && (f != 4 || _characters[charNum].weaponHit == 0 || _weaponsDisabled))) _screen->drawGridBox(44, 0, 22, 34, 1); if (_characters[charNum].weaponHit) { @@ -202,7 +202,7 @@ void LoLEngine::gui_drawCharPortraitWithStats(int charNum) { if (!cp) _screen->hideMouse(); - uint8 col = (charNum != _unkDrawPortraitIndex || countActiveCharacters() == 1) ? 1 : 212; + uint8 col = (charNum != _selectedCharacter || countActiveCharacters() == 1) ? 1 : 212; _screen->drawBox(0, 0, 65, 33, col); _screen->copyRegion(0, 0, _activeCharsXpos[charNum], 143, 66, 34, _screen->_curPage, cp, Screen::CR_NO_P_CHECK); @@ -214,7 +214,7 @@ void LoLEngine::gui_drawCharPortraitWithStats(int charNum) { _screen->setFont(tmpFid); } -void LoLEngine::gui_drawPortraitBox(int x, int y, int w, int h, int frameColor1, int frameColor2, int fillColor) { +void LoLEngine::gui_drawBox(int x, int y, int w, int h, int frameColor1, int frameColor2, int fillColor) { w--; h--; if (fillColor != -1) _screen->fillRect(x + 1, y + 1, x + w - 1, y + h - 1, fillColor); @@ -334,12 +334,12 @@ void LoLEngine::gui_drawCompass() { if (!(_screen->_drawGuiFlag & 0x4000)) return; - if (_updateUnk2 == -1) { + if (_compassDirection == -1) { _compassDirectionIndex = -1; - _updateUnk2 = _currentDirection << 6; + _compassDirection = _currentDirection << 6; } - int t = ((_updateUnk2 + 4) >> 3) & 0x1f; + int t = ((_compassDirection + 4) >> 3) & 0x1f; if (t == _compassDirectionIndex) return; @@ -352,12 +352,502 @@ void LoLEngine::gui_drawCompass() { const CompassDef *c = &_compassDefs[t]; _screen->drawShape(_screen->_curPage, _gameShapes[22 + _lang], 294, 3, 0, 0); - _screen->drawShape(_screen->_curPage, _gameShapes[25 + c->shapeIndex], 298 + c->x, c->y + 9, 0, c->flags | 0x300); + _screen->drawShape(_screen->_curPage, _gameShapes[25 + c->shapeIndex], 298 + c->x, c->y + 9, 0, c->flags | 0x300, _screen->_paletteOverlay1, 1); _screen->drawShape(_screen->_curPage, _gameShapes[25 + c->shapeIndex], 299 + c->x, c->y + 8, 0, c->flags); if (!_screen->_curPage) _screen->showMouse(); } +int LoLEngine::gui_enableControls() { + _floatingMouseArrowControl = 0; + + if (!_hideControls) { + for (int i = 76; i < 85; i++) + gui_disableArrowButton(i, 2); + } + + gui_toggleFightButtons(false); + return 1; +} + +int LoLEngine::gui_disableControls(int controlMode) { + if (_hideControls) + return 0; + + _floatingMouseArrowControl = (controlMode & 2) ? 2 : 1; + + gui_toggleFightButtons(true); + + for (int i = 76; i < 85; i++) + gui_disableArrowButton(i, ((controlMode & 2) && (i > 78)) ? 2 : 3); + + return 1; +} + +void LoLEngine::gui_disableArrowButton(int shapeIndex, int mode) { + static const int16 arrowButtonX[] = { 0x000C, 0x0021, 0x0122, 0x000C, 0x0021, 0x0036, 0x000C, 0x0021, 0x0036 }; + static const int16 arrowButtonY[] = { 0x00B4, 0x00B4, 0x0020, 0x0084, 0x0084, 0x0084, 0x0096, 0x0096, 0x0096 }; + + if (shapeIndex == 78 && !(_screen->_drawGuiFlag & 0x1000)) + return; + + if (_hideControls && _hideInventory) + return; + + if (mode == 0) + shapeIndex = _lastArrowButtonShape; + + int pageNum = 0; + + int16 x1 = arrowButtonX[shapeIndex - 76]; + int16 y1 = arrowButtonY[shapeIndex - 76]; + int16 x2 = 0; + int16 y2 = 0; + uint32 t = 0; + + switch (mode) { + case 1: + mode = 0x100; + _lastArrowButtonShape = shapeIndex; + break; + + case 0: + if (!_lastArrowButtonShape) + return; + + t = _system->getMillis(); + if (_arrowButtonTimer > t) + delay(_arrowButtonTimer - t); + + case 2: + mode = 0; + _lastArrowButtonShape = 0; + break; + + case 3: + mode = 0; + _lastArrowButtonShape = 0; + pageNum = 6; + + x2 = x1; + y2 = y1; + x1 = 0; + y1 = 0; + break; + + default: + break; + } + + _screen->drawShape(pageNum, _gameShapes[shapeIndex], x1, y1, 0, mode, _screen->_paletteOverlay1, 1); + + if (pageNum != 6) + return; + + int cp = _screen->setCurPage(6); + + _screen->drawGridBox(x1, y1, _gameShapes[shapeIndex][3], _gameShapes[shapeIndex][2], 1); + _screen->copyRegion(x1, y1, x2, y2, _gameShapes[shapeIndex][3], _gameShapes[shapeIndex][2], pageNum, 0, Screen::CR_NO_P_CHECK); + + _screen->setCurPage(cp); + + _arrowButtonTimer = _system->getMillis() + 6 * _tickLength; +} + +void LoLEngine::gui_toggleFightButtons(bool disable) { + for (int i = 0; i < 3; i++) { + if (!(_characters[i].flags & 1)) + continue; + + if (disable) + _characters[i].flags |= 0x2000; + else + _characters[i].flags &= 0xdfff; + + if (disable && !textEnabled()) { + int u = _selectedCharacter; + _selectedCharacter = 99; + int f = _updateFlags; + _updateFlags &= 0xfffd; + + gui_drawCharPortraitWithStats(i); + + _updateFlags = f; + _selectedCharacter = u; + } else { + gui_drawCharPortraitWithStats(i); + } + } +} + +int LoLEngine::clickedUpArrow(Button *button) { + return 1; +} + +int LoLEngine::clickedDownArrow(Button *button) { + return 1; +} + +int LoLEngine::clickedLeftArrow(Button *button) { + return 1; +} + +int LoLEngine::clickedRightArrow(Button *button) { + return 1; +} + +int LoLEngine::clickedTurnLeftArrow(Button *button) { + return 1; +} + +int LoLEngine::clickedTurnRightArrow(Button *button) { + return 1; +} + +int LoLEngine::clickedAttackButton(Button *button) { + return 1; +} + +int LoLEngine::clickedMagicButton(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk9(Button *button) { + return 1; +} + +int LoLEngine::clickedScreen(Button *button) { + return 1; +} + +int LoLEngine::clickedPortraitLeft(Button *button) { + return 1; +} + +int LoLEngine::clickedLiveMagicBarsLeft(Button *button) { + return 1; +} + +int LoLEngine::clickedPortraitEtcRight(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk14(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk15(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk16(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk17(Button *button) { + return 1; +} + +int LoLEngine::clickedInventorySlot(Button *button) { + return 1; +} + +int LoLEngine::clickedInventoryScroll(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk20(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk21(Button *button) { + return 1; +} + +int LoLEngine::clickedScroll(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk23(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk24(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk25(Button *button) { + return 1; +} + +int LoLEngine::clickedOptions(Button *button) { + return 1; +} + +int LoLEngine::clickedRestParty(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk28(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk29(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk30(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk31(Button *button) { + return 1; +} + +int LoLEngine::clickedUnk32(Button *button) { + return 1; +} + +GUI_LoL::GUI_LoL(LoLEngine *vm) : GUI(vm), _vm(vm), _screen(vm->_screen) { + memset(_dialogueButtonString, 0, 3 * sizeof(const char*)); + _dialogueButtonPosX = _dialogueButtonPosY = _dialogueNumButtons = _dialogueButtonXoffs = _dialogueHighlightedButton = 0; + _scrollUpFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::scrollUp); + _scrollDownFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::scrollDown); +} + +int GUI_LoL::processButtonList(Button *list, uint16 inputFlag, int8 mouseWheel) { + if ((inputFlag & 0xFF) == 199) + _pressFlag = true; + else if ((inputFlag & 0xFF) == 200) + _pressFlag = false; + + int returnValue = 0; + while (list) { + /*if (list->flags & 8) { + list = list->nextButton; + continue; + } + + if (mouseWheel && list->mouseWheel == mouseWheel && list->buttonCallback) { + if ((*list->buttonCallback.get())(list)) + break; + } + + int x = list->x; + int y = list->y; + assert(_screen->getScreenDim(list->dimTableIndex) != 0); + + if (x < 0) + x += _screen->getScreenDim(list->dimTableIndex)->w << 3; + x += _screen->getScreenDim(list->dimTableIndex)->sx << 3; + + if (y < 0) + y += _screen->getScreenDim(list->dimTableIndex)->h; + y += _screen->getScreenDim(list->dimTableIndex)->sy; + + if (_vm->_mouseX >= x && _vm->_mouseY >= y && x + list->width >= _vm->_mouseX && y + list->height >= _vm->_mouseY) { + int processMouseClick = 0; + if (list->flags & 0x400) { + if ((inputFlag & 0xFF) == 199 || _pressFlag) { + if (!(list->flags2 & 1)) { + list->flags2 |= 1; + list->flags2 |= 4; + processButton(list); + _screen->updateScreen(); + inputFlag = 0; + } + } else if ((inputFlag & 0xFF) == 200) { + if (list->flags2 & 1) { + list->flags2 &= 0xFFFE; + processButton(list); + processMouseClick = 1; + inputFlag = 0; + } + } + } + + if (processMouseClick) { + if (list->buttonCallback) { + if ((*list->buttonCallback.get())(list)) + break; + } + } + } else { + if (list->flags2 & 1) { + list->flags2 &= 0xFFFE; + processButton(list); + } + + if (list->flags2 & 4) { + list->flags2 &= 0xFFFB; + processButton(list); + _screen->updateScreen(); + } + } + + list = list->nextButton;*/ + } + + if (!returnValue) + returnValue = inputFlag & 0xFF; + + return returnValue; +} + +void GUI_LoL::drawDialogueBox(int numStr, const char *s1, const char *s2, const char *s3) { + if (numStr == 1 && _vm->_speechFlag) { + _screen->setScreenDim(5); + _dialogueButtonString[0] = _dialogueButtonString[1] = _dialogueButtonString[2] = 0; + } else { + _screen->setScreenDim(5); + _dialogueNumButtons = numStr; + _dialogueButtonString[0] = s1; + _dialogueButtonString[1] = s2; + _dialogueButtonString[2] = s3; + _dialogueHighlightedButton = 0; + + const ScreenDim *d = _screen->getScreenDim(5); + _dialogueButtonPosY = d->sy + d->h - 9; + + if (numStr == 1) { + _dialogueButtonXoffs = 0; + _dialogueButtonPosX = d->sx + d->w - 77; + } else { + _dialogueButtonXoffs = d->w / numStr; + _dialogueButtonPosX = d->sx + (_dialogueButtonXoffs >> 1) - 37; + } + + drawDialogueButtons(); + } + + if (!_vm->shouldQuit()) + _vm->removeInputTop(); +} + +void GUI_LoL::drawDialogueButtons() { + int cp = _screen->setCurPage(0); + Screen::FontId of = _screen->setFont(Screen::FID_6_FNT); + + int x = _dialogueButtonPosX; + + for (int i = 0; i < _dialogueNumButtons; i++) { + _vm->gui_drawBox(x, _dialogueButtonPosY, 74, 9, 136, 251, -1); + _screen->printText(_dialogueButtonString[i], x + 37 - (_screen->getTextWidth(_dialogueButtonString[i])) / 2, + _dialogueButtonPosY + 2, _dialogueHighlightedButton == i ? 144 : 254, 0); + x += _dialogueButtonXoffs; + } + _screen->setFont(of); + _screen->setCurPage(cp); +} + +uint16 GUI_LoL::processDialogue() { + int df = _dialogueHighlightedButton; + int res = 0; + int x = _dialogueButtonPosX; + + for (int i = 0; i < _dialogueNumButtons; i++) { + if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, x, _dialogueButtonPosY, x + 74, _dialogueButtonPosY + 9)) { + _dialogueHighlightedButton = i; + break; + } + x += _dialogueButtonXoffs; + } + + if (_dialogueNumButtons == 0) { + int e = _vm->checkInput(0, false) & 0xCF; + _vm->removeInputTop(); + + if (e == 200) { + _vm->snd_dialogueSpeechUpdate(1); + //_dlgTimer = 0; + } + + if (_vm->snd_characterSpeaking() != 2) { + //if (_dlgTimer < _system->getMillis()) { + res = 1; + if (!_vm->shouldQuit()) + _vm->removeInputTop(); + //} + } + } else { + int e = _vm->checkInput(0, false); + _vm->removeInputTop(); + switch (e) { + case 100: + case 101: + _vm->snd_dialogueSpeechUpdate(1); + //_dlgTimer = 0; + res = _dialogueHighlightedButton + 1; + break; + + case 110: + case 111: + if (_dialogueNumButtons > 1 && _dialogueHighlightedButton > 0) + _dialogueHighlightedButton--; + break; + + case 112: + case 113: + if (_dialogueNumButtons > 1 && _dialogueHighlightedButton < (_dialogueNumButtons - 1)) + _dialogueHighlightedButton++; + break; + + case 200: + case 300: + x = _dialogueButtonPosX; + + for (int i = 0; i < _dialogueNumButtons; i++) { + if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, x, _dialogueButtonPosY, x + 74, _dialogueButtonPosY + 9)) { + _dialogueHighlightedButton = i; + res = _dialogueHighlightedButton + 1; + break; + } + x += _dialogueButtonXoffs; + } + + break; + + default: + break; + } + } + + if (df != _dialogueHighlightedButton) + drawDialogueButtons(); + + if (res == 0) + return 0; + + _vm->updatePortraits(); + + if (!_vm->textEnabled() && _vm->_hideControls) { + _screen->setScreenDim(5); + const ScreenDim *d = _screen->getScreenDim(5); + _screen->hideMouse(); + _screen->fillRect(d->sx, d->sy + d->h - 9, d->sx + d->w - 1, d->sy + d->h - 1, d->unkA); + _screen->showMouse(); + } else { + const ScreenDim *d = _screen->_curDim; + _screen->hideMouse(); + _screen->fillRect(d->sx, d->sy, d->sx + d->w - 2, d->sy + d->h - 1, d->unkA); + _screen->clearDim(4); + _screen->setScreenDim(4); + _screen->showMouse(); + //_screen->setDialogueColumn(8, 0); + //_screen->setDialogueLine(8, 0); + } + + return res; +} + +char *GUI_LoL::getTableString(int id) { + return (char *) _vm->getLangString(id); +} + +void GUI_LoL::update() { + _vm->update(); +} + } // end of namespace Kyra diff --git a/engines/kyra/gui_lol.h b/engines/kyra/gui_lol.h new file mode 100644 index 0000000000..52dde8b6b5 --- /dev/null +++ b/engines/kyra/gui_lol.h @@ -0,0 +1,94 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef KYRA_GUI_LOL_H +#define KYRA_GUI_LOL_H + +#include "kyra/gui.h" + +namespace Kyra { + +class LoLEngine; +class Screen_LoL; + +class GUI_LoL : public GUI { + friend class LoLEngine; +public: + GUI_LoL(LoLEngine *vm); + + void initStaticData(); + + // button specific + void processButton(Button *button) {} + int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel); + + // utilities for thumbnail creation + void createScreenThumbnail(Graphics::Surface &dst) {} + + // tim player specific + void drawDialogueBox(int numStr, const char *s1, const char *s2, const char *s3); + uint16 processDialogue(); + void update(); + char *getTableString(int id); + +private: + LoLEngine *_vm; + Screen_LoL *_screen; + + bool _pressFlag; + + int scrollUp(Button *button) { return 0; } + int scrollDown(Button *button) { return 0; } + + Button *getButtonListData() { return 0; } + Button *getScrollUpButton() { return 0; } + Button *getScrollDownButton() { return 0; } + + Button::Callback _scrollUpFunctor; + Button::Callback _scrollDownFunctor; + Button::Callback getScrollUpButtonHandler() const { return _scrollUpFunctor; } + Button::Callback getScrollDownButtonHandler() const { return _scrollDownFunctor; } + + uint8 defaultColor1() const { return 0; } + uint8 defaultColor2() const { return 0; } + + const char *getMenuTitle(const Menu &menu) { return 0; } + const char *getMenuItemTitle(const MenuItem &menuItem) { return 0; } + const char *getMenuItemLabel(const MenuItem &menuItem) { return 0; } + + void drawDialogueButtons(); + + const char *_dialogueButtonString[3]; + uint16 _dialogueButtonPosX; + uint16 _dialogueButtonPosY; + int _dialogueNumButtons; + uint16 _dialogueButtonXoffs; + int _dialogueHighlightedButton; +}; + +} // end of namespace Kyra + +#endif + diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp index 372fc5809e..ef81f7856f 100644 --- a/engines/kyra/items_lol.cpp +++ b/engines/kyra/items_lol.cpp @@ -62,8 +62,8 @@ void LoLEngine::giveCredits(int credits, int redraw) { if (redraw) { gui_drawMoneyBox(6); - //if (credits) - // TODO: delay/update + if (credits) + update(); } credits -= t; } @@ -153,18 +153,18 @@ void LoLEngine::clearItemTableEntry(int itemIndex) { _itemsInPlay[itemIndex].shpCurFrame_flg |= 0x8000; } -void *LoLEngine::cmzGetItemOffset(uint16 index) { +CLevelItem *LoLEngine::findItem(uint16 index) { if (index & 0x8000) - return &_lvlBuffer[index & 0x7fff]; + return &_cLevelItems[index & 0x7fff]; else - return &_itemsInPlay[index]; + return (CLevelItem *)&_itemsInPlay[index]; } -void LoLEngine::runItemScript(int reg1, int slot, int reg0, int reg3, int reg4) { +void LoLEngine::runItemScript(int reg1, int item, int reg0, int reg3, int reg4) { EMCState scriptState; memset(&scriptState, 0, sizeof(EMCState)); - uint8 func = slot ? _itemProperties[_itemsInPlay[slot].itemPropertyIndex].itemScriptFunc : 3; + uint8 func = item ? _itemProperties[_itemsInPlay[item].itemPropertyIndex].itemScriptFunc : 3; if (func == 0xff) return; @@ -173,7 +173,7 @@ void LoLEngine::runItemScript(int reg1, int slot, int reg0, int reg3, int reg4) scriptState.regs[0] = reg0; scriptState.regs[1] = reg1; - scriptState.regs[2] = slot; + scriptState.regs[2] = item; scriptState.regs[3] = reg3; scriptState.regs[4] = reg4; diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp index 112e5fc9fc..a5e1e432d0 100644 --- a/engines/kyra/kyra_v1.cpp +++ b/engines/kyra/kyra_v1.cpp @@ -257,6 +257,29 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop) { _debugger->attach(); else if (event.kbd.keycode == 'q') quitGame(); + } else { + switch(event.kbd.keycode) { + case Common::KEYCODE_SPACE: + keys = 100; + break; + case Common::KEYCODE_RETURN: + keys = 101; + break; + case Common::KEYCODE_UP: + keys = 110; + break; + case Common::KEYCODE_RIGHT: + keys = 111; + break; + case Common::KEYCODE_DOWN: + keys = 112; + break; + case Common::KEYCODE_LEFT: + keys = 113; + break; + default: + break; + } } break; @@ -275,6 +298,15 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop) { breakLoop = true; } break; + case Common::EVENT_RBUTTONDOWN: + case Common::EVENT_RBUTTONUP: { + Common::Point pos = getMousePos(); + _mouseX = pos.x; + _mouseY = pos.y; + keys = (event.type == Common::EVENT_RBUTTONDOWN ? 299 : (300 | 0x800)); + breakLoop = true; + } break; + case Common::EVENT_WHEELUP: mouseWheel = -1; break; diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index bd85b892e4..c37e4b45f4 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -29,6 +29,9 @@ #include "kyra/sound.h" #include "kyra/util.h" +#include "sound/voc.h" +#include "sound/audiostream.h" + #include "common/endian.h" #include "base/version.h" @@ -36,6 +39,8 @@ namespace Kyra { LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(system, flags) { _screen = 0; + _gui = 0; + _dlg = 0; switch (_flags.lang) { case Common::EN_ANY: @@ -66,6 +71,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _lastMusicTrack = -1; _lastSfxTrack = -1; _curTlkFile = -1; + _lastSpeaker = _lastSpeechId = -1; memset(_moneyColumnHeight, 0, 5); _credits = 0; @@ -73,9 +79,9 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _itemsInPlay = 0; _itemProperties = 0; _itemInHand = 0; - memset(_inventoryItemIndex, 0, 48); + memset(_inventory, 0, 48); _inventoryCurItem = 0; - _unkInventFlag = 0; + _hideControls = 0; _itemIconShapes = _itemShapes = _gameShapes = _thrownShapes = _iceShapes = _fireballShapes = 0; _levelShpList = _levelDatList = 0; @@ -87,16 +93,18 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _charSelection = -1; _characters = 0; _spellProperties = 0; - _charFlagUnk = 0; + _updateFlags = 0; _selectedSpell = 0; - _updateCharNum = _updateCharV1 = _updateCharV2 = _updateCharV3 = _updateCharV4 = _updateCharV5 = _updateCharV6 = 0; - _updateCharTime = _updatePortraitNext = 0; + _updateCharNum = _updateCharV1 = _updateCharV2 = _updateCharV3 = _updateCharV4 = _restorePalette = _hideInventory = 0; + _palUpdateTimer = _updatePortraitNext = 0; _lampStatusTimer = 0xffffffff; _weaponsDisabled = false; - _unkDrawPortraitIndex = 0; + _lastArrowButtonShape = 0; + _arrowButtonTimer = 0; + _selectedCharacter = 0; _unkFlag = 0; - _scriptBoolSkipExec = _boolScriptFuncDone = false; + _scriptBoolSkipExec = _sceneUpdateRequired = false; _unkScriptByte = 0; _currentDirection = 0; _currentBlock = 0; @@ -106,16 +114,16 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _wllShapeMap = 0; _lvlShapeTop = _lvlShapeBottom = _lvlShapeLeftRight = 0; _levelBlockProperties = 0; - _lvlBuffer = 0; - _lvl415 = 0; + _cLevelItems = 0; + _monsterProperties = 0; _lvlBlockIndex = _lvlShapeIndex = 0; _unkDrawLevelBool = true; _vcnBlocks = 0; _vcnShift = 0; _vcnExpTable = 0; _vmpPtr = 0; - _tlcTable2 = 0; - _tlcTable1 = 0; + _trueLightTable2 = 0; + _trueLightTable1 = 0; _levelShapeProperties = 0; _levelShapes = 0; _blockDrawingBuffer = 0; @@ -125,8 +133,10 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _lampOilStatus = _brightness = _lampStatusUnk = 0; _tempBuffer5120 = 0; _tmpData136 = 0; - _lvlBuffer = 0; + _cLevelItems = 0; _unkGameFlag = 0; + _lastMouseRegion = 0; + _preSeq_X1 = _preSeq_Y1 = _preSeq_X2 = _preSeq_Y2 = 0; _dscUnk1 = 0; _dscShapeIndex = 0; @@ -155,8 +165,16 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _curMusicFileIndex = -1; _sceneDrawVar1 = _sceneDrawVar2 = _sceneDrawVar3 = _wllProcessFlag = 0; - _unkCmzU1 = _unkCmzU2 = 0; + _partyPosX = _partyPosY = 0; _shpDmX = _shpDmY = _dmScaleW = _dmScaleH = 0; + + _intFlag3 = 3; + _floatingMouseArrowControl = 0; + + memset(_activeTim, 0, 10 * sizeof(TIM*)); + memset(_activeVoiceFile, 0, sizeof(_activeVoiceFile)); + + //_dlgAnimCallback = &TextDisplayer_LoL::portraitAnimation1; } LoLEngine::~LoLEngine() { @@ -166,7 +184,9 @@ LoLEngine::~LoLEngine() { delete[] _levelLangFile; delete _screen; + delete _gui; delete _tim; + delete _dlg; delete[] _itemsInPlay; delete[] _itemProperties; @@ -224,6 +244,11 @@ LoLEngine::~LoLEngine() { delete *i; _timIntroOpcodes.clear(); + for (Common::Array<const TIMOpcode*>::iterator i = _timIngameOpcodes.begin(); i != _timIngameOpcodes.end(); ++i) + delete *i; + _timIngameOpcodes.clear(); + + delete[] _wllVmpMap; delete[] _wllShapeMap; delete[] _wllBuffer3; @@ -234,17 +259,17 @@ LoLEngine::~LoLEngine() { delete[] _lvlShapeLeftRight; delete[] _tempBuffer5120; delete[] _tmpData136; - delete[] _lvlBuffer; + delete[] _cLevelItems; delete[] _levelBlockProperties; - delete[] _lvl415; + delete[] _monsterProperties; delete[] _levelFileData; delete[] _vcnExpTable; delete[] _vcnBlocks; delete[] _vcnShift; delete[] _vmpPtr; - delete[] _tlcTable2; - delete[] _tlcTable1; + delete[] _trueLightTable2; + delete[] _trueLightTable1; delete[] _levelShapeProperties; delete[] _blockDrawingBuffer; delete[] _sceneWindowBuffer; @@ -271,6 +296,10 @@ Screen *LoLEngine::screen() { return _screen; } +GUI *LoLEngine::gui() const { + return _gui; +} + Common::Error LoLEngine::init() { _screen = new Screen_LoL(this, _system); assert(_screen); @@ -279,9 +308,16 @@ Common::Error LoLEngine::init() { KyraEngine_v1::init(); initStaticResource(); + _gui = new GUI_LoL(this); + assert(_gui); + _gui->initStaticData(); + initButtonList(); + _tim = new TIMInterpreter(this, _screen, _system); assert(_tim); + _dlg = new TextDisplayer_LoL(this, _screen); + _screen->setAnimBlockPtr(10000); _screen->setScreenDim(0); @@ -294,8 +330,7 @@ Common::Error LoLEngine::init() { if (!_sound->init()) error("Couldn't init sound"); - _unkAudioSpecOffs = 0x48; - _unkLangAudio = _lang ? true : false; + _speechFlag = speechEnabled() ? 0x48 : 0; _wllVmpMap = new uint8[80]; memset(_wllVmpMap, 0, 80); @@ -324,10 +359,10 @@ Common::Error LoLEngine::init() { _levelBlockProperties = new LevelBlockProperty[1025]; memset(_levelBlockProperties, 0, 1025 * sizeof(LevelBlockProperty)); - _lvlBuffer = new LVL[30]; - memset(_lvlBuffer, 0, 30 * sizeof(LVL)); - _lvl415 = new uint8[415]; - memset(_lvl415, 0, 415); + _cLevelItems = new CLevelItem[30]; + memset(_cLevelItems, 0, 30 * sizeof(CLevelItem)); + _monsterProperties = new MonsterProperty[5]; + memset(_monsterProperties, 0, 5 * sizeof(MonsterProperty)); _vcnExpTable = new uint8[128]; for (int i = 0; i < 128; i++) @@ -363,11 +398,10 @@ Common::Error LoLEngine::init() { } Common::Error LoLEngine::go() { - if (!saveFileLoadable(0)) { - setupPrologueData(true); + setupPrologueData(true); + + if (!saveFileLoadable(0)) showIntro(); - setupPrologueData(false); - } preInit(); @@ -400,7 +434,6 @@ Common::Error LoLEngine::go() { case 1: // Show intro setupPrologueData(true); showIntro(); - setupPrologueData(true); break; case 2: // "Lore of the Lands" (only CD version) @@ -425,21 +458,27 @@ Common::Error LoLEngine::go() { if (processSelection == 0) { setupPrologueData(true); _sound->loadSoundFile("LOREINTR"); - _sound->playTrack(6); + _sound->playTrack(6); /*int character = */chooseCharacter(); _sound->playTrack(1); _screen->fadeToBlack(); - setupPrologueData(true); } + setupPrologueData(false); + if (!shouldQuit() && (processSelection == 0 || processSelection == 3)) startup(); if (!shouldQuit() && processSelection == 0) startupNew(); - if (!shouldQuit() && (processSelection == 0 || processSelection == 3)) + if (!shouldQuit() && (processSelection == 0 || processSelection == 3)) { + //_dlgAnimCallback = &TextDisplayer_LoL::portraitAnimation2; + _screen->_fadeFlag = 3; + _sceneUpdateRequired = true; + setUnkFlags(1); runLoop(); + } return Common::kNoError; } @@ -449,44 +488,30 @@ Common::Error LoLEngine::go() { void LoLEngine::preInit() { debugC(9, kDebugLevelMain, "LoLEngine::preInit()"); - if (!_res->loadFileList("FILEDATA.FDT")) - error("Couldn't load file list: 'FILEDATA.FDT'"); + _res->loadPakFile("GENERAL.PAK"); + if (_flags.isTalkie) + _res->loadPakFile("STARTUP.PAK"); _screen->loadFont(Screen::FID_9_FNT, "FONT9P.FNT"); _screen->loadFont(Screen::FID_6_FNT, "FONT6P.FNT"); - uint8 *pal = _screen->getPalette(0); - memset(pal, 0, 768); - _screen->setScreenPalette(pal); - - // TODO: We need to check if the SYSEX events of intro and ingame differ. - // If they differ, we really need to setup the proper ingame SYSEX when starting - // the game. But the proper place to do it would not be in this function. - /*if (_sound->getMusicType() == Sound::kMidiMT32 || _sound->getSfxType() == Sound::kMidiMT32) { - _sound->loadSoundFile("LOLSYSEX"); - _sound->playTrack(0); - - while (_sound->isPlaying() && !shouldQuit()) - delay(10); - }*/ - - if (shouldQuit()) - return; - - _eventList.clear(); - loadTalkFile(0); char filename[32]; snprintf(filename, sizeof(filename), "LANDS.%s", _languageExt[_lang]); _res->exists(filename, true); _landsFile = _res->fileData(filename, 0); - - initializeCursors(); + loadItemIconShapes(); } -void LoLEngine::initializeCursors() { - debugC(9, kDebugLevelMain, "LoLEngine::initializeCursors()"); +void LoLEngine::loadItemIconShapes() { + debugC(9, kDebugLevelMain, "LoLEngine::loadItemIconShapes()"); + + if (_itemIconShapes) { + for (int i = 0; i < _numItemIconShapes; i++) + delete[] _itemIconShapes[i]; + delete[] _itemIconShapes; + } _screen->loadBitmap("ITEMICN.SHP", 3, 3, 0); const uint8 *shp = _screen->getCPagePtr(3); @@ -512,6 +537,12 @@ void LoLEngine::setMouseCursorToItemInHand() { _screen->setMouseCursor(o, o, getItemIconShapePtr(_itemInHand)); } +bool LoLEngine::posWithinRect(int mouseX, int mouseY, int x1, int y1, int x2, int y2) { + if (mouseX < x1 || mouseX > x2 || mouseY < y1 || mouseY > y2) + return false; + return true; +} + uint8 *LoLEngine::getItemIconShapePtr(int index) { int ix = _itemProperties[_itemsInPlay[index].itemPropertyIndex].shpIndex; if (_itemProperties[_itemsInPlay[index].itemPropertyIndex].flags & 0x200) @@ -585,6 +616,7 @@ void LoLEngine::startup() { memset(_screen->getPalette(1), 0, 0x300); memset(_screen->getPalette(2), 0, 0x300); + loadItemIconShapes(); _screen->setMouseCursor(0, 0, _itemIconShapes[0x85]); _screen->loadBitmap("ITEMSHP.SHP", 3, 3, 0); @@ -629,19 +661,29 @@ void LoLEngine::startup() { runInitScript("ONETIME.INF", 0); _emc->load("ITEM.INF", &_itemScript, &_opcodes); - _tlcTable1 = new uint8[256]; - _tlcTable2 = new uint8[5120]; + _trueLightTable1 = new uint8[256]; + _trueLightTable2 = new uint8[5120]; _loadSuppFilesFlag = 1; + _dlg->setAnimParameters("<MORE>", 10, 31, 0); + _dlg->setAnimFlag(true); + + _screen->_dimLineCount = 0; + + // reconfigure TIM player for ingame scripts + _tim->toggleDialogueSpeech(speechEnabled()); + _tim->toggleRefresh(true); + setMouseCursorToItemInHand(); } void LoLEngine::startupNew() { _selectedSpell = 0; - _updateUnk2 = _compassDirectionIndex = -1; - /* - _unk3 = -1;*/ + _compassUnk = 0; + _compassDirection = _compassDirectionIndex = -1; + + _lastMouseRegion = -1; _unkGameFlag |= 0x1B; /* _unk5 = 1; @@ -651,11 +693,12 @@ void LoLEngine::startupNew() { _currentLevel = 1; giveCredits(41, 0); - _inventoryItemIndex[0] = makeItem(0xd8, 0, 0); - _inventoryItemIndex[1] = makeItem(0xd9, 0, 0); - _inventoryItemIndex[2] = makeItem(0xda, 0, 0); + _inventory[0] = makeItem(0xd8, 0, 0); + _inventory[1] = makeItem(0xd9, 0, 0); + _inventory[2] = makeItem(0xda, 0, 0); memset(_availableSpells, -1, 7); + _availableSpells[0] = 0; setupScreenDims(); //memset(_unkWordArraySize8, 0x100, 8); @@ -670,21 +713,80 @@ void LoLEngine::startupNew() { _screen->showMouse(); } +int LoLEngine::setUnkFlags(int unk) { + if (unk < 1 || unk > 14) + return 0; + + int r = (_intFlag3 & (2 << unk)) ? 1 : 0; + _intFlag3 |= (2 << unk); + + return r; +} + +int LoLEngine::removeUnkFlags(int unk) { + if (unk < 1 || unk > 14) + return 0; + + int r = (_intFlag3 & (2 << unk)) ? 1 : 0; + _intFlag3 &= ~(2 << unk); + + return r; +} + void LoLEngine::runLoop() { - _screen->updateScreen(); + setUnkFlags(2); bool _runFlag = true; + _unkFlag |= 0x800; + while (!shouldQuit() && _runFlag) { - checkInput(0, false); - removeInputTop(); - _screen->updateScreen(); - _system->delayMillis(10); + if (_nextScriptFunc) { + runResidentScript(_nextScriptFunc, 2); + _nextScriptFunc = 0; + } + + //processUnkAnimStructs(); + //checkFloatingPointerRegions(); + //processCharacters(); + checkInput(0, true); + + update(); + + if (_sceneUpdateRequired) + gui_drawScene(0); + else + runLoopSub4(0); + + /*if (_partyDeathFlag != -1) { + checkForPartyDeath(_partyDeathFlag); + _partyDeathFlag = -1; + }*/ + + _system->delayMillis(_tickLength); } } +void LoLEngine::update() { + updateWsaAnimations(); + + if (_updateCharNum != -1 && _system->getMillis() > _updatePortraitNext) + updatePortraitWithStats(); + + if (_screen->_drawGuiFlag & 0x800 || !(_updateFlags & 4)) + updateLampStatus(); + + if (_screen->_drawGuiFlag & 0x4000 && !(_updateFlags & 4) && (_compassDirection == -1 || (_currentDirection << 6) != _compassDirection || _compassUnk)) + updateCompass(); + + snd_characterSpeaking(); + restorePaletteEntry(); + + _screen->updateScreen(); +} + #pragma mark - Localization -const char *LoLEngine::getLangString(uint16 id) { +char *LoLEngine::getLangString(uint16 id) { debugC(9, kDebugLevelMain, "LoLEngine::getLangString(0x%.04X)", id); if (id == 0xFFFF) @@ -701,7 +803,7 @@ const char *LoLEngine::getLangString(uint16 id) { if (!buffer) return 0; - const char *string = (const char *)getTableEntry(buffer, realId); + char *string = (char *)getTableEntry(buffer, realId); char *srcBuffer = _stringBuffer[_lastUsedStringBuffer]; Util::decodeString1(string, srcBuffer); @@ -780,12 +882,39 @@ void LoLEngine::setupPrologueData(bool load) { memset(_screen->getPalette(1), 0, 768); } else { delete _chargenWSA; _chargenWSA = 0; + + if (!_res->loadFileList("FILEDATA.FDT")) + error("Couldn't load file list: 'FILEDATA.FDT'"); + + uint8 *pal = _screen->getPalette(0); + memset(pal, 0, 768); + _screen->setScreenPalette(pal); + + // TODO: We need to check if the SYSEX events of intro and ingame differ. + // If they differ, we really need to setup the proper ingame SYSEX when starting + // the game. But the proper place to do it would not be in this function. + /*if (_sound->getMusicType() == Sound::kMidiMT32 || _sound->getSfxType() == Sound::kMidiMT32) { + _sound->loadSoundFile("LOLSYSEX"); + _sound->playTrack(0); + + while (_sound->isPlaying() && !shouldQuit()) + delay(10); + }*/ + + if (shouldQuit()) + return; + + _eventList.clear(); } } void LoLEngine::showIntro() { debugC(9, kDebugLevelMain, "LoLEngine::showIntro()"); + uint8 *pal = _screen->getPalette(0); + memset(pal, 0, 768); + _screen->setScreenPalette(pal); + TIM *intro = _tim->load("LOLINTRO.TIM", &_timIntroOpcodes); _screen->loadFont(Screen::FID_8_FNT, "NEW8P.FNT"); @@ -828,6 +957,9 @@ void LoLEngine::showIntro() { _tim->unload(intro); _tim->clearLangData(); + for (int i = 0; i < TIM::kWSASlots; i++) + _tim->freeAnimStruct(i); + _screen->fadePalette(_screen->getPalette(1), 30, 0); } @@ -1236,10 +1368,9 @@ bool LoLEngine::addCharacter(int id) { i = 0; for (; i < 11; i++) { - uint16 *tmp = &_characters[numChars].items[i]; - if (*tmp) { - *tmp = makeItem(*tmp, 0, 0); - runItemScript(numChars, *tmp, 0x80, 0, 0); + if (_characters[numChars].items[i]) { + _characters[numChars].items[i] = makeItem(_characters[numChars].items[i], 0, 0); + runItemScript(numChars, _characters[numChars].items[i], 0x80, 0, 0); } } @@ -1301,7 +1432,7 @@ void LoLEngine::updatePortraitWithStats() { y = 144; redraw = true; } else if (_updateCharV2 == 1) { - if (_unkLangAudio) { + if (textEnabled()) { x = 90; y = 130; } else { @@ -1309,7 +1440,7 @@ void LoLEngine::updatePortraitWithStats() { y = 144; } } else if (_updateCharV2 == 2) { - if (_unkLangAudio) { + if (textEnabled()) { x = 16; y = 134; } else { @@ -1325,11 +1456,10 @@ void LoLEngine::updatePortraitWithStats() { f -= 5; f += 7; - if (_unkAudioSpecOffs) { - //TODO - //if (unk() == 2) - // _updateCharV1 = 2; - //else + if (_speechFlag) { + if (snd_characterSpeaking() == 2) + _updateCharV1 = 2; + else _updateCharV1 = 1; } @@ -1367,24 +1497,44 @@ void LoLEngine::updatePortraits() { void LoLEngine::updatePortraitUnkTimeSub(int unk1, int unk2) { if (_updateCharV4 == unk1 || !unk1) { - _updateCharV5 = 1; - _updateCharTime = _system->getMillis(); + _restorePalette = 1; + _palUpdateTimer = _system->getMillis(); } if (!unk2) return; updatePortraits(); - if (_updateCharV6) { + if (_hideInventory) { _screen->hideMouse(); _screen->clearDim(3); _screen->showMouse(); } - _updateCharV5 = 0; + _restorePalette = 0; //initGuiUnk(11); } +void LoLEngine::charCallback4(int redraw) { + for (int i = 0; i < 3; i++) { + if (!(_characters[i].flags & 1) || (_characters[i].flags & 8) || (_characters[i].curFaceFrame > 1)) + continue; + + if (_characters[i].curFaceFrame == 1) { + _characters[i].curFaceFrame = 0; + gui_drawCharPortraitWithStats(i); + _characters[i].rand = _rnd.getRandomNumberRng(1, 12); + } else { + _characters[i].rand--; + if (_characters[i].rand <= 0 && !redraw) { + _characters[i].curFaceFrame = 1; + gui_drawCharPortraitWithStats(i); + //resetAnimStructs(9, 0, 1); + } + } + } +} + void LoLEngine::setCharFaceFrame(int charNum, int frameNum) { _characters[charNum].curFaceFrame = frameNum; } @@ -1402,32 +1552,224 @@ void LoLEngine::faceFrameRefresh(int charNum) { } void LoLEngine::setupScreenDims() { - if (_unkLangAudio) + if (textEnabled()) { _screen->modifyScreenDim(4, 11, 124, 28, 45); - else + _screen->modifyScreenDim(5, 85, 123, 233, 54); + } else { _screen->modifyScreenDim(4, 11, 124, 28, 9); - _screen->modifyScreenDim(5, 85, 123, 233, 18); + _screen->modifyScreenDim(5, 85, 123, 233, 18); + } +} + +void LoLEngine::initDialogueSequence(int controlMode) { + unkHideInventory(); + gui_prepareForSequence(112, 0, 176, 120, controlMode); + + _updateFlags |= 3; + + _dlg->setupField(true); + _dlg->expandField(); + setupScreenDims(); + gui_disableControls(controlMode); +} + +void LoLEngine::toggleSelectedCharacterFrame(bool mode) { + if (countActiveCharacters() == 1) + return; + + int col = mode ? 212 : 1; + + int cp = _screen->setCurPage(0); + int x = _activeCharsXpos[_selectedCharacter]; + + _screen->drawBox(x, 143, x + 65, 176, col); + _screen->setCurPage(cp); +} + +void LoLEngine::unkHideInventory() { + _hideInventory = 1; + + if (!textEnabled() || !(_hideControls & 2)) + charCallback4(1); + + removeUnkFlags(2); +} + +void LoLEngine::gui_prepareForSequence(int x, int y, int w, int h, int unk) { + //resetGuiUnk(x, y, w, h, unk); + + _preSeq_X1 = x; + _preSeq_Y1 = y; + _preSeq_X2 = x + w; + _preSeq_Y2 = y + h; + + int mouseOffs = _itemInHand ? 10 : 0; + _screen->setMouseCursor(mouseOffs, mouseOffs, getItemIconShapePtr(_itemInHand)); + + _lastMouseRegion = -1; + + if (w == 320) { + setLampMode(0); + _lampStatusSuspended = true; + } +} + +void LoLEngine::restoreSceneAfterDialogueSequence(int redraw) { + gui_enableControls(); + _dlg->setupField(false); + _updateFlags &= 0xffdf; + + //loadLevel_initGui() + + for (int i = 0; i < 6; i++) + _tim->freeAnimStruct(i); + + _updateFlags = 0; + + if (redraw) { + if (_screen->_fadeFlag != 2) + _screen->fadeClearSceneWindow(10); + gui_drawPlayField(); + _screen->setPaletteBrightness(_screen->_currentPalette, _brightness, _lampOilStatus); + _screen->_fadeFlag = 0; + } + + _hideInventory = 0; +} + +void LoLEngine::restorePaletteEntry() { + if (!_restorePalette) + return; + + _screen->copyColour(192, 252, _system->getMillis() - _palUpdateTimer, 60 * _tickLength); + + if (_hideInventory) + return; + + _screen->clearDim(3); + + ///initGuiUnk(11); + + _restorePalette = 0; +} + +void LoLEngine::updateWsaAnimations() { + if (_updateFlags & 8) + return; + + //TODO } void LoLEngine::loadTalkFile(int index) { char file[8]; - + if (index == _curTlkFile) return; - if (_curTlkFile >= 0) { + if (_curTlkFile > 0 && index > 0) { snprintf(file, sizeof(file), "%02d.TLK", _curTlkFile); _res->unloadPakFile(file); } + if (index > 0) + _curTlkFile = index; + snprintf(file, sizeof(file), "%02d.TLK", index); _res->loadPakFile(file); +} + +bool LoLEngine::snd_playCharacterSpeech(int id, int8 speaker, int) { + if (!_speechFlag) + return true; + + if (speaker < 65) { + if (_characters[speaker].flags & 1) + speaker = (int) _characters[speaker].name[0]; + else + speaker = 0; + } + + if (_lastSpeechId == id && speaker == _lastSpeaker) + return true; + + _lastSpeechId = id; + _lastSpeaker = speaker; + + Common::List<const char*> playList; + + char pattern1[8]; + char pattern2[5]; + char file1[13]; + char file2[13]; + + snprintf(pattern2, sizeof(pattern2), "%02d", id & 0x4000 ? 0 : _curTlkFile); + + if (id & 0x4000) { + snprintf(pattern1, sizeof(pattern1), "%03X", id & 0x3fff); + } else if (id < 1000) { + snprintf(pattern1, sizeof(pattern1), "%03d", id); + } else { + snprintf(pattern1, sizeof(pattern1), "@%04d", id - 1000); + } + + for (char i = '0'; i != -1; i++) { + snprintf(file1, sizeof(file1), "%s%c%c.%s", pattern1, (char)speaker, i, pattern2); + snprintf(file2, sizeof(file2), "%s%c%c.%s", pattern1, '_', i, pattern2); + if (_res->exists(file1)) { + char *f = new char[strlen(file1) + 1]; + strcpy(f, file1); + playList.push_back(f); + } else if (_res->exists(file2)) { + char *f = new char[strlen(file2) + 1]; + strcpy(f, file2); + playList.push_back(f); + } else { + i = -2; + } + } + + if (playList.empty()) + return false; + + do { + update(); + if (snd_characterSpeaking() == 0) + break; + } while (_sound->voiceIsPlaying()); + + strcpy(_activeVoiceFile, *playList.begin()); + _tim->setActiveSpeechFile(_activeVoiceFile); + + _sound->voicePlayFromList(playList); + + for (Common::List<const char*>::iterator i = playList.begin(); i != playList.end(); i++) + delete []*i; + playList.clear(); + + _tim->setDialogueCompleteFlag(0); + + return true; +} + +int LoLEngine::snd_characterSpeaking() { + if (_sound->voiceIsPlaying(_activeVoiceFile)) + return 2; + + _lastSpeechId = _lastSpeaker = -1; - _curTlkFile = index; + return 1; } -void LoLEngine::snd_playVoiceFile(int) { +int LoLEngine::snd_dialogueSpeechUpdate(int finish) { + if (!_sound->voiceIsPlaying(_activeVoiceFile)) + return -1; + + //_dlgTimer = 0; + if (finish) + _tim->setDialogueCompleteFlag(1); + + return 1; } void LoLEngine::snd_playSoundEffect(int track, int volume) { @@ -1508,5 +1850,14 @@ int LoLEngine::snd_stopMusic() { return snd_playTrack(-1); } +void LoLEngine::runLoopSub4(int a) { + cmzS7(a, _currentBlock); +} + +void LoLEngine::calcCoordinates(uint16 & x, uint16 & y, int block, uint16 xOffs, uint16 yOffs) { + x = (block & 0x1f) << 8 | xOffs; + y = ((block & 0xffe0) << 3) | yOffs; +} + } // end of namespace Kyra diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index dd998d7bd9..736b2f4894 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -29,6 +29,9 @@ #include "kyra/kyra_v1.h" #include "kyra/script_tim.h" #include "kyra/script.h" +#include "kyra/sound.h" +#include "kyra/gui_lol.h" +#include "kyra/text_lol.h" #include "common/list.h" @@ -107,20 +110,35 @@ struct LevelBlockProperty { uint8 flags; }; -struct LVL { +struct MonsterProperty { + uint8 id; + uint8 maxWidth; + uint16 unk[9]; + uint16 *pos; + uint16 unk2[8]; + uint16 unk3[8]; + uint16 unk4[2]; + uint8 b; + uint16 unk5[2]; + uint16 unk6[5]; + uint8 unk7[4]; + uint8 unk8[3]; +}; + +struct CLevelItem { uint16 itemIndexUnk; - uint8 field_2; - uint16 field_3; + uint8 unk2; + uint16 unk3; uint16 blockPropertyIndex; uint16 p_1a; uint16 p_1b; int8 level; - uint16 p_2a; - uint16 p_2b; - uint8 field_10; - uint8 field_11; - uint8 field_12; - uint8 field_13; + uint16 itemPosX; + uint16 itemPosY; + uint8 field10; + uint16 anon8; + uint8 anon9; + uint8 field_14; uint8 field_15; uint8 field_16; @@ -132,7 +150,7 @@ struct LVL { int16 field_1D; uint8 field_1F; uint8 field_20; - uint8 *offs_lvl415; + MonsterProperty *monsters; uint8 field_25; uint8 field_26; uint8 field_27; @@ -145,6 +163,34 @@ struct LVL { uint8 field_2E; }; +struct ItemInPlay { + uint16 itemIndexUnk; + uint8 unk2; + uint16 unk3; + uint16 blockPropertyIndex; + uint16 p_1a; + uint16 p_1b; + int8 level; + uint16 itemPropertyIndex; + uint16 shpCurFrame_flg; + uint8 field10; + uint16 anon8; + uint8 anon9; +}; + +struct ItemProperty { + uint16 nameStringId; + uint8 shpIndex; + uint16 flags; + uint16 unk5; + uint8 itemScriptFunc; + int8 unk8; + uint8 unk9; + uint8 unkA; + uint16 unkB; + uint8 unkD; +}; + struct LevelShapeProperty { uint16 shapeIndex[10]; uint8 scaleFlag[10]; @@ -161,26 +207,31 @@ struct CompassDef { uint8 flags; }; -struct ScriptOffsUnkStruct { - uint8 field_0; - uint8 field_1; - uint8 field_2; - uint8 field_3; - uint8 field_4; - uint8 field_5; - uint8 field_6; - uint8 field_7; - uint8 field_8; +struct ButtonDef { + uint16 buttonflags; + uint8 clickedShapeId; + uint8 unk1; + uint16 unk2; + int16 x; + int16 y; + uint16 w; + uint16 h; + uint16 index; + uint16 flag; }; class LoLEngine : public KyraEngine_v1 { +friend class GUI_LoL; +friend class TextDisplayer_LoL; public: LoLEngine(OSystem *system, const GameFlags &flags); ~LoLEngine(); Screen *screen(); + GUI *gui() const; private: Screen_LoL *_screen; + GUI_LoL *_gui; TIMInterpreter *_tim; Common::Error init(); @@ -190,18 +241,28 @@ private: void initStaticResource(); void preInit(); - void initializeCursors(); + void loadItemIconShapes(); int mainMenu(); void startup(); void startupNew(); + // main loop void runLoop(); + void update(); + + int setUnkFlags(int unk); + int removeUnkFlags(int unk); + int _intFlag3; + // mouse void setMouseCursorToIcon(int icon); void setMouseCursorToItemInHand(); uint8 *getItemIconShapePtr(int index); + bool posWithinRect(int mouseX, int mouseY, int x1, int y1, int x2, int y2); + + int _floatingMouseArrowControl; // intro void setupPrologueData(bool load); @@ -257,20 +318,25 @@ private: // sound void loadTalkFile(int index); - void snd_playVoiceFile(int); + void snd_playVoiceFile(int track) {} + bool snd_playCharacterSpeech(int id, int8 speaker, int); + int snd_characterSpeaking(); + int snd_dialogueSpeechUpdate(int finish); void snd_playSoundEffect(int track, int volume); void snd_loadSoundFile(int track); int snd_playTrack(int track); int snd_stopMusic(); + int _lastSpeechId; + int _lastSpeaker; + char _activeVoiceFile[13]; int _lastSfxTrack; int _lastMusicTrack; int _curMusicFileIndex; char _curMusicFileExt; - int _curTlkFile; - int _unkAudioSpecOffs; - bool _unkLangAudio; + int _curTlkFile; + int _speechFlag; char **_ingameSoundList; int _ingameSoundListSize; @@ -289,7 +355,7 @@ private: void gui_drawScene(int pageNum); void gui_drawAllCharPortraitsWithStats(); void gui_drawCharPortraitWithStats(int charNum); - void gui_drawPortraitBox(int x, int y, int w, int h, int frameColor1, int frameColor2, int fillColor); + void gui_drawBox(int x, int y, int w, int h, int frameColor1, int frameColor2, int fillColor); void gui_drawCharFaceShape(int charNum, int x, int y, int pageNum); void gui_drawLiveMagicBar(int x, int y, int curPoints, int unk, int maxPoints, int w, int h, int col1, int col2, int flag); void gui_drawMoneyBox(int pageNum); @@ -298,14 +364,63 @@ private: void gui_drawCompass(); void gui_drawScroll(); + int gui_enableControls(); + int gui_disableControls(int controlMode); + void gui_disableArrowButton(int shapeIndex, int mode); + void gui_toggleFightButtons(bool disable); + void gui_prepareForSequence(int x, int y, int w, int h, int unk); + bool _weaponsDisabled; - int _unkDrawPortraitIndex; - int _updateUnk2; + int _lastArrowButtonShape; + uint32 _arrowButtonTimer; + int _selectedCharacter; + int _compassDirection; + int _compassUnk; int _compassDirectionIndex; const CompassDef *_compassDefs; int _compassDefsSize; + void initButtonList(); + ButtonDef *_buttonData; + Button *_buttonList; + + int clickedUpArrow(Button *button); + int clickedDownArrow(Button *button); + int clickedLeftArrow(Button *button); + int clickedRightArrow(Button *button); + int clickedTurnLeftArrow(Button *button); + int clickedTurnRightArrow(Button *button); + int clickedAttackButton(Button *button); + int clickedMagicButton(Button *button); + int clickedUnk9(Button *button); + int clickedScreen(Button *button); + int clickedPortraitLeft(Button *button); + int clickedLiveMagicBarsLeft(Button *button); + int clickedPortraitEtcRight(Button *button); + int clickedUnk14(Button *button); + int clickedUnk15(Button *button); + int clickedUnk16(Button *button); + int clickedUnk17(Button *button); + int clickedInventorySlot(Button *button); + int clickedInventoryScroll(Button *button); + int clickedUnk20(Button *button); + int clickedUnk21(Button *button); + int clickedScroll(Button *button); + int clickedUnk23(Button *button); + int clickedUnk24(Button *button); + int clickedUnk25(Button *button); + int clickedOptions(Button *button); + int clickedRestParty(Button *button); + int clickedUnk28(Button *button); + int clickedUnk29(Button *button); + int clickedUnk30(Button *button); + int clickedUnk31(Button *button); + int clickedUnk32(Button *button); + + // text + TextDisplayer_LoL *_dlg; + // emc scripts void runInitScript(const char *filename, int func); void runInfScript(const char *filename); @@ -318,7 +433,7 @@ private: uint8 _unkScriptByte; uint16 _currentDirection; uint16 _currentBlock; - bool _boolScriptFuncDone; + bool _sceneUpdateRequired; int16 _scriptExecutedFuncs[18]; uint16 _gameFlags[15]; uint16 _unkEMC46[16]; @@ -338,17 +453,32 @@ private: int olol_loadLevelShapes(EMCState *script); int olol_closeLevelShapeFile(EMCState *script); int olol_loadDoorShapes(EMCState *script); + int olol_initAnimStruct(EMCState *script); + int olol_freeAnimStruct(EMCState *script); int olol_setMusicTrack(EMCState *script); int olol_getUnkArrayVal(EMCState *script); int olol_setUnkArrayVal(EMCState *script); int olol_setGlobalVar(EMCState *script); int olol_mapShapeToBlock(EMCState *script); int olol_resetBlockShapeAssignment(EMCState *script); + int olol_loadMonsterProperties(EMCState *script); + int olol_loadTimScript(EMCState *script); + int olol_runTimScript(EMCState *script); + int olol_releaseTimScript(EMCState *script); + int olol_initDialogueSequence(EMCState *script); + int olol_restoreSceneAfterDialogueSequence(EMCState *script); int olol_loadLangFile(EMCState *script); + int olol_stopTimScript(EMCState *script); int olol_loadSoundFile(EMCState *script); int olol_setPaletteBrightness(EMCState *script); + int olol_playDialogueTalkText(EMCState *script); + int olol_setNextFunc(EMCState *script); int olol_assignCustomSfx(EMCState *script); + // tim scripts + TIMInterpreter::Animation *initTimAnimStruct(int index, const char *filename, int x, int y, uint16 copyPara, uint16 wsaFlags); + TIM *_activeTim[10]; + // tim opcode void setupOpcodeTable(); @@ -359,6 +489,8 @@ private: int tlol_processWsaFrame(const TIM *tim, const uint16 *param); int tlol_displayText(const TIM *tim, const uint16 *param); + Common::Array<const TIMOpcode*> _timIngameOpcodes; + // translation int _lang; @@ -368,13 +500,19 @@ private: int _lastUsedStringBuffer; char _stringBuffer[5][512]; // TODO: The original used a size of 512, it looks a bit large. // Maybe we can someday reduce the size. - const char *getLangString(uint16 id); + char *getLangString(uint16 id); uint8 *getTableEntry(uint8 *buffer, uint16 id); static const char * const _languageExt[]; // graphics void setupScreenDims(); + void initDialogueSequence(int controlMode); + void unkHideInventory(); + void restoreSceneAfterDialogueSequence(int redraw); + void toggleSelectedCharacterFrame(bool mode); + void restorePaletteEntry(); + void updateWsaAnimations(); uint8 **_itemIconShapes; int _numItemIconShapes; @@ -405,21 +543,21 @@ private: void updatePortraitWithStats(); void updatePortraits(); void updatePortraitUnkTimeSub(int unk1, int unk2); - + void charCallback4(int redraw); void setCharFaceFrame(int charNum, int frameNum); void faceFrameRefresh(int charNum); LoLCharacter *_characters; uint16 _activeCharsXpos[3]; - int _charFlagUnk; + int _updateFlags; int _updateCharNum; int _updateCharV1; int _updateCharV2; int _updateCharV3; int _updateCharV4; - int _updateCharV5; - int _updateCharV6; - uint32 _updateCharTime; + int _restorePalette; + int _hideInventory; + uint32 _palUpdateTimer; uint32 _updatePortraitNext; int _loadLevelFlag; @@ -433,19 +571,30 @@ private: const LoLCharacter *_charDefaults; int _charDefaultsSize; + // lamp + void resetLampStatus(); + void setLampMode(bool lampOn); + void updateLampStatus(); + + int _lampOilStatus; + int _brightness; + int _lampStatusUnk; + uint32 _lampStatusTimer; + bool _lampStatusSuspended; + // level void loadLevel(int index); void addLevelItems(); int initCmzWithScript(int block); - void initCMZ1(LVL *l, int a); - void initCMZ2(LVL *l, uint16 a, uint16 b); - int cmzS1(uint16 a, uint16 b, uint16 c, uint16 d); - void cmzS2(LVL *l, int a); - void cmzS3(LVL *l); + void initCMZ1(CLevelItem *l, int a); + void initCMZ2(CLevelItem *l, uint16 a, uint16 b); + int cmzS1(uint16 x1, uint16 y1, uint16 x2, uint16 y2); + void cmzS2(CLevelItem *l, int a); + void cmzS3(CLevelItem *l); void cmzS4(uint16 &itemIndex, int a); int cmzS5(uint16 a, uint16 b); void cmzS6(uint16 &itemIndex, int a); - void cmzS7(int itemIndex, int a); + void cmzS7(int a, int block); void loadLevelWLL(int index, bool mapShapes); void moveItemToBlock(uint16 *cmzItemIndex, uint16 item); int assignLevelShapes(int index); @@ -484,17 +633,15 @@ private: void drawScriptShapes(int pageNum); void updateSceneWindow(); - void turnOnLamp(); - void updateLampStatus(); + void updateCompass(); void moveParty(uint16 direction, int unk1, int unk2, int unk3); uint16 calcNewBlockPostion(uint16 curBlock, uint16 direction); - void setLF1(uint16 & a, uint16 & b, int block, uint16 d, uint16 e); void setLF2(int block); int _unkFlag; - int _scriptFuncIndex; + int _nextScriptFunc; uint8 _currentLevel; bool _loadLevelFlag2; int _lvlBlockIndex; @@ -520,16 +667,11 @@ private: int _sceneDrawVar3; int _wllProcessFlag; - uint8 *_tlcTable2; - uint8 *_tlcTable1; + uint8 *_trueLightTable2; + uint8 *_trueLightTable1; int _loadSuppFilesFlag; - int _lampOilStatus; - int _brightness; - int _lampStatusUnk; - uint32 _lampStatusTimer; - uint8 *_wllVmpMap; int8 *_wllShapeMap; uint8 *_wllBuffer3; @@ -542,11 +684,11 @@ private: LevelBlockProperty *_levelBlockProperties; LevelBlockProperty *_curBlockCaps[18]; - LVL *_lvlBuffer; - uint8 *_lvl415; + CLevelItem *_cLevelItems; + MonsterProperty *_monsterProperties; - uint16 _unkCmzU1; - uint16 _unkCmzU2; + uint16 _partyPosX; + uint16 _partyPosY; Common::SeekableReadStream *_lvlShpFileHandle; uint16 _lvlShpNum; @@ -559,6 +701,8 @@ private: int16 _dmScaleW; int16 _dmScaleH; + int _lastMouseRegion; + int _preSeq_X1, _preSeq_Y1, _preSeq_X2, _preSeq_Y2; uint8 _unkGameFlag; uint8 *_tempBuffer5120; @@ -616,39 +760,11 @@ private: int _sceneDrawPage2; // items - struct ItemInPlay { - uint16 itemIndexUnk; - uint8 unk2; - uint16 unk3; - uint16 blockPropertyIndex; - uint16 unk7; - uint16 anonymous_4; - int8 level; - uint16 itemPropertyIndex; - uint16 shpCurFrame_flg; - uint8 field10; - uint16 anon8; - uint8 anon9; - }; - - struct ItemProperty { - uint16 nameStringId; - uint8 shpIndex; - uint16 flags; - uint16 unk5; - uint8 itemScriptFunc; - uint8 unk8; - uint8 unk9; - uint8 unkA; - uint16 unkB; - uint8 unkD; - }; - void giveCredits(int credits, int redraw); int makeItem(int itemIndex, int curFrame, int flags); bool testUnkItemFlags(int itemIndex); void clearItemTableEntry(int itemIndex); - void *cmzGetItemOffset(uint16 index); + CLevelItem *findItem(uint16 index); void runItemScript(int reg1, int item, int reg0, int reg3, int reg4); uint8 _moneyColumnHeight[5]; @@ -658,12 +774,16 @@ private: ItemProperty *_itemProperties; int _itemInHand; - uint16 _inventoryItemIndex[48]; + uint16 _inventory[48]; int _inventoryCurItem; - int _unkInventFlag; + int _hideControls; EMCData _itemScript; + // misc + void runLoopSub4(int a); + void calcCoordinates(uint16 & x, uint16 & y, int block, uint16 xOffs, uint16 yOffs); + // spells int8 _availableSpells[7]; int _selectedSpell; diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk index 0775fe3ec4..e427ee1b43 100644 --- a/engines/kyra/module.mk +++ b/engines/kyra/module.mk @@ -65,6 +65,7 @@ MODULE_OBJS := \ staticres.o \ text.o \ text_lok.o \ + text_lol.o \ text_hof.o \ text_mr.o \ timer.o \ diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp index a458b93fae..698330e275 100644 --- a/engines/kyra/scene_lol.cpp +++ b/engines/kyra/scene_lol.cpp @@ -35,7 +35,7 @@ namespace Kyra { void LoLEngine::loadLevel(int index) { _unkFlag |= 0x800; setMouseCursorToIcon(0x85); - _scriptFuncIndex = 0; + _nextScriptFunc = 0; snd_stopMusic(); @@ -57,7 +57,7 @@ void LoLEngine::loadLevel(int index) { // TODO _currentLevel = index; - _charFlagUnk = 0; + _updateFlags = 0; // TODO @@ -111,32 +111,33 @@ void LoLEngine::addLevelItems() { int LoLEngine::initCmzWithScript(int block) { int i = _levelBlockProperties[block].itemIndex; int cnt = 0; + CLevelItem *t = 0; - while (i) { - void *t = cmzGetItemOffset(i); - i = (i & 0x8000) ? ((LVL*)t)->itemIndexUnk : ((ItemInPlay*)t)->itemIndexUnk; + while (i) { + t = findItem(i); + i = t->itemIndexUnk; if (!(i & 0x8000)) continue; i &= 0x7fff; - LVL *l = &_lvlBuffer[i]; + t = &_cLevelItems[i]; cnt++; - initCMZ1(l, 14); + initCMZ1(t, 14); - checkScriptUnk(l->blockPropertyIndex); + checkScriptUnk(t->blockPropertyIndex); - initCMZ2(l, 0, 0); + initCMZ2(t, 0, 0); } return cnt; } -void LoLEngine::initCMZ1(LVL *l, int a) { +void LoLEngine::initCMZ1(CLevelItem *l, int a) { if (l->field_14 == 13 && a != 14) return; if (a == 7) { - l->p_2a = _unkCmzU1; - l->p_2b = _unkCmzU2; + l->itemPosX = _partyPosX; + l->itemPosY = _partyPosX; } if (l->field_14 == 1 && a == 7) { @@ -145,9 +146,9 @@ void LoLEngine::initCMZ1(LVL *l, int a) { continue; l->field_14 = a; l->field_15 = 0; - l->p_2a = _unkCmzU1; - l->p_2b = _unkCmzU2; - cmzS2(l, cmzS1(l->p_1a, l->p_1b, l->p_2a, l->p_2b)); + l->itemPosX = _partyPosX; + l->itemPosY = _partyPosY; + cmzS2(l, cmzS1(l->p_1a, l->p_1b, l->itemPosX, l->itemPosY)); } } else { l->field_14 = a; @@ -168,7 +169,7 @@ void LoLEngine::initCMZ1(LVL *l, int a) { } -void LoLEngine::initCMZ2(LVL *l, uint16 a, uint16 b) { +void LoLEngine::initCMZ2(CLevelItem *l, uint16 a, uint16 b) { bool cont = true; int t = l->blockPropertyIndex; if (l->blockPropertyIndex) { @@ -184,7 +185,7 @@ void LoLEngine::initCMZ2(LVL *l, uint16 a, uint16 b) { if (l->p_1a != a || l->p_1b != b) { l->p_1a = a; l->p_1b = b; - l->field_13 = (++l->field_13) & 3; + l->anon9 = (++l->anon9) & 3; } if (l->blockPropertyIndex == 0) @@ -193,34 +194,64 @@ void LoLEngine::initCMZ2(LVL *l, uint16 a, uint16 b) { cmzS6(_levelBlockProperties[l->blockPropertyIndex].itemIndex, ((uint16)l->field_16) | 0x8000); _levelBlockProperties[l->blockPropertyIndex].field_8 = 5; checkScriptUnk(l->blockPropertyIndex); - uint8 *v = l->offs_lvl415; - if (v[80] == 0 || cont == false) + if (l->monsters->unk8[0] == 0 || cont == false) return; - if ((!(READ_LE_UINT16(&v[62]) & 0x100) || ((l->field_13 & 1) == 0)) && l->blockPropertyIndex == t) + if ((!(l->monsters->unk5[0] & 0x100) || ((l->anon9 & 1) == 0)) && l->blockPropertyIndex == t) return; if (l->blockPropertyIndex != t) runResidentScriptCustom(l->blockPropertyIndex, 0x800, -1, l->field_16, 0, 0); - if (_charFlagUnk & 1) + if (_updateFlags & 1) return; - cmzS7(l->offs_lvl415[50], l->blockPropertyIndex); + cmzS7(l->monsters->unk3[5], l->blockPropertyIndex); } -int LoLEngine::cmzS1(uint16 a, uint16 b, uint16 c, uint16 d) { - // TODO +int LoLEngine::cmzS1(uint16 x1, uint16 y1, uint16 x2, uint16 y2) { + int16 r = 0; + int16 t1 = y1 - y2; + if (t1 < 0) { + r++; + t1 = -t1; + } - return 0; + r <<= 1; + + int16 t2 = x2 - x1; + + if (t2 < 0) { + r++; + t2 = -t2; + } + + uint8 f = 0; + + if (t2 >= t1) { + if (t2 > t1) + f = 1; + SWAP(t1, t2); + } + + r = (r << 1) | f; + + t1 = (t1 + 1) >> 1; + + f = 0; + f = (t2 > t1) ? 1 : 0; + r = (r << 1) | f; + + static const uint8 Retv[] = { 1, 2, 1, 0, 7, 6, 7, 0, 3, 2, 3, 4, 5, 6, 5, 4}; + return Retv[r]; } -void LoLEngine::cmzS2(LVL *l, int a) { +void LoLEngine::cmzS2(CLevelItem *l, int a) { // TODO } -void LoLEngine::cmzS3(LVL *l) { +void LoLEngine::cmzS3(CLevelItem *l) { // TODO } @@ -237,7 +268,7 @@ void LoLEngine::cmzS6(uint16 &itemIndex, int a) { // TODO } -void LoLEngine::cmzS7(int itemIndex, int a) { +void LoLEngine::cmzS7(int a, int block) { if (!(_unkGameFlag & 1)) return; @@ -245,24 +276,28 @@ void LoLEngine::cmzS7(int itemIndex, int a) { } void LoLEngine::moveItemToBlock(uint16 *cmzItemIndex, uint16 item) { - uint16 *tmp = 0; - while (*cmzItemIndex & 0x8000) { - tmp = (uint16*) cmzGetItemOffset(*cmzItemIndex); - cmzItemIndex = tmp; + CLevelItem *tmp = 0; + + while (*cmzItemIndex & 0x8000) { + tmp = findItem(*cmzItemIndex); + cmzItemIndex = &tmp->itemIndexUnk; } - uint16 *t = (uint16*) cmzGetItemOffset(*cmzItemIndex); - ((ItemInPlay*)t)->level = -1; + tmp = findItem(item); + tmp->level = -1; + uint16 ix = *cmzItemIndex; if (ix == item) return; *cmzItemIndex = item; - cmzItemIndex = t; + cmzItemIndex = &tmp->itemIndexUnk; - while (*cmzItemIndex) - cmzItemIndex = (uint16*) cmzGetItemOffset(*cmzItemIndex); + while (*cmzItemIndex) { + tmp = findItem(*cmzItemIndex); + cmzItemIndex = &tmp->itemIndexUnk; + } *cmzItemIndex = ix; } @@ -394,10 +429,10 @@ void LoLEngine::loadLevelCmzFile(int index) { _levelBlockProperties[i].flags = *t++; for (int i = 0; i < 30; i++) { - if (_lvlBuffer[i].blockPropertyIndex) { - _lvlBuffer[i].blockPropertyIndex = 0; - _lvlBuffer[i].offs_lvl415 = _lvl415 + _lvlBuffer[i].field_20; - initCMZ2(&_lvlBuffer[i], _lvlBuffer[i].p_1a, _lvlBuffer[i].p_1b); + if (_cLevelItems[i].blockPropertyIndex) { + _cLevelItems[i].blockPropertyIndex = 0; + _cLevelItems[i].monsters = _monsterProperties + _cLevelItems[i].field_20; + initCMZ2(&_cLevelItems[i], _cLevelItems[i].p_1a, _cLevelItems[i].p_1b); } } @@ -413,15 +448,15 @@ void LoLEngine::loadCMZ_Sub(int index1, int index2) { //int r = 0; for (int i = 0; i < 30; i++) { - if (_lvlBuffer[i].field_14 >= 14 || _lvlBuffer[i].blockPropertyIndex == 0 || _lvlBuffer[i].field_1D <= 0) + if (_cLevelItems[i].field_14 >= 14 || _cLevelItems[i].blockPropertyIndex == 0 || _cLevelItems[i].field_1D <= 0) continue; - int t = (val * _lvlBuffer[i].field_1D) >> 8; - _lvlBuffer[i].field_1D = t; + int t = (val * _cLevelItems[i].field_1D) >> 8; + _cLevelItems[i].field_1D = t; if (index2 < index1) - _lvlBuffer[i].field_1D++; - if (_lvlBuffer[i].field_1D == 0) - _lvlBuffer[i].field_1D = 1; + _cLevelItems[i].field_1D++; + if (_cLevelItems[i].field_1D == 0) + _cLevelItems[i].field_1D = 1; } } @@ -475,7 +510,7 @@ void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int b) { memset(_monsterPalettes[pos + i], 0, size); } - /*for (int i = 0; i < 4; i++) { + for (int i = 0; i < 4; i++) { for (int ii = 0; ii < 16; ii++) { uint8 **of = &_buf4[(monsterIndex << 7) + (i << 5) + (ii << 1)]; int s = (i << 4) + ii + 17; @@ -483,7 +518,7 @@ void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int b) { ////TODO } - }*/ + } _monsterUnk[monsterIndex] = b & 0xff; uint8 *tsh = _screen->makeShapeCopy(p, 16); @@ -678,8 +713,8 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight char tname[13]; snprintf(tname, sizeof(tname), "LEVEL%.02d.TLC", _currentLevel); Common::SeekableReadStream *s = _res->createReadStream(tname); - s->read(_tlcTable1, 256); - s->read(_tlcTable2, 5120); + s->read(_trueLightTable1, 256); + s->read(_trueLightTable2, 5120); delete s; _loadSuppFilesFlag = 1; @@ -689,10 +724,10 @@ void LoLEngine::resetItems(int flag) { for (int i = 0; i < 1024; i++) { _levelBlockProperties[i].field_8 = 5; uint16 id = _levelBlockProperties[i].itemIndex; - LVL *r = 0; + CLevelItem *r = 0; while (id & 0x8000) { - r = (LVL*)cmzGetItemOffset(id); + r = (CLevelItem*)findItem(id); assert(r); id = r->itemIndexUnk; } @@ -711,9 +746,9 @@ void LoLEngine::resetItems(int flag) { } void LoLEngine::resetLvlBuffer() { - memset(_lvlBuffer, 0, 30 * sizeof(LVL)); + memset(_cLevelItems, 0, 30 * sizeof(CLevelItem)); for (int i = 0; i < 30; i++) - _lvlBuffer[i].field_14 = 0x10; + _cLevelItems[i].field_14 = 0x10; } void LoLEngine::resetBlockProperties() { @@ -739,17 +774,26 @@ bool LoLEngine::testWallInvisibility(int block, int direction) { return true; } -void LoLEngine::turnOnLamp() { +void LoLEngine::resetLampStatus() { _screen->_drawGuiFlag |= 0x400; _lampOilStatus = 255; updateLampStatus(); } +void LoLEngine::setLampMode(bool lampOn) { + _screen->_drawGuiFlag &= 0xFBFF; + if (!(_screen->_drawGuiFlag & 0x800) || !lampOn) + return; + + _screen->drawShape(0, _gameShapes[43], 291, 56, 0, 0); + _lampOilStatus = 8; +} + void LoLEngine::updateLampStatus() { uint8 newLampOilStatus = 0; uint8 tmp2 = 0; - if ((_charFlagUnk & 4) || !(_screen->_drawGuiFlag & 0x800)) + if ((_updateFlags & 4) || !(_screen->_drawGuiFlag & 0x800)) return; if (!_brightness || !_lampStatusUnk) { @@ -790,6 +834,10 @@ void LoLEngine::updateLampStatus() { _lampOilStatus = newLampOilStatus; } +void LoLEngine::updateCompass() { + +} + void LoLEngine::moveParty(uint16 direction, int unk1, int unk2, int unk3) { // TODO _currentBlock = calcNewBlockPostion(_currentBlock, direction); @@ -801,12 +849,6 @@ uint16 LoLEngine::calcNewBlockPostion(uint16 curBlock, uint16 direction) { return (curBlock + blockPosTable[direction]) & 0x3ff; } -void LoLEngine::setLF1(uint16 & a, uint16 & b, int block, uint16 d, uint16 e) { - a = block & 0x1f; - a = ((a >> 8) | ((a & 0xff) << 8)) | d; - b = ((block & 0xffe0) << 3) | e; -} - void LoLEngine::setLF2(int block) { if (!(_screen->_drawGuiFlag & 0x1000)) return; @@ -833,23 +875,24 @@ void LoLEngine::drawScene(int pageNum) { drawVcnBlocks(_vcnBlocks, _blockDrawingBuffer, _vcnShift, _sceneDrawPage1); drawSceneShapes(); - if (pageNum) { + if (!pageNum) { drawScriptShapes(_sceneDrawPage1); - _screen->copyRegion(112, 112, 0, 0, 176, 120, _sceneDrawPage1, _sceneDrawPage2); - _screen->copyRegion(112, 112, 0, 0, 176, 120, _sceneDrawPage1, 0); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK); _sceneDrawPage1 ^= _sceneDrawPage2; _sceneDrawPage2 ^= _sceneDrawPage1; _sceneDrawPage1 ^= _sceneDrawPage2; } + runLoopSub4(0); gui_drawCompass(); - _boolScriptFuncDone = false; + _sceneUpdateRequired = false; } void LoLEngine::updateSceneWindow() { _screen->hideMouse(); - _screen->copyRegion(112, 0, 112, 0, 176, 120, 0, _sceneDrawPage2); + _screen->copyRegion(112, 0, 112, 0, 176, 120, 0, _sceneDrawPage2, Screen::CR_NO_P_CHECK); _screen->showMouse(); } @@ -1427,9 +1470,9 @@ void LoLEngine::drawDoorOrMonsterShape(uint8 *shape, uint8 *table, int x, int y, if (flg & 0x1000) { if (table) - _screen->drawShape(_sceneDrawPage1, shape, x, y, 13, flg | 0x9104, table, ovl, 1, _tlcTable1, _tlcTable2, _dmScaleW, _dmScaleH); + _screen->drawShape(_sceneDrawPage1, shape, x, y, 13, flg | 0x9104, table, ovl, 1, _trueLightTable1, _trueLightTable2, _dmScaleW, _dmScaleH); else - _screen->drawShape(_sceneDrawPage1, shape, x, y, 13, flg | 0x1104, ovl, 1, _tlcTable1, _tlcTable2, _dmScaleW, _dmScaleH); + _screen->drawShape(_sceneDrawPage1, shape, x, y, 13, flg | 0x1104, ovl, 1, _trueLightTable1, _trueLightTable2, _dmScaleW, _dmScaleH); } else { if (table) _screen->drawShape(_sceneDrawPage1, shape, x, y, 13, flg | 0x8104, table, ovl, 1, _dmScaleW, _dmScaleH); diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp index a7be3e5371..78ac2c3a89 100644 --- a/engines/kyra/screen_lol.cpp +++ b/engines/kyra/screen_lol.cpp @@ -44,6 +44,8 @@ Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system), _fadeFlag = 2; _drawGuiFlag = 0; + _curDimIndex = 0; + _dimLineCount = 0; } Screen_LoL::~Screen_LoL() { @@ -63,6 +65,8 @@ void Screen_LoL::setScreenDim(int dim) { debugC(9, kDebugLevelScreen, "Screen_LoL::setScreenDim(%d)", dim); assert(dim < _screenDimTableCount); _curDim = _customDimTable[dim] ? (const ScreenDim *)_customDimTable[dim] : &_screenDimTable[dim]; + _curDimIndex = dim; + _dimLineCount = 0; } const ScreenDim *Screen_LoL::getScreenDim(int dim) { @@ -89,6 +93,7 @@ void Screen_LoL::clearDim(int dim) { void Screen_LoL::clearCurDim() { fillRect(_curDim->sx << 3, _curDim->sy, ((_curDim->sx + _curDim->w) << 3) - 1, (_curDim->sy + _curDim->h) - 1, _curDim->unkA); + _dimLineCount = 0; } void Screen_LoL::fprintString(const char *format, int x, int y, uint8 col1, uint8 col2, uint16 flags, ...) { @@ -277,6 +282,22 @@ void Screen_LoL::drawGridBox(int x, int y, int w, int h, int col) { } } +void Screen_LoL::fadeClearSceneWindow(int delay) { + if (_fadeFlag == 1) + return; + + uint8 *tpal = new uint8[768]; + + memcpy(tpal, _currentPalette, 768); + memset(tpal, 0, 384); + loadSpecialColours(tpal); + fadePalette(tpal, delay); + fillRect(112, 0, 288, 120, 0); + delete[] tpal; + + _fadeFlag = 1; +} + void Screen_LoL::fadeToBlack(int delay, const UpdateFunctor *upFunc) { Screen::fadeToBlack(delay, upFunc); _fadeFlag = 2; @@ -290,7 +311,7 @@ void Screen_LoL::setPaletteBrightness(uint8 *palette, int brightness, int modifi void Screen_LoL::generateBrightnessPalette(uint8 *src, uint8 *dst, int brightness, int modifier) { memcpy(dst, src, 0x300); - setPaletteColoursSpecial(dst); + loadSpecialColours(dst); brightness = (8 - brightness) << 5; if (modifier >= 0 && modifier < 8 && _drawGuiFlag & 0x800) { brightness = 256 - ((((modifier & 0xfffe) << 5) * (256 - brightness)) >> 8); @@ -304,10 +325,55 @@ void Screen_LoL::generateBrightnessPalette(uint8 *src, uint8 *dst, int brightnes } } -void Screen_LoL::setPaletteColoursSpecial(uint8 *palette) { - const uint8 src[] = { 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00 }; - palette += 0x240; - memcpy(palette, src, 12); +void Screen_LoL::loadSpecialColours(uint8 *destPalette) { + memcpy(destPalette + 0x240, _screenPalette + 0x240, 12); +} + +void Screen_LoL::loadColour254(uint8 *destPalEntry) { + memcpy(destPalEntry, _screenPalette + 0x2fa, 3); +} + +bool Screen_LoL::copyColour(int dstColorIndex, int srcColorIndex, uint32 time1, uint32 time2) { + uint8 *s = _screenPalette + 3 * dstColorIndex; + uint8 *e = _screenPalette + 3 * srcColorIndex; + uint8 *p = getPalette(1) + 3 * dstColorIndex; + + bool res = false; + + uint16 t1 = 0; + uint16 t2 = 0; + int32 t3 = 0; + + uint8 tmpPalEntry[3]; + + for (int i = 0; i < 3; i++) { + if (time1 < time2) { + t1 = *e & 0x3f; + t2 = *s & 0x3f; + + t3 = t1 - t2; + if (!t3) + res = true; + + t3 = (((((t3 << 8) / time2) * time1) >> 8) & 0xffff) + t2; + } else { + t1 = *e & 0x3f; + *p = t3 = t1; + res = false; + } + + tmpPalEntry[i] = t3 & 0xff; + s++; + e++; + p++; + } + + uint8 tpal[768]; + memcpy(tpal, _screenPalette, 768); + memcpy(tpal + dstColorIndex * 3, tmpPalEntry, 3); + setScreenPalette(tpal); + + return res; } uint8 Screen_LoL::getShapePaletteSize(const uint8 *shp) { diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h index a4c7d8c749..0f8746ef00 100644 --- a/engines/kyra/screen_lol.h +++ b/engines/kyra/screen_lol.h @@ -39,6 +39,7 @@ public: void setScreenDim(int dim); const ScreenDim *getScreenDim(int dim); + int curDimIndex() { return _curDimIndex; } void modifyScreenDim(int dim, int x, int y, int w, int h); void clearDim(int dim); void clearCurDim(); @@ -47,15 +48,17 @@ public: void fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint16 flags, ...); void drawGridBox(int x, int y, int w, int h, int col); + void fadeClearSceneWindow(int delay); void fadeToBlack(int delay=0x54, const UpdateFunctor *upFunc = 0); void setPaletteBrightness(uint8 *palDst, int brightness, int modifier); void generateBrightnessPalette(uint8 *palSrc, uint8 *palDst, int brightness, int modifier); - void setPaletteColoursSpecial(uint8 *palette); + void loadSpecialColours(uint8 *destPalette); + void loadColour254(uint8 *destPalEntry); + bool copyColour(int dstColorIndex, int srcColorIndex, uint32 time1, uint32 time2); void generateGrayOverlay(const uint8 *srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColours); uint8 *generateLevelOverlay(const uint8 *srcPal, uint8 *ovl, int opColor, int weight); - uint8 *getLevelOverlay(int index) { return _levelOverlays[index]; } uint8 getShapePaletteSize(const uint8 *shp); @@ -65,6 +68,7 @@ public: uint8 *_grayOverlay; int _fadeFlag; int _drawGuiFlag; + int _dimLineCount; private: LoLEngine *_vm; @@ -73,6 +77,7 @@ private: static const int _screenDimTableCount; ScreenDim **_customDimTable; + int _curDimIndex; uint8 *_levelOverlays[8]; }; diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp index 9bbf04fa09..00ef33e3cf 100644 --- a/engines/kyra/script_lol.cpp +++ b/engines/kyra/script_lol.cpp @@ -85,18 +85,18 @@ void LoLEngine::runResidentScriptCustom(int func, int reg0, int reg1, int reg2, } bool LoLEngine::checkScriptUnk(int func) { - if (_boolScriptFuncDone) + if (_sceneUpdateRequired) return true; for (int i = 0; i < 15; i++) { if (_scriptExecutedFuncs[i] == func) { - _boolScriptFuncDone = true; + _sceneUpdateRequired = true; return true; } } if (_currentBlock == func){ - _boolScriptFuncDone = true; + _sceneUpdateRequired = true; return true; } @@ -182,9 +182,9 @@ int LoLEngine::olol_getItemPara(EMCState *script) { case 0: return i->blockPropertyIndex; case 1: - return i->unk7; + return i->p_1a; case 2: - return i->anonymous_4; + return i->p_1b; case 3: return i->level; case 4: @@ -228,35 +228,45 @@ int LoLEngine::olol_getCharacterStat(EMCState *script) { switch (stackPos(1)) { case 0: return c->flags; + case 1: return c->raceClassSex; - case 2: - case 3: - case 4: - default: - break; + case 5: return c->hitPointsCur; + case 6: return c->hitPointsMax; + case 7: return c->magicPointsCur; + case 8: return c->magicPointsMax; + case 9: return c->field_37; + case 10: return c->items[d]; + case 11: return c->field_66[d] + c->field_69[d]; + case 12: return c->field_27[d]; + case 13: return (d & 0x80) ? c->field_25 : c->field_17[d]; + case 14: return c->field_69[d]; + case 15: return c->id; + + default: + break; } return 0; @@ -275,40 +285,60 @@ int LoLEngine::olol_setCharacterStat(EMCState *script) { // fall through please add "// fall through" at the end of the // case. switch (stackPos(1)) { + case 0: c->flags = e; + break; + case 1: c->raceClassSex = e & 0x0f; - case 2: - case 3: - case 4: - default: break; + case 5: //// TODO break; + case 6: c->hitPointsMax = e; + break; + case 7: //// TODO break; + case 8: c->magicPointsMax = e; + break; + case 9: c->field_37 = e; + break; + case 10: c->items[d] = 0; + break; + case 11: c->field_66[d] = e; + break; + case 12: c->field_27[d] = e; + break; + case 13: if (d & 0x80) c->field_25 = e; else c->field_17[d] = e; + break; + case 14: c->field_69[d] = e; + break; + + default: + break; } return 0; @@ -360,6 +390,18 @@ int LoLEngine::olol_loadDoorShapes(EMCState *script) { return 1; } +int LoLEngine::olol_initAnimStruct(EMCState *script) { + if (initTimAnimStruct(stackPos(1), stackPosString(0), stackPos(2), stackPos(3), stackPos(4), stackPos(5))) + return 1; + return 0; +} + +int LoLEngine::olol_freeAnimStruct(EMCState *script) { + if (_tim->freeAnimStruct(stackPos(0))) + return 1; + return 0; +} + int LoLEngine::olol_setMusicTrack(EMCState *script) { _curMusicTheme = stackPos(0); return 1; @@ -382,7 +424,7 @@ int LoLEngine::olol_setGlobalVar(EMCState *script) { switch (stackPos(0)) { case 0: _currentBlock = b; - setLF1(_unkCmzU1, _unkCmzU2, _currentBlock, 0x80, 0x80); + calcCoordinates(_partyPosX, _partyPosY, _currentBlock, 0x80, 0x80); setLF2(_currentBlock); break; case 1: @@ -405,8 +447,14 @@ int LoLEngine::olol_setGlobalVar(EMCState *script) { case 7: break; case 8: - _charFlagUnk = b; - //TODO + _updateFlags = b; + if (b == 1) { + if (!textEnabled() || !(_hideControls & 2)) + charCallback4(1); + removeUnkFlags(2); + } else { + setUnkFlags(2); + } break; case 9: _lampStatusUnk = b & 0xff; @@ -441,6 +489,95 @@ int LoLEngine::olol_resetBlockShapeAssignment(EMCState *script) { return 1; } +int LoLEngine::olol_loadMonsterProperties(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadMonsterProperties(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", + (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), + stackPos(6), stackPos(7), stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPos(12), stackPos(13), + stackPos(14), stackPos(15), stackPos(16), stackPos(17), stackPos(18), stackPos(19), stackPos(20), + stackPos(21), stackPos(22), stackPos(23), stackPos(24), stackPos(25), stackPos(26), stackPos(27), + stackPos(28), stackPos(29), stackPos(30), stackPos(31), stackPos(32), stackPos(33), stackPos(34), + stackPos(35), stackPos(36), stackPos(37), stackPos(38), stackPos(39), stackPos(40), stackPos(41)); + + MonsterProperty *l = &_monsterProperties[stackPos(0) * 83]; + l->id = stackPos(1) & 0xff; + + int shpWidthMax = 0; + + for (int i = 0; i < 16; i++) { + uint8 m = _monsterShapes[(l->id << 4) + i][3]; + if (m > shpWidthMax) + shpWidthMax = m; + } + + l->maxWidth = shpWidthMax; + + l->unk[0] = (stackPos(2) << 8) / 100; + l->unk[1] = 256; + l->unk[2] = (stackPos(3) << 8) / 100; + l->unk[3] = stackPos(4); + l->unk[4] = (stackPos(5) << 8) / 100; + l->unk[5] = (stackPos(6) << 8) / 100; + l->unk[6] = (stackPos(7) << 8) / 100; + l->unk[7] = (stackPos(8) << 8) / 100; + l->unk[8] = 0; + + for (int i = 0; i < 8; i++) { + l->unk2[i] = stackPos(9 + i); + l->unk3[i] = (stackPos(17 + i) << 8) / 100; + } + + l->pos = &l->unk[0]; + l->unk4[0] = stackPos(25); + l->unk4[1] = stackPos(26); + l->b = 1; + l->unk5[0] = stackPos(27); + l->unk5[1] = stackPos(28); + // FIXME??? + l->unk5[1] = stackPos(29); + // + + for (int i = 0; i < 5; i++) + l->unk6[2 + i] = stackPos(30 + i); + + for (int i = 0; i < 2; i++) { + l->unk7[i] = stackPos(35 + i); + l->unk7[i + 2] = stackPos(37 + i); + } + + for (int i = 0; i < 3; i++) + l->unk8[2 + i] = stackPos(39 + i); + + return 1; +} + +int LoLEngine::olol_loadTimScript(EMCState *script) { + if (_activeTim[stackPos(0)]) + return 1; + char file[13]; + snprintf(file, sizeof(file), "%s.TIM", stackPosString(1)); + _activeTim[stackPos(0)] = _tim->load(file, &_timIngameOpcodes); + return 1; +} + +int LoLEngine::olol_runTimScript(EMCState *script) { + return _tim->exec(_activeTim[stackPos(0)], stackPos(1)); +} + +int LoLEngine::olol_releaseTimScript(EMCState *script) { + _tim->unload(_activeTim[stackPos(0)]); + return 1; +} + +int LoLEngine::olol_initDialogueSequence(EMCState *script) { + initDialogueSequence(stackPos(0)); + return 1; +} + +int LoLEngine::olol_restoreSceneAfterDialogueSequence(EMCState *script) { + restoreSceneAfterDialogueSequence(stackPos(0)); + return 1; +} + int LoLEngine::olol_loadLangFile(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadLangFile(%p) (%s)", (const void *)script, stackPosString(0)); char filename[13]; @@ -451,6 +588,11 @@ int LoLEngine::olol_loadLangFile(EMCState *script) { return 1; } +int LoLEngine::olol_stopTimScript(EMCState *script) { + _tim->stopAllFuncs(_activeTim[stackPos(0)]); + return 1; +} + int LoLEngine::olol_loadSoundFile(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadSoundFile(%p) (%d)", (const void *)script, stackPos(0)); snd_loadSoundFile(stackPos(0)); @@ -466,6 +608,23 @@ int LoLEngine::olol_setPaletteBrightness(EMCState *script) { return old; } +int LoLEngine::olol_playDialogueTalkText(EMCState *script) { + int track = stackPos(0); + + if (!snd_playCharacterSpeech(track, 0, 0) || textEnabled()) { + char *s = getLangString(track); + _dlg->play(4, s, script, 0, 1); + } + + return 1; +} + +int LoLEngine::olol_setNextFunc(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setNextFunc(%p) (%d)", (const void *)script, stackPos(0)); + _nextScriptFunc = stackPos(0); + return 1; +} + int LoLEngine::olol_assignCustomSfx(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_assignCustomSfx(%p) (%s, %d)", (const void *)script, stackPosString(0), stackPos(1)); const char *c = stackPosString(0); @@ -484,6 +643,37 @@ int LoLEngine::olol_assignCustomSfx(EMCState *script) { #pragma mark - +TIMInterpreter::Animation *LoLEngine::initTimAnimStruct(int index, const char *filename, int x, int y, uint16 copyPara, uint16 wsaFlags) { + TIMInterpreter::Animation *a = _tim->initAnimStructIntern(index, filename, x, y, copyPara, wsaFlags); + + _tim->setWsaDrawPage2(0); + + if (wsaFlags & 1) { + if (_screen->_fadeFlag != 1) + _screen->fadeClearSceneWindow(10); + memcpy(_screen->getPalette(3) + 384, _screen->_currentPalette + 384, 384); + } else if (wsaFlags & 2) { + _screen->fadeToBlack(10); + } + + if (wsaFlags & 7) { + _screen->hideMouse(); + a->wsa->setDrawPage(0); + a->wsa->setX(x); + a->wsa->setY(y); + a->wsa->displayFrame(0, 0); + _screen->showMouse(); + } + + if (wsaFlags & 3) { + _screen->loadSpecialColours(_screen->getPalette(3)); + _screen->fadePalette(_screen->getPalette(3), 10); + _screen->_fadeFlag = 0; + } + + return a; +} + int LoLEngine::tlol_setupPaletteFade(const TIM *tim, const uint16 *param) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::t2_playSoundEffect(%p, %p) (%d)", (const void*)tim, (const void*)param, param[0]); _screen->getFadeParams(_screen->getPalette(0), param[0], _tim->_palDelayInc, _tim->_palDiff); @@ -595,9 +785,9 @@ void LoLEngine::setupOpcodeTable() { // 0x18 Opcode(olol_loadDoorShapes); + Opcode(olol_initAnimStruct); OpcodeUnImpl(); - OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_freeAnimStruct); // 0x1C OpcodeUnImpl(); @@ -651,7 +841,7 @@ void LoLEngine::setupOpcodeTable() { OpcodeUnImpl(); OpcodeUnImpl(); OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_loadMonsterProperties); // 0x40 OpcodeUnImpl(); @@ -674,13 +864,13 @@ void LoLEngine::setupOpcodeTable() { // 0x4C OpcodeUnImpl(); OpcodeUnImpl(); - OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_loadTimScript); + Opcode(olol_runTimScript); // 0x50 - OpcodeUnImpl(); - OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_releaseTimScript); + Opcode(olol_initDialogueSequence); + Opcode(olol_restoreSceneAfterDialogueSequence); OpcodeUnImpl(); // 0x54 @@ -691,7 +881,7 @@ void LoLEngine::setupOpcodeTable() { // 0x58 OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_stopTimScript); OpcodeUnImpl(); OpcodeUnImpl(); @@ -740,11 +930,11 @@ void LoLEngine::setupOpcodeTable() { // 0x78 OpcodeUnImpl(); OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_playDialogueTalkText); OpcodeUnImpl(); // 0x7C - OpcodeUnImpl(); + Opcode(olol_setNextFunc); OpcodeUnImpl(); OpcodeUnImpl(); OpcodeUnImpl(); @@ -846,7 +1036,6 @@ void LoLEngine::setupOpcodeTable() { OpcodeUnImpl(); Common::Array<const TIMOpcode*> *timTable = 0; - SetTimOpcodeTable(_timIntroOpcodes); // 0x00 @@ -860,6 +1049,35 @@ void LoLEngine::setupOpcodeTable() { OpcodeTim(tlol_displayText); OpcodeTimUnImpl(); OpcodeTimUnImpl(); + + SetTimOpcodeTable(_timIngameOpcodes); + + // 0x00 + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + + // 0x04 + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + + // 0x08 + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + + // 0x0C + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + OpcodeTimUnImpl(); + + // 0x10 + OpcodeTimUnImpl(); } } // end of namespace Kyra diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 24f7fce576..3df1daf306 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -28,6 +28,7 @@ #include "kyra/resource.h" #include "kyra/sound.h" #include "kyra/wsamovie.h" +#include "kyra/gui_lol.h" #include "common/endian.h" @@ -37,7 +38,7 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *sy #define COMMAND(x) { &TIMInterpreter::x, #x } #define COMMAND_UNIMPL() { 0, 0 } #define cmd_return(n) cmd_return_##n - static const CommandEntry commandProcs[] = { + static const CommandEntry commandProcsHOF[] = { // 0x00 COMMAND(cmd_initFunc0), COMMAND(cmd_stopCurFunc), @@ -74,22 +75,69 @@ TIMInterpreter::TIMInterpreter(KyraEngine_v1 *vm, Screen_v2 *screen, OSystem *sy COMMAND(cmd_initFuncNow), COMMAND(cmd_stopFuncNow), // 0x1C + COMMAND(cmd_processDialogue), + COMMAND(cmd_dialogueBox), + COMMAND(cmd_return(n1)) + }; + + static const CommandEntry commandProcsLOL[] = { + // 0x00 + COMMAND(cmd_initFunc0), + COMMAND(cmd_stopAllFuncs), + COMMAND(cmd_initWSA), + COMMAND(cmd_uninitWSA), + // 0x04 + COMMAND(cmd_initFunc), + COMMAND(cmd_stopFunc), + COMMAND(cmd_wsaDisplayFrame), + COMMAND_UNIMPL(), + // 0x08 + COMMAND(cmd_loadVocFile), + COMMAND(cmd_unloadVocFile), + COMMAND(cmd_playVocFile), + COMMAND_UNIMPL(), + // 0x0C + COMMAND(cmd_loadSoundFile), + COMMAND(cmd_return(1)), + COMMAND(cmd_playMusicTrack), + COMMAND_UNIMPL(), + // 0x10 COMMAND(cmd_return(1)), COMMAND(cmd_return(1)), + COMMAND_UNIMPL(), + COMMAND_UNIMPL(), + // 0x14 + COMMAND(cmd_setLoopIp), + COMMAND(cmd_continueLoop), + COMMAND(cmd_resetLoopIp), + COMMAND(cmd_resetAllRuntimes), + // 0x18 + COMMAND(cmd_return(1)), + COMMAND(cmd_execOpcode), + COMMAND(cmd_initFuncNow), + COMMAND(cmd_stopFuncNow), + // 0x1C + COMMAND(cmd_processDialogue), + COMMAND(cmd_dialogueBox), COMMAND(cmd_return(n1)) }; #undef cmd_return - _commands = commandProcs; - _commandsSize = ARRAYSIZE(commandProcs); + _commands = vm->game() == GI_LOL ? commandProcsLOL : commandProcsHOF ; + _commandsSize = vm->game() == GI_LOL ? ARRAYSIZE(commandProcsLOL) : ARRAYSIZE(commandProcsHOF); memset(&_animations, 0, sizeof(_animations)); _langData = 0; _textDisplayed = false; _textAreaBuffer = new uint8[320*40]; assert(_textAreaBuffer); + _dlgSpeechEnabled = false; + _refresh = false; + _drawPage2 = 8; - _palDelayInc = _palDiff = _palDelayAcc = 0; + _palDelayInc = _palDiff = _palDelayAcc = 0; + _dialogueComplete = 0; + _activeVoiceFile = 0; } TIMInterpreter::~TIMInterpreter() { @@ -159,9 +207,9 @@ void TIMInterpreter::setLangData(const char *filename) { _langData = _vm->resource()->fileData(filename, 0); } -void TIMInterpreter::exec(TIM *tim, bool loop) { +int TIMInterpreter::exec(TIM *tim, bool loop) { if (!tim) - return; + return 0; _currentTim = tim; if (!_currentTim->func[0].ip) { @@ -170,14 +218,37 @@ void TIMInterpreter::exec(TIM *tim, bool loop) { } do { + if (_refresh) + _vm->gui()->update(); for (_currentFunc = 0; _currentFunc < TIM::kCountFuncs; ++_currentFunc) { TIM::Function &cur = _currentTim->func[_currentFunc]; if (_currentTim->procFunc != -1) execCommand(28, &_currentTim->procParam); - bool running = true; + if (_refresh) + _vm->gui()->update(); + + if (_dlgSpeechEnabled && _currentTim->procParam > 1 && cur.loopIp) { + if (!_vm->sound()->voiceIsPlaying(_activeVoiceFile)) { + cur.loopIp = 0; + _currentTim->dlgFunc = _currentFunc; + advanceToOpcode(21); + _currentTim->dlgFunc = -1; + } + } + + bool running = true; + int cnt = 0; while (cur.ip && cur.nextTime <= _system->getMillis() && running) { + if (cnt++ > 0) { + if (_currentTim->procFunc != -1) + execCommand(28, &_currentTim->procParam); + + if (_refresh) + _vm->gui()->update(); + } + int8 opcode = int8(cur.ip[2] & 0xFF); switch (execCommand(opcode, cur.ip + 3)) { @@ -193,6 +264,7 @@ void TIMInterpreter::exec(TIM *tim, bool loop) { case -3: _currentTim->procFunc = _currentFunc; + _currentTim->dlgFunc = -1; break; case 22: @@ -206,11 +278,18 @@ void TIMInterpreter::exec(TIM *tim, bool loop) { if (cur.ip) { cur.ip += cur.ip[0]; cur.lastTime = cur.nextTime; - cur.nextTime += cur.ip[1] * _vm->tickLength(); + cur.nextTime += (cur.ip[1] ) * _vm->tickLength(); } } } - } while (loop); + } while (loop && !_vm->shouldQuit()); + + return _currentTim->clickedButton; +} + +void TIMInterpreter::stopAllFuncs(TIM *tim) { + for (int i = 0; i < TIM::kCountFuncs; ++i) + tim->func[i].ip = 0; } void TIMInterpreter::refreshTimersAfterPause(uint32 elapsedTime) { @@ -342,6 +421,7 @@ TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char anim->x = x; anim->y = y; anim->wsaCopyParams = wsaFlags; + _drawPage2 = 8; uint16 wsaOpenFlags = ((wsaFlags & 0x10) != 0) ? 2 : 0; @@ -367,7 +447,7 @@ TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char _screen->checkedPageUpdate(8, 4); _screen->updateScreen(); } - + if (wsaFlags & 4) { snprintf(file, 32, "%s.CPS", filename); @@ -410,6 +490,41 @@ TIMInterpreter::Animation *TIMInterpreter::initAnimStruct(int index, const char return anim; } +TIMInterpreter::Animation *TIMInterpreter::initAnimStructIntern(int index, const char *filename, int x, int y, uint16 copyPara, uint16 wsaFlags) { + Animation *anim = &_animations[index]; + anim->x = x; + anim->y = y; + anim->wsaCopyParams = wsaFlags; + + uint16 wsaOpenFlags = 0; + if (wsaFlags & 0x10) + wsaOpenFlags |= 2; + if (wsaFlags & 8) + wsaOpenFlags |= 1; + + char file[32]; + snprintf(file, 32, "%s.WSA", filename); + + if (_vm->resource()->exists(file)) { + anim->wsa = new WSAMovie_v2(_vm, _screen); + assert(anim->wsa); + anim->wsa->open(file, wsaOpenFlags, _screen->getPalette(3)); + } + + return anim; +} + +int TIMInterpreter::freeAnimStruct(int index) { + Animation *anim = &_animations[index]; + if (!anim) + return 0; + + delete anim->wsa; + memset(anim, 0, sizeof(Animation)); + + return 1; +} + char *TIMInterpreter::getTableEntry(uint idx) { if (!_langData) return 0; @@ -424,6 +539,22 @@ const char *TIMInterpreter::getCTableEntry(uint idx) const { return (const char *)(_langData + READ_LE_UINT16(_langData + (idx<<1))); } +void TIMInterpreter::advanceToOpcode(int opcode) { + TIM::Function *f = &_currentTim->func[_currentTim->dlgFunc]; + uint16 len = f->ip[0]; + + while ((f->ip[2] & 0xFF) != opcode) { + if ((f->ip[2] & 0xFF) == 1) { + f->ip[0] = len; + break; + } + len = f->ip[0]; + f->ip += len; + } + + f->nextTime = _system->getMillis(); +} + int TIMInterpreter::execCommand(int cmd, const uint16 *param) { if (cmd < 0 || cmd >= _commandsSize) { warning("Calling unimplemented TIM command %d from file '%s'", cmd, _currentTim->filename); @@ -519,8 +650,10 @@ int TIMInterpreter::cmd_wsaDisplayFrame(const uint16 *param) { anim.wsa->setX(anim.x); anim.wsa->setY(anim.y); - anim.wsa->setDrawPage((anim.wsaCopyParams & 0x4000) != 0 ? 2 : 8); + anim.wsa->setDrawPage((anim.wsaCopyParams & 0x4000) != 0 ? 2 : _drawPage2); anim.wsa->displayFrame(frame, anim.wsaCopyParams & 0xF0FF, 0, 0); + if (!_drawPage2) + _screen->updateScreen(); return 1; } @@ -573,7 +706,14 @@ int TIMInterpreter::cmd_playMusicTrack(const uint16 *param) { } int TIMInterpreter::cmd_setLoopIp(const uint16 *param) { - _currentTim->func[_currentFunc].loopIp = _currentTim->func[_currentFunc].ip; + if (_dlgSpeechEnabled) { + if (_vm->sound()->voiceIsPlaying(_activeVoiceFile)) + _currentTim->func[_currentFunc].loopIp = _currentTim->func[_currentFunc].ip; + else + advanceToOpcode(21); + } else { + _currentTim->func[_currentFunc].loopIp = _currentTim->func[_currentFunc].ip; + } return 1; } @@ -585,14 +725,16 @@ int TIMInterpreter::cmd_continueLoop(const uint16 *param) { func.ip = func.loopIp; - uint16 factor = param[0]; - if (factor) { - const uint32 random = _vm->_rnd.getRandomNumberRng(0, 0x8000); - uint32 waitTime = (random * factor) / 0x8000; - func.nextTime += waitTime * _vm->tickLength(); + if (!_vm->sound()->voiceIsPlaying(_activeVoiceFile)) { + uint16 factor = param[0]; + if (factor) { + const uint32 random = _vm->_rnd.getRandomNumberRng(0, 0x8000); + uint32 waitTime = (random * factor) / 0x8000; + func.nextTime += waitTime * _vm->tickLength(); + } } - return 1; + return -2; } int TIMInterpreter::cmd_resetLoopIp(const uint16 *param) { @@ -645,5 +787,59 @@ int TIMInterpreter::cmd_stopFuncNow(const uint16 *param) { return 1; } +int TIMInterpreter::cmd_stopAllFuncs(const uint16 *param) { + while (_currentTim->dlgFunc == -1 && _currentTim->clickedButton == 0 && !_vm->shouldQuit()) { + _vm->gui()->update(); + _currentTim->clickedButton = _vm->gui()->processDialogue(); + } + + for (int i = 0; i < TIM::kCountFuncs; ++i) + _currentTim->func[i].ip = 0; + + return -1; +} + +int TIMInterpreter::cmd_processDialogue(const uint16 *param) { + int res = _vm->gui()->processDialogue(); + if (!res ||!_currentTim->procParam) + return 0; + + if (_vm->sound()->voiceIsPlaying(_activeVoiceFile)) + _dialogueComplete = 0; + + _currentTim->func[_currentTim->procFunc].loopIp = 0; + _currentTim->dlgFunc = _currentTim->procFunc; + _currentTim->procFunc = -1; + _currentTim->clickedButton = res; + + if (_currentTim->procParam) + advanceToOpcode(21); + + return res; +} + +int TIMInterpreter::cmd_dialogueBox(const uint16 *param) { + uint16 func = *param; + assert(func < TIM::kCountFuncs); + _currentTim->procParam = func; + _currentTim->clickedButton = 0; + + const char *tmpStr[3]; + int cnt = 0; + + for (int i = 1; i < 4; i++) { + if (param[i] != 0xffff) { + tmpStr[i-1] = _vm->gui()->getTableString(param[i]); + cnt++; + } else { + tmpStr[i-1] = 0; + } + } + + _vm->gui()->drawDialogueBox(cnt, tmpStr[0], tmpStr[1], tmpStr[2]); + + return -3; +} + } // end of namespace Kyra diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h index 3299622a19..5e31d40b9b 100644 --- a/engines/kyra/script_tim.h +++ b/engines/kyra/script_tim.h @@ -42,6 +42,9 @@ typedef Common::Functor2<const TIM*, const uint16*, int> TIMOpcode; struct TIM { char filename[13]; + uint16 clickedButton; + int16 dlgFunc; + int16 procFunc; uint16 procParam; @@ -50,14 +53,14 @@ struct TIM { }; struct Function { - const uint16 *ip; + uint16 *ip; uint32 lastTime; uint32 nextTime; - const uint16 *loopIp; + uint16 *loopIp; - const uint16 *avtl; + uint16 *avtl; } func[kCountFuncs]; enum { @@ -92,16 +95,26 @@ public: TIM *load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes); void unload(TIM *&tim) const; + Animation *initAnimStructIntern(int index, const char *filename, int x, int y, uint16 copyPara, uint16 wsaFlags); + int freeAnimStruct(int index); + void setLangData(const char *filename); void clearLangData() { delete[] _langData; _langData = 0; } + void toggleDialogueSpeech(bool enable) { _dlgSpeechEnabled = enable; } + void toggleRefresh(bool enable) { _refresh = enable; } + void setWsaDrawPage2(int pageNum) { _drawPage2 = pageNum; } + void setDialogueCompleteFlag(int val) { _dialogueComplete = val; } + void setActiveSpeechFile(const char *filename) { _activeVoiceFile = filename; } + const char *getCTableEntry(uint idx) const; void resetFinishedFlag() { _finished = false; } bool finished() const { return _finished; } - void exec(TIM *tim, bool loop); + int exec(TIM *tim, bool loop); void stopCurFunc() { if (_currentTim) cmd_stopCurFunc(0); } + void stopAllFuncs(TIM *tim); void refreshTimersAfterPause(uint32 elapsedTime); @@ -109,6 +122,7 @@ public: void setupTextPalette(uint index, int fadePalette); int _palDelayInc, _palDiff, _palDelayAcc; + private: KyraEngine_v1 *_vm; Screen_v2 *_screen; @@ -121,9 +135,8 @@ private: Common::String _vocFiles[120]; - Animation _animations[TIM::kWSASlots]; - Animation *initAnimStruct(int index, const char *filename, int x, int y, int, int offscreenBuffer, uint16 wsaFlags); + Animation _animations[TIM::kWSASlots]; char _audioFilename[32]; @@ -132,6 +145,14 @@ private: bool _textDisplayed; uint8 *_textAreaBuffer; + bool _dlgSpeechEnabled; + bool _refresh; + int _drawPage2; + + int _dialogueComplete; + const char *_activeVoiceFile; + + void advanceToOpcode(int del); int execCommand(int cmd, const uint16 *param); typedef int (TIMInterpreter::*CommandProc)(const uint16 *); @@ -163,6 +184,11 @@ private: int cmd_execOpcode(const uint16 *param); int cmd_initFuncNow(const uint16 *param); int cmd_stopFuncNow(const uint16 *param); + + int cmd_stopAllFuncs(const uint16 *param); + int cmd_processDialogue(const uint16 *param); + int cmd_dialogueBox(const uint16 *param); + #define cmd_return(n, v) \ int cmd_return_##n(const uint16 *) { return v; } diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp index 5063fb5fed..487e0cfc07 100644 --- a/engines/kyra/sound.cpp +++ b/engines/kyra/sound.cpp @@ -115,6 +115,29 @@ int32 Sound::voicePlay(const char *file, bool isSfx) { return audioStream->getTotalPlayTime(); } +void Sound::voicePlayFromList(Common::List<const char*> fileList) { + int h = 0; + while (_mixer->isSoundHandleActive(_soundChannels[h].channelHandle) && h < kNumChannelHandles) + h++; + if (h >= kNumChannelHandles) + return; + + Audio::AppendableAudioStream *out = Audio::makeAppendableAudioStream(22050, Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED); + + for (Common::List<const char*>::iterator i = fileList.begin(); i != fileList.end(); i++) { + int size; + int rate; + uint8 *file = _vm->resource()->fileData(*i, (uint32*)&size); + Common::MemoryReadStream vocStream(file, (uint32)size); + uint8 *data = Audio::loadVOCFromStream(vocStream, size, rate); + out->queueBuffer(data, size); + } + out->finish(); + + _soundChannels[h].file = *fileList.begin(); + _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_soundChannels[h].channelHandle, out); +} + void Sound::voiceStop(const char *file) { if (!file) { for (int h = 0; h < kNumChannelHandles; h++) { diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index fc2e38d114..db344e7825 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -197,6 +197,14 @@ public: virtual int32 voicePlay(const char *file, bool isSfx = false); /** + * Queues the specified voice files in an AppendableAudioStream + * and plays them. + * + * @param fileList: files to be played + */ + virtual void voicePlayFromList(Common::List<const char*> fileList); + + /** * Checks if a voice is being played. * * @return true when playing, else false diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index 36ec89f308..961f188c98 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -40,6 +40,7 @@ #include "kyra/gui_lok.h" #include "kyra/gui_hof.h" #include "kyra/gui_mr.h" +#include "kyra/gui_lol.h" namespace Kyra { @@ -2622,6 +2623,14 @@ const int8 KyraEngine_MR::_albumWSAY[] = { // lands of lore static res +void GUI_LoL::initStaticData() { + +} + +void LoLEngine::initButtonList() { + +} + const ScreenDim Screen_LoL::_screenDimTable[] = { { 0x00, 0x00, 0x28, 0xC8, 0xC7, 0xCF, 0x00, 0x00 }, // Taken from Intro { 0x08, 0x48, 0x18, 0x38, 0xFE, 0x01, 0x00, 0x00 }, diff --git a/engines/kyra/text_lol.cpp b/engines/kyra/text_lol.cpp new file mode 100644 index 0000000000..fe7ac6d81d --- /dev/null +++ b/engines/kyra/text_lol.cpp @@ -0,0 +1,573 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "kyra/lol.h" +#include "kyra/screen_lol.h" +#include "kyra/util.h" + +namespace Kyra { + +TextDisplayer_LoL::TextDisplayer_LoL(LoLEngine *vm, Screen_LoL *screen) : _vm(vm), _screen(screen), + _scriptParameter(0), _stringLength(0), _animWidth(0), _animColour1(0), _animColour2(0), _animFlag(true), + _printFlag(false), _lineWidth(0), _numChars(0), _numCharsPrinted(0), _posX(0), _posY(0), _colour1(0), _colour2(0) { + + memset(_stringParameters, 0, 15 * sizeof(char*)); + _buffer = new char[600]; + memset(_buffer, 0, 600); + + _out = new char[1024]; + memset(_out, 0, 1024); + + _backupBuffer = new char[40]; + memset(_out, 0, 40); + + _currentLine = new char[85]; + memset(_out, 0, 85); + + _pageBuffer1 = new uint8[0xfa00]; + _pageBuffer2 = new uint8[0xfa00]; +} + +TextDisplayer_LoL::~TextDisplayer_LoL() { + delete[] _buffer; + delete[] _out; + delete[] _backupBuffer; + delete[] _currentLine; + delete[] _pageBuffer1; + delete[] _pageBuffer2; +} + +void TextDisplayer_LoL::setupField(bool mode) { + if (_vm->textEnabled()) { + if (mode) { + _screen->copyRegionToBuffer(3, 0, 0, 320, 200, _pageBuffer1); + _screen->copyRegion(80, 142, 0, 0, 240, 37, 0, 3, Screen::CR_NO_P_CHECK); + _screen->copyRegionToBuffer(3, 0, 0, 320, 200, _pageBuffer2); + _screen->copyBlockToPage(3, 0, 0, 320, 200, _pageBuffer1); + } else { + _screen->clearDim(4); + int cp = _screen->setCurPage(2); + _screen->copyRegionToBuffer(3, 0, 0, 320, 200, _pageBuffer1); + _screen->copyBlockToPage(3, 0, 0, 320, 200, _pageBuffer2); + _screen->copyRegion(80, 142, 0, 0, 240, 37, 3, 2, Screen::CR_NO_P_CHECK); + + for (int i = 177; i > 141; i--) { + uint32 endTime = _vm->_system->getMillis() + _vm->_tickLength; + _screen->hideMouse(); + _screen->copyRegion(83, i, 83, i - 1, 235, 3, 0, 0, Screen::CR_NO_P_CHECK); + _screen->copyRegion(83, i + 1, 83, i + 1, 235, 1, 2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + _screen->showMouse(); + _vm->delayUntil(endTime); + } + + _screen->copyBlockToPage(3, 0, 0, 320, 200, _pageBuffer1); + _screen->setCurPage(cp); + + _vm->_updateFlags &= 0xfffd; + } + } else { + if (!mode) + _screen->clearDim(4); + _vm->toggleSelectedCharacterFrame(1); + } +} + +void TextDisplayer_LoL::expandField() { + if (_vm->textEnabled()) { + _vm->_restorePalette = 0; + _vm->_updateCharV4 = 0; + //_vm->toggleGuiUnk(11, 0); + _screen->clearDim(3); + _screen->copyRegionToBuffer(3, 0, 0, 320, 200, _pageBuffer1); + _screen->copyRegion(83, 140, 0, 0, 235, 3, 0, 2, Screen::CR_NO_P_CHECK); + + for (int i = 140; i < 177; i++) { + uint32 endTime = _vm->_system->getMillis() + _vm->_tickLength; + _screen->hideMouse(); + _screen->copyRegion(0, 0, 83, i, 235, 3, 2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + _screen->showMouse(); + _vm->delayUntil(endTime); + } + + _screen->copyBlockToPage(3, 0, 0, 320, 200, _pageBuffer1); + _vm->_updateFlags |= 2; + + } else { + _screen->clearDim(3); + _vm->toggleSelectedCharacterFrame(0); + } +} +void TextDisplayer_LoL::setAnimParameters(const char *str, int x, uint8 col1, uint8 col2) { + static const char defaultStr[] = "<MORE>"; + + if (str) { + _animString = str; + _animWidth = x; + _animColour1 = col1; + _animColour2 = col2; + } else { + _animString = defaultStr; + _animWidth = 7; + _animColour1 = 0; + _animColour2 = 0; + } +} + +void TextDisplayer_LoL::play(int dim, char *str, EMCState *script, int16 *paramList, int16 paramIndex) { + memcpy(_curPara, _stringParameters, 15 * sizeof(char*)); + char *cmds = _curPara[0]; + + if (dim == 3) { + if (_vm->_updateFlags & 2) { + _screen->clearDim(4); + dim = _screen->curDimIndex(); + _colour1 = 254; + } else { + _screen->clearDim(3); + dim = _screen->curDimIndex(); + _colour1 = 192; + uint8 col[3]; + _screen->loadColour254(col); + _screen->setPaletteIndex(192, col[0], col[1], col[2]); + //toggleGuiUnk(11, 1); + _vm->_updateCharV4 = 0; + _vm->_restorePalette = 0; + } + + } else { + _screen->setScreenDim(dim); + _colour1 = 254; + } + + int cp = _screen->setCurPage(0); + Screen::FontId of = _screen->setFont(Screen::FID_9_FNT); + + memset(_backupBuffer, 0, 40); + + if (preprocessString(str, script, paramList, paramIndex)) { + vsnprintf(_out, 1024, str, cmds); + _stringLength = strlen(_out); + displayText(_out); + } else { + _stringLength = strlen(str); + displayText(str); + displayText(str); + } + + for (int i = 0; i < 10; i++) { + if (!_backupBuffer[i << 1]) + break; + str[_backupBuffer[(i << 1) + 1]] = _backupBuffer[i << 1]; + } + + _screen->setScreenDim(dim); + _screen->setCurPage(cp); + _screen->setFont(of); + + _vm->_restorePalette = 0; +} + +bool TextDisplayer_LoL::preprocessString(char *str, EMCState *script, int16 *paramList, int16 paramIndex) { + int cnt = 0; + bool res = false; + char *tmpd = _buffer; + char **cmds = _curPara; + + for (char *s = str; *s;) { + if (*s++ != '%') + continue; + + char pos = *s; + char para1 = 0; + bool eos = false; + + switch (pos) { + case '\0': + eos = true; + break; + case '#': + para1 = *++s; + switch (para1) { + case 'E': + case 'G': + case 'X': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 's': + case 'u': + case 'x': + break; + default: + eos = true; + break; + } + break; + case ' ': + case '+': + case '-': + ++s; + default: + break; + } + + if (eos) + continue; + + char para2 = *s; + + switch (para2) { + case '\0': + eos = true; + break; + case '0': + ++s; + break; + default: + while(para2 && para2 > 47 && para2 < 58) + para2 = *++s; + break; + } + + if (eos) + continue; + + char para3 = *++s; + + switch (para3) { + case 'a': + _backupBuffer[cnt++] = para3; + _backupBuffer[cnt++] = (int16) (s - str); + snprintf(tmpd, 7, "%d", _scriptParameter); + *cmds++ = tmpd; + tmpd += strlen(tmpd) + 1; + res = true; + *s++ = 's'; + break; + + case 'n': + _backupBuffer[cnt++] = para3; + _backupBuffer[cnt++] = (int16) (s - str); + *cmds++ = _vm->_characters[script ? script->stack[script->sp + paramIndex] : paramList[paramIndex]].name; + paramIndex++; + res = true; + *s++ = 's'; + break; + + case 's': + *cmds++ = _vm->getLangString(script ? script->stack[script->sp + paramIndex] : paramList[paramIndex]); + paramIndex++; + res = true; + s++; + break; + + case 'X': + case 'd': + case 'u': + case 'x': + snprintf(tmpd, 7, "%d", script ? script->stack[script->sp + paramIndex] : paramList[paramIndex]); + *cmds++ = tmpd; + tmpd += strlen(tmpd) + 1; + paramIndex++; + res = true; + *s++ = 's'; + break; + + case '\0': + default: + continue; + } + } + + return res; +} + +void TextDisplayer_LoL::displayText(char *str, ...) { + _printFlag = false; + + _lineWidth = 0; + _numChars = 0; + _numCharsPrinted = 0; + + _tempString1 = str; + _tempString2 = 0; + + _currentLine[0] = 0; + + memset(_ctrl, 0, 3); + + _colour1 = _screen->_curDim->unk8; + _colour2 = _screen->_curDim->unkA; + _posX = _screen->_curDim->unkC; + _posY = _screen->_curDim->unkE; + + char c = parseCommand(); + + va_list args; + va_start(args, str); + + const ScreenDim *sd = _screen->_curDim; + + while (c) { + char a = tolower(_ctrl[1]); + + if (!_tempString2 && c == '%' ) { + if (a == 'd') { + snprintf(_scriptParaString, 11, "%d", va_arg(args, int)); + _tempString2 = _scriptParaString; + } else if (a == 's') { + _tempString2 = va_arg(args, char*); + } else { + break; + } + + _ctrl[0] = _ctrl[2]; + _ctrl[2] = _ctrl[1] = 0; + c = parseCommand(); + } + + switch (c - 1) { + case 0: + printLine(_currentLine); + //if (!_dlgAnimCallback) + // break; + + portraitAnimation2(); + _numCharsPrinted = 0; + break; + + case 1: + printLine(_currentLine); + _colour2 = parseCommand(); + break; + + case 5: + printLine(_currentLine); + _colour1 = parseCommand(); + break; + + case 8: + //TODO + break; + + case 11: + //TODO + break; + + case 12: + printLine(_currentLine); + _screen->_dimLineCount++; + _posX = 0; + _posY++; + break; + + case 18: + //TODO + break; + + case 23: + //TODO + break; + + case 24: + //TODO + break; + + case 26: + //TODO + break; + + case 28: + //TODO + break; + + default: + _lineWidth += _screen->getCharWidth(c); + _currentLine[_numChars++] = c; + _currentLine[_numChars] = 0; + + if ((_posX + _lineWidth) > (sd->w << 3)) + printLine(_currentLine); + + break; + } + + c = parseCommand(); + } + + va_end(args); + + if (_numChars) + printLine(_currentLine); +} + +char TextDisplayer_LoL::parseCommand() { + if (!_ctrl[1]) + readNextPara(); + + char res = _ctrl[1]; + _ctrl[1] = _ctrl[2]; + _ctrl[2] = 0; + + if (!_ctrl[1]) + readNextPara(); + + return res; +} + +void TextDisplayer_LoL::readNextPara() { + char d = 0; + + if (_tempString2) { + if (*_tempString2) { + d = *_tempString2++; + } else { + _tempString2 = 0; + d = _ctrl[0]; + } + } + + if (!d && _tempString1) { + if (*_tempString1) + d = *_tempString1++; + else + _tempString1 = 0; + } + + _ctrl[1] = d; + _ctrl[2] = 0; +} + +void TextDisplayer_LoL::printLine(char *str) { + const ScreenDim *sd = _screen->_curDim; + + int fh = (_screen->getFontHeight() + _screen->_charOffset); + int lines = (sd->h - _screen->_charOffset) / fh; + + while (_posY >= lines) { + if (lines <= _screen->_dimLineCount && _animFlag) { + _screen->_dimLineCount = 0; + //if (_dlgAnimCallback) { + portraitAnimation2(); + _numCharsPrinted = 0; + //} + } + + int h1 = ((sd->h / fh) - 1) * fh; + int h2 = sd->h - fh; + + if (h2) + _screen->copyRegion(sd->sx << 3, sd->sy + fh, sd->sx << 3, sd->sy, sd->w << 3, h2, _screen->_curPage, _screen->_curPage, Screen::CR_NO_P_CHECK); + + _screen->fillRect(sd->sx << 3, sd->sy + h1, (sd->sx + sd->w - 1) << 3, sd->sy + sd->h - 1, _colour2); + + _posY--; + } + + int x1 = (sd->sx << 3) + _posX; + int y = sd->sy + fh * _posY; + int w = sd->w << 3; + int lw = _lineWidth; + int s = _numChars; + char c = 0; + + if ((lw + _posX) > w) { + if ((lines - 1) <= _screen->_dimLineCount && _animFlag) + w -= (_animWidth * (_screen->getFontWidth() + _screen->_charWidth)); + + w -= _posX; + + int n2 = 0; + int n1 = s - 1; + + while (n1 > 0) { + //cut off line after last space + c = str[n1]; + lw -= _screen->getCharWidth(c); + + if (!n2 && lw <= w) + n2 = n1; + + if (n2 && c == ' ') { + s = n1; + _printFlag = false; + break; + } + + n1--; + } + + if (!n1) { + if (_posX && !_printFlag) { + s = lw = 0; + _printFlag = true; + } else { + s = n2; + } + } + } + + c = str[s]; + str[s] = 0; + + _screen->printText(str, x1, y, _colour1, _colour2); + _posX += lw; + _numCharsPrinted += strlen(str); + + str[s] = c; + + if (c == ' ') + s++; + + if (str[s] == ' ') + s++; + + strcpy(str, &str[s]); + _numChars = strlen(str); + _lineWidth = _screen->getTextWidth(str); + + if (!_numChars && _posX < (sd->w << 3)) + return; + + _posX = 0; + _posY++; + _screen->_dimLineCount++; + + printLine(str); +} + +/*void TextDisplayer_LoL::portraitAnimation1(const char *str, uint16 lineWidth, uint8 col1, uint8 col2, uint16 numCharsPrinted) { + +}*/ + +void TextDisplayer_LoL::portraitAnimation2() { + // TODO +} + +} // end of namespace Kyra diff --git a/engines/kyra/text_lol.h b/engines/kyra/text_lol.h new file mode 100644 index 0000000000..3d040dc82b --- /dev/null +++ b/engines/kyra/text_lol.h @@ -0,0 +1,104 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef KYRA_TEXT_LOL_H +#define KYRA_TEXT_LOL_H + +namespace Kyra { + +class Screen_v2; +class LoLEngine; +struct EMCState; + +class TextDisplayer_LoL { +friend class LoLEngine; +public: + TextDisplayer_LoL(LoLEngine *vm, Screen_LoL *screen); + ~TextDisplayer_LoL(); + + void setAnimParameters(const char *str, int x, uint8 col1, uint8 col2); + void setAnimFlag(bool flag) { _animFlag = flag; } + + void setupField(bool mode); + void expandField(); + + void play(int dim, char *str, EMCState *script, int16 *paramList, int16 paramIndex); + + int16 _scriptParameter; + +private: + void displayText(char *str, ...); + char parseCommand(); + void readNextPara(); + void printLine(char *str); + bool preprocessString(char *str, EMCState *script, int16 *paramList, int16 paramIndex); + + //typedef void (LoLEngine::*DialogueAnimCallback)(const char *str, uint16 lineWidth, uint8 col1, uint8 col2); + //DialogueAnimCallback _dlgAnimCallback; + //void portraitAnimation1(const char *str); + void portraitAnimation2(); + + + char *_stringParameters[15]; + char *_curPara[15]; + char *_buffer; + char *_out; + char *_backupBuffer; + char *_tempString1; + char *_tempString2; + char *_currentLine; + char _ctrl[3]; + + char _scriptParaString[11]; + uint32 _stringLength; + + uint16 _lineWidth; + uint32 _numChars; + uint32 _numCharsPrinted; + + const char *_animString; + int16 _animWidth; + uint8 _animColour1; + uint8 _animColour2; + + bool _animFlag; + bool _printFlag; + + uint8 _posX; + uint8 _posY; + uint8 _colour1; + uint8 _colour2; + + uint8 *_pageBuffer1; + uint8 *_pageBuffer2; + + LoLEngine *_vm; + Screen_LoL *_screen; +}; + +} // end of namespace Kyra + +#endif + |