From ff268e8fd5997b60a035147bb9adbf1ead100d49 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 18 Jan 2009 17:04:24 +0000 Subject: LOL: Some drawing code and some opcodes so that the first scene will show up. Playing is not possible. This is still somewhat messy since a lot of stuff hasn't been figured out yet. svn-id: r35903 --- dists/engine-data/kyra.dat | Bin 242675 -> 253175 bytes engines/kyra/gui_lol.cpp | 361 ++++++++ engines/kyra/items_lol.cpp | 186 +++++ engines/kyra/lol.cpp | 936 ++++++++++++++++++++- engines/kyra/lol.h | 520 +++++++++++- engines/kyra/module.mk | 4 + engines/kyra/resource.h | 54 +- engines/kyra/scene_lol.cpp | 1369 +++++++++++++++++++++++++++++++ engines/kyra/screen_lol.cpp | 225 ++++- engines/kyra/screen_lol.h | 29 + engines/kyra/screen_v2.cpp | 5 +- engines/kyra/screen_v2.h | 2 +- engines/kyra/script.h | 2 +- engines/kyra/script_lol.cpp | 450 ++++++++++ engines/kyra/staticres.cpp | 270 +++++- tools/create_kyradat/create_kyradat.cpp | 60 +- tools/create_kyradat/create_kyradat.h | 44 +- tools/create_kyradat/lol_cd.h | 42 + tools/create_kyradat/lol_demo.h | 2 +- tools/create_kyradat/misc.h | 44 +- 20 files changed, 4576 insertions(+), 29 deletions(-) create mode 100644 engines/kyra/gui_lol.cpp create mode 100644 engines/kyra/items_lol.cpp create mode 100644 engines/kyra/scene_lol.cpp create mode 100644 engines/kyra/script_lol.cpp create mode 100644 tools/create_kyradat/lol_cd.h diff --git a/dists/engine-data/kyra.dat b/dists/engine-data/kyra.dat index 572106f4a4..d0601cdb6a 100644 Binary files a/dists/engine-data/kyra.dat and b/dists/engine-data/kyra.dat differ diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp new file mode 100644 index 0000000000..8497e2f561 --- /dev/null +++ b/engines/kyra/gui_lol.cpp @@ -0,0 +1,361 @@ +/* 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" + +namespace Kyra { + +void LoLEngine::gui_drawPlayField() { + _screen->loadBitmap("PLAYFLD.CPS", 3, 3, 0); + + if (_screen->_drawGuiFlag & 0x4000) { + // 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; + } + + if (_screen->_drawGuiFlag & 0x1000) + // draw automap book + _screen->drawShape(2, _gameShapes[78], 289, 32, 0, 0); + + int cp = _screen->setCurPage(2); + + if (_screen->_drawGuiFlag & 0x2000) { + gui_drawScroll(); + } else { + _selectedSpell = 0; + } + + if (_screen->_drawGuiFlag & 0x800) + turnOnLamp(); + + //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) + drawScene(pageNum); +} + +void LoLEngine::gui_drawInventory() { + if (!_unkInventFlag || !_updateCharV6) { + for (int i = 0; i < 9; i++) + gui_drawInventoryItem(i); + } +} + +void LoLEngine::gui_drawInventoryItem(int index) { + static const uint16 inventoryXpos[] = { 0x6A, 0x7F, 0x94, 0xA9, 0xBE, 0xD3, 0xE8, 0xFD, 0x112 }; + int x = inventoryXpos[index]; + int item = _inventoryCurItem + index; + if (item > 48) + item -= 48; + + int flag = item & 1 ? 0 : 1; + + _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); + _screen->showMouse(); +} + +void LoLEngine::gui_drawScroll() { + _screen->copyRegion(112, 0, 12, 0, 87, 15, 2, 2, Screen::CR_NO_P_CHECK); + int h = 0; + + for (int i = 0; i < 7; i++) { + if (_availableSpells[i] != -1) + h += 9; + } + + if (h == 18) + h = 27; + + if (h) { + _screen->copyRegion(201, 1, 17, 15, 6, h, 2, 2, Screen::CR_NO_P_CHECK); + _screen->copyRegion(208, 1, 89, 15, 6, h, 2, 2, Screen::CR_NO_P_CHECK); + _screen->fillRect(21, 15, 89, h + 15, 206); + } + + _screen->copyRegion(112, 16, 12, h + 15, 87, 14, 2, 2, Screen::CR_NO_P_CHECK); + + int y = 15; + for (int i = 0; i < 7; i++) { + if (_availableSpells[i] == -1) + continue; + uint8 col = (i == _selectedSpell) ? 132 : 1; + _screen->fprintString(getLangString(_spellProperties[_availableSpells[i]].spellNameCode), 24, y, col, 0, 0); + y += 9; + } +} + +void LoLEngine::gui_drawAllCharPortraitsWithStats() { + int numChars = countActiveCharacters(); + if (!numChars) + return; + + for (int i = 0; i < numChars; i++) + gui_drawCharPortraitWithStats(i); +} + +void LoLEngine::gui_drawCharPortraitWithStats(int charNum) { + if (!(_characters[charNum].flags & 1) || _charFlagUnk & 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_drawCharFaceShape(0, 0, 1, _screen->_curPage); + + gui_drawLiveMagicBar(33, 32, _characters[charNum].magicPointsCur, 0, _characters[charNum].magicPointsMax, 5, 32, 162, 1, 0); + gui_drawLiveMagicBar(39, 32, _characters[charNum].hitPointsCur, 0, _characters[charNum].hitPointsMax, 5, 32, 154, 1, 1); + + _screen->printText(getLangString(0x4253), 33, 1, 160, 0); + _screen->printText(getLangString(0x4254), 39, 1, 152, 0); + + int spellLevels = 0; + for (int i = 0; i < 4; i++) { + if (_spellProperties[_availableSpells[_selectedSpell]].mpRequired[i] <= _characters[charNum].magicPointsCur && + _spellProperties[_availableSpells[_selectedSpell] + 1].unkArr[i] <= _characters[charNum].hitPointsCur) + spellLevels++; + } + + if (_characters[charNum].flags & 0x10) { + // magic submenu open + _screen->drawShape(_screen->_curPage, _gameShapes[73], 44, 0, 0, 0); + if (spellLevels < 4) + _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; + } + // draw hand/weapon + _screen->drawShape(_screen->_curPage, _gameShapes[shapeNum], 44, 0, 0, 0); + // draw magic symbol + _screen->drawShape(_screen->_curPage, _gameShapes[72 + _characters[charNum].field_41], 44, 17, 0, 0); + + if (spellLevels == 0) + _screen->drawGridBox(44, 17, 22, 15, 1); + } + + uint16 f = _characters[charNum].flags & 0x314C; + if ((f == 0 && (f != 4 || _characters[charNum].weaponHit == 0)) || _weaponsDisabled) + _screen->drawGridBox(44, 0, 22, 34, 1); + + if (_characters[charNum].weaponHit) { + _screen->drawShape(_screen->_curPage, _gameShapes[34], 44, 0, 0, 0); + _screen->fprintString("%d", 57, 7, 254, 0, 1, _characters[charNum].weaponHit); + } + if (_characters[charNum].damageSuffered) + _screen->fprintString("%d", 17, 28, 254, 0, 1, _characters[charNum].damageSuffered); + + if (!cp) + _screen->hideMouse(); + + uint8 col = (charNum != _unkDrawPortraitIndex || 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); + + if (!cp) + _screen->showMouse(); + + _screen->setCurPage(cp); + _screen->setFont(tmpFid); +} + +void LoLEngine::gui_drawPortraitBox(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); + + _screen->drawClippedLine(x + 1, y, x + w, y, frameColor2); + _screen->drawClippedLine(x + w, y, x + w, y + h - 1, frameColor2); + _screen->drawClippedLine(x, y, x, y + h, frameColor1); + _screen->drawClippedLine(x, y + h, x + w, y + h, frameColor1); +} + +void LoLEngine::gui_drawCharFaceShape(int charNum, int x, int y, int pageNum) { + if (_characters[charNum].curFaceFrame < 7 && _characters[charNum].nextFaceFrame) + _characters[charNum].curFaceFrame = _characters[charNum].nextFaceFrame; + + if (_characters[charNum].nextFaceFrame == 0 && _characters[charNum].curFaceFrame > 1 && _characters[charNum].curFaceFrame < 7) + _characters[charNum].curFaceFrame = _characters[charNum].nextFaceFrame; + + int frm = (_characters[charNum].flags & 0x1108 && _characters[charNum].curFaceFrame < 7) ? 1 : _characters[charNum].curFaceFrame; + + if (_characters[charNum].hitPointsCur <= (_characters[charNum].hitPointsMax >> 1)) + frm += 14; + + if (!pageNum) + _screen->hideMouse(); + + _screen->drawShape(pageNum, _characterFaceShapes[frm][charNum], x, y, 0, 0x100, _screen->_paletteOverlay2, (_characters[charNum].flags & 0x80 ? 1 : 0)); + + if (_characters[charNum].flags & 0x40) + // draw spider web + _screen->drawShape(pageNum, _gameShapes[21], x, y, 0, 0); + + if (!pageNum) + _screen->showMouse(); +} + +void LoLEngine::gui_drawLiveMagicBar(int x, int y, int curPoints, int unk, int maxPoints, int w, int h, int col1, int col2, int flag) { + w--; + h--; + + if (maxPoints < 1) + return; + + int t = (curPoints < 1) ? 0 : curPoints; + curPoints = (maxPoints < t) ? maxPoints : t; + + int barHeight = (curPoints * h) / maxPoints; + + if (barHeight < 1 && curPoints < 1) + barHeight = 1; + + _screen->drawClippedLine(x - 1, y - h, x - 1, y, 1); + + if (flag) { + t = maxPoints >> 1; + if (t > curPoints) + col1 = 144; + t = maxPoints >> 2; + if (t > curPoints) + col1 = 132; + } + + if (barHeight > 0) + _screen->fillRect(x, y - barHeight, x + w, y, col1); + + if (barHeight < h) + _screen->fillRect(x, y - h, x + w, y - barHeight, col2); + + if (unk > 0 && unk < maxPoints) + _screen->drawBox(x, y - barHeight, x + w, y, col1 - 2); +} + +void LoLEngine::calcCharPortraitXpos() { + int nc = countActiveCharacters(); + + // TODO + + int t = (235 - (nc * 66)) / (nc + 1); + for (int i = 0; i < nc; i++) + _activeCharsXpos[i] = i * 66 + t * (i + 1) + 83; +} + +void LoLEngine::gui_drawMoneyBox(int pageNum) { + static const uint16 moneyX[] = { 0x128, 0x134, 0x12b, 0x131, 0x12e}; + static const uint16 moneyY[] = { 0x73, 0x73, 0x74, 0x74, 0x75}; + + int backupPage = _screen->_curPage; + _screen->_curPage = pageNum; + + _screen->fillRect(292, 97, 316, 118, 252, pageNum); + + for (int i = 0; i < 5; i++) { + if (!_moneyColumnHeight[i]) + continue; + + uint8 h = _moneyColumnHeight[i] - 1; + _screen->drawClippedLine(moneyX[i], moneyY[i], moneyX[i], moneyY[i] - h, 0xd2); + _screen->drawClippedLine(moneyX[i] + 1, moneyY[i], moneyX[i] + 1, moneyY[i] - h, 0xd1); + _screen->drawClippedLine(moneyX[i] + 2, moneyY[i], moneyX[i] + 2, moneyY[i] - h, 0xd0); + _screen->drawClippedLine(moneyX[i] + 3, moneyY[i], moneyX[i] + 3, moneyY[i] - h, 0xd1); + _screen->drawClippedLine(moneyX[i] + 4, moneyY[i], moneyX[i] + 4, moneyY[i] - h, 0xd2); + } + + Screen::FontId backupFont = _screen->setFont(Screen::FID_6_FNT); + _screen->fprintString("%d", 305, 98, 254, 0, 1, _credits); + + _screen->setFont(backupFont); + _screen->_curPage = backupPage; + + if (pageNum == 6) { + _screen->hideMouse(); + _screen->copyRegion(292, 97, 292, 97, 25, 22, 6, 0); + _screen->showMouse(); + } +} + +void LoLEngine::gui_drawCompass() { + if (!(_screen->_drawGuiFlag & 0x4000)) + return; + + if (_updateUnk2 == -1) { + _compassDirectionIndex = -1; + _updateUnk2 = _unkPara2 << 6; + } + + int t = ((_updateUnk2 + 4) >> 3) & 0x1f; + + if (t == _compassDirectionIndex) + return; + + _compassDirectionIndex = t; + + if (!_screen->_curPage) + _screen->hideMouse(); + + 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], 299 + c->x, c->y + 8, 0, c->flags); + + if (!_screen->_curPage) + _screen->showMouse(); +} + +} // end of namespace Kyra + diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp new file mode 100644 index 0000000000..805df9337b --- /dev/null +++ b/engines/kyra/items_lol.cpp @@ -0,0 +1,186 @@ +/* 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" + +namespace Kyra { + +void LoLEngine::giveCredits(int credits, int redraw) { + static const uint8 stashSetupData[] = { 4, 4, 4, 4, 2, 2, 2, 3, 3, 0, 1, 1 }; + + if (redraw) + snd_playSoundEffect(0x65, 0xff); + + int t = credits / 30; + if (!t) + t = 1; + + int cnt = 0; + + while (credits) { + if (t > credits) + t = credits; + + if (_credits < 60 && t >= 0) { + cnt = 0; + + do { + if (_credits < 60) { + int d = stashSetupData[_credits % 12] - _credits / 12; + if (d < 0) + d += 5; + _moneyColumnHeight[d]++; + } + _credits++; + } while(++cnt < t); + } else if (_credits >= 60) { + _credits += t; + } + + if (redraw) { + gui_drawMoneyBox(6); + //if (credits) + // TODO: delay/update + } + credits -= t; + } +} + +int LoLEngine::makeItem(int itemIndex, int curFrame, int flags) { + int cnt = 0; + int r = 0; + int i = 1; + + for (; i < 400; i++) { + if (_itemsInPlay[i].shpCurFrame_flg & 0x8000) { + cnt = 0; + break; + } + + if (_itemsInPlay[i].level < 1 || _itemsInPlay[i].level > 29 || _itemsInPlay[i].level == _currentLevel) + continue; + + int diff = ABS(_currentLevel - _itemsInPlay[i].level); + + if (diff <= cnt) + continue; + + bool t = false; + int ii = i; + while (ii && !t) { + t = testUnkItemFlags(ii); + if (t) + break; + else + ii = _itemsInPlay[ii - 1].itemIndexUnk; + } + + if (t) { + cnt = diff; + r = i; + } + } + + int slot = i; + if (cnt) { + slot = r; + if (testUnkItemFlags(r)) { + if (_itemsInPlay[r].itemIndexUnk) + _itemsInPlay[_itemsInPlay[r].itemIndexUnk].level = _itemsInPlay[r].level; + clearItemTableEntry(r); + slot = r; + } else { + int ii = _itemsInPlay[slot].itemIndexUnk; + while(ii) { + if (testUnkItemFlags(ii)) { + _itemsInPlay[slot].itemIndexUnk = _itemsInPlay[ii].itemIndexUnk; + clearItemTableEntry(ii); + slot = ii; + break; + } else { + slot = ii; + } + ii = _itemsInPlay[slot].itemIndexUnk; + } + } + } + + memset(&_itemsInPlay[slot], 0, sizeof(ItemInPlay)); + + _itemsInPlay[slot].itemPropertyIndex = itemIndex; + _itemsInPlay[slot].shpCurFrame_flg = (curFrame & 0x1fff) | flags; + _itemsInPlay[slot].level = -1; + + return slot; +} + +bool LoLEngine::testUnkItemFlags(int itemIndex) { + if (!(_itemsInPlay[itemIndex].shpCurFrame_flg & 0x4000)) + return false; + + if (_itemProperties[_itemsInPlay[itemIndex].itemPropertyIndex].flags & 4) + return false; + + return true; + +} + +void LoLEngine::clearItemTableEntry(int itemIndex) { + memset(&_itemsInPlay[itemIndex], 0, sizeof(ItemInPlay)); + _itemsInPlay[itemIndex].shpCurFrame_flg |= 0x8000; +} + +void *LoLEngine::cmzGetItemOffset(uint16 index) { + if (index & 0x8000) + return &_lvlBuffer[index & 0x7fff]; + else + return &_itemsInPlay[index]; +} + +void LoLEngine::runItemScript(int reg1, int slot, int reg0, int reg3, int reg4) { + EMCState scriptState; + memset(&scriptState, 0, sizeof(EMCState)); + + uint8 func = slot ? _itemProperties[_itemsInPlay[slot].itemPropertyIndex].itemScriptFunc : 3; + if (func == 0xff) + return; + + _emc->init(&scriptState, &_itemScript); + _emc->start(&scriptState, func); + + scriptState.regs[0] = reg0; + scriptState.regs[1] = reg1; + scriptState.regs[2] = slot; + scriptState.regs[3] = reg3; + scriptState.regs[4] = reg4; + + while (_emc->isValid(&scriptState)) + _emc->run(&scriptState); +} + +} // end of namespace Kyra + + diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 8daf1d857f..bf52f300ad 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -58,26 +58,205 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy break; } - memset(_shapes, 0, sizeof(_shapes)); - _chargenWSA = 0; _lastUsedStringBuffer = 0; _landsFile = 0; + _levelLangFile = 0; + + _lastSfxTrack = -1; + + memset(_moneyColumnHeight, 0, 5); + _credits = 0; + + _itemsInPlay = 0; + _itemProperties = 0; + _itemInHand = 0; + memset(_inventoryItemIndex, 0, 48); + _inventoryCurItem = 0; + _unkInventFlag = 0; + + _itemIconShapes = _itemShapes = _gameShapes = _thrownShapes = _iceShapes = _fireballShapes = 0; + _levelShpList = _levelDatList = 0; + _monsterShapes = _monsterPalettes = 0; + _buf4 = 0; + _gameShapeMap = 0; + memset(_monsterUnk, 0, 3); + + _charSelection = -1; + _characters = 0; + _spellProperties = 0; + _charFlagUnk = 0; + _selectedSpell = 0; + _updateCharNum = _updateCharV1 = _updateCharV2 = _updateCharV3 = _updateCharV4 = _updateCharV5 = _updateCharV6 = 0; + _updateCharTime = _updatePortraitNext = 0; + _lampStatusTimer = 0xffffffff; + + _weaponsDisabled = false; + _unkDrawPortraitIndex = 0; + _unkFlag = 0; + _scriptBoolSkipExec = _boolScriptFuncDone = false; + _unkScriptByte = 0; + _unkPara2 = 0; + _currentBlock = 0; + memset(_scriptExecutedFuncs, 0, 18 * sizeof(uint16)); + + _wllVmpMap = _wllBuffer3 = _wllBuffer4 = _wllBuffer5 = 0; + _wllShapeMap = 0; + _lvlShapeTop = _lvlShapeBottom = _lvlShapeLeftRight = 0; + _cmzBuffer = 0; + _lvlBuffer = 0; + _lvl415 = 0; + _lvlBlockIndex = _lvlShapeIndex = 0; + _unkDrawLevelBool = true; + _vcnBlocks = 0; + _vcnShift = 0; + _vcnExpTable = 0; + _vmpPtr = 0; + _tlcTable2 = 0; + _tlcTable1 = 0; + _levelShapeProperties = 0; + _levelShapes = 0; + _blockDrawingBuffer = 0; + _sceneWindowBuffer = 0; + memset (_doorShapes, 0, 2 * sizeof(uint8*)); + + _lampOilStatus = _brightness = _lampStatusUnk = 0; + _tempBuffer5120 = 0; + _lvlBuffer = 0; + _unkGameFlag = 0; + + _dscUnk1 = 0; + _dscShapeIndex = 0; + _dscOvlMap = 0; + _dscShapeScaleW = 0; + _dscShapeScaleH = 0; + _dscShapeX = 0; + _dscShapeY = 0; + _dscTileIndex = 0; + _dscUnk2 = 0; + _dscDoorShpIndex = 0; + _dscDim1 = 0; + _dscDim2 = 0; + _dscBlockMap = _dscDoor1 = _dscDoor2 = _dscShapeOvlIndex = 0; + _dscBlockIndex = 0; + _dscDimMap = 0; + _dscDoorX = _dscDoorY = 0; + _dscDoor4 = 0; + + _ingameSoundList = 0; + _ingameSoundListSize = 0; + + _sceneDrawVar1 = _sceneDrawVar2 = _sceneDrawVar3 = _wllProcessFlag = 0; + _unkCmzU1 = _unkCmzU2 = 0; + _shpDoorX = _shpDoorY = _doorScaleW = _doorScaleH = 0; } LoLEngine::~LoLEngine() { setupPrologueData(false); - for (uint i = 0; i < ARRAYSIZE(_shapes); ++i) - delete[] _shapes[i]; delete[] _landsFile; + delete[] _levelLangFile; delete _screen; delete _tim; + delete [] _itemsInPlay; + delete [] _itemProperties; + + delete [] _characters; + + if (_itemIconShapes) { + for (int i = 0; i < _numItemIconShapes; i++) + delete [] _itemIconShapes[i]; + delete []_itemIconShapes; + } + if (_itemShapes) { + for (int i = 0; i < _numItemShapes; i++) + delete [] _itemShapes[i]; + delete []_itemShapes; + } + if (_gameShapes) { + for (int i = 0; i < _numGameShapes; i++) + delete [] _gameShapes[i]; + delete []_gameShapes; + } + if (_thrownShapes) { + for (int i = 0; i < _numThrownShapes; i++) + delete [] _thrownShapes[i]; + delete []_thrownShapes; + } + if (_iceShapes) { + for (int i = 0; i < _numIceShapes; i++) + delete [] _iceShapes[i]; + delete []_iceShapes; + } + if (_fireballShapes) { + for (int i = 0; i < _numFireballShapes; i++) + delete [] _fireballShapes[i]; + delete []_fireballShapes; + } + + if (_monsterShapes) { + for (int i = 0; i < 48; i++) + delete [] _monsterShapes[i]; + delete []_monsterShapes; + } + if (_monsterPalettes) { + for (int i = 0; i < 48; i++) + delete [] _monsterPalettes[i]; + delete []_monsterPalettes; + } + if (_buf4) { + for (int i = 0; i < 384; i++) + delete [] _buf4[i]; + delete []_buf4; + } + for (Common::Array::iterator i = _timIntroOpcodes.begin(); i != _timIntroOpcodes.end(); ++i) delete *i; _timIntroOpcodes.clear(); + + delete []_wllVmpMap; + delete []_wllShapeMap; + delete []_wllBuffer3; + delete []_wllBuffer4; + delete []_wllBuffer5; + delete []_lvlShapeTop; + delete []_lvlShapeBottom; + delete []_lvlShapeLeftRight; + delete []_tempBuffer5120; + delete []_lvlBuffer; + delete []_cmzBuffer; + delete []_lvl415; + + delete []_lvlShpHeader; + delete []_levelFileData; + delete []_vcnExpTable; + delete []_vcnBlocks; + delete []_vcnShift; + delete []_vmpPtr; + delete []_tlcTable2; + delete []_tlcTable1; + delete []_levelShapeProperties; + delete []_blockDrawingBuffer; + delete []_sceneWindowBuffer; + + if (_levelShapes) { + for (int i = 0; i < 400; i++) + delete [] _levelShapes[i]; + delete []_levelShapes; + } + + for (int i = 0; i < 2; i++) + delete _doorShapes[i]; + + delete _lvlShpFileHandle; + + if (_ingameSoundList) { + for (int i = 0; i < _ingameSoundListSize; i++) + delete []_ingameSoundList[i]; + delete []_ingameSoundList; + } } Screen *LoLEngine::screen() { @@ -90,6 +269,7 @@ Common::Error LoLEngine::init() { _screen->setResolution(); KyraEngine_v1::init(); + initStaticResource(); _tim = new TIMInterpreter(this, _screen, _system); assert(_tim); @@ -97,9 +277,77 @@ Common::Error LoLEngine::init() { _screen->setAnimBlockPtr(10000); _screen->setScreenDim(0); + _itemsInPlay = new ItemInPlay[401]; + memset(_itemsInPlay, 0, sizeof(ItemInPlay) * 400); + + _characters = new LoLCharacter[4]; + memset(_characters, 0, sizeof(LoLCharacter) * 3); + if (!_sound->init()) error("Couldn't init sound"); + _unkAudioSpecOffs = 0x48; + _unkLangAudio = _lang ? true : false; + + _wllVmpMap = new uint8[80]; + memset(_wllVmpMap, 0, 80); + _wllShapeMap = new int8[80]; + memset(_wllShapeMap, 0, 80); + _wllBuffer3 = new uint8[80]; + memset(_wllBuffer3, 0, 80); + _wllBuffer4 = new uint8[80]; + memset(_wllBuffer4, 0, 80); + _wllBuffer5 = new uint8[80]; + memset(_wllBuffer5, 0, 80); + _lvlShapeTop = new int16[18]; + memset(_lvlShapeTop, 0, 18 * sizeof(int16)); + _lvlShapeBottom = new int16[18]; + memset(_lvlShapeBottom, 0, 18 * sizeof(int16)); + _lvlShapeLeftRight = new int16[36]; + memset(_lvlShapeLeftRight, 0, 36 * sizeof(int16)); + _levelShapeProperties = new LevelShapeProperty[100]; + memset(_levelShapeProperties, 0, 100 * sizeof(LevelShapeProperty)); + _levelShapes = new uint8*[400]; + memset(_levelShapes, 0, 400 * sizeof(uint8*)); + _blockDrawingBuffer = new uint16[1320]; + memset(_blockDrawingBuffer, 0, 1320 * sizeof(uint16)); + _sceneWindowBuffer = new uint8[21120]; + memset(_sceneWindowBuffer, 0, 21120); + + _cmzBuffer = new CMZ[1025]; + memset(_cmzBuffer, 0, 1025 * sizeof(CMZ)); + _lvlBuffer = new LVL[30]; + memset(_lvlBuffer, 0, 30 * sizeof(LVL)); + _lvl415 = new uint8[415]; + memset(_lvl415, 0, 415); + + _vcnExpTable = new uint8[128]; + for (int i = 0; i < 128; i++) + _vcnExpTable[i] = i & 0x0f; + + _tempBuffer5120 = new uint8[5120]; + memset(_tempBuffer5120, 0, 5120); + + memset(_gameFlags, 0, 15 * sizeof(uint16)); + + _lvlShpHeader = 0; + _levelFileData = 0; + _lvlShpFileHandle = 0; + + _sceneDrawPage1 = 2; + _sceneDrawPage2 = 6; + + _monsterShapes = new uint8*[48]; + memset(_monsterShapes, 0, 48 * sizeof(uint8*)); + _monsterPalettes = new uint8*[48]; + memset(_monsterPalettes, 0, 48 * sizeof(uint8*)); + + _buf4 = new uint8*[384]; + memset(_buf4, 0, 384 * sizeof(uint8*)); + memset(&_scriptData, 0, sizeof(EMCData)); + + _levelFlagUnk = 0; + return Common::kNoError; } @@ -171,10 +419,17 @@ Common::Error LoLEngine::go() { _sound->playTrack(1); _screen->fadeToBlack(); setupPrologueData(true); - } else if (processSelection == 3) { - //XXX } + if (!shouldQuit() && (processSelection == 0 || processSelection == 3)) + startup(); + + if (!shouldQuit() && processSelection == 0) + startupNew(); + + if (!shouldQuit() && (processSelection == 0 || processSelection == 3)) + runLoop(); + return Common::kNoError; } @@ -223,8 +478,35 @@ void LoLEngine::initializeCursors() { debugC(9, kDebugLevelMain, "LoLEngine::initializeCursors()"); _screen->loadBitmap("ITEMICN.SHP", 3, 3, 0); - _shapes[0] = _screen->makeShapeCopy(_screen->getCPagePtr(3), 0); - _screen->setMouseCursor(0, 0, _shapes[0]); + const uint8 *shp = _screen->getCPagePtr(3); + _numItemIconShapes = READ_LE_UINT16(shp); + _itemIconShapes = new uint8*[_numItemIconShapes]; + for (int i = 0; i < _numItemIconShapes; i++) + _itemIconShapes[i] = _screen->makeShapeCopy(shp, i); + + _screen->setMouseCursor(0, 0, _itemIconShapes[0]); +} + +void LoLEngine::setMouseCursorToIcon(int icon) { + _screen->_drawGuiFlag |= 0x200; + int i = _itemProperties[_itemsInPlay[_itemInHand].itemPropertyIndex].shpIndex; + if (i == icon) + return; + _screen->setMouseCursor(0, 0, _itemIconShapes[icon]); +} + +void LoLEngine::setMouseCursorToItemInHand() { + _screen->_drawGuiFlag &= 0xFDFF; + int o = (_itemInHand == 0) ? 0 : 10; + _screen->setMouseCursor(o, o, getItemIconShapePtr(_itemInHand)); +} + +uint8 *LoLEngine::getItemIconShapePtr(int index) { + int ix = _itemProperties[_itemsInPlay[index].itemPropertyIndex].shpIndex; + if (_itemProperties[_itemsInPlay[index].itemPropertyIndex].flags & 0x200) + ix += (_itemsInPlay[index].shpCurFrame_flg & 0x1fff) - 1; + + return _itemIconShapes[ix]; } int LoLEngine::mainMenu() { @@ -275,6 +557,120 @@ int LoLEngine::mainMenu() { return selection; } +void LoLEngine::startup() { + _screen->clearPage(0); + _screen->loadBitmap("PLAYFLD.CPS", 3, 3, _screen->_currentPalette); + + uint8 *tmpPal = new uint8[0x300]; + memcpy(tmpPal, _screen->_currentPalette, 0x300); + memset(_screen->_currentPalette, 0x3f, 0x180); + memcpy(_screen->_currentPalette + 3, tmpPal + 3, 3); + memset(_screen->_currentPalette + 0x240, 0x3f, 12); + _screen->generateOverlay(_screen->_currentPalette, _screen->_paletteOverlay1, 1, 6); + _screen->generateOverlay(_screen->_currentPalette, _screen->_paletteOverlay2, 0x90, 0x41); + memcpy(_screen->_currentPalette, tmpPal, 0x300); + delete []tmpPal; + + memset(_screen->getPalette(1), 0, 0x300); + memset(_screen->getPalette(2), 0, 0x300); + + _screen->setMouseCursor(0, 0, _itemIconShapes[0x85]); + + _screen->loadBitmap("ITEMSHP.SHP", 3, 3, 0); + const uint8 *shp = _screen->getCPagePtr(3); + _numItemShapes = READ_LE_UINT16(shp); + _itemShapes = new uint8*[_numItemShapes]; + for (int i = 0; i < _numItemShapes; i++) + _itemShapes[i] = _screen->makeShapeCopy(shp, i); + + _screen->loadBitmap("GAMESHP.SHP", 3, 3, 0); + shp = _screen->getCPagePtr(3); + _numGameShapes = READ_LE_UINT16(shp); + _gameShapes = new uint8*[_numGameShapes]; + for (int i = 0; i < _numGameShapes; i++) + _gameShapes[i] = _screen->makeShapeCopy(shp, i); + + _screen->loadBitmap("THROWN.SHP", 3, 3, 0); + shp = _screen->getCPagePtr(3); + _numThrownShapes = READ_LE_UINT16(shp); + _thrownShapes = new uint8*[_numThrownShapes]; + for (int i = 0; i < _numThrownShapes; i++) + _thrownShapes[i] = _screen->makeShapeCopy(shp, i); + + _screen->loadBitmap("ICE.SHP", 3, 3, 0); + shp = _screen->getCPagePtr(3); + _numIceShapes = READ_LE_UINT16(shp); + _iceShapes = new uint8*[_numIceShapes]; + for (int i = 0; i < _numIceShapes; i++) + _iceShapes[i] = _screen->makeShapeCopy(shp, i); + + _screen->loadBitmap("FIREBALL.SHP", 3, 3, 0); + shp = _screen->getCPagePtr(3); + _numFireballShapes = READ_LE_UINT16(shp); + _fireballShapes = new uint8*[_numFireballShapes]; + for (int i = 0; i < _numFireballShapes; i++) + _fireballShapes[i] = _screen->makeShapeCopy(shp, i); + + memset(_itemsInPlay, 0, 400 * sizeof(ItemInPlay)); + for (int i = 0; i < 400; i++) + _itemsInPlay[i].shpCurFrame_flg |= 0x8000; + + runInitScript("ONETIME.INF", 0); + _emc->load("ITEM.INF", &_itemScript, &_opcodes); + + _tlcTable1 = new uint8[256]; + _tlcTable2 = new uint8[5120]; + + _loadSuppFilesFlag = 1; + + setMouseCursorToItemInHand(); +} + +void LoLEngine::startupNew() { + _selectedSpell = 0; + _updateUnk2 = _compassDirectionIndex = -1; + /* + _unk3 = -1;*/ + _unkGameFlag |= 0x1B; + /* + _unk5 = 1; + _unk6 = 1; + _unk7 = 1 + _unk8 = 1*/ + _currentLevel = 1; + + giveCredits(41, 0); + _inventoryItemIndex[0] = makeItem(0xd8, 0, 0); + _inventoryItemIndex[1] = makeItem(0xd9, 0, 0); + _inventoryItemIndex[2] = makeItem(0xda, 0, 0); + + memset(_availableSpells, -1, 7); + setupScreenDims(); + + //memset(_unkWordArraySize8, 0x100, 8); + + static int selectIds[] = { -9, -1, -8, -5 }; + addCharacter(selectIds[_charSelection]); + + // TODO + + loadLevel(1); + + _screen->showMouse(); +} + +void LoLEngine::runLoop() { + _screen->updateScreen(); + + bool _runFlag = true; + while (!shouldQuit() && _runFlag) { + checkInput(0, false); + removeInputTop(); + _screen->updateScreen(); + _system->delayMillis(10); + } +} + #pragma mark - Localization const char *LoLEngine::getLangString(uint16 id) { @@ -363,7 +759,7 @@ void LoLEngine::setupPrologueData(bool load) { _chargenWSA = new WSAMovie_v2(this, _screen); assert(_chargenWSA); - _charSelection = -1; + //_charSelection = -1; _charSelectionInfoResult = -1; _selectionAnimFrames[0] = _selectionAnimFrames[2] = 0; @@ -414,6 +810,7 @@ void LoLEngine::showIntro() { } _screen->showMouse(); _sound->voiceStop(); + _sound->beginFadeOut(); _eventList.clear(); @@ -807,14 +1204,535 @@ int LoLEngine::selectionCharAccept() { return -1; } +bool LoLEngine::addCharacter(int id) { + int numChars = countActiveCharacters(); + if (numChars == 4) + return false; + + int i = 0; + for (; i < _charDefaultsSize; i++) { + if (_charDefaults[i].id == id) { + memcpy(&_characters[numChars], &_charDefaults[i], sizeof(LoLCharacter)); + break; + } + } + if (i == _charDefaultsSize) + return false; + + loadCharFaceShapes(numChars, id); + + _characters[numChars].rand = _rnd.getRandomNumberRng(1, 12); + + 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); + } + } + + calcCharPortraitXpos(); + if (numChars > 0) + initCharacter(numChars, 2, 6, 0); + + return true; +} + +void LoLEngine::initCharacter(int charNum, int firstFaceFrame, int unk2, int redraw) { + _characters[charNum].nextFaceFrame = firstFaceFrame; + if (firstFaceFrame || unk2) + initCharacterUnkSub(charNum, 6, unk2, 1); + if (redraw) + gui_drawCharPortraitWithStats(charNum); +} + +void LoLEngine::initCharacterUnkSub(int charNum, int unk1, int unk2, int unk3) { + for (int i = 0; i < 5; i++) { + if (_characters[charNum].arrayUnk1[i] == 0 || (unk3 && _characters[charNum].arrayUnk1[i] == unk1)) { + _characters[charNum].arrayUnk1[i] = unk1; + _characters[charNum].arrayUnk2[i] = unk2; + + // TODO + + break; + } + } +} + +int LoLEngine::countActiveCharacters() { + int i = 0; + while (_characters[i].flags & 1) + i++; + return i; +} + +void LoLEngine::loadCharFaceShapes(int charNum, int id) { + if (id < 0) + id = -id; + + char file[] = "FACE%02d.SHP"; + sprintf(file, "FACE%02d.SHP", id); + _screen->loadBitmap(file, 3, 3, 0); + + const uint8 *p = _screen->getCPagePtr(3); + for (int i = 0; i < 40; i++) + _characterFaceShapes[i][charNum] = _screen->makeShapeCopy(p, i); +} + +void LoLEngine::updatePortraitWithStats() { + int x = 0; + int y = 0; + bool redraw = false; + + if (_updateCharV2 == 0) { + x = _activeCharsXpos[_updateCharNum]; + y = 144; + redraw = true; + } else if (_updateCharV2 == 1) { + if (_unkLangAudio) { + x = 90; + y = 130; + } else { + x = _activeCharsXpos[_updateCharNum]; + y = 144; + } + } else if (_updateCharV2 == 2) { + if (_unkLangAudio) { + x = 16; + y = 134; + } else { + x = _activeCharsXpos[_updateCharNum] + 10; + y = 145; + } + } + + int f = _rnd.getRandomNumberRng(1, 6) - 1; + if (f == _characters[_updateCharNum].curFaceFrame) + f++; + if (f > 5) + f -= 5; + f += 7; + + if (_unkAudioSpecOffs) { + //TODO + //if (unk() == 2) + // _updateCharV1 = 2; + //else + _updateCharV1 = 1; + } + + if (--_updateCharV1) { + setCharFaceFrame(_updateCharNum, f); + if (redraw) + gui_drawCharPortraitWithStats(_updateCharNum); + else + gui_drawCharFaceShape(_updateCharNum, x, y, 0); + _updatePortraitNext = _system->getMillis() + 10 * _tickLength; + } else if (_updateCharV1 == 0 && _updateCharV3 != 0) { + faceFrameRefresh(_updateCharNum); + if (redraw) { + gui_drawCharPortraitWithStats(_updateCharNum); + updatePortraitUnkTimeSub(0, 0); + } else { + gui_drawCharFaceShape(_updateCharNum, x, y, 0); + } + _updateCharNum = -1; + } +} + +void LoLEngine::updatePortraits() { + if (_updateCharNum == -1) + return; + + _updateCharV1 = _updateCharV3 = 1; + updatePortraitWithStats(); + _updateCharV1 = 1; + _updateCharNum = -1; + + if (!_updateCharV2) + updatePortraitUnkTimeSub(0, 0); +} + +void LoLEngine::updatePortraitUnkTimeSub(int unk1, int unk2) { + if (_updateCharV4 == unk1 || !unk1) { + _updateCharV5 = 1; + _updateCharTime = _system->getMillis(); + } + + if (!unk2) + return; + + updatePortraits(); + if (_updateCharV6) { + _screen->hideMouse(); + _screen->clearDim(3); + _screen->showMouse(); + } + + _updateCharV5 = 0; + //initGuiUnk(11); +} + +void LoLEngine::setCharFaceFrame(int charNum, int frameNum) { + _characters[charNum].curFaceFrame = frameNum; +} + +void LoLEngine::faceFrameRefresh(int charNum) { + if (_characters[charNum].curFaceFrame == 1) + initCharacter(charNum, 0, 0, 0); + else if (_characters[charNum].curFaceFrame == 6) + if (_characters[charNum].nextFaceFrame != 5) + initCharacter(charNum, 0, 0, 0); + else + _characters[charNum].curFaceFrame = 5; + else + _characters[charNum].curFaceFrame = 0; +} + +void LoLEngine::setupScreenDims() { + if (_unkLangAudio) + _screen->modifyScreenDim(4, 11, 124, 28, 45); + else + _screen->modifyScreenDim(4, 11, 124, 28, 9); + _screen->modifyScreenDim(5, 85, 123, 233, 18); +} + +void LoLEngine::snd_playSoundEffect(int track, int volume) { + debugC(9, kDebugLevelMain | kDebugLevelSound, "LoLEngine::snd_playSoundEffect(%d, %d)", track, volume); + + if (track == 1 && (_lastSfxTrack == -1 || _lastSfxTrack == 1)) + return; + + _lastSfxTrack = track; + + int16 volIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2 + 1]); + + if (volIndex > 0) + volIndex = (volIndex * volume) >> 8; + else + volIndex *= -1; + + // volume TODO + + int16 vocIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2]); + if (vocIndex != -1) { + _sound->voicePlay(_ingameSoundList[vocIndex], true); + } else if (_flags.platform == Common::kPlatformPC) { + if (_sound->getSfxType() == Sound::kMidiMT32) + track = track < _ingameMT32SoundIndexSize ? _ingameMT32SoundIndex[track] - 1 : -1; + else if (_sound->getSfxType() == Sound::kMidiGM) + track = track < _ingameGMSoundIndexSize ? _ingameGMSoundIndex[track] - 1: -1; + + if (track != -1) + KyraEngine_v1::snd_playSoundEffect(track); + } +} + #pragma mark - Opcodes +typedef Common::Functor1Mem OpcodeV2; +#define SetOpcodeTable(x) table = &x; +#define Opcode(x) table->push_back(new OpcodeV2(this, &LoLEngine::x)) +#define OpcodeUnImpl() table->push_back(new OpcodeV2(this, 0)) + typedef Common::Functor2Mem TIMOpcodeLoL; #define SetTimOpcodeTable(x) timTable = &x; #define OpcodeTim(x) timTable->push_back(new TIMOpcodeLoL(this, &LoLEngine::x)) #define OpcodeTimUnImpl() timTable->push_back(new TIMOpcodeLoL(this, 0)) void LoLEngine::setupOpcodeTable() { + Common::Array *table = 0; + + SetOpcodeTable(_opcodes); + // 0x00 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + Opcode(o1_getRand); + + // 0x04 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + Opcode(o2_setGameFlag); + + // 0x08 + Opcode(o2_testGameFlag); + Opcode(o2_loadLevelSupplemenaryFiles); + Opcode(o2_loadCmzFile); + Opcode(o2_loadMonsterShapes); + + // 0x0C + OpcodeUnImpl(); + Opcode(o2_allocItemPropertiesBuffer); + Opcode(o2_setItemProperty); + Opcode(o2_makeItem); + + // 0x10 + OpcodeUnImpl(); + OpcodeUnImpl(); + Opcode(o2_getItemPara); + Opcode(o2_getCharacterStat); + + // 0x14 + Opcode(o2_setCharacterStat); + Opcode(o2_loadLevelShapes); + Opcode(o2_closeLevelShapeFile); + OpcodeUnImpl(); + + // 0x18 + Opcode(o2_loadDoorShapes); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x1C + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x20 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x24 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x28 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x2C + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x30 + Opcode(o2_setGlobalVar); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x34 + OpcodeUnImpl(); + Opcode(o2_mapShapeToBlock); + Opcode(o2_resetBlockShapeAssignment); + OpcodeUnImpl(); + + // 0x38 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x3C + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x40 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x44 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x48 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x4C + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x50 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x54 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x58 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x5C + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x60 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x64 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x68 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + Opcode(o2_setPaletteBrightness); + + // 0x6C + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x70 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x74 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x78 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x7C + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x80 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x84 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x88 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x8C + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x90 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x94 + Opcode(o2_assignCustomSfx); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x98 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0x9C + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0xA0 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0xA4 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0xA8 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0xAC + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0xB0 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0xB4 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0xB8 + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + + // 0xBC + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + OpcodeUnImpl(); + Common::Array *timTable = 0; SetTimOpcodeTable(_timIntroOpcodes); diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index a6b7378b0f..194d24ddf8 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -28,6 +28,7 @@ #include "kyra/kyra_v1.h" #include "kyra/script_tim.h" +#include "kyra/script.h" #include "common/list.h" @@ -37,6 +38,143 @@ class Screen_LoL; class WSAMovie_v2; struct Button; +struct LoLCharacter { + uint16 flags; + char name[11]; + uint8 raceClassSex; + int16 id; + uint8 curFaceFrame; + uint8 nextFaceFrame; + uint16 field_12; + uint16 field_14; + uint8 field_16; + uint16 field_17[5]; + uint16 field_21; + uint16 field_23; + uint16 field_25; + uint16 field_27[2]; + uint8 field_2B; + uint16 field_2C; + uint16 field_2E; + uint16 field_30; + uint16 field_32; + uint16 field_34; + uint8 field_36; + uint16 field_37; + uint16 hitPointsCur; + uint16 hitPointsMax; + uint16 magicPointsCur; + uint16 magicPointsMax; + uint8 field_41; + uint16 damageSuffered; + uint16 weaponHit; + uint16 field_46; + uint16 field_48; + uint16 field_4A; + uint16 field_4C; + uint16 rand; + uint16 items[11]; + uint8 field_66[3]; + uint8 field_69[3]; + uint8 field_6C; + uint8 field_6D; + uint16 field_6E; + uint16 field_70; + uint16 field_72; + uint16 field_74; + uint16 field_76; + uint8 arrayUnk2[5]; + uint8 arrayUnk1[5]; +}; + +struct SpellProperty { + uint16 field_0; + uint16 unkArr[4]; + uint16 field_A; + uint16 field_C; + uint16 field_E; + uint16 spellNameCode; + uint16 mpRequired[4]; + uint16 field_1A; +}; + +struct CMZ { + uint8 unk[4]; + uint16 itemIndex; + uint8 field_6; + uint8 field_7; + uint8 field_8; + uint8 flags; +}; + +struct LVL { + uint8 field_0; + uint8 field_1; + uint8 field_2; + uint8 field_3; + uint8 field_4; + uint16 cmzIndex; + uint16 p_1a; + uint16 p_1b; + uint8 field_B; + uint16 p_2a; + uint16 p_2b; + uint8 field_10; + uint8 field_11; + uint8 field_12; + uint8 field_13; + uint8 field_14; + uint8 field_15; + uint8 field_16; + uint8 field_17; + uint8 field_18; + uint16 field_19; + uint8 field_1B; + uint8 field_1C; + int16 field_1D; + uint8 field_1F; + uint8 field_20; + uint8 *offs_lvl415; + uint8 field_25; + uint8 field_26; + uint8 field_27; + uint8 field_28; + uint8 field_29; + uint8 field_2A; + uint8 field_2B; + uint8 field_2C; + uint8 field_2D; + uint8 field_2E; +}; + +struct LevelShapeProperty { + uint16 shapeIndex[10]; + uint8 scaleFlag[10]; + uint16 shapeX[10]; + uint16 shapeY[10]; + int8 next; + uint8 flags; +}; + +struct CompassDef { + uint8 shapeIndex; + int8 x; + int8 y; + 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; +}; + class LoLEngine : public KyraEngine_v1 { public: LoLEngine(OSystem *system, const GameFlags &flags); @@ -51,12 +189,22 @@ private: Common::Error go(); // initialization + void initStaticResource(); void preInit(); void initializeCursors(); - int mainMenu(); + void startup(); + void startupNew(); + + void runLoop(); + + // mouse + void setMouseCursorToIcon(int icon); + void setMouseCursorToItemInHand(); + uint8 *getItemIconShapePtr(int index); + // intro void setupPrologueData(bool load); @@ -111,8 +259,84 @@ private: // sound void snd_playVoiceFile(int) { /* XXX */ } - - // opcode + void snd_playSoundEffect(int track, int volume); + + int _lastSfxTrack; + + int _unkAudioSpecOffs; + bool _unkLangAudio; + + char **_ingameSoundList; + int _ingameSoundListSize; + + const uint16 *_ingameSoundIndex; + int _ingameSoundIndexSize; + const uint8 *_ingameGMSoundIndex; + int _ingameGMSoundIndexSize; + const uint8 *_ingameMT32SoundIndex; + int _ingameMT32SoundIndexSize; + + // gui + void gui_drawPlayField(); + 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_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); + void gui_drawInventory(); + void gui_drawInventoryItem(int index); + void gui_drawCompass(); + void gui_drawScroll(); + + bool _weaponsDisabled; + int _unkDrawPortraitIndex; + int _updateUnk2; + int _compassDirectionIndex; + + const CompassDef *_compassDefs; + int _compassDefsSize; + + // emc scripts + void runInitScript(const char *filename, int func); + void runInfScript(const char *filename); + void runResidentScript(int func, int reg0); + void runResidentScriptCustom(int func, int reg0, int reg1, int reg2, int reg3, int reg4); + bool checkScriptUnk(int func); + + EMCData _scriptData; + bool _scriptBoolSkipExec; + uint8 _unkScriptByte; + uint16 _unkPara2; + uint16 _currentBlock; + bool _boolScriptFuncDone; + int16 _scriptExecutedFuncs[18]; + + uint16 _gameFlags[15]; + + // emc opcode + int o2_setGameFlag(EMCState *script); + int o2_testGameFlag(EMCState *script); + int o2_loadLevelSupplemenaryFiles(EMCState *script); + int o2_loadCmzFile(EMCState *script); + int o2_loadMonsterShapes(EMCState *script); + int o2_allocItemPropertiesBuffer(EMCState *script); + int o2_setItemProperty(EMCState *script); + int o2_makeItem(EMCState *script); + int o2_getItemPara(EMCState *script); + int o2_getCharacterStat(EMCState *script); + int o2_setCharacterStat(EMCState *script); + int o2_loadLevelShapes(EMCState *script); + int o2_closeLevelShapeFile(EMCState *script); + int o2_loadDoorShapes(EMCState *script); + int o2_setGlobalVar(EMCState *script); + int o2_mapShapeToBlock(EMCState *script); + int o2_resetBlockShapeAssignment(EMCState *script); + int o2_setPaletteBrightness(EMCState *script); + int o2_assignCustomSfx(EMCState *script); + + // tim opcode void setupOpcodeTable(); Common::Array _timIntroOpcodes; @@ -126,6 +350,7 @@ private: int _lang; uint8 *_landsFile; + uint8 *_levelLangFile; int _lastUsedStringBuffer; char _stringBuffer[5][512]; // TODO: The original used a size of 512, it looks a bit large. @@ -136,7 +361,294 @@ private: static const char * const _languageExt[]; // graphics - uint8 *_shapes[138]; + void setupScreenDims(); + + uint8 **_itemIconShapes; + int _numItemIconShapes; + uint8 **_itemShapes; + int _numItemShapes; + uint8 **_gameShapes; + int _numGameShapes; + uint8 **_thrownShapes; + int _numThrownShapes; + uint8 **_iceShapes; + int _numIceShapes; + uint8 **_fireballShapes; + int _numFireballShapes; + + const int8 *_gameShapeMap; + int _gameShapeMapSize; + + uint8 *_characterFaceShapes[40][3]; + + // characters + bool addCharacter(int id); + void initCharacter(int charNum, int firstFaceFrame, int unk2, int redraw); + void initCharacterUnkSub(int charNum, int unk1, int unk2, int unk3); + int countActiveCharacters(); + void loadCharFaceShapes(int charNum, int id); + void calcCharPortraitXpos(); + + void updatePortraitWithStats(); + void updatePortraits(); + void updatePortraitUnkTimeSub(int unk1, int unk2); + + void setCharFaceFrame(int charNum, int frameNum); + void faceFrameRefresh(int charNum); + + LoLCharacter *_characters; + uint16 _activeCharsXpos[3]; + int _charFlagUnk; + int _updateCharNum; + int _updateCharV1; + int _updateCharV2; + int _updateCharV3; + int _updateCharV4; + int _updateCharV5; + int _updateCharV6; + uint32 _updateCharTime; + uint32 _updatePortraitNext; + + int _loadLevelFlag; + int _levelFlagUnk; + + uint8 **_monsterShapes; + uint8 **_monsterPalettes; + uint8 **_buf4; + uint8 _monsterUnk[3]; + + const LoLCharacter *_charDefaults; + int _charDefaultsSize; + + // 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 cmzS4(uint16 &itemIndex, int a); + int cmzS5(uint16 a, uint16 b); + void cmzS6(uint16 &itemIndex, int a); + void cmzS7(int itemIndex, int a); + void loadLevelWLL(int index, bool mapShapes); + void moveItemToCMZ(uint16 *cmzItemIndex, uint16 item); + int assignLevelShapes(int index); + uint8 *getLevelShapes(int index); + void loadLevelCMZ(int index); + void loadCMZ_Sub(int index1, int index2); + void loadCmzFile(const char *file); + void loadMonsterShapes(const char *file, int monsterIndex, int b); + void releaseMonsterShapes(int monsterIndex); + void loadLevelShpDat(const char *shpFile, const char *datFile, bool flag); + void loadLevelSupplemenaryFiles(const char *file, int specialColor, int weight, int vcnLen, int vmpLen, const char *langFile); + + void drawScene(int pageNum); + + void generateBlockDrawingBuffer(int block, int b); + void generateBlockDrawingBufferF0(int16 wllOffset, uint8 wllIndex, uint8 wllVmpIndex, int16 vmpOffset, uint8 len, uint8 numEntries); + void generateBlockDrawingBufferF1(int16 wllOffset, uint8 wllIndex, uint8 wllVmpIndex, int16 vmpOffset, uint8 len, uint8 numEntries); + bool testWllBuffer5Value(int index); + void assignBlockCaps(int a, int b); + + void drawVcnBlocks(uint8 *vcnBlocks, uint16 *blockDrawingBuffer, uint8 *vcnShift, int pageNum); + void drawSceneShapes(); + void setLevelShapesDim(int index, int16 &x1, int16 &x2, int dim); + void scaleLevelShapesDim(int index, int16 &y1, int16 &y2, int dim); + void drawLevelModifyScreenDim(int dim, int16 x1, int16 y1, int16 x2, int16 y2); + void drawDecorations(int index); + void drawIceShapes(int index, int iceShapeIndex); + void drawDoor(uint8 *shape, uint8 *table, int index, int unk2, int w, int h, int flags); + void drawDoorShapes(uint8 *shape, uint8 *table, int x, int y, int flags, const uint8 *ovl); + void drawScriptShapes(int pageNum); + void updateSceneWindow(); + + void turnOnLamp(); + void updateLampStatus(); + + void setLF1(uint16 & a, uint16 & b, int block, uint16 d, uint16 e); + void setLF2(int block); + + int _unkFlag; + int _scriptFuncIndex; + uint8 _currentLevel; + bool _loadLevelFlag2; + int _lvlBlockIndex; + int _lvlShapeIndex; + bool _unkDrawLevelBool; + uint8 *_vcnBlocks; + uint8 *_vcnShift; + uint8 *_vcnExpTable; + uint16 *_vmpPtr; + uint16 *_blockDrawingBuffer; + uint8 *_sceneWindowBuffer; + LevelShapeProperty *_levelShapeProperties; + uint8 **_levelShapes; + + char _lastSuppFile[12]; + char _lastSuppLangFile[12]; + char *_lastSuppLangFilePtr; + int _lastSpecialColor; + int _lastSpecialColorWeight; + + int _sceneDrawVar1; + int _sceneDrawVar2; + int _sceneDrawVar3; + int _wllProcessFlag; + + uint8 *_tlcTable2; + uint8 *_tlcTable1; + + int _loadSuppFilesFlag; + + int _lampOilStatus; + int _brightness; + int _lampStatusUnk; + uint32 _lampStatusTimer; + + uint8 *_wllVmpMap; + int8 *_wllShapeMap; + uint8 *_wllBuffer3; + uint8 *_wllBuffer4; + uint8 *_wllBuffer5; + + int16 *_lvlShapeTop; + int16 *_lvlShapeBottom; + int16 *_lvlShapeLeftRight; + + CMZ *_cmzBuffer; + CMZ *_curBlockCaps[18]; + LVL *_lvlBuffer; + uint8 *_lvl415; + + uint16 _unkCmzU1; + uint16 _unkCmzU2; + + Common::SeekableReadStream *_lvlShpFileHandle; + uint16 _lvlShpNum; + uint32 *_lvlShpHeader; + uint16 _levelFileDataSize; + LevelShapeProperty *_levelFileData; + + uint8 *_doorShapes[2]; + int16 _shpDoorX; + int16 _shpDoorY; + int16 _doorScaleW; + int16 _doorScaleH; + + uint8 _unkGameFlag; + + uint8 *_tempBuffer5120; + + const char *const * _levelDatList; + int _levelDatListSize; + const char *const * _levelShpList; + int _levelShpListSize; + + const int8 *_dscUnk1; + int _dscUnk1Size; + const int8 *_dscShapeIndex; + int _dscShapeIndexSize; + const uint8 *_dscOvlMap; + int _dscOvlMapSize; + const uint16 *_dscShapeScaleW; + int _dscShapeScaleWSize; + const uint16 *_dscShapeScaleH; + int _dscShapeScaleHSize; + const int16 *_dscShapeX; + int _dscShapeXSize; + const int8 *_dscShapeY; + int _dscShapeYSize; + const uint8 *_dscTileIndex; + int _dscTileIndexSize; + const uint8 *_dscUnk2; + int _dscUnk2Size; + const uint8 *_dscDoorShpIndex; + int _dscDoorShpIndexSize; + const int8 *_dscDim1; + int _dscDim1Size; + const int8 *_dscDim2; + int _dscDim2Size; + const uint8 *_dscBlockMap; + int _dscBlockMapSize; + const uint8 *_dscDimMap; + int _dscDimMapSize; + const uint8 *_dscDoor2; + int _dscDoor2Size; + const uint16 *_dscDoorScaleTable; + int _dscDoorScaleTableSize; + const uint16 *_dscDoor4; + int _dscDoor4Size; + const uint8 *_dscShapeOvlIndex; + int _dscShapeOvlIndexSize; + const int8 *_dscBlockIndex; + int _dscBlockIndexSize; + const uint8 *_dscDoor1; + int _dscDoor1Size; + const int16 *_dscDoorX; + int _dscDoorXSize; + const int16 *_dscDoorY; + int _dscDoorYSize; + + int _sceneDrawPage1; + int _sceneDrawPage2; + + // items + struct ItemInPlay { + uint16 itemIndexUnk; + uint8 unk2; + uint16 unk3; + uint16 cmzIndex; + 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); + void runItemScript(int reg1, int item, int reg0, int reg3, int reg4); + + uint8 _moneyColumnHeight[5]; + uint16 _credits; + + ItemInPlay *_itemsInPlay; + ItemProperty *_itemProperties; + + int _itemInHand; + uint16 _inventoryItemIndex[48]; + int _inventoryCurItem; + int _unkInventFlag; + + EMCData _itemScript; + + // spells + int8 _availableSpells[7]; + int _selectedSpell; + const SpellProperty *_spellProperties; + int _spellPropertiesSize; // unneeded void setWalkspeed(uint8) {} diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk index 18ab2ecdb5..0775fe3ec4 100644 --- a/engines/kyra/module.mk +++ b/engines/kyra/module.mk @@ -12,10 +12,12 @@ MODULE_OBJS := \ gui_v2.o \ gui_hof.o \ gui_mr.o \ + gui_lol.o \ items_lok.o \ items_v2.o \ items_hof.o \ items_mr.o \ + items_lol.o \ kyra_v1.o \ kyra_lok.o \ kyra_v2.o \ @@ -33,6 +35,7 @@ MODULE_OBJS := \ scene_v2.o \ scene_hof.o \ scene_mr.o \ + scene_lol.o \ screen.o \ screen_lok.o \ screen_lol.o \ @@ -44,6 +47,7 @@ MODULE_OBJS := \ script_v2.o \ script_hof.o \ script_mr.o \ + script_lol.o \ script.o \ script_tim.o \ seqplayer.o \ diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index 5ef26caa78..1f865e855f 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -39,6 +39,7 @@ #include "kyra/kyra_v1.h" #include "kyra/kyra_hof.h" +#include "kyra/lol.h" namespace Kyra { @@ -210,6 +211,40 @@ enum kKyraResources { k3ItemMagicTable, k3ItemStringMap, + lolCharacterDefs, + lolIngameSfxFiles, + lolIngameSfxIndex, + lolIngameGMSfxIndex, + lolIngameMT32SfxIndex, + lolSpellProperties, + lolGameShapeMap, + lolLevelShpList, + lolLevelDatList, + lolCompassDefs, + + lolDscUnk1, + lolDscShapeIndex, + lolDscOvlMap, + lolDscScaleWidthData, + lolDscScaleHeightData, + lolDscX, + lolDscY, + lolDscTileIndex, + lolDscUnk2, + lolDscDoorShapeIndex, + lolDscDimData1, + lolDscDimData2, + lolDscBlockMap, + lolDscDimMap, + lolDscDoor1, + lolDscDoor2, + lolDscDoorScale, + lolDscDoor4, + lolDscDoorX, + lolDscDoorY, + lolDscOvlIndex, + lolDscBlockIndex, + kMaxResIDs }; @@ -236,6 +271,10 @@ public: const HofSeqData *loadHofSequenceData(int id, int &entries); const ItemAnimData_v1 *loadShapeAnimData_v1(int id, int &entries); const ItemAnimData_v2 *loadShapeAnimData_v2(int id, int &entries); + const LoLCharacter *loadCharData(int id, int &entries); + const SpellProperty *loadSpellData(int id, int &entries); + const CompassDef *loadCompassData(int id, int &entries); + const uint16 *loadRawDataBe16(int id, int &entries); // use '-1' to prefetch/unload all ids // prefetchId retruns false if only on of the resources @@ -267,6 +306,10 @@ private: bool loadHofSequenceData(const char *filename, void *&ptr, int &size); bool loadShapeAnimData_v1(const char *filename, void *&ptr, int &size); bool loadShapeAnimData_v2(const char *filename, void *&ptr, int &size); + bool loadCharData(const char *filename, void *&ptr, int &size); + bool loadSpellData(const char *filename, void *&ptr, int &size); + bool loadCompassData(const char *filename, void *&ptr, int &size); + bool loadRawDataBe16(const char *filename, void *&ptr, int &size); void freeRawData(void *&ptr, int &size); void freeStringTable(void *&ptr, int &size); @@ -276,6 +319,10 @@ private: void freeHofSequenceData(void *&ptr, int &size); void freeHofShapeAnimDataV1(void *&ptr, int &size); void freeHofShapeAnimDataV2(void *&ptr, int &size); + void freeCharData(void *&ptr, int &size); + void freeSpellData(void *&ptr, int &size); + void freeCompassData(void *&ptr, int &size); + void freeRawDataBe16(void *&ptr, int &size); const char *getFilename(const char *name); Common::SeekableReadStream *getFile(const char *name); @@ -290,7 +337,12 @@ private: k2SeqData, k2ShpAnimDataV1, - k2ShpAnimDataV2 + k2ShpAnimDataV2, + + lolCharData, + lolSpellData, + lolCompassData, + lolRawDataBe16 }; struct BuiltinRes { diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp new file mode 100644 index 0000000000..2fada31d9c --- /dev/null +++ b/engines/kyra/scene_lol.cpp @@ -0,0 +1,1369 @@ +/* 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/resource.h" + +#include "common/endian.h" + +namespace Kyra { + +void LoLEngine::loadLevel(int index) { + _unkFlag |= 0x800; + setMouseCursorToIcon(0x85); + _scriptFuncIndex = 0; + + // TODO + + updatePortraits(); + + for (int i = 0; i < 400; i++) { + delete [] _levelShapes[i]; + _levelShapes[i] = 0; + } + + _emc->unload(&_scriptData); + + _currentLevel = index; + _charFlagUnk = 0; + + releaseMonsterShapes(0); + releaseMonsterShapes(1); + + //TODO + + //loadTalkFile(index); + loadLevelWLL(index, true); + _loadLevelFlag = 1; + + char filename[] = "level%d.ini"; + sprintf(filename, "level%d.ini", index); + + int f = _levelFlagUnk & (1 << ((index + 0xff) & 0xff)); + + runInitScript(filename, f ? 0 : 1); + + if (f) + loadLevelCMZ(index); + + sprintf(filename, "level%d.inf", index); + runInfScript(filename); + + addLevelItems(); + initCmzWithScript(_currentBlock); + + _screen->generateGrayOverlay(_screen->_currentPalette, _screen->_grayOverlay,32, 16, 0, 0, 128, true); + + _loadLevelFlag2 = false; + if (_screen->_fadeFlag == 3) + _screen->fadeToBlack(10); + + gui_drawPlayField(); + + _screen->setPaletteBrightness(_screen->_currentPalette, _brightness, _lampOilStatus); + setMouseCursorToItemInHand(); + //TODO +} + +void LoLEngine::addLevelItems() { + for (int i = 0; i < 400; i++) { + if (_itemsInPlay[i].level != _currentLevel) + continue; + + moveItemToCMZ(&_cmzBuffer[_itemsInPlay[i].cmzIndex].itemIndex, i); + + _cmzBuffer[_itemsInPlay[i].cmzIndex].field_8 = 5; + _itemsInPlay[i].unk2 = 0; + } +} + +int LoLEngine::initCmzWithScript(int block) { + int i = _cmzBuffer[block].itemIndex; + int cnt = 0; + + while (i) { + void *t = cmzGetItemOffset(i); + i = (i & 0x8000) ? ((LVL*)t)->field_0 : ((ItemInPlay*)t)->itemIndexUnk; + if (!(i & 0x8000)) + continue; + + i &= 0x7fff; + LVL *l = &_lvlBuffer[i]; + + cnt++; + initCMZ1(l, 14); + + checkScriptUnk(l->cmzIndex); + + initCMZ2(l, 0, 0); + } + return cnt; +} + +void LoLEngine::initCMZ1(LVL *l, int a) { + if (l->field_14 == 13 && a != 14) + return; + if (a == 7) { + l->p_2a = _unkCmzU1; + l->p_2b = _unkCmzU2; + } + + if (l->field_14 == 1 && a == 7) { + for (int i = 0; i < 30; i++) { + if (l->field_14 != 1) + 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)); + } + } else { + l->field_14 = a; + l->field_15 = 0; + if (a == 14) + l->field_1D = 0; + if (a == 13 && (l->field_19 & 0x20)) { + l->field_14 = 0; + cmzS3(l); + if (_currentLevel != 29) + initCMZ1(l, 14); + runResidentScriptCustom(0x404, -1, l->field_16, l->field_16, 0, 0); + checkScriptUnk(l->cmzIndex); + if (l->field_14 == 14) + initCMZ2(l, 0, 0); + } + } + +} + +void LoLEngine::initCMZ2(LVL *l, uint16 a, uint16 b) { + bool cont = true; + int t = l->cmzIndex; + if (l->cmzIndex) { + cmzS4(_cmzBuffer[l->cmzIndex].itemIndex, ((uint16)l->field_16) | 0x8000); + _cmzBuffer[l->cmzIndex].field_8 = 5; + checkScriptUnk(l->cmzIndex); + } else { + cont = false; + } + + l->cmzIndex = cmzS5(a, 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; + } + + if (l->cmzIndex == 0) + return; + + cmzS6(_cmzBuffer[l->cmzIndex].itemIndex, ((uint16)l->field_16) | 0x8000); + _cmzBuffer[l->cmzIndex].field_8 = 5; + checkScriptUnk(l->cmzIndex); + uint8 *v = l->offs_lvl415; + + if (v[80] == 0 || cont == false) + return; + + if ((!(READ_LE_UINT16(&v[62]) & 0x100) || ((l->field_13 & 1) == 0)) && l->cmzIndex == t) + return; + + if (l->cmzIndex != t) + runResidentScriptCustom(l->cmzIndex, 0x800, -1, l->field_16, 0, 0); + + if (_charFlagUnk & 1) + return; + + cmzS7(l->offs_lvl415[50], l->cmzIndex); +} + +int LoLEngine::cmzS1(uint16 a, uint16 b, uint16 c, uint16 d) { + // TODO + + return 0; +} + +void LoLEngine::cmzS2(LVL *l, int a) { + // TODO +} + +void LoLEngine::cmzS3(LVL *l) { + // TODO +} + +void LoLEngine::cmzS4(uint16 &itemIndex, int a) { + // TODO +} + +int LoLEngine::cmzS5(uint16 a, uint16 b) { + // TODO + return 0; +} + +void LoLEngine::cmzS6(uint16 &itemIndex, int a) { + // TODO +} + +void LoLEngine::cmzS7(int itemIndex, int a) { + if (!(_unkGameFlag & 1)) + return; + + // TODO +} + +void LoLEngine::moveItemToCMZ(uint16 *cmzItemIndex, uint16 item) { + uint16 *tmp = 0; + while (*cmzItemIndex & 0x8000) { + tmp = (uint16*) cmzGetItemOffset(*cmzItemIndex); + cmzItemIndex = tmp; + } + uint16 *t = (uint16*) cmzGetItemOffset(*cmzItemIndex); + + ((ItemInPlay*)t)->level = -1; + uint16 ix = *cmzItemIndex; + + if (ix == item) + return; + + *cmzItemIndex = item; + cmzItemIndex = t; + + while (*cmzItemIndex) + cmzItemIndex = (uint16*) cmzGetItemOffset(*cmzItemIndex); + + *cmzItemIndex = ix; +} + +void LoLEngine::loadLevelWLL(int index, bool mapShapes) { + char filename[] = "level%00d.wll"; + sprintf(filename, "level%00d.wll", index); + + uint32 size; + uint8 *file = _res->fileData(filename, &size); + + uint16 c = READ_LE_UINT16(file); + loadLevelShpDat(_levelShpList[c], _levelDatList[c], false); + + uint8 *d = file + 2; + size = (size - 2) / 12; + for (uint32 i = 0; i < size; i++) { + c = READ_LE_UINT16(d); + d += 2; + _wllVmpMap[c] = *d; + d += 2; + + if (mapShapes) { + int16 sh = (int16) READ_LE_UINT16(d); + if (sh > 0) + _wllShapeMap[c] = assignLevelShapes(sh); + else + _wllShapeMap[c] = *d; + } + d += 2; + _wllBuffer3[c] = *d; + d += 2; + _wllBuffer5[c] = *d; + d += 2; + _wllBuffer4[c] = *d; + d += 2; + } + + delete []file; + + delete _lvlShpFileHandle; + _lvlShpFileHandle = 0; +} + +int LoLEngine::assignLevelShapes(int index) { + uint16 *p1 = (uint16 *) _tempBuffer5120; + uint16 *p2 = (uint16 *) (_tempBuffer5120 + 4000); + + uint16 r = p2[index]; + if (r) + return r; + + uint16 o = _lvlBlockIndex++; + + memcpy(&_levelShapeProperties[o], &_levelFileData[index], sizeof(LevelShapeProperty)); + + for (int i = 0; i < 10; i++) { + uint16 t = _levelShapeProperties[o].shapeIndex[i]; + if (t == 0xffff) + continue; + + uint16 pv = p1[t]; + if (pv) { + _levelShapeProperties[o].shapeIndex[i] = pv; + } else { + _levelShapes[_lvlShapeIndex] = getLevelShapes(t); + p1[t] = _lvlShapeIndex; + _levelShapeProperties[o].shapeIndex[i] = _lvlShapeIndex++; + } + } + + p2[index] = o; + if (_levelShapeProperties[o].next) + _levelShapeProperties[o].next = assignLevelShapes(_levelShapeProperties[o].next); + + return o; +} + +uint8 *LoLEngine::getLevelShapes(int shapeIndex) { + if (_lvlShpNum <= shapeIndex) + return 0; + + uint32 offs = _lvlShpHeader[shapeIndex] + 2; + _lvlShpFileHandle->seek(offs, 0); + + uint8 tmp[16]; + _lvlShpFileHandle->read(tmp, 16); + uint16 size = _screen->getShapeSize(tmp); + + _lvlShpFileHandle->seek(offs, 0); + uint8 *res = new uint8[size]; + _lvlShpFileHandle->read(res, size); + + return res; +} + +void LoLEngine::loadLevelCMZ(int index) { + //char filename[] = "_LEVEL%d.TMP"; + //sprintf(filename, "_LEVEL%d.TMP", index); + // TODO ??? + memset(_tempBuffer5120, 0, 5120); + uint16 tmpLvlVal = 0; + + + char filename[] = "level%d.cmz"; + sprintf(filename, "level%d.cmz", index); + + _screen->loadBitmap(filename, 3, 3, 0); + const uint8 *p = _screen->getCPagePtr(2); + uint16 len = READ_LE_UINT16(p + 4); + + uint8 *cmzdata = new uint8[0x1000]; + + for (int i = 0; i < 1024; i++) + memcpy(&cmzdata[i << 2], &p[i * len + 6], 4); + + memset(_cmzBuffer, 0, 1024 * sizeof(CMZ)); + + uint8 *c = cmzdata; + uint8 *t = _tempBuffer5120; + + for (int i = 0; i < 1024; i++) { + for (int ii = 0; ii < 4; ii++) + _cmzBuffer[i].unk[ii] = *c++ ^ *t++; + } + + for (int i = 0; i < 1024; i++) + _cmzBuffer[i].flags = *t++; + + for (int i = 0; i < 30; i++) { + if (_lvlBuffer[i].cmzIndex) { + _lvlBuffer[i].cmzIndex = 0; + _lvlBuffer[i].offs_lvl415 = _lvl415 + _lvlBuffer[i].field_20; + initCMZ2(&_lvlBuffer[i], _lvlBuffer[i].p_1a, _lvlBuffer[i].p_1b); + } + } + + loadCMZ_Sub(tmpLvlVal, (_unkGameFlag & 0x30) >> 4); + + delete []cmzdata; +} + +void LoLEngine::loadCMZ_Sub(int index1, int index2) { + static const int table[] = { 0x66, 0x100, 0x180, 0x100, 0x100, 0xC0, 0x140, 0x100, 0x80, 0x80, 0x100, 0x100 }; + int val = (table[index2] << 8) / table[index1]; + + //int r = 0; + + for (int i = 0; i < 30; i++) { + if (_lvlBuffer[i].field_14 >= 14 || _lvlBuffer[i].cmzIndex == 0 || _lvlBuffer[i].field_1D <= 0) + continue; + + int t = (val * _lvlBuffer[i].field_1D) >> 8; + _lvlBuffer[i].field_1D = t; + if (index2 < index1) + _lvlBuffer[i].field_1D++; + if (_lvlBuffer[i].field_1D == 0) + _lvlBuffer[i].field_1D = 1; + } +} + +void LoLEngine::loadCmzFile(const char *file) { + memset(_cmzBuffer, 0, 1024 * sizeof(CMZ)); + _screen->loadBitmap(file, 2, 2, 0); + const uint8 *h = _screen->getCPagePtr(2); + uint16 len = READ_LE_UINT16(&h[4]); + const uint8 *p = h + 6; + + for (int i = 0; i < 1024; i++) { + for (int ii = 0; ii < 4; ii++) + _cmzBuffer[i].unk[ii] = p[i * len + ii]; + + _cmzBuffer[i].field_8 = 5; + + if (_wllBuffer4[_cmzBuffer[i].unk[0]] == 17) { + _cmzBuffer[i].flags &= 0xef; + _cmzBuffer[i].flags |= 0x20; + } + } +} + +void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int b) { + releaseMonsterShapes(monsterIndex); + _screen->loadBitmap(file, 3, 3, 0); + + const uint8 *p = _screen->getCPagePtr(2); + const uint8 *ts[16]; + + for (int i = 0; i < 16; i++) { + ts[i] = _screen->getPtrToShape(p, i); + + bool replaced = false; + int pos = monsterIndex << 4; + + for (int ii = 0; ii < i; ii++) { + if (ts[i] != ts[ii]) + continue; + + _monsterShapes[pos + i] = _monsterShapes[pos + ii]; + replaced = true; + break; + } + + if (!replaced) + _monsterShapes[pos + i] = _screen->makeShapeCopy(p, i); + + int size = _screen->getShapePaletteSize(_monsterShapes[pos + i]) << 3; + _monsterPalettes[pos + i] = new uint8[size]; + memset(_monsterPalettes[pos + i], 0, size); + } + + /*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; + *of = _screen->makeShapeCopy(p, s); + ////TODO + } + }*/ + _monsterUnk[monsterIndex] = b & 0xff; + + uint8 *tsh = _screen->makeShapeCopy(p, 16); + + _screen->clearPage(3); + _screen->drawShape(2, tsh, 0, 0, 0, 0); + + uint8 *tmpPal1 = new uint8[64]; + uint8 *tmpPal2 = new uint8[256]; + uint16 *tmpPal3 = new uint16[256]; + memset (tmpPal1, 0, 64); + memset (tmpPal2, 0, 256); + memset (tmpPal3, 0xff, 512); + + for (int i = 0; i < 64; i++) { + tmpPal1[i] = *p; + p += 320; + } + + p = _screen->getCPagePtr(2); + + for (int i = 0; i < 16; i++) { + int pos = (monsterIndex << 4) + i; + memcpy(tmpPal2, _monsterShapes[pos] + 10, 256); + uint8 numCol = *tmpPal2; + + for (int ii = 0; ii < numCol; ii++) { + uint8 *cl = (uint8*)memchr(tmpPal1, tmpPal2[1 + ii], 64); + if (!cl) + continue; + tmpPal3[ii] = (uint16) (cl - tmpPal1); + } + + for (int ii = 0; ii < 8; ii++) { + memcpy(tmpPal2, _monsterShapes[pos] + 10, 256); + for (int iii = 0; iii < numCol; iii++) { + if (tmpPal3[iii] == 0xffff) + continue; + if (p[tmpPal3[iii] * 320 + ii + 1]) + tmpPal2[1 + iii] = p[tmpPal3[iii] * 320 + ii + 1]; + } + memcpy(_monsterPalettes[pos] + ii * numCol, &tmpPal2[1], numCol); + } + } + + delete []tmpPal1; + delete []tmpPal2; + delete []tmpPal3; + delete [] tsh; +} + +void LoLEngine::releaseMonsterShapes(int monsterIndex) { + for (int i = 0; i < 16; i++) { + int pos = (monsterIndex << 4) + i; + if (_monsterShapes[pos]) { + delete []_monsterShapes[pos]; + _monsterShapes[pos] = 0; + } + + if (_monsterPalettes[pos]) { + delete []_monsterPalettes[pos]; + _monsterPalettes[pos] = 0; + } + } +} + +void LoLEngine::loadLevelShpDat(const char *shpFile, const char *datFile, bool flag) { + memset(_tempBuffer5120, 0, 5120); + + _lvlShpFileHandle = _res->getFileStream(shpFile); + _lvlShpNum = _lvlShpFileHandle->readUint16LE(); + delete []_lvlShpHeader; + _lvlShpHeader = new uint32[_lvlShpNum]; + for (int i = 0; i < _lvlShpNum; i++) + _lvlShpHeader[i] = _lvlShpFileHandle->readUint32LE(); + + Common::SeekableReadStream *s = _res->getFileStream(datFile); + + _levelFileDataSize = s->readUint16LE(); + delete []_levelFileData; + _levelFileData = new LevelShapeProperty[_levelFileDataSize]; + for (int i = 0; i < _levelFileDataSize; i++) { + LevelShapeProperty * l = &_levelFileData[i]; + for (int ii = 0; ii < 10; ii++) + l->shapeIndex[ii] = s->readUint16LE(); + for (int ii = 0; ii < 10; ii++) + l->scaleFlag[ii] = s->readByte(); + for (int ii = 0; ii < 10; ii++) + l->shapeX[ii] = s->readUint16LE(); + for (int ii = 0; ii < 10; ii++) + l->shapeY[ii] = s->readUint16LE(); + l->next = s->readByte(); + l->flags = s->readByte(); + } + + delete []s; + + if (!flag) { + _lvlBlockIndex = 1; + _lvlShapeIndex = 1; + } +} + +void LoLEngine::loadLevelSupplemenaryFiles(const char *file, int specialColor, int weight, int vcnLen, int vmpLen, const char *langFile) { + if (file) { + _lastSpecialColor = specialColor; + _lastSpecialColorWeight = weight; + strcpy(_lastSuppFile, file); + if (langFile) { + strcpy(_lastSuppLangFile, langFile); + _lastSuppLangFilePtr = _lastSuppLangFile; + } else { + _lastSuppLangFilePtr = 0; + } + } + + char fname[] = " "; + sprintf(fname, "%s.%s", _lastSuppFile, "VCN"); + + _screen->loadBitmap(fname, 3, 3, 0); + const uint8 *v = _screen->getCPagePtr(2); + int tlen = READ_LE_UINT16(v); + v += 2; + + if (vcnLen == -1) + vcnLen = tlen << 5; + + if (_vcnBlocks) + delete []_vcnBlocks; + _vcnBlocks = new uint8[vcnLen]; + + if (_vcnShift) + delete []_vcnShift; + _vcnShift = new uint8[tlen]; + + memcpy(_vcnShift, v, tlen); + v += tlen; + + memcpy(_vcnExpTable, v, 128); + v += 128; + + if (_lastSuppLangFilePtr) { + if (_levelLangFile) + delete []_levelLangFile; + _levelLangFile = _res->fileData(_lastSuppLangFilePtr, 0); + } + + memcpy(_screen->_currentPalette, v, 384); + v += 384; + /*uint8 tmpPal = new uint8[384]; + memcpy(tmpPal, _screen->_currentPalette + 384, 384); + memset(_screen->_currentPalette + 384, 0xff, 384); + memcpy(_screen->_currentPalette + 384, tmpPal, 384);*/ + + //loadSwampIceCol(); + + memcpy(_vcnBlocks, v, vcnLen); + v += vcnLen; + + sprintf(fname, "%s.%s", _lastSuppFile, "VMP"); + _screen->loadBitmap(fname, 3, 3, 0); + v = _screen->getCPagePtr(2); + + if (vmpLen == -1) + vmpLen = READ_LE_UINT16(v); + v += 2; + + if (_vmpPtr) + delete []_vmpPtr; + _vmpPtr = new uint16[vmpLen]; + + for (int i = 0; i < vmpLen; i++) + _vmpPtr[i] = READ_LE_UINT16(&v[i << 1]); + + for (int i = 0; i < 7; i++) { + weight = 100 - (i * _lastSpecialColorWeight); + weight = (weight > 0) ? (weight * 255) / 100 : 0; + _screen->generateLevelOverlay(_screen->_currentPalette, _screen->getLevelOverlay(i), _lastSpecialColor, weight); + + for (int ii = 0; ii < 128; ii++) { + if (_screen->getLevelOverlay(i)[ii] == 255) + _screen->getLevelOverlay(i)[ii] = 0; + } + + for (int ii = 128; ii < 256; ii++) + _screen->getLevelOverlay(i)[ii] = ii & 0xff; + } + + for (int i = 0; i < 256; i++) + _screen->getLevelOverlay(7)[i] = i & 0xff; + + _loadSuppFilesFlag = 0; + _screen->generateBrightnessPalette(_screen->_currentPalette, _screen->getPalette(1), _brightness, _lampOilStatus); + + char tname[] = "LEVEL%02d.TLC"; + sprintf(tname, "LEVEL%02d.TLC", _currentLevel); + Common::SeekableReadStream *s = _res->getFileStream(tname); + s->read(_tlcTable1, 256); + s->read(_tlcTable2, 5120); + delete []s; + + _loadSuppFilesFlag = 1; +} + +void LoLEngine::turnOnLamp() { + _screen->_drawGuiFlag |= 0x400; + _lampOilStatus = 255; + updateLampStatus(); +} + +void LoLEngine::updateLampStatus() { + uint8 newLampOilStatus = 0; + uint8 tmp2 = 0; + + if ((_charFlagUnk & 4) || !(_screen->_drawGuiFlag & 0x800)) + return; + + if (!_brightness || !_lampStatusUnk) { + newLampOilStatus = 8; + if (newLampOilStatus != _lampOilStatus && _screen->_fadeFlag == 0) + _screen->setPaletteBrightness(_screen->_currentPalette, _lampOilStatus, newLampOilStatus); + } else { + tmp2 = (_lampStatusUnk < 100) ? _lampStatusUnk : 100; + newLampOilStatus = (3 - (tmp2 - 1) / 25) << 1; + + if (_lampOilStatus == 255) { + if (_screen->_fadeFlag == 0) + _screen->setPaletteBrightness(_screen->_currentPalette, _brightness, newLampOilStatus); + _lampStatusTimer = _system->getMillis() + (10 + _rnd.getRandomNumberRng(1, 30)) * _tickLength; + } else { + if ((_lampOilStatus & 0xfe) == (newLampOilStatus & 0xfe)) { + if (_system->getMillis() <= _lampStatusTimer) { + newLampOilStatus = _lampOilStatus; + } else { + newLampOilStatus = _lampOilStatus ^ 1; + _lampStatusTimer = _system->getMillis() + (10 + _rnd.getRandomNumberRng(1, 30)) * _tickLength; + } + } else { + if (_screen->_fadeFlag == 0) + _screen->setPaletteBrightness(_screen->_currentPalette, _lampOilStatus, newLampOilStatus); + } + } + } + + if (newLampOilStatus == _lampOilStatus) + return; + + _screen->hideMouse(); + + _screen->drawShape(_screen->_curPage, _gameShapes[35 + newLampOilStatus], 291, 56, 0, 0); + _screen->showMouse(); + + _lampOilStatus = newLampOilStatus; +} + +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; + _cmzBuffer[block].flags |= 7; + // TODO +} + +void LoLEngine::drawScene(int pageNum) { + if (pageNum && pageNum != _sceneDrawPage1) { + _sceneDrawPage1 ^= _sceneDrawPage2; + _sceneDrawPage2 ^= _sceneDrawPage1; + _sceneDrawPage1 ^= _sceneDrawPage2; + updateSceneWindow(); + } + + if (pageNum && pageNum != _sceneDrawPage1) { + _sceneDrawPage1 ^= _sceneDrawPage2; + _sceneDrawPage2 ^= _sceneDrawPage1; + _sceneDrawPage1 ^= _sceneDrawPage2; + updateSceneWindow(); + } + + generateBlockDrawingBuffer(_currentBlock, _unkPara2); + drawVcnBlocks(_vcnBlocks, _blockDrawingBuffer, _vcnShift, _sceneDrawPage1); + drawSceneShapes(); + + if (pageNum) { + drawScriptShapes(_sceneDrawPage1); + _screen->copyRegion(112, 112, 0, 0, 176, 120, _sceneDrawPage1, _sceneDrawPage2); + _screen->copyRegion(112, 112, 0, 0, 176, 120, _sceneDrawPage1, 0); + _sceneDrawPage1 ^= _sceneDrawPage2; + _sceneDrawPage2 ^= _sceneDrawPage1; + _sceneDrawPage1 ^= _sceneDrawPage2; + } + + gui_drawCompass(); + + _boolScriptFuncDone = false; +} + +void LoLEngine::updateSceneWindow() { + _screen->hideMouse(); + _screen->copyRegion(112, 0, 112, 0, 176, 120, 0, _sceneDrawPage2); + _screen->showMouse(); +} + +void LoLEngine::generateBlockDrawingBuffer(int block, int b) { + _sceneDrawVar1 = _dscBlockMap[_unkPara2]; + _sceneDrawVar2 = _dscBlockMap[_unkPara2 + 4]; + _sceneDrawVar3 = _dscBlockMap[_unkPara2 + 8]; + + memset(_blockDrawingBuffer, 0, 660 * sizeof(uint16)); + + _wllProcessFlag = ((block >> 5) + (block & 0x1f) + _unkPara2) & 1; + + if (_wllProcessFlag) + generateBlockDrawingBufferF1(0, 15, 1, -330, 22, 15); + else + generateBlockDrawingBufferF0(0, 15, 1, -330, 22, 15); + + assignBlockCaps(block, b); + + uint8 t = _curBlockCaps[0]->unk[_sceneDrawVar2]; + if (t) + generateBlockDrawingBufferF0(-2, 3, t, 102, 3, 5); + + t = _curBlockCaps[6]->unk[_sceneDrawVar3]; + if (t) + generateBlockDrawingBufferF1(21, 3, t, 102, 3, 5); + + t = _curBlockCaps[1]->unk[_sceneDrawVar2]; + uint8 t2 = _curBlockCaps[2]->unk[_sceneDrawVar1]; + + if (testWllBuffer5Value(t) && !(_wllBuffer5[t2] & 8)) + generateBlockDrawingBufferF0(2, 3, t, 102, 3, 5); + else if (t && (_wllBuffer5[t2] & 8)) + generateBlockDrawingBufferF0(2, 3, t2, 102, 3, 5); + + t = _curBlockCaps[5]->unk[_sceneDrawVar3]; + t2 = _curBlockCaps[4]->unk[_sceneDrawVar1]; + + if (testWllBuffer5Value(t) && !(_wllBuffer5[t2] & 8)) + generateBlockDrawingBufferF1(17, 3, t, 102, 3, 5); + else if(t && (_wllBuffer5[t2] & 8)) + generateBlockDrawingBufferF1(17, 3, t2, 102, 3, 5); + + t = _curBlockCaps[2]->unk[_sceneDrawVar2]; + if (t) + generateBlockDrawingBufferF0(8, 3, t, 97, 1, 5); + + t = _curBlockCaps[4]->unk[_sceneDrawVar3]; + if (t) + generateBlockDrawingBufferF1(13, 3, t, 97, 1, 5); + + t = _curBlockCaps[1]->unk[_sceneDrawVar1]; + if (testWllBuffer5Value(t)) + generateBlockDrawingBufferF0(-4, 3, t, 129, 6, 5); + + t = _curBlockCaps[5]->unk[_sceneDrawVar1]; + if (testWllBuffer5Value(t)) + generateBlockDrawingBufferF0(20, 3, t, 129, 6, 5); + + t = _curBlockCaps[2]->unk[_sceneDrawVar1]; + if (testWllBuffer5Value(t)) + generateBlockDrawingBufferF0(2, 3, t, 129, 6, 5); + + t = _curBlockCaps[4]->unk[_sceneDrawVar1]; + if (testWllBuffer5Value(t)) + generateBlockDrawingBufferF0(14, 3, t, 129, 6, 5); + + t = _curBlockCaps[3]->unk[_sceneDrawVar1]; + if (t) + generateBlockDrawingBufferF0(8, 3, t, 129, 6, 5); + + t = _curBlockCaps[7]->unk[_sceneDrawVar2]; + if (t) + generateBlockDrawingBufferF0(0, 3, t, 117, 2, 6); + + t = _curBlockCaps[11]->unk[_sceneDrawVar3]; + if (t) + generateBlockDrawingBufferF1(20, 3, t, 117, 2, 6); + + t = _curBlockCaps[8]->unk[_sceneDrawVar2]; + if (t) + generateBlockDrawingBufferF0(6, 2, t, 81, 2, 8); + + t = _curBlockCaps[10]->unk[_sceneDrawVar3]; + if (t) + generateBlockDrawingBufferF1(14, 2, t, 81, 2, 8); + + t = _curBlockCaps[8]->unk[_sceneDrawVar1]; + if (testWllBuffer5Value(t)) + generateBlockDrawingBufferF0(-4, 2, t, 159, 10, 8); + + t = _curBlockCaps[10]->unk[_sceneDrawVar1]; + if (testWllBuffer5Value(t)) + generateBlockDrawingBufferF0(16, 2, t, 159, 10, 8); + + t = _curBlockCaps[9]->unk[_sceneDrawVar1]; + if (t) + generateBlockDrawingBufferF0(6, 2, t, 159, 10, 8); + + t = _curBlockCaps[12]->unk[_sceneDrawVar2]; + if (t) + generateBlockDrawingBufferF0(3, 1, t, 45, 3, 12); + + t = _curBlockCaps[14]->unk[_sceneDrawVar3]; + if (t) + generateBlockDrawingBufferF1(16, 1, t, 45, 3, 12); + + t = _curBlockCaps[12]->unk[_sceneDrawVar1]; + if (!(_wllBuffer5[t] & 8)) + generateBlockDrawingBufferF0(-13, 1, t, 239, 16, 12); + + t = _curBlockCaps[14]->unk[_sceneDrawVar1]; + if (!(_wllBuffer5[t] & 8)) + generateBlockDrawingBufferF0(19, 1, t, 239, 16, 12); + + t = _curBlockCaps[13]->unk[_sceneDrawVar1]; + if (t) + generateBlockDrawingBufferF0(3, 1, t, 239, 16, 12); + + t = _curBlockCaps[15]->unk[_sceneDrawVar2]; + t2 = _curBlockCaps[17]->unk[_sceneDrawVar3]; + if (t) + generateBlockDrawingBufferF0(0, 0, t, 0, 3, 15); + if (t2) + generateBlockDrawingBufferF1(19, 0, t, 0, 3, 15); +} + +void LoLEngine::generateBlockDrawingBufferF0(int16 wllOffset, uint8 wllIndex, uint8 wllVmpIndex, int16 vmpOffset, uint8 len, uint8 numEntries) { + if (!_wllVmpMap[wllVmpIndex]) + return; + + uint16 *vmp = &_vmpPtr[(_wllVmpMap[wllVmpIndex] - 1) * 431 + vmpOffset + 330]; + + for (int i = 0; i < numEntries; i++) { + uint16 *bl = &_blockDrawingBuffer[(wllIndex + i) * 22 + wllOffset]; + for (int ii = 0; ii < len; ii++) { + if ((wllOffset + ii >= 0) && (wllOffset + ii < 22) && *vmp) + *bl = *vmp; + bl++; + vmp++; + } + } +} + +void LoLEngine::generateBlockDrawingBufferF1(int16 wllOffset, uint8 wllIndex, uint8 wllVmpIndex, int16 vmpOffset, uint8 len, uint8 numEntries) { + if (!_wllVmpMap[wllVmpIndex]) + return; + + uint16 *vmp = &_vmpPtr[(_wllVmpMap[wllVmpIndex] - 1) * 431 + vmpOffset + 330]; + + for (int i = 0; i < numEntries; i++) { + for (int ii = 0; ii < len; ii++) { + if ((wllOffset + ii >= 0) && (wllOffset + ii < 22)) { + uint16 t = vmp[len * i + len - 1 - ii]; + if (t) { + if (t & 04000) + t -= 0x4000; + else + t |= 0x4000; + + _blockDrawingBuffer[(wllIndex + i) * 22 + wllOffset + ii] = t; + } + } + } + } +} + +bool LoLEngine::testWllBuffer5Value(int index) { + if (!index || (_wllBuffer5[index] & 8)) + return false; + return true; +} + +void LoLEngine::assignBlockCaps(int a, int b) { + for (int i = 0; i < 18; i++) { + uint16 t = (a + _dscBlockIndex[b * 18 + i]) & 0x3ff; + _scriptExecutedFuncs[i] = t; + + _curBlockCaps[i] = &_cmzBuffer[t]; + _lvlShapeLeftRight[i] = _lvlShapeLeftRight[18 + i] = -1; + } +} + +void LoLEngine::drawVcnBlocks(uint8 *vcnBlocks, uint16 *blockDrawingBuffer, uint8 *vcnShift, int pageNum) { + uint8 *d = _sceneWindowBuffer; + + for (int y = 0; y < 15; y++) { + for (int x = 0; x < 22; x++) { + bool flag = false; + int remainder = 0; + + uint16 vcnOffset = *blockDrawingBuffer++; + + if (vcnOffset & 0x8000) { + remainder = vcnOffset - 0x8000; + vcnOffset = 0; + } + + if (vcnOffset & 0x4000) { + flag = true; + vcnOffset &= 0x3fff; + } + + if (!vcnOffset) { + vcnOffset = blockDrawingBuffer[329]; + if (vcnOffset & 0x4000) { + flag = true; + vcnOffset &= 0x3fff; + } + } + + uint8 shift = vcnShift[vcnOffset]; + uint8 *src = &vcnBlocks[vcnOffset << 5]; + + if (flag) { + for (int blockY = 0; blockY < 8; blockY++) { + src += 3; + for (int blockX = 0; blockX < 4; blockX++) { + uint8 t = *src--; + *d++ = _vcnExpTable[(t & 0x0f) | shift]; + *d++ = _vcnExpTable[(t >> 4) | shift]; + } + src += 5; + d += 168; + } + } else { + for (int blockY = 0; blockY < 8; blockY++) { + for (int blockX = 0; blockX < 4; blockX++) { + uint8 t = *src++; + *d++ = _vcnExpTable[(t >> 4) | shift]; + *d++ = _vcnExpTable[(t & 0x0f) | shift]; + } + d += 168; + } + } + d -= 1400; + + if (remainder) { + d -= 8; + flag = false; + + if (remainder & 0x4000) { + remainder &= 0x3fff; + flag = true; + } + + shift = vcnShift[remainder]; + src = &vcnBlocks[remainder << 5]; + + if (flag) { + for (int blockY = 0; blockY < 8; blockY++) { + src += 3; + for (int blockX = 0; blockX < 4; blockX++) { + uint8 t = *src--; + uint8 h = _vcnExpTable[(t & 0x0f) | shift]; + uint8 l = _vcnExpTable[(t >> 4) | shift]; + if (h) + *d = h; + d++; + if (l) + *d = l; + d++; + } + src += 5; + d += 168; + } + } else { + for (int blockY = 0; blockY < 8; blockY++) { + for (int blockX = 0; blockX < 4; blockX++) { + uint8 t = *src++; + uint8 h = _vcnExpTable[(t >> 4) | shift]; + uint8 l = _vcnExpTable[(t & 0x0f) | shift]; + if (h) + *d = h; + d++; + if (l) + *d = l; + d++; + } + d += 168; + } + } + d -= 1400; + } + } + d += 1232; + } + + _screen->copyBlockToPage(pageNum, 112, 0, 176, 120, _sceneWindowBuffer); +} + +void LoLEngine::drawSceneShapes() { + for (int i = 0; i < 18; i++) { + uint8 t = _dscTileIndex[i]; + uint8 s = _curBlockCaps[t]->unk[_sceneDrawVar1]; + + int16 x1 = 0; + int16 x2 = 0; + + int16 dimY1 = 0; + int16 dimY2 = 0; + + setLevelShapesDim(t, x1, x2, 13); + + if (x2 <= x1) + continue; + + drawDecorations(t); + + uint16 w = _wllBuffer5[s]; + + if (i == 16) + w |= 0x80; + + drawIceShapes(t, 0); + + //if (_curBlockCaps[t]->itemIndex && (w & 0x80)) + //sub_3AA55(t); + + drawIceShapes(t, 1); + + if (!(w & 8)) + continue; + + uint16 v = 20 * (s - _dscUnk2[s]); + + scaleLevelShapesDim(t, dimY1, dimY2, 13); + drawDoor(_doorShapes[_dscDoorShpIndex[s]], 0, t, 10, 0, -v, 2); + setLevelShapesDim(t, dimY1, dimY2, 13); + } +} + +void LoLEngine::setLevelShapesDim(int index, int16 &x1, int16 &x2, int dim) { + if (_lvlShapeLeftRight[index << 1] == -1) { + x1 = 0; + x2 = 22; + + int16 y1 = 0; + int16 y2 = 120; + + int m = index * 18; + + for (int i = 0; i < 18; i++) { + uint8 d = _curBlockCaps[i]->unk[_sceneDrawVar1]; + uint8 a = _wllBuffer5[d]; + + if (a & 8) { + int t = _dscDim2[(m + i) << 1]; + + if (t > x1) { + x1 = t; + if (!(a & 0x10)) + scaleLevelShapesDim(index, y1, y2, -1); + } + + t = _dscDim2[((m + i) << 1) + 1]; + + if (t < x2) { + x2 = t; + if (!(a & 0x10)) + scaleLevelShapesDim(index, y1, y2, -1); + } + } else { + int t = _dscDim1[m + i]; + + if (!_wllVmpMap[d] || t == -40) + continue; + + if (t == -41) { + x1 = 22; + x2 = 0; + break; + } + + if (t > 0 && x2 > t) + x2 = t; + + if (t < 0 && x1 < -t) + x1 = -t; + } + + if (x2 < x1) + break; + } + + x1 += 14; + x2 += 14; + + _lvlShapeTop[index] = y1; + _lvlShapeBottom[index] = y2; + _lvlShapeLeftRight[index << 1] = x1; + _lvlShapeLeftRight[(index << 1) + 1] = x2; + } else { + x1 = _lvlShapeLeftRight[index << 1]; + x2 = _lvlShapeLeftRight[(index << 1) + 1]; + } + + drawLevelModifyScreenDim(dim, x1, 0, x2, 15); +} + +void LoLEngine::scaleLevelShapesDim(int index, int16 &y1, int16 &y2, int dim) { + static const int8 dscY1[] = { 0x1E, 0x18, 0x10, 0x00 }; + static const int8 dscY2[] = { 0x3B, 0x47, 0x56, 0x78 }; + + uint8 a = _dscDimMap[index]; + + if (dim == -1 && a != 3) + a++; + + y1 = dscY1[a]; + y2 = dscY2[a]; + + if (dim == -1) + return; + + const ScreenDim *cDim = _screen->getScreenDim(dim); + + _screen->modifyScreenDim(dim, cDim->sx, y1, cDim->w, y2 - y1); +} + +void LoLEngine::drawLevelModifyScreenDim(int dim, int16 x1, int16 y1, int16 x2, int16 y2) { + _screen->modifyScreenDim(dim, x1, y1 << 3, x2 - x1, (y2 - y1) << 3); +} + +void LoLEngine::drawDecorations(int index) { + for (int i = 1; i >= 0; i--) { + int s = index * 2 + i; + uint16 scaleW = _dscShapeScaleW[s]; + uint16 scaleH = _dscShapeScaleH[s]; + int8 ix = _dscShapeIndex[s]; + uint8 shpIx = ABS(ix); + uint8 ovlIndex = _dscShapeOvlIndex[_dscDimMap[index] * 5] + 2; + if (ovlIndex > 7) + ovlIndex = 7; + + if (!scaleW || !scaleH) + continue; + + uint8 d = (_unkPara2 + _dscUnk1[s]) & 3; + int8 l = _wllShapeMap[_curBlockCaps[index]->unk[d]]; + + uint8 *shapeData = 0; + + int x = 0; + int y = 0; + int flags = 0; + + while (l > 0) { + if ((_levelShapeProperties[l].flags & 8) && index != 3 && index != 9 && index != 13) { + l = _levelShapeProperties[l].next; + continue; + } + + if (_dscOvlMap[shpIx] == 1 && ((_levelShapeProperties[l].flags & 2) || ((_levelShapeProperties[l].flags & 4) && _wllProcessFlag))) + ix = -ix; + + int xOffs = 0; + int yOffs = 0; + uint8 *ovl = 0; + + if (_levelShapeProperties[l].scaleFlag[shpIx] & 1) { + xOffs = _levelShapeProperties[l].shapeX[shpIx]; + yOffs = _levelShapeProperties[l].shapeY[shpIx]; + shpIx = _dscOvlMap[shpIx]; + ovl = _screen->getLevelOverlay(ovlIndex); + } else if (_levelShapeProperties[l].shapeIndex[shpIx] != 0xffff) { + scaleW = scaleH = 0x100; + ovl = _screen->getLevelOverlay(7); + } + + if (_levelShapeProperties[l].shapeIndex[shpIx] != 0xffff) { + shapeData = _levelShapes[_levelShapeProperties[l].shapeIndex[shpIx]]; + if (shapeData) { + if (ix < 0) { + x = _dscShapeX[s] + xOffs + ((_levelShapeProperties[l].shapeX[shpIx] * scaleW) >> 8); + if (ix == _dscShapeIndex[s]) { + x = _dscShapeX[s] - ((_levelShapeProperties[l].shapeX[shpIx] * scaleW) >> 8) - + _screen->getShapeScaledWidth(shapeData, scaleW) - xOffs; + } + flags = 0x105; + } else { + x = _dscShapeX[s] + xOffs + ((_levelShapeProperties[l].shapeX[shpIx] * scaleW) >> 8); + flags = 0x104; + } + + y = _dscShapeY[s] + yOffs + ((_levelShapeProperties[l].shapeY[shpIx] * scaleH) >> 8); + _screen->drawShape(_sceneDrawPage1, shapeData, x + 112, y, 13, flags, ovl, 1, scaleW, scaleH); + + if ((_levelShapeProperties[l].flags & 1) && (shpIx >= 0) && (shpIx < 4)) { + //draw shadow + x += (_screen->getShapeScaledWidth(shapeData, scaleW)); + flags ^= 1; + _screen->drawShape(_sceneDrawPage1, shapeData, x + 112, y, 13, flags, ovl, 1, scaleW, scaleH); + } + } + } + + l = _levelShapeProperties[l].next; + shpIx = (_dscShapeIndex[s] < 0) ? -_dscShapeIndex[s] : _dscShapeIndex[s]; + } + } +} + +void LoLEngine::drawIceShapes(int index, int iceShapeIndex) { + uint8 f = _curBlockCaps[index]->flags; + if (!(f & 0xf0)) + return; +} + +void LoLEngine::drawDoor(uint8 *shape, uint8 *table, int index, int unk2, int w, int h, int flags) { + uint8 c = _dscDoor1[(_unkPara2 << 5) + unk2]; + int r = (c / 5) + 5 * _dscDimMap[index]; + uint16 d = _dscDoor2[r]; + uint16 t = (index << 5) + c; + + _shpDoorY = _dscDoorY[t] + 120; + + if (flags & 1) { + // TODO + } + + int u = 0; + + if (flags & 2) { + uint8 w = _dscDimMap[index]; + _doorScaleW = _dscDoorScaleTable[w << 1]; + _doorScaleH = _dscDoorScaleTable[(w << 1) + 1]; + u = _dscDoor4[w]; + } + + d += 2; + + if (!_doorScaleW || !_doorScaleH) + return; + + int s = _screen->getShapeScaledHeight(shape, _doorScaleH) >> 1; + + if (w) + w = (w * _doorScaleW) >> 8; + + if (h) + h = (h * _doorScaleH) >> 8; + + _shpDoorX = _dscDoorX[t] + w + 200; + _shpDoorY = _shpDoorY + 4 - s + h - u; + + if (d > 7) + d = 7; + + uint8 *ovl = _screen->getLevelOverlay(d); + int doorScaledWitdh = _screen->getShapeScaledWidth(shape, _doorScaleW); + + _shpDoorX -= (doorScaledWitdh >> 1); + _shpDoorY -= s; + + drawDoorShapes(shape, table, _shpDoorX, _shpDoorY, flags, ovl); +} + +void LoLEngine::drawDoorShapes(uint8 *shape, uint8 *table, int x, int y, int flags, const uint8 *ovl) { + int flg = 0; + + if (flags & 0x10) + flg |= 1; + + if (flags & 0x20) + flg |= 0x1000; + + if (flags & 0x40) + flg |= 2; + + if (flg & 0x1000) { + if (table) + _screen->drawShape(_sceneDrawPage1, shape, x, y, 13, flg | 0x9104, table, ovl, 1, _tlcTable1, _tlcTable2, _doorScaleW, _doorScaleH); + else + _screen->drawShape(_sceneDrawPage1, shape, x, y, 13, flg | 0x1104, ovl, 1, _tlcTable1, _tlcTable2, _doorScaleW, _doorScaleH); + } else { + if (table) + _screen->drawShape(_sceneDrawPage1, shape, x, y, 13, flg | 0x8104, table, ovl, 1, _doorScaleW, _doorScaleH); + else + _screen->drawShape(_sceneDrawPage1, shape, x, y, 13, flg | 0x104, ovl, 1, _doorScaleW, _doorScaleH); + } +} + +void LoLEngine::drawScriptShapes(int pageNum) { + // TODO +} + +} // end of namespace Kyra + diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp index 8e7abee545..4d78203d32 100644 --- a/engines/kyra/screen_lol.cpp +++ b/engines/kyra/screen_lol.cpp @@ -29,18 +29,66 @@ namespace Kyra { Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system), _vm(vm) { + _customDimTable = new ScreenDim*[_screenDimTableCount]; + memset(_customDimTable, 0, sizeof(ScreenDim*) * _screenDimTableCount); + + _paletteOverlay1 = new uint8[0x100]; + _paletteOverlay2 = new uint8[0x100]; + _grayOverlay = new uint8[0x100]; + memset(_paletteOverlay1, 0, 0x100); + memset(_paletteOverlay2, 0, 0x100); + memset(_grayOverlay, 0, 0x100); + + for (int i = 0; i < 8; i++) + _levelOverlays[i] = new uint8[256]; + + _fadeFlag = 2; + _drawGuiFlag = 0; +} + +Screen_LoL::~Screen_LoL() { + for (int i = 0; i < _screenDimTableCount; i++) + delete _customDimTable[i]; + delete []_customDimTable; + + for (int i = 0; i < 8; i++) + delete []_levelOverlays[i]; + + delete []_paletteOverlay1; + delete []_paletteOverlay2; + delete []_grayOverlay; } void Screen_LoL::setScreenDim(int dim) { debugC(9, kDebugLevelScreen, "Screen_LoL::setScreenDim(%d)", dim); assert(dim < _screenDimTableCount); - _curDim = &_screenDimTable[dim]; + _curDim = _customDimTable[dim] ? (const ScreenDim *)_customDimTable[dim] : &_screenDimTable[dim]; } const ScreenDim *Screen_LoL::getScreenDim(int dim) { debugC(9, kDebugLevelScreen, "Screen_LoL::getScreenDim(%d)", dim); assert(dim < _screenDimTableCount); - return &_screenDimTable[dim]; + return _customDimTable[dim] ? (const ScreenDim *)_customDimTable[dim] : &_screenDimTable[dim]; +} + +void Screen_LoL::modifyScreenDim(int dim, int x, int y, int w, int h) { + delete _customDimTable[dim]; + _customDimTable[dim] = new ScreenDim; + memcpy(_customDimTable[dim], &_screenDimTable[dim], sizeof(ScreenDim)); + _customDimTable[dim]->sx = x; + _customDimTable[dim]->sy = y; + _customDimTable[dim]->w = w; + _customDimTable[dim]->h = h; + setScreenDim(dim); +} + +void Screen_LoL::clearDim(int dim) { + const ScreenDim *tmp = getScreenDim(dim); + fillRect(tmp->sx << 3, tmp->sy, ((tmp->sx + tmp->w) << 3) - 1, (tmp->sy + tmp->h) - 1, tmp->unkA); +} + +void Screen_LoL::clearCurDim() { + fillRect(_curDim->sx << 3, _curDim->sy, ((_curDim->sx + _curDim->w) << 3) - 1, (_curDim->sy + _curDim->h) - 1, _curDim->unkA); } void Screen_LoL::fprintString(const char *format, int x, int y, uint8 col1, uint8 col2, uint16 flags, ...) { @@ -95,5 +143,178 @@ void Screen_LoL::fprintStringIntro(const char *format, int x, int y, uint8 c1, u printText(buffer, x, y, c1, c2); } +void Screen_LoL::generateGrayOverlay(const uint8 *srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool skipSpecialColours) { + uint8 tmpPal[768]; + + for (int i = 0; i != lastColor; i++) { + int v = (((srcPal[3 * i] & 0x3f) * factor) / 0x40) + addR; + tmpPal[3 * i] = (v > 0x3f) ? 0x3f : v & 0xff; + v = (((srcPal[3 * i + 1] & 0x3f) * factor) / 0x40) + addG; + tmpPal[3 * i + 1] = (v > 0x3f) ? 0x3f : v & 0xff; + v = (((srcPal[3 * i + 2] & 0x3f) * factor) / 0x40) + addB; + tmpPal[3 * i + 2] = (v > 0x3f) ? 0x3f : v & 0xff; + } + + for (int i = 0; i < lastColor; i++) + grayOverlay[i] = findLeastDifferentColor(tmpPal + 3 * i, srcPal, lastColor, skipSpecialColours); +} + +uint8 *Screen_LoL::generateLevelOverlay(const uint8 *srcPal, uint8 *ovl, int opColor, int weight) { + if (!srcPal || !ovl) + return ovl; + + if (weight > 255) + weight = 255; + + uint16 r = srcPal[opColor * 3]; + uint16 g = srcPal[opColor * 3 + 1]; + uint16 b = srcPal[opColor * 3 + 2]; + + uint8 *d = ovl; + *d++ = 0; + + for (int i = 1; i != 255; i++) { + uint16 a = srcPal[i * 3]; + uint8 dr = a - ((((a - r) * (weight >> 1)) << 1) >> 8); + a = srcPal[i * 3 + 1]; + uint8 dg = a - ((((a - g) * (weight >> 1)) << 1) >> 8); + a = srcPal[i * 3 + 2]; + uint8 db = a - ((((a - b) * (weight >> 1)) << 1) >> 8); + + int l = opColor; + int m = 0x7fff; + int ii = 127; + int x = 1; + const uint8 *s = srcPal + 3; + + do { + if (i == x) { + s += 3; + } else { + int t = *s++ - dr; + int c = t * t; + t = *s++ - dg; + c += (t * t); + t = *s++ - db; + c += (t * t); + + if (!c) { + l = x; + break; + } + + if (c <= m) { + m = c; + l = x; + } + } + x++; + } while (--ii); + + *d++ = l & 0xff; + } + + return ovl; +} + +void Screen_LoL::drawGridBox(int x, int y, int w, int h, int col) { + if (w <= 0 || x >= 320 || h <= 0 || y >= 200) + return; + + if (x < 0) { + x += w; + if (x <= 0) + return; + w = x; + x = 0; + } + + int tmp = x + w; + if (tmp >= 320) { + w = 320 - x; + } + + int pitch = 320 - w; + + if (y < 0) { + y += h; + if (y <= 0) + return; + h = y; + y = 0; + } + + tmp = y + h; + if (tmp >= 200) { + h = 200 - y; + } + + tmp = (y + x) & 1; + uint8 *p = getPagePtr(_curPage) + y * 320 + x; + uint8 s = (tmp >> 8) & 1; + + w >>= 1; + int w2 = w; + + while (h--) { + if (w) { + while (w--) { + *(p + tmp) = col; + p += 2; + } + } else { + w = 1; + } + + if (s == 1) { + if (tmp == 0) + *p = col; + p++; + } + tmp ^= 1; + p += pitch; + w = w2; + } +} + +void Screen_LoL::fadeToBlack(int delay, const UpdateFunctor *upFunc) { + Screen::fadeToBlack(delay, upFunc); + _fadeFlag = 2; +} + +void Screen_LoL::setPaletteBrightness(uint8 *palette, int brightness, int modifier) { + generateBrightnessPalette(palette, getPalette(1), brightness, modifier); + fadePalette(getPalette(1), 5, 0); + _fadeFlag = 0; +} + +void Screen_LoL::generateBrightnessPalette(uint8 *src, uint8 *dst, int brightness, int modifier) { + memcpy(dst, src, 0x300); + setPaletteColoursSpecial(dst); + brightness = (8 - brightness) << 5; + if (modifier >= 0 && modifier < 8 && _drawGuiFlag & 0x800) { + brightness = 256 - ((((modifier & 0xfffe) << 5) * (256 - brightness)) >> 8); + if (brightness < 0) + brightness = 0; + } + + for (int i = 0; i < 384; i++) { + uint16 c = (dst[i] * brightness) >> 8; + dst[i] = c & 0xff; + } +} + +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); +} + +uint8 Screen_LoL::getShapePaletteSize(const uint8 *shp) { + debugC(9, kDebugLevelScreen, "Screen_LoL::getShapePaletteSize(%p)", (const void *)shp); + + return shp[10]; +} + } // end of namespace Kyra diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h index bba748813a..a4c7d8c749 100644 --- a/engines/kyra/screen_lol.h +++ b/engines/kyra/screen_lol.h @@ -35,17 +35,46 @@ class LoLEngine; class Screen_LoL : public Screen_v2 { public: Screen_LoL(LoLEngine *vm, OSystem *system); + ~Screen_LoL(); void setScreenDim(int dim); const ScreenDim *getScreenDim(int dim); + void modifyScreenDim(int dim, int x, int y, int w, int h); + void clearDim(int dim); + void clearCurDim(); void fprintString(const char *format, int x, int y, uint8 col1, uint8 col2, uint16 flags, ...); 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 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 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); + + uint8 *_paletteOverlay1; + uint8 *_paletteOverlay2; + uint8 *_grayOverlay; + int _fadeFlag; + int _drawGuiFlag; + private: LoLEngine *_vm; static const ScreenDim _screenDimTable[]; static const int _screenDimTableCount; + + ScreenDim **_customDimTable; + + uint8 *_levelOverlays[8]; }; } // end of namespace Kyra diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp index b2952ee113..ff8d228c56 100644 --- a/engines/kyra/screen_v2.cpp +++ b/engines/kyra/screen_v2.cpp @@ -90,11 +90,14 @@ void Screen_v2::applyOverlay(int x, int y, int w, int h, int pageNum, const uint } } -int Screen_v2::findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *palette, uint16 numColors) { +int Screen_v2::findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *palette, uint16 numColors, bool skipSpecialColours) { int m = 0x7fff; int r = 0x101; for (int i = 0; i < numColors; i++) { + if (skipSpecialColours && i >= 0xc0 && i <= 0xc3) + continue; + int v = paletteEntry[0] - *palette++; int c = v * v; v = paletteEntry[1] - *palette++; diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h index d95bff35d1..dd001da731 100644 --- a/engines/kyra/screen_v2.h +++ b/engines/kyra/screen_v2.h @@ -45,7 +45,7 @@ public: // palette handling uint8 *generateOverlay(const uint8 *palette, uint8 *buffer, int color, uint16 factor); void applyOverlay(int x, int y, int w, int h, int pageNum, const uint8 *overlay); - int findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *palette, uint16 numColors); + int findLeastDifferentColor(const uint8 *paletteEntry, const uint8 *palette, uint16 numColors, bool skipSpecialColours = false); virtual void getFadeParams(const uint8 *palette, int delay, int &delayInc, int &diff); diff --git a/engines/kyra/script.h b/engines/kyra/script.h index 6e08017974..ae9ece8154 100644 --- a/engines/kyra/script.h +++ b/engines/kyra/script.h @@ -53,7 +53,7 @@ struct EMCState { uint16 bp; uint16 sp; int16 regs[30]; // VM registers - int16 stack[61]; // VM stack + int16 stack[100]; // VM stack }; #define stackPos(x) (script->stack[script->sp+x]) diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp new file mode 100644 index 0000000000..488ec54d14 --- /dev/null +++ b/engines/kyra/script_lol.cpp @@ -0,0 +1,450 @@ +/* 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 "common/endian.h" + +namespace Kyra { + +void LoLEngine::runInitScript(const char *filename, int func) { + EMCData scriptData; + EMCState scriptState; + memset(&scriptData, 0, sizeof(EMCData)); + _emc->load(filename, &scriptData, &_opcodes); + + _emc->init(&scriptState, &scriptData); + _emc->start(&scriptState, 0); + while (_emc->isValid(&scriptState)) + _emc->run(&scriptState); + + if (func) { + _emc->init(&scriptState, &scriptData); + _emc->start(&scriptState, func); + while (_emc->isValid(&scriptState)) + _emc->run(&scriptState); + } + + _emc->unload(&scriptData); +} + +void LoLEngine::runInfScript(const char *filename) { + _emc->load(filename, &_scriptData, &_opcodes); + runResidentScript(0x400, -1); +} + +void LoLEngine::runResidentScript(int func, int reg0) { + runResidentScriptCustom(func, reg0, -1, 0, 0, 0); +} + +void LoLEngine::runResidentScriptCustom(int func, int reg0, int reg1, int reg2, int reg3, int reg4) { + EMCState scriptState; + memset(&scriptState, 0, sizeof(EMCState)); + + if (!_scriptBoolSkipExec) { + _emc->init(&scriptState, &_scriptData); + _emc->start(&scriptState, func); + + scriptState.regs[0] = reg0; + scriptState.regs[1] = reg1; + scriptState.regs[2] = reg2; + scriptState.regs[3] = reg3; + scriptState.regs[4] = reg4; + scriptState.regs[5] = func; + scriptState.regs[6] = _unkScriptByte; + + while (_emc->isValid(&scriptState)) + _emc->run(&scriptState); + } + + checkScriptUnk(func); +} + +bool LoLEngine::checkScriptUnk(int func) { + if (_boolScriptFuncDone) + return true; + + for (int i = 0; i < 15; i++) { + if (_scriptExecutedFuncs[i] == func) { + _boolScriptFuncDone = true; + return true; + } + } + + if (_currentBlock == func){ + _boolScriptFuncDone = true; + return true; + } + + return false; +} + +int LoLEngine::o2_setGameFlag(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_setGameFlag(%p) (%d)", (const void *)script, stackPos(0)); + if (stackPos(1)) + _gameFlags[stackPos(0) >> 4] |= (1 << (stackPos(0) & 0x0f)); + else + _gameFlags[stackPos(0) >> 4] &= (~(1 << (stackPos(0) & 0x0f))); + + return 1; +} + +int LoLEngine::o2_testGameFlag(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_testGameFlag(%p) (%d)", (const void *)script, stackPos(0)); + if (!stackPos(0)) + return 0; + + if (_gameFlags[stackPos(0) >> 4] & (1 << (stackPos(0) & 0x0f))) + return 1; + + return 0; +} + +int LoLEngine::o2_loadLevelSupplemenaryFiles(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_loadLevelSupplemenaryFiles(%p) (%d)", (const void *)script, stackPos(0)); + loadLevelSupplemenaryFiles(stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), (stackPos(5) == -1) ? 0 : stackPosString(5)); + return 1; +} + +int LoLEngine::o2_loadCmzFile(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_loadCmzFile(%p) (%d)", (const void *)script, stackPos(0)); + loadCmzFile(stackPosString(0)); + return 1; +} + +int LoLEngine::o2_loadMonsterShapes(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_loadMonsterShapes(%p) (%d)", (const void *)script, stackPos(0)); + loadMonsterShapes(stackPosString(0), stackPos(1), stackPos(2)); + return 1; +} + +int LoLEngine::o2_allocItemPropertiesBuffer(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_allocItemPropertiesBuffer(%p) (%d)", (const void *)script, stackPos(0)); + delete []_itemProperties; + _itemProperties = new ItemProperty[stackPos(0)]; + return 1; +} + +int LoLEngine::o2_setItemProperty(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_setItemProperty(%p) (%d)", (const void *)script, stackPos(0)); + ItemProperty *tmp = &_itemProperties[stackPos(0)]; + + tmp->nameStringId = stackPos(1); + tmp->shpIndex = stackPos(2); + tmp->unk5 = stackPos(3); + tmp->itemScriptFunc = stackPos(4); + tmp->unk8 = stackPos(5); + tmp->unk9 = stackPos(6); + tmp->unkA = stackPos(7); + tmp->flags = stackPos(8); + tmp->unkB = stackPos(9); + return 1; +} + +int LoLEngine::o2_makeItem(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_makeItem(%p) (%d)", (const void *)script, stackPos(0)); + return makeItem(stackPos(0), stackPos(1), stackPos(2)); +} + +int LoLEngine::o2_getItemPara(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_getItemPara(%p) (%d)", (const void *)script, stackPos(0)); + if(!stackPos(0)) + return 0; + + ItemInPlay *i = &_itemsInPlay[stackPos(0)]; + ItemProperty *p = &_itemProperties[i->itemPropertyIndex]; + + switch(stackPos(1)) { + case 0: + return i->cmzIndex; + case 1: + return i->unk7; + case 2: + return i->anonymous_4; + case 3: + return i->level; + case 4: + return i->itemPropertyIndex; + case 5: + return i->shpCurFrame_flg; + case 6: + return p->nameStringId; + case 7: + break; + case 8: + return p->shpIndex; + case 9: + return p->unk5; + case 10: + return p->itemScriptFunc; + case 11: + case 12: + case 13: + return p[stackPos(1)].unkB & 0x0f; + case 14: + return p->unkB; + case 15: + return i->shpCurFrame_flg & 0x1fff; + case 16: + return p->flags; + case 17: + return (p->unk9 << 8) | p->unk8; + default: + break; + } + + return -1; +} + +int LoLEngine::o2_getCharacterStat(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_getCharacterStat(%p) (%d)", (const void *)script, stackPos(0)); + LoLCharacter *c = &_characters[stackPos(0)]; + int d = stackPos(2); + + 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; + } + + return 0; +} + +int LoLEngine::o2_setCharacterStat(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_setCharacterStat(%p) (%d)", (const void *)script, stackPos(0)); + LoLCharacter *c = &_characters[stackPos(0)]; + int d = stackPos(2); + int e = stackPos(3); + + switch(stackPos(1)) { + case 0: + c->flags = e; + case 1: + c->raceClassSex = e & 0x0f; + case 2: + case 3: + case 4: + default: + break; + case 5: + //// TODO + break; + case 6: + c->hitPointsMax = e; + case 7: + //// TODO + break; + case 8: + c->magicPointsMax = e; + case 9: + c->field_37 = e; + case 10: + c->items[d] = 0; + case 11: + c->field_66[d] = e; + case 12: + c->field_27[d] = e; + case 13: + if (d & 0x80) + c->field_25 = e; + else + c->field_17[d] = e; + case 14: + c->field_69[d] = e; + } + + return 0; +} + +int LoLEngine::o2_loadLevelShapes(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_loadLevelShapes(%p) (%d)", (const void *)script, stackPos(0)); + loadLevelShpDat(stackPosString(0), stackPosString(1), true); + return 1; +} + +int LoLEngine::o2_closeLevelShapeFile(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_closeLevelShapeFile(%p) (%d)", (const void *)script, stackPos(0)); + delete _lvlShpFileHandle; + _lvlShpFileHandle = 0; + return 1; +} + +int LoLEngine::o2_loadDoorShapes(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_loadDoorShapes(%p) (%d)", (const void *)script, stackPos(0)); + _screen->loadBitmap(stackPosString(0), 3, 3, 0); + const uint8 *p = _screen->getCPagePtr(2); + if (_doorShapes[0]) + delete []_doorShapes[0]; + _doorShapes[0] = _screen->makeShapeCopy(p, stackPos(1)); + if (_doorShapes[1]) + delete []_doorShapes[1]; + _doorShapes[1] = _screen->makeShapeCopy(p, stackPos(2)); + + for (int i = 0; i < 20; i++) { + _wllBuffer5[i + 3] |= 7; + int t = i % 5; + if (t == 4) + _wllBuffer5[i + 3] &= 0xf8; + if (t == 3) + _wllBuffer5[i + 3] &= 0xfd; + } + + if (stackPos(3)) { + for (int i = 3; i < 13; i++) + _wllBuffer5[i] &= 0xfd; + } + + if (stackPos(4)) { + for (int i = 13; i < 23; i++) + _wllBuffer5[i] &= 0xfd; + } + + return 1; +} + +int LoLEngine::o2_setGlobalVar(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_setGlobalVar(%p) (%d)", (const void *)script, stackPos(0)); + //uint16 a = stackPos(1); + uint16 b = stackPos(2); + + switch (stackPos(0)) { + case 0: + _currentBlock = b; + setLF1(_unkCmzU1, _unkCmzU2, _currentBlock, 0x80, 0x80); + setLF2(_currentBlock); + break; + case 1: + _unkPara2 = b; + break; + case 2: + _currentLevel = b & 0xff; + break; + case 3: + break; + case 4: + _brightness = b & 0xff; + break; + case 5: + _credits = b; + break; + case 6: + //TODO + break; + case 7: + break; + case 8: + _charFlagUnk = b; + //TODO + break; + case 9: + _lampStatusUnk = b & 0xff; + break; + case 10: + _loadLevelFlag2 = b & 0xff; + //TODO + break; + case 11: + //TODO + break; + case 12: + //TODO + break; + default: + break; + } + + return 1; +} + +int LoLEngine::o2_mapShapeToBlock(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_mapShapeToBlock(%p) (%d)", (const void *)script, stackPos(0)); + return assignLevelShapes(stackPos(0)); +} + +int LoLEngine::o2_resetBlockShapeAssignment(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_resetBlockShapeAssignment(%p) (%d)", (const void *)script, stackPos(0)); + uint8 v = stackPos(0) & 0xff; + memset(_wllShapeMap + 3, v, 5); + memset(_wllShapeMap + 13, v, 5); + return 1; +} + +int LoLEngine::o2_setPaletteBrightness(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_setPaletteBrightness(%p) (%d)", (const void *)script, stackPos(0)); + uint16 old = _brightness; + _brightness = stackPos(0); + if (stackPos(1) == 1) + _screen->setPaletteBrightness(_screen->_currentPalette, stackPos(0), _lampOilStatus); + return old; +} + +int LoLEngine::o2_assignCustomSfx(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::o2_assignCustomSfx(%p) (%d)", (const void *)script, stackPos(0)); + const char *c = stackPosString(0); + int i = stackPos(1); + + if (!c || i > 250) + return 0; + + if (_ingameSoundIndex[i] == 0xffff) + return 0; + + strcpy(_ingameSoundList[_ingameSoundIndex[i]], c); + + return 0; +} + +} // end of namespace Kyra + + diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index f97f5c808a..8882bed10c 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -43,7 +43,7 @@ namespace Kyra { -#define RESFILE_VERSION 32 +#define RESFILE_VERSION 33 namespace { bool checkKyraDat(Common::SeekableReadStream *file) { @@ -221,6 +221,11 @@ bool StaticResource::init() { { k2ShpAnimDataV1, proc(loadShapeAnimData_v1), proc(freeHofShapeAnimDataV1) }, { k2ShpAnimDataV2, proc(loadShapeAnimData_v2), proc(freeHofShapeAnimDataV2) }, + { lolCharData, proc(loadCharData), proc(freeCharData) }, + { lolSpellData, proc(loadSpellData), proc(freeSpellData) }, + { lolCompassData, proc(loadCompassData), proc(freeCompassData) }, + { lolRawDataBe16, proc(loadRawDataBe16), proc(freeRawDataBe16) }, + { 0, 0, 0 } }; #undef proc @@ -361,6 +366,42 @@ bool StaticResource::init() { { k2SeqplaySfxFiles, kStringList, "S_SFXFILES.TXT" }, { k2SeqplaySeqData, k2SeqData, "S_DATA.SEQ" }, { k2SeqplayIntroTracks, kStringList, "S_INTRO.TRA" }, + + // Ingame + { lolCharacterDefs, lolCharData, "CHARACTER.DEF" }, + { lolIngameSfxFiles, kStringList, "SFXFILES.TRA" }, + { lolIngameSfxIndex, kRawData, "SFXINDEX.MAP" }, + { lolIngameGMSfxIndex, kRawData, "SFX_GM.MAP" }, + { lolIngameMT32SfxIndex, kRawData, "SFX_MT32.MAP" }, + { lolSpellProperties, lolSpellData, "SPELLS.DEF" }, + { lolGameShapeMap, kRawData, "GAMESHP.MAP" }, + { lolLevelShpList, kStringList, "SHPFILES.TXT" }, + { lolLevelDatList, kStringList, "DATFILES.TXT" }, + { lolCompassDefs, lolCompassData, "COMPASS.DEF" }, + + { lolDscUnk1, kRawData, "DSCSHPU1.DEF" }, + { lolDscShapeIndex, kRawData, "DSCSHPI1.DEF" }, + { lolDscOvlMap, kRawData, "DSCSHPI2.DEF" }, + { lolDscScaleWidthData, lolRawDataBe16, "DSCSHPW.DEF" }, + { lolDscScaleHeightData, lolRawDataBe16, "DSCSHPH.DEF" }, + { lolDscX, lolRawDataBe16, "DSCSHPX.DEF" }, + { lolDscY, kRawData, "DSCSHPY.DEF" }, + { lolDscTileIndex, kRawData, "DSCSHPT.DEF" }, + { lolDscUnk2, kRawData, "DSCSHPU2.DEF" }, + { lolDscDoorShapeIndex, kRawData, "DSCDOOR.DEF" }, + { lolDscDimData1, kRawData, "DSCDIM1.DEF" }, + { lolDscDimData2, kRawData, "DSCDIM2.DEF" }, + { lolDscBlockMap, kRawData, "DSCBLOCK1.DEF" }, + { lolDscDimMap, kRawData, "DSCDIM.DEF" }, + { lolDscDoorScale, lolRawDataBe16, "DSCDOOR3.DEF" }, + { lolDscDoor2, kRawData, "DSCDOOR2.DEF" }, + { lolDscDoor4, lolRawDataBe16, "DSCDOOR4.DEF" }, + { lolDscOvlIndex, kRawData, "DSCBLOCK2.DEF" }, + { lolDscBlockIndex, kRawData, "DSCBLOCKX.DEF" }, + { lolDscDoor1, kRawData, "DSCDOOR1.DEF" }, + { lolDscDoorX, lolRawDataBe16, "DSCDOORX.DEF" }, + { lolDscDoorY, lolRawDataBe16, "DSCDOORY.DEF" }, + { 0, 0, 0 } }; @@ -374,7 +415,7 @@ bool StaticResource::init() { _builtIn = 0; _filenameTable = kyra3StaticRes; } else if (_vm->game() == GI_LOL) { - if (!_vm->gameFlags().isDemo) + if (!_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie) return true; _builtIn = 0; _filenameTable = lolStaticRes; @@ -424,6 +465,22 @@ const ItemAnimData_v2 *StaticResource::loadShapeAnimData_v2(int id, int &entries return (const ItemAnimData_v2*)getData(id, k2ShpAnimDataV2, entries); } +const LoLCharacter *StaticResource::loadCharData(int id, int &entries) { + return (const LoLCharacter*)getData(id, lolCharData, entries); +} + +const SpellProperty *StaticResource::loadSpellData(int id, int &entries) { + return (const SpellProperty*)getData(id, lolSpellData, entries); +} + +const CompassDef *StaticResource::loadCompassData(int id, int &entries) { + return (const CompassDef*)getData(id, lolCompassData, entries); +} + +const uint16 *StaticResource::loadRawDataBe16(int id, int &entries) { + return (const uint16*)getData(id, lolRawDataBe16, entries); +} + bool StaticResource::prefetchId(int id) { if (id == -1) { for (int i = 0; _filenameTable[i].filename; ++i) @@ -852,6 +909,144 @@ bool StaticResource::loadShapeAnimData_v2(const char *filename, void *&ptr, int return true; } +bool StaticResource::loadCharData(const char *filename, void *&ptr, int &size) { + Common::SeekableReadStream *file = getFile(filename); + + if (!file) + return false; + + size = file->size() / 130; + LoLCharacter *charData = new LoLCharacter[size]; + + for (int i = 0; i < size; i++) { + LoLCharacter *t = &charData[i]; + + t->flags = file->readUint16LE(); + file->read(t->name, 11); + t->raceClassSex = file->readByte(); + t->id = file->readSint16LE(); + t->curFaceFrame = file->readByte(); + t->nextFaceFrame = file->readByte(); + t->field_12 = file->readUint16LE(); + t->field_14 = file->readUint16LE(); + t->field_16 = file->readByte(); + for (int ii = 0; ii < 5; ii++) + t->field_17[ii] = file->readUint16LE(); + t->field_21 = file->readUint16LE(); + t->field_23 = file->readUint16LE(); + t->field_25 = file->readUint16LE(); + for (int ii = 0; ii < 2; ii++) + t->field_27[ii] = file->readUint16LE(); + t->field_2B = file->readByte(); + t->field_2C = file->readUint16LE(); + t->field_2E = file->readUint16LE(); + t->field_30 = file->readUint16LE(); + t->field_32 = file->readUint16LE(); + t->field_34 = file->readUint16LE(); + t->field_36 = file->readByte(); + t->field_37 = file->readUint16LE(); + t->hitPointsCur = file->readUint16LE();; + t->hitPointsMax = file->readUint16LE();; + t->magicPointsCur = file->readUint16LE();; + t->magicPointsMax = file->readUint16LE();; + t->field_41 = file->readByte(); + t->damageSuffered = file->readUint16LE(); + t->weaponHit = file->readUint16LE(); + t->field_46 = file->readUint16LE(); + t->field_48 = file->readUint16LE(); + t->field_4A = file->readUint16LE(); + t->field_4C = file->readUint16LE(); + t->rand = file->readUint16LE(); + for (int ii = 0; ii < 11; ii++) + t->items[ii] = file->readUint16LE(); + for (int ii = 0; ii < 3; ii++) + t->field_66[ii] = file->readByte(); + for (int ii = 0; ii < 3; ii++) + t->field_69[ii] = file->readByte(); + t->field_6C = file->readByte(); + t->field_6D = file->readByte(); + t->field_6E = file->readUint16LE(); + t->field_70 = file->readUint16LE(); + t->field_72 = file->readUint16LE(); + t->field_74 = file->readUint16LE(); + t->field_76 = file->readUint16LE(); + for (int ii = 0; ii < 5; ii++) + t->arrayUnk2[ii] = file->readByte(); + for (int ii = 0; ii < 5; ii++) + t->arrayUnk1[ii] = file->readByte(); + }; + + ptr = charData; + + return true; +} + +bool StaticResource::loadSpellData(const char *filename, void *&ptr, int &size) { + Common::SeekableReadStream *file = getFile(filename); + + if (!file) + return false; + + size = file->size() / 28; + SpellProperty *spellData = new SpellProperty[size]; + + for (int i = 0; i < size; i++) { + SpellProperty *t = &spellData[i]; + + t->field_0 = file->readUint16LE(); + for (int ii = 0; ii < 4; ii++) + t->unkArr[ii] = file->readUint16LE(); + t->field_A = file->readUint16LE(); + t->field_C = file->readUint16LE(); + t->field_E = file->readUint16LE(); + t->spellNameCode = file->readUint16LE(); + for (int ii = 0; ii < 4; ii++) + t->mpRequired[ii] = file->readUint16LE(); + t->field_1A = file->readUint16LE(); + }; + + ptr = spellData; + + return true; +} + +bool StaticResource::loadCompassData(const char *filename, void *&ptr, int &size) { + Common::SeekableReadStream *file = getFile(filename); + + if (!file) + return false; + + size = file->size() / 4; + CompassDef *defs = new CompassDef[size]; + + for (int i = 0; i < size; i++) { + CompassDef *t = &defs[i]; + t->shapeIndex = file->readByte(); + t->x = file->readByte(); + t->y = file->readByte(); + t->flags = file->readByte(); + }; + + ptr = defs; + + return true; +} + +bool StaticResource::loadRawDataBe16(const char *filename, void *&ptr, int &size) { + Common::SeekableReadStream *file = getFile(filename); + + size = file->size() >> 1; + + uint16 *r = new uint16[size]; + + for (int i = 0; i < size; i++) + r[i] = file->readUint16BE(); + + ptr = r; + + return true; +} + void StaticResource::freeRawData(void *&ptr, int &size) { uint8 *data = (uint8*)ptr; delete[] data; @@ -920,6 +1115,34 @@ void StaticResource::freeHofShapeAnimDataV2(void *&ptr, int &size) { size = 0; } +void StaticResource::freeCharData(void *&ptr, int &size) { + LoLCharacter *d = (LoLCharacter *)ptr; + delete[] d; + ptr = 0; + size = 0; +} + +void StaticResource::freeSpellData(void *&ptr, int &size) { + SpellProperty *d = (SpellProperty *)ptr; + delete[] d; + ptr = 0; + size = 0; +} + +void StaticResource::freeCompassData(void *&ptr, int &size) { + CompassDef *d = (CompassDef *)ptr; + delete[] d; + ptr = 0; + size = 0; +} + +void StaticResource::freeRawDataBe16(void *&ptr, int &size) { + uint16 *data = (uint16*)ptr; + delete[] data; + ptr = 0; + size = 0; +} + void StaticResource::freePaletteTable(void *&ptr, int &size) { uint8 **data = (uint8**)ptr; while (size--) @@ -1403,6 +1626,49 @@ void KyraEngine_MR::initStaticResource() { _itemStringMap = _staticres->loadRawData(k3ItemStringMap, _itemStringMapSize); } +void LoLEngine::initStaticResource() { + _charDefaults = _staticres->loadCharData(lolCharacterDefs, _charDefaultsSize); + _ingameSoundIndex = (const uint16 *)_staticres->loadRawData(lolIngameSfxIndex, _ingameSoundIndexSize); + _ingameGMSoundIndex = _staticres->loadRawData(lolIngameGMSfxIndex, _ingameGMSoundIndexSize); + _ingameMT32SoundIndex = _staticres->loadRawData(lolIngameMT32SfxIndex, _ingameMT32SoundIndexSize); + _spellProperties = _staticres->loadSpellData(lolSpellProperties, _spellPropertiesSize); + _gameShapeMap = (const int8*)_staticres->loadRawData(lolGameShapeMap, _gameShapeMapSize); + _levelShpList = _staticres->loadStrings(lolLevelShpList, _levelShpListSize); + _levelDatList = _staticres->loadStrings(lolLevelDatList, _levelDatListSize); + _compassDefs = _staticres->loadCompassData(lolCompassDefs, _compassDefsSize); + + _dscUnk1 = (const int8*)_staticres->loadRawData(lolDscUnk1, _dscUnk1Size); + _dscShapeIndex = (const int8*)_staticres->loadRawData(lolDscShapeIndex, _dscShapeIndexSize); + _dscOvlMap = _staticres->loadRawData(lolDscOvlMap, _dscOvlMapSize); + _dscShapeScaleW = (const uint16 *)_staticres->loadRawDataBe16(lolDscScaleWidthData, _dscShapeScaleWSize); + _dscShapeScaleH = (const uint16 *)_staticres->loadRawDataBe16(lolDscScaleHeightData, _dscShapeScaleHSize); + _dscShapeX = (const int16 *)_staticres->loadRawDataBe16(lolDscX, _dscShapeXSize); + _dscShapeY = (const int8 *)_staticres->loadRawData(lolDscY, _dscShapeYSize); + _dscTileIndex = _staticres->loadRawData(lolDscTileIndex, _dscTileIndexSize); + _dscUnk2 = _staticres->loadRawData(lolDscUnk2, _dscUnk2Size); + _dscDoorShpIndex = _staticres->loadRawData(lolDscDoorShapeIndex, _dscDoorShpIndexSize); + _dscDim1 = (const int8 *)_staticres->loadRawData(lolDscDimData1, _dscDim1Size); + _dscDim2 = (const int8 *)_staticres->loadRawData(lolDscDimData2, _dscDim2Size); + _dscBlockMap = _staticres->loadRawData(lolDscBlockMap, _dscBlockMapSize); + _dscDimMap = _staticres->loadRawData(lolDscDimMap, _dscDimMapSize); + _dscDoorScaleTable = (const uint16 *)_staticres->loadRawDataBe16(lolDscDoorScale, _dscDoorScaleTableSize); + _dscDoor2 = _staticres->loadRawData(lolDscDoor2, _dscDoor2Size); + _dscShapeOvlIndex = _staticres->loadRawData(lolDscOvlIndex, _dscShapeOvlIndexSize); + _dscDoor4 = (const uint16 *)_staticres->loadRawDataBe16(lolDscDoor4, _dscDoor4Size); + _dscBlockIndex = (const int8 *)_staticres->loadRawData(lolDscBlockIndex, _dscBlockIndexSize); + _dscDoor1 = _staticres->loadRawData(lolDscDoor1, _dscDoor1Size); + _dscDoorX = (const int16 *)_staticres->loadRawDataBe16(lolDscDoorX, _dscDoorXSize); + _dscDoorY = (const int16 *)_staticres->loadRawDataBe16(lolDscDoorY, _dscDoorYSize); + + const char *const *tmpSndList = _staticres->loadStrings(lolIngameSfxFiles, _ingameSoundListSize); + _ingameSoundList = new char*[_ingameSoundListSize]; + for (int i = 0; i < _ingameSoundListSize; i++) { + _ingameSoundList[i] = new char[strlen(tmpSndList[i]) + 1]; + strcpy(_ingameSoundList[i], tmpSndList[i]); + } + _staticres->unloadId(lolIngameSfxFiles); +} + const ScreenDim Screen_LoK::_screenDimTable[] = { { 0x00, 0x00, 0x28, 0xC8, 0x0F, 0x0C, 0x00, 0x00 }, { 0x08, 0x48, 0x18, 0x38, 0x0F, 0x0C, 0x00, 0x00 }, diff --git a/tools/create_kyradat/create_kyradat.cpp b/tools/create_kyradat/create_kyradat.cpp index 456da29fa0..51524e57a0 100644 --- a/tools/create_kyradat/create_kyradat.cpp +++ b/tools/create_kyradat/create_kyradat.cpp @@ -31,7 +31,7 @@ #include "md5.h" enum { - kKyraDatVersion = 32, + kKyraDatVersion = 33, kIndexSize = 12 }; @@ -53,6 +53,7 @@ enum { #include "malcolm.h" +#include "lol_cd.h" #include "lol_demo.h" const Game kyra1FanTranslations[] = { @@ -72,6 +73,7 @@ bool extractStringsWoSuffix(PAKFile &out, const Game *g, const byte *data, const bool extractPaddedStrings(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch = 0); bool extractRaw16to8(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch = 0); bool extractMrShapeAnimData(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch = 0); +bool extractRaw16(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch = 0); int extractHofSeqData_checkString(const void *ptr, uint8 checkSize); int extractHofSeqData_isSequence(const void *ptr, const Game *g, uint32 maxCheckSize); @@ -96,6 +98,8 @@ const ExtractType extractTypeTable[] = { { k3TypeRaw16to8, extractRaw16to8, createFilename }, { k3TypeShpData, extractMrShapeAnimData, createFilename }, + { lolTypeRaw16, extractRaw16, createFilename }, + { -1, 0, 0} }; @@ -256,7 +260,42 @@ const ExtractFilename extractFilenames[] = { // LANDS OF LORE // Demo Sequence Player - { lSeqplayIntroTracks, k2TypeSoundList, "S_INTRO.TRA" }, + { lolSeqplayIntroTracks, k2TypeSoundList, "S_INTRO.TRA" }, + + // Ingame + { lolCharacterDefs, kTypeRawData, "CHARACTER.DEF" }, + { lolIngameSfxFiles, k2TypeSfxList, "SFXFILES.TRA" }, + { lolIngameSfxIndex, kTypeRawData, "SFXINDEX.MAP" }, + { lolGMSfxIndex, kTypeRawData, "SFX_GM.MAP" }, + { lolMT32SfxIndex, kTypeRawData, "SFX_MT32.MAP" }, + { lolSpellProperties, kTypeRawData, "SPELLS.DEF" }, + { lolGameShapeMap, kTypeRawData, "GAMESHP.MAP" }, + { lolLevelShpList, kTypeStringList, "SHPFILES.TXT" }, + { lolLevelDatList, kTypeStringList, "DATFILES.TXT" }, + { lolCompassDefs, k3TypeRaw16to8, "COMPASS.DEF" }, + + { lolDscUnk1, kTypeRawData, "DSCSHPU1.DEF" }, + { lolDscShapeIndex1, kTypeRawData, "DSCSHPI1.DEF" }, + { lolDscShapeIndex2, kTypeRawData, "DSCSHPI2.DEF" }, + { lolDscScaleWidthData, lolTypeRaw16, "DSCSHPW.DEF" }, + { lolDscScaleHeightData, lolTypeRaw16, "DSCSHPH.DEF" }, + { lolDscX, lolTypeRaw16, "DSCSHPX.DEF" }, + { lolDscY, kTypeRawData, "DSCSHPY.DEF" }, + { lolDscTileIndex, kTypeRawData, "DSCSHPT.DEF" }, + { lolDscUnk2, kTypeRawData, "DSCSHPU2.DEF" }, + { lolDscDoorShapeIndex, kTypeRawData, "DSCDOOR.DEF" }, + { lolDscDimData1, kTypeRawData, "DSCDIM1.DEF" }, + { lolDscDimData2, kTypeRawData, "DSCDIM2.DEF" }, + { lolDscBlockMap, kTypeRawData, "DSCBLOCK1.DEF" }, + { lolDscDimMap, kTypeRawData, "DSCDIM.DEF" }, + { lolDscDoorScale, lolTypeRaw16, "DSCDOOR3.DEF" }, + { lolDscDoor2, k3TypeRaw16to8, "DSCDOOR2.DEF" }, + { lolDscShapeOvlIndex, k3TypeRaw16to8, "DSCBLOCK2.DEF" }, + { lolDscBlockIndex, kTypeRawData, "DSCBLOCKX.DEF" }, + { lolDscDoor4, lolTypeRaw16, "DSCDOOR4.DEF" }, + { lolDscDoor1, kTypeRawData, "DSCDOOR1.DEF" }, + { lolDscDoorX, lolTypeRaw16, "DSCDOORX.DEF" }, + { lolDscDoorY, lolTypeRaw16, "DSCDOORY.DEF" }, { -1, 0, 0 } }; @@ -1012,6 +1051,20 @@ bool extractRaw16to8(PAKFile &out, const Game *g, const byte *data, const uint32 return out.addFile(filename, buffer, outsize); } +bool extractRaw16(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch) { + uint8 *buffer = new uint8[size]; + const uint8 *src = data; + uint8 *dst = buffer; + + for (int i = 0; i < (size >> 1); i++) { + WRITE_BE_UINT16(dst, READ_LE_UINT16(src)); + src += 2; + dst += 2; + } + + return out.addFile(filename, buffer, size); +} + bool extractMrShapeAnimData(PAKFile &out, const Game *g, const byte *data, const uint32 size, const char *filename, int fmtPatch) { int outsize = 1; uint8 *buffer = new uint8[size + 1]; @@ -1070,7 +1123,7 @@ enum { uint32 getFeatures(const Game *g) { uint32 features = 0; - if (g->special == kTalkieVersion || g->special == k2CDFile1E || g->special == k2CDFile1F || g->special == k2CDFile1G || g->special == k2CDFile1I || g->special == k2CDFile2E || g->special == k2CDFile2F || g->special == k2CDFile2G || g->game == kKyra3) + if (g->special == kTalkieVersion || g->special == k2CDFile1E || g->special == k2CDFile1F || g->special == k2CDFile1G || g->special == k2CDFile1I || g->special == k2CDFile2E || g->special == k2CDFile2F || g->special == k2CDFile2G || g->special == kLolCD || g->game == kKyra3) features |= GF_TALKIE; else if (g->special == kDemoVersion || g->special == k2DemoVersion || g->special == k2DemoLol) features |= GF_DEMO; @@ -1352,6 +1405,7 @@ const Game *gameDescs[] = { kyra3Games, lolDemos, + lolGames, 0 }; diff --git a/tools/create_kyradat/create_kyradat.h b/tools/create_kyradat/create_kyradat.h index 8e985f9031..8c1fd3f84b 100644 --- a/tools/create_kyradat/create_kyradat.h +++ b/tools/create_kyradat/create_kyradat.h @@ -174,7 +174,41 @@ enum kExtractID { k3ItemMagicTable, k3ItemStringMap, - lSeqplayIntroTracks, + lolSeqplayIntroTracks, + + lolCharacterDefs, + lolIngameSfxFiles, + lolIngameSfxIndex, + lolGMSfxIndex, + lolMT32SfxIndex, + lolSpellProperties, + lolGameShapeMap, + lolLevelShpList, + lolLevelDatList, + lolCompassDefs, + + lolDscUnk1, + lolDscShapeIndex1, + lolDscShapeIndex2, + lolDscScaleWidthData, + lolDscScaleHeightData, + lolDscX, + lolDscY, + lolDscTileIndex, + lolDscUnk2, + lolDscDoorShapeIndex, + lolDscDimData1, + lolDscDimData2, + lolDscBlockMap, + lolDscDimMap, + lolDscShapeOvlIndex, + lolDscBlockIndex, + lolDscDoor1, + lolDscDoor2, + lolDscDoorScale, + lolDscDoor4, + lolDscDoorX, + lolDscDoorY, kMaxResIDs }; @@ -219,7 +253,9 @@ enum kSpecial { k2DemoVersionTlkE = 19, k2DemoVersionTlkF = 20, k2DemoVersionTlkG = 21, - k2DemoLol = 22 + k2DemoLol = 22, + + kLolCD = 23 }; struct SpecialExtension { @@ -267,7 +303,9 @@ enum kExtractType { k2TypeSfxList, k3TypeRaw16to8, - k3TypeShpData + k3TypeShpData, + + lolTypeRaw16 }; struct ExtractType { diff --git a/tools/create_kyradat/lol_cd.h b/tools/create_kyradat/lol_cd.h new file mode 100644 index 0000000000..8380b9961e --- /dev/null +++ b/tools/create_kyradat/lol_cd.h @@ -0,0 +1,42 @@ +const ExtractEntry lolCDFile2[] = { + { lolCharacterDefs, 0x00029D60, 0x0002A1F2 }, + { lolIngameSfxFiles, 0x0002A330, 0x0002AC22 }, + { lolIngameSfxIndex, 0x0002AC22, 0x0002B00A }, + { lolGMSfxIndex, 0x0002B010, 0x0002B10A }, + { lolMT32SfxIndex, 0x0002B110, 0x0002B20A }, + { lolSpellProperties, 0x0002B5D0, 0x0002B6E8 }, + { lolGameShapeMap, 0x0002B35D, 0x0002B52C }, + { lolLevelShpList, 0x00032826, 0x000328A5 }, + { lolLevelDatList, 0x000328A5, 0x000329A4 }, + { lolCompassDefs, 0x000286C4, 0x000287C4 }, + + { lolDscUnk1, 0x00032017, 0x0003203B }, + { lolDscShapeIndex1, 0x0003203B, 0x0003205F }, + { lolDscShapeIndex2, 0x0003205F, 0x00032069 }, + { lolDscScaleWidthData, 0x00032069, 0x000320B1 }, + { lolDscScaleHeightData, 0x000320B1, 0x000320F9 }, + { lolDscX, 0x000320F9, 0x00032141 }, + { lolDscY, 0x00032141, 0x00032165 }, + { lolDscTileIndex, 0x00032165, 0x00032177 }, + { lolDscUnk2, 0x00032177, 0x0003218E }, + { lolDscDoorShapeIndex, 0x0003218E, 0x000321A5 }, + { lolDscDimData1, 0x00031C03, 0x00031D47 }, + { lolDscDimData2, 0x00031D47, 0x00031FD0 }, + { lolDscBlockMap, 0x00031B64, 0x00031B70 }, + { lolDscDimMap, 0x00031B70, 0x00031B82 }, + { lolDscDoorScale, 0x00031B82, 0x00031B92 }, + { lolDscDoor2, 0x00031B92, 0x00031B9A }, + { lolDscShapeOvlIndex, 0x00031B9A, 0x00031BBA }, + { lolDscDoor4, 0x00031BBA, 0x00031BC2 }, + { lolDscBlockIndex, 0x00033B53, 0x00033B9B }, + { lolDscDoor1, 0x0002B550, 0x0002B5D0 }, + { lolDscDoorX, 0x00027CC0, 0x00028140 }, + { lolDscDoorY, 0x00028140, 0x000285C0 }, + + { -1, 0, 0 } +}; + +const Game lolGames[] = { + { kLol, EN_ANY, kLolCD, "263998ec600afca1cc7b935c473df670", lolCDFile2}, + GAME_DUMMY_ENTRY +}; diff --git a/tools/create_kyradat/lol_demo.h b/tools/create_kyradat/lol_demo.h index ce114f4e73..378b8c5dce 100644 --- a/tools/create_kyradat/lol_demo.h +++ b/tools/create_kyradat/lol_demo.h @@ -3,7 +3,7 @@ const ExtractEntry lolDemo[] = { { k2SeqplayStrings, 0x0001B5EE, 0x0001B6F0 }, { k2SeqplaySfxFiles, 0x0001B6F0, 0x0001B7B5 }, { k2SeqplaySeqData, 0x0001B320, 0x0001B56C }, - { lSeqplayIntroTracks, 0x0001B7B5, 0x0001B7CF }, + { lolSeqplayIntroTracks, 0x0001B7B5, 0x0001B7CF }, { -1, 0, 0 } }; diff --git a/tools/create_kyradat/misc.h b/tools/create_kyradat/misc.h index c519418d37..91ee915319 100644 --- a/tools/create_kyradat/misc.h +++ b/tools/create_kyradat/misc.h @@ -481,12 +481,50 @@ const int kyra3Need[] = { -1 }; +const int lolCDFile2Need[] = { + lolCharacterDefs, + lolIngameSfxFiles, + lolIngameSfxIndex, + lolGMSfxIndex, + lolMT32SfxIndex, + lolSpellProperties, + lolGameShapeMap, + lolLevelShpList, + lolLevelDatList, + lolCompassDefs, + lolDscUnk1, + lolDscShapeIndex1, + lolDscShapeIndex2, + lolDscScaleWidthData, + lolDscScaleHeightData, + lolDscX, + lolDscY, + lolDscTileIndex, + lolDscUnk2, + lolDscDoorShapeIndex, + lolDscDimData1, + lolDscDimData2, + lolDscBlockMap, + lolDscDimMap, + lolDscDoor2, + lolDscShapeOvlIndex, + lolDscBlockIndex, + lolDscDoor1, + lolDscDoor2, + lolDscDoorScale, + lolDscDoor4, + lolDscDoorX, + lolDscDoorY, + + -1 +}; + const int lolDemoNeed[] = { k2SeqplayPakFiles, k2SeqplayStrings, k2SeqplaySeqData, k2SeqplaySfxFiles, - lSeqplayIntroTracks, + lolSeqplayIntroTracks, -1 }; @@ -519,6 +557,8 @@ const GameNeed gameNeedTable[] = { { kKyra3, -1, kyra3Need }, + { kLol, kLolCD, lolCDFile2Need }, + { -1, -1, 0 } }; @@ -544,6 +584,8 @@ const SpecialExtension specialTable[] = { { k2DemoVersion, "DEM" }, { k2DemoLol, "DEM" }, + { kLolCD, "CD" }, + { -1, 0 } }; -- cgit v1.2.3