diff options
author | athrxx | 2019-01-26 01:31:34 +0100 |
---|---|---|
committer | athrxx | 2019-03-06 20:48:15 +0100 |
commit | 1dfdcc7252ac83643cae7a7447c025da2af63843 (patch) | |
tree | b6736d006bf67d5264dd171c336f0915695d1f88 /engines/kyra/engine/scene_lol.cpp | |
parent | 8b53d20b51771680c3d31aa02c0285b7a8be4e85 (diff) | |
download | scummvm-rg350-1dfdcc7252ac83643cae7a7447c025da2af63843.tar.gz scummvm-rg350-1dfdcc7252ac83643cae7a7447c025da2af63843.tar.bz2 scummvm-rg350-1dfdcc7252ac83643cae7a7447c025da2af63843.zip |
KYRA: cleanup dir
Reorganize all files in sub directories. The file placement isn't as intuitive as it might be for other engines, which is probably the reason why this hasn't been done before.
Diffstat (limited to 'engines/kyra/engine/scene_lol.cpp')
-rw-r--r-- | engines/kyra/engine/scene_lol.cpp | 1577 |
1 files changed, 1577 insertions, 0 deletions
diff --git a/engines/kyra/engine/scene_lol.cpp b/engines/kyra/engine/scene_lol.cpp new file mode 100644 index 0000000000..93ff588ece --- /dev/null +++ b/engines/kyra/engine/scene_lol.cpp @@ -0,0 +1,1577 @@ +/* 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. + * + */ + +#ifdef ENABLE_LOL + +#include "kyra/engine/lol.h" +#include "kyra/graphics/screen_lol.h" +#include "kyra/resource/resource.h" +#include "kyra/engine/timer.h" + +#include "common/endian.h" +#include "common/system.h" + +namespace Kyra { + +void LoLEngine::loadLevel(int index) { + _flagsTable[73] |= 0x08; + setMouseCursorToIcon(0x85); + _nextScriptFunc = 0; + + snd_stopMusic(); + + stopPortraitSpeechAnim(); + + for (int i = 0; i < 400; i++) { + delete[] _levelDecorationShapes[i]; + _levelDecorationShapes[i] = 0; + } + _emc->unload(&_scriptData); + + resetItems(1); + disableMonsters(); + resetBlockProperties(); + + releaseMonsterShapes(0); + releaseMonsterShapes(1); + + for (int i = 0x50; i < 0x53; i++) + _timer->disable(i); + + _currentLevel = index; + _updateFlags = 0; + + setDefaultButtonState(); + + loadTalkFile(index); + + loadLevelWallData(index, true); + _loadLevelFlag = 1; + + Common::String filename = Common::String::format("LEVEL%d.INI", index); + + int f = _hasTempDataFlags & (1 << (index - 1)); + + runInitScript(filename.c_str(), f ? 0 : 1); + + if (f) + restoreBlockTempData(index); + + filename = Common::String::format("LEVEL%d.INF", index); + runInfScript(filename.c_str()); + + addLevelItems(); + deleteMonstersFromBlock(_currentBlock); + + if (!_flags.use16ColorMode) + _screen->generateGrayOverlay(_screen->getPalette(0), _screen->_grayOverlay, 32, 16, 0, 0, 128, true); + + _sceneDefaultUpdate = 0; + if (_screen->_fadeFlag == 3) + _screen->fadeToBlack(10); + + gui_drawPlayField(); + + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); + setMouseCursorToItemInHand(); + + if (_flags.use16ColorMode) + _screen->fadeToPalette1(10); + + snd_playTrack(_curMusicTheme); +} + +void LoLEngine::addLevelItems() { + for (int i = 0; i < 400; i++) { + if (_itemsInPlay[i].level != _currentLevel) + continue; + + assignBlockItem(&_levelBlockProperties[_itemsInPlay[i].block], i); + + _levelBlockProperties[_itemsInPlay[i].block].direction = 5; + _itemsInPlay[i].nextDrawObject = 0; + } +} + +void LoLEngine::assignBlockItem(LevelBlockProperty *l, uint16 item) { + uint16 *index = &l->assignedObjects; + LoLObject *tmp = 0; + + while (*index & 0x8000) { + tmp = findObject(*index); + index = &tmp->nextAssignedObject; + } + + tmp = findObject(item); + ((LoLItem *)tmp)->level = -1; + + uint16 ix = *index; + + if (ix == item) + return; + + *index = item; + index = &tmp->nextAssignedObject; + + while (*index) { + tmp = findObject(*index); + index = &tmp->nextAssignedObject; + } + + *index = ix; +} + +void LoLEngine::loadLevelWallData(int index, bool mapShapes) { + Common::String filename = Common::String::format("LEVEL%d.WLL", index); + + uint32 size; + uint8 *file = _res->fileData(filename.c_str(), &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] = assignLevelDecorationShapes(sh); + else + _wllShapeMap[c] = *d; + } + d += 2; + _specialWallTypes[c] = *d; + d += 2; + _wllWallFlags[c] = *d; + d += 2; + _wllAutomapData[c] = *d; + d += 2; + } + + delete[] file; + + delete _lvlShpFileHandle; + _lvlShpFileHandle = 0; +} + +int LoLEngine::assignLevelDecorationShapes(int index) { + uint16 *p1 = (uint16 *)_tempBuffer5120; + uint16 *p2 = (uint16 *)(_tempBuffer5120 + 4000); + + uint16 r = p2[index]; + if (r) + return r; + + uint16 o = _mappedDecorationsCount++; + + memcpy(&_levelDecorationProperties[o], &_levelDecorationData[index], sizeof(LevelDecorationProperty)); + + for (int i = 0; i < 10; i++) { + uint16 t = _levelDecorationProperties[o].shapeIndex[i]; + if (t == 0xFFFF) + continue; + + uint16 pv = p1[t]; + if (pv) { + _levelDecorationProperties[o].shapeIndex[i] = pv; + } else { + releaseDecorations(_lvlShapeIndex, 1); + _levelDecorationShapes[_lvlShapeIndex] = getLevelDecorationShapes(t); + p1[t] = _lvlShapeIndex; + _levelDecorationProperties[o].shapeIndex[i] = _lvlShapeIndex++; + } + } + + p2[index] = o; + if (_levelDecorationProperties[o].next) + _levelDecorationProperties[o].next = assignLevelDecorationShapes(_levelDecorationProperties[o].next); + + return o; +} + +uint8 *LoLEngine::getLevelDecorationShapes(int shapeIndex) { + if (_decorationCount <= shapeIndex) + return 0; + + _lvlShpFileHandle->seek(shapeIndex * 4 + 2, SEEK_SET); + uint32 offs = _lvlShpFileHandle->readUint32LE() + 2; + _lvlShpFileHandle->seek(offs, SEEK_SET); + + uint8 tmp[16]; + _lvlShpFileHandle->read(tmp, 16); + uint16 size = _screen->getShapeSize(tmp); + + _lvlShpFileHandle->seek(offs, SEEK_SET); + uint8 *res = new uint8[size]; + _lvlShpFileHandle->read(res, size); + + return res; +} + +void LoLEngine::releaseDecorations(int first, int num) { + for (int i = first; i < (first + num); i++) { + delete[] _levelDecorationShapes[i]; + _levelDecorationShapes[i] = 0; + } +} + +void LoLEngine::loadBlockProperties(const char *cmzFile) { + memset(_levelBlockProperties, 0, 1024 * sizeof(LevelBlockProperty)); + _screen->loadBitmap(cmzFile, 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++) + _levelBlockProperties[i].walls[ii] = p[i * len + ii]; + + _levelBlockProperties[i].direction = 5; + + if (_wllAutomapData[_levelBlockProperties[i].walls[0]] == 17) { + _levelBlockProperties[i].flags &= 0xEF; + _levelBlockProperties[i].flags |= 0x20; + } + } +} + +const uint8 *LoLEngine::getBlockFileData(int levelIndex) { + _screen->loadBitmap(Common::String::format("LEVEL%d.CMZ", levelIndex).c_str(), 15, 15, 0); + return _screen->getCPagePtr(14); +} + +void LoLEngine::loadLevelShpDat(const char *shpFile, const char *datFile, bool flag) { + memset(_tempBuffer5120, 0, 5120); + + _lvlShpFileHandle = _res->createReadStream(shpFile); + _decorationCount = _lvlShpFileHandle->readUint16LE(); + + Common::SeekableReadStream *s = _res->createReadStream(datFile); + + _levelDecorationDataSize = s->readUint16LE(); + delete[] _levelDecorationData; + _levelDecorationData = new LevelDecorationProperty[_levelDecorationDataSize]; + for (int i = 0; i < _levelDecorationDataSize; i++) { + LevelDecorationProperty *l = &_levelDecorationData[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->readSint16LE(); + for (int ii = 0; ii < 10; ii++) + l->shapeY[ii] = s->readSint16LE(); + l->next = s->readByte(); + l->flags = s->readByte(); + } + + delete s; + + if (!flag) { + _mappedDecorationsCount = 1; + _lvlShapeIndex = 1; + } +} + +void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight, int vcnLen, int vmpLen, const char *palFile) { + if (file) { + _lastSpecialColor = specialColor; + _lastSpecialColorWeight = weight; + strcpy(_lastBlockDataFile, file); + if (palFile) + _lastOverridePalFile = palFile; + else + _lastOverridePalFile.clear(); + } + + if (_flags.use16ColorMode) { + if (_lastSpecialColor == 1) + _lastSpecialColor = 0x44; + else if (_lastSpecialColor == 0x66) + _lastSpecialColor = scumm_stricmp(_lastBlockDataFile, "YVEL2") ? 0xCC : 0x44; + else if (_lastSpecialColor == 0x6B) + _lastSpecialColor = 0xCC; + else + _lastSpecialColor = 0x44; + } + + Common::String fname; + const uint8 *v = 0; + int tlen = 0; + + if (_flags.use16ColorMode) { + fname = Common::String::format("%s.VCF", _lastBlockDataFile); + _screen->loadBitmap(fname.c_str(), 3, 3, 0); + v = _screen->getCPagePtr(2); + tlen = READ_LE_UINT16(v) << 5; + v += 2; + + delete[] _vcfBlocks; + _vcfBlocks = new uint8[tlen]; + + memcpy(_vcfBlocks, v, tlen); + } + + fname = Common::String::format("%s.VCN", _lastBlockDataFile); + _screen->loadBitmap(fname.c_str(), 3, 3, 0); + v = _screen->getCPagePtr(2); + tlen = READ_LE_UINT16(v); + v += 2; + + if (vcnLen == -1) + vcnLen = tlen << 5; + + delete[] _vcnBlocks; + _vcnBlocks = new uint8[vcnLen]; + + if (!_flags.use16ColorMode) { + delete[] _vcnShift; + _vcnShift = new uint8[tlen]; + + memcpy(_vcnShift, v, tlen); + v += tlen; + + memcpy(_vcnColTable, v, 128); + v += 128; + + if (!_lastOverridePalFile.empty()) { + _res->loadFileToBuf(_lastOverridePalFile.c_str(), _screen->getPalette(0).getData(), 384); + } else { + _screen->getPalette(0).copy(v, 0, 128); + } + + v += 384; + } + + if (_currentLevel == 11) { + if (_flags.use16ColorMode) { + _screen->loadPalette("LOLICE.NOL", _screen->getPalette(2)); + + } else { + _screen->loadPalette("SWAMPICE.COL", _screen->getPalette(2)); + _screen->getPalette(2).copy(_screen->getPalette(0), 128); + } + + if (_flagsTable[52] & 0x04) { + uint8 *pal0 = _screen->getPalette(0).getData(); + uint8 *pal2 = _screen->getPalette(2).getData(); + for (int i = 1; i < _screen->getPalette(0).getNumColors() * 3; i++) + SWAP(pal0[i], pal2[i]); + } + } + + memcpy(_vcnBlocks, v, vcnLen); + v += vcnLen; + + fname = Common::String::format("%s.VMP", _lastBlockDataFile); + _screen->loadBitmap(fname.c_str(), 3, 3, 0); + v = _screen->getCPagePtr(2); + + if (vmpLen == -1) + vmpLen = READ_LE_UINT16(v); + v += 2; + + delete[] _vmpPtr; + _vmpPtr = new uint16[vmpLen]; + + for (int i = 0; i < vmpLen; i++) + _vmpPtr[i] = READ_LE_UINT16(&v[i << 1]); + + Palette tpal(256); + if (_flags.use16ColorMode) { + uint8 *dst = tpal.getData(); + _res->loadFileToBuf("LOL.NOL", dst, 48); + for (int i = 1; i < 16; i++) { + int s = ((i << 4) | i) * 3; + SWAP(dst[s], dst[i * 3]); + SWAP(dst[s + 1], dst[i * 3 + 1]); + SWAP(dst[s + 2], dst[i * 3 + 2]); + } + } else { + tpal.copy(_screen->getPalette(0)); + } + + for (int i = 0; i < 7; i++) { + weight = 100 - (i * _lastSpecialColorWeight); + weight = (weight > 0) ? (weight * 255) / 100 : 0; + _screen->generateOverlay(tpal, _screen->getLevelOverlay(i), _lastSpecialColor, weight); + + int l = _flags.use16ColorMode ? 256 : 128; + uint8 *levelOverlay = _screen->getLevelOverlay(i); + for (int ii = 0; ii < l; ii++) { + if (levelOverlay[ii] == 255) + levelOverlay[ii] = 0; + } + + for (int ii = l; ii < 256; ii++) + levelOverlay[ii] = ii & 0xFF; + } + + uint8 *levelOverlay = _screen->getLevelOverlay(7); + for (int i = 0; i < 256; i++) + levelOverlay[i] = i & 0xFF; + + if (_flags.use16ColorMode) { + _screen->getLevelOverlay(6)[0xEE] = 0xEE; + if (_lastSpecialColor == 0x44) + _screen->getLevelOverlay(5)[0xEE] = 0xEE; + + for (int i = 0; i < 7; i++) + memcpy(_screen->getLevelOverlay(i), _screen->getLevelOverlay(i + 1), 256); + + _screen->loadPalette("LOL.NOL", _screen->getPalette(0)); + + for (int i = 0; i < 8; i++) { + uint8 *pl = _screen->getLevelOverlay(7 - i); + for (int ii = 0; ii < 16; ii++) + _vcnColTable[(i << 4) + ii] = pl[(ii << 4) | ii]; + } + } + + _loadSuppFilesFlag = 0; + generateBrightnessPalette(_screen->getPalette(0), _screen->getPalette(1), _brightness, _lampEffect); + + if (_flags.isTalkie) { + Common::SeekableReadStream *s = _res->createReadStream(Common::String::format("LEVEL%.02d.TLC", _currentLevel)); + s->read(_transparencyTable1, 256); + s->read(_transparencyTable2, 5120); + delete s; + } else { + createTransparencyTables(); + } + + _loadSuppFilesFlag = 1; +} + +void LoLEngine::resetItems(int flag) { + for (int i = 0; i < 1024; i++) { + _levelBlockProperties[i].direction = 5; + uint16 id = _levelBlockProperties[i].assignedObjects; + LoLObject *r = 0; + + while (id & 0x8000) { + r = findObject(id); + id = r->nextAssignedObject; + } + + if (!id) + continue; + + LoLItem *it = &_itemsInPlay[id]; + it->level = _currentLevel; + it->block = i; + if (r) + r->nextAssignedObject = 0; + } + + if (flag) + memset(_flyingObjects, 0, 8 * sizeof(FlyingObject)); +} + +void LoLEngine::disableMonsters() { + memset(_monsters, 0, 30 * sizeof(LoLMonster)); + for (int i = 0; i < 30; i++) + _monsters[i].mode = 0x10; +} + +void LoLEngine::resetBlockProperties() { + for (int i = 0; i < 1024; i++) { + LevelBlockProperty *l = &_levelBlockProperties[i]; + if (l->flags & 0x10) { + l->flags &= 0xEF; + if (testWallInvisibility(i, 0) && testWallInvisibility(i, 1)) + l->flags |= 0x40; + } else { + if (l->flags & 0x40) + l->flags &= 0xBF; + else if (l->flags & 0x80) + l->flags &= 0x7F; + } + } +} + +bool LoLEngine::testWallFlag(int block, int direction, int flag) { + if (_levelBlockProperties[block].flags & 0x10) + return true; + + if (direction != -1) + return (_wllWallFlags[_levelBlockProperties[block].walls[direction ^ 2]] & flag) ? true : false; + + for (int i = 0; i < 4; i++) { + if (_wllWallFlags[_levelBlockProperties[block].walls[i]] & flag) + return true; + } + + return false; +} + +bool LoLEngine::testWallInvisibility(int block, int direction) { + uint8 w = _levelBlockProperties[block].walls[direction]; + if (_wllVmpMap[w] || _wllShapeMap[w] || _levelBlockProperties[block].flags & 0x80) + return false; + return true; +} + +void LoLEngine::resetLampStatus() { + _flagsTable[31] |= 0x04; + _lampEffect = -1; + updateLampStatus(); +} + +void LoLEngine::setLampMode(bool lampOn) { + _flagsTable[31] &= 0xFB; + if (!(_flagsTable[31] & 0x08) || !lampOn) + return; + + _screen->drawShape(0, _gameShapes[_flags.isTalkie ? 43 : 41], 291, 56, 0, 0); + _lampEffect = 8; +} + +void LoLEngine::updateLampStatus() { + int8 newLampEffect = 0; + uint8 tmpOilStatus = 0; + + if ((_updateFlags & 4) || !(_flagsTable[31] & 0x08)) + return; + + if (!_brightness || !_lampOilStatus) { + newLampEffect = 8; + if (newLampEffect != _lampEffect && _screen->_fadeFlag == 0) + setPaletteBrightness(_screen->getPalette(0), _brightness, newLampEffect); + } else { + tmpOilStatus = (_lampOilStatus < 100) ? _lampOilStatus : 100; + newLampEffect = (3 - ((tmpOilStatus - 1) / 25)) << 1; + + if (_lampEffect == -1) { + if (_screen->_fadeFlag == 0) + setPaletteBrightness(_screen->getPalette(0), _brightness, newLampEffect); + _lampStatusTimer = _system->getMillis() + (10 + rollDice(1, 30)) * _tickLength; + } else { + if ((_lampEffect & 0xFE) == (newLampEffect & 0xFE)) { + if (_system->getMillis() <= _lampStatusTimer) { + newLampEffect = _lampEffect; + } else { + newLampEffect = _lampEffect ^ 1; + _lampStatusTimer = _system->getMillis() + (10 + rollDice(1, 30)) * _tickLength; + } + } else { + if (_screen->_fadeFlag == 0) + setPaletteBrightness(_screen->getPalette(0), _brightness, newLampEffect); + } + } + } + + if (newLampEffect == _lampEffect) + return; + + _screen->hideMouse(); + + _screen->drawShape(_screen->_curPage, _gameShapes[(_flags.isTalkie ? 35 : 33) + newLampEffect], 291, 56, 0, 0); + _screen->showMouse(); + + _lampEffect = newLampEffect; +} + +void LoLEngine::updateCompass() { + if (!(_flagsTable[31] & 0x40) || (_updateFlags & 4)) + return; + + if (_compassDirection == -1) { + _compassStep = 0; + gui_drawCompass(); + return; + } + + if (_compassTimer >= _system->getMillis()) + return; + + if ((_currentDirection << 6) == _compassDirection && (!_compassStep)) + return; + + _compassTimer = _system->getMillis() + 3 * _tickLength; + int dir = _compassStep >= 0 ? 1 : -1; + if (_compassStep) + _compassStep -= (((ABS(_compassStep) >> 4) + 2) * dir); + + int16 diff = _compassBroken ? (int8(_rnd.getRandomNumber(255)) - _compassDirection) : (_currentDirection << 6) - _compassDirection; + if (diff <= -128) + diff += 256; + if (diff >= 128) + diff -= 256; + + diff >>= 2; + _compassStep += diff; + _compassStep = CLIP(_compassStep, -24, 24); + _compassDirection += _compassStep; + + if (_compassDirection < 0) + _compassDirection += 256; + if (_compassDirection > 255) + _compassDirection -= 256; + + if (((((_compassDirection + 3) & 0xFD) >> 6) == _currentDirection) && (_compassStep < 2) && (ABS(diff) < 4)) { + _compassDirection = _currentDirection << 6; + _compassStep = 0; + } + + gui_drawCompass(); +} + +void LoLEngine::moveParty(uint16 direction, int unk1, int unk2, int buttonShape) { + if (buttonShape) + gui_toggleButtonDisplayMode(buttonShape, 1); + + uint16 opos = _currentBlock; + uint16 npos = calcNewBlockPosition(_currentBlock, direction); + + if (!checkBlockPassability(npos, direction)) { + notifyBlockNotPassable(unk2 ? 0 : 1); + gui_toggleButtonDisplayMode(buttonShape, 0); + return; + } + + _scriptDirection = direction; + _currentBlock = npos; + _sceneDefaultUpdate = 1; + + calcCoordinates(_partyPosX, _partyPosY, _currentBlock, 0x80, 0x80); + _flagsTable[73] &= 0xFD; + + runLevelScript(opos, 4); + runLevelScript(npos, 1); + + if (!(_flagsTable[73] & 0x02)) { + initTextFading(2, 0); + + if (_sceneDefaultUpdate) { + switch (unk2) { + case 0: + movePartySmoothScrollUp(2); + break; + case 1: + movePartySmoothScrollDown(2); + break; + case 2: + movePartySmoothScrollLeft(1); + break; + case 3: + movePartySmoothScrollRight(1); + break; + default: + break; + } + } else { + gui_drawScene(0); + } + + gui_toggleButtonDisplayMode(buttonShape, 0); + + if (npos == _currentBlock) { + runLevelScript(opos, 8); + runLevelScript(npos, 2); + + if (_levelBlockProperties[npos].walls[0] == 0x1A) + memset(_levelBlockProperties[npos].walls, 0, 4); + } + } + + updateAutoMap(_currentBlock); +} + +uint16 LoLEngine::calcBlockIndex(uint16 x, uint16 y) { + return (((y & 0xFF00) >> 3) | (x >> 8)) & 0x3FF; +} + +void LoLEngine::calcCoordinates(uint16 &x, uint16 &y, int block, uint16 xOffs, uint16 yOffs) { + x = (block & 0x1F) << 8 | xOffs; + y = ((block & 0xFFE0) << 3) | yOffs; +} + +void LoLEngine::calcCoordinatesForSingleCharacter(int charNum, uint16 &x, uint16 &y) { + static const uint8 xOffsets[] = { 0x80, 0x00, 0x00, 0x40, 0xC0, 0x00, 0x40, 0x80, 0xC0 }; + int c = countActiveCharacters(); + if (!c) + return; + + c = (c - 1) * 3 + charNum; + + x = xOffsets[c]; + y = 0x80; + + calcCoordinatesAddDirectionOffset(x, y, _currentDirection); + + x |= (_partyPosX & 0xFF00); + y |= (_partyPosY & 0xFF00); +} + +void LoLEngine::calcCoordinatesAddDirectionOffset(uint16 &x, uint16 &y, int direction) { + if (!direction) + return; + + int tx = x; + int ty = y; + + if (direction & 1) + SWAP(tx, ty); + + if (direction != 1) + ty = (ty - 256) * -1; + + if (direction != 3) { + tx = (tx - 256) * -1; + } + + x = tx; + y = ty; +} + +bool LoLEngine::checkBlockPassability(uint16 block, uint16 direction) { + if (testWallFlag(block, direction, 1)) + return false; + + uint16 d = _levelBlockProperties[block].assignedObjects; + + while (d) { + if (d & 0x8000) + return false; + d = findObject(d)->nextAssignedObject; + } + + return true; +} + +void LoLEngine::notifyBlockNotPassable(int scrollFlag) { + if (scrollFlag) + movePartySmoothScrollBlocked(2); + + snd_stopSpeech(true); + _txt->printMessage(0x8002, "%s", getLangString(0x403F)); + snd_playSoundEffect(19, -1); +} + +int LoLEngine::clickedDoorSwitch(uint16 block, uint16 direction) { + uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]]; + if (!clickedShape(v)) + return 0; + + snd_playSoundEffect(78, -1); + _blockDoor = 0; + runLevelScript(block, 0x40); + + if (!_blockDoor) { + delay(15 * _tickLength); + processDoorSwitch(block, 0); + } + + return 1; +} + +int LoLEngine::clickedNiche(uint16 block, uint16 direction) { + uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]]; + if (!clickedShape(v) || !_itemInHand) + return 0; + + uint16 x = 0x80; + uint16 y = 0xFF; + calcCoordinatesAddDirectionOffset(x, y, _currentDirection); + calcCoordinates(x, y, block, x, y); + setItemPosition(_itemInHand, x, y, 8, 1); + setHandItem(0); + return 1; +} + +void LoLEngine::movePartySmoothScrollBlocked(int speed) { + if (!_smoothScrollingEnabled || (_smoothScrollingEnabled && _needSceneRestore)) + return; + + _screen->backupSceneWindow(_sceneDrawPage2 == 2 ? 2 : 6, 6); + + for (int i = 0; i < 2; i++) { + uint32 delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollZoomStepTop(6, 2, _scrollXTop[i], _scrollYTop[i]); + _screen->smoothScrollZoomStepBottom(6, 2, _scrollXBottom[i], _scrollYBottom[i]); + _screen->restoreSceneWindow(2, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + if (!_smoothScrollModeNormal) + i++; + } + + for (int i = 2; i; i--) { + uint32 delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollZoomStepTop(6, 2, _scrollXTop[i], _scrollYTop[i]); + _screen->smoothScrollZoomStepBottom(6, 2, _scrollXBottom[i], _scrollYBottom[i]); + _screen->restoreSceneWindow(2, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + if (!_smoothScrollModeNormal) + i++; + } + + if (_sceneDefaultUpdate != 2) { + _screen->restoreSceneWindow(6, 0); + _screen->updateScreen(); + } + + updateDrawPage2(); +} + +void LoLEngine::movePartySmoothScrollUp(int speed) { + if (!_smoothScrollingEnabled || (_smoothScrollingEnabled && _needSceneRestore)) + return; + + int d = 0; + + if (_sceneDrawPage2 == 2) { + d = smoothScrollDrawSpecialGuiShape(6); + gui_drawScene(6); + _screen->backupSceneWindow(6, 12); + _screen->backupSceneWindow(2, 6); + } else { + d = smoothScrollDrawSpecialGuiShape(2); + gui_drawScene(2); + _screen->backupSceneWindow(2, 12); + _screen->backupSceneWindow(6, 6); + } + + for (int i = 0; i < 5; i++) { + uint32 delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollZoomStepTop(6, 2, _scrollXTop[i], _scrollYTop[i]); + _screen->smoothScrollZoomStepBottom(6, 2, _scrollXBottom[i], _scrollYBottom[i]); + + if (d) + _screen->copyGuiShapeToSurface(14, 2); + + _screen->restoreSceneWindow(2, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + if (!_smoothScrollModeNormal) + i++; + } + + if (d) + _screen->copyGuiShapeToSurface(14, 12); + + if (_sceneDefaultUpdate != 2) { + _screen->restoreSceneWindow(12, 0); + _screen->updateScreen(); + } + + updateDrawPage2(); +} + +void LoLEngine::movePartySmoothScrollDown(int speed) { + if (!_smoothScrollingEnabled) + return; + + int d = smoothScrollDrawSpecialGuiShape(2); + gui_drawScene(2); + _screen->backupSceneWindow(2, 6); + + for (int i = 4; i >= 0; i--) { + uint32 delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollZoomStepTop(6, 2, _scrollXTop[i], _scrollYTop[i]); + _screen->smoothScrollZoomStepBottom(6, 2, _scrollXBottom[i], _scrollYBottom[i]); + + if (d) + _screen->copyGuiShapeToSurface(14, 2); + + _screen->restoreSceneWindow(2, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + if (!_smoothScrollModeNormal) + i++; + } + + if (d) + _screen->copyGuiShapeToSurface(14, 12); + + if (_sceneDefaultUpdate != 2) { + _screen->restoreSceneWindow(6, 0); + _screen->updateScreen(); + } + + updateDrawPage2(); +} + +void LoLEngine::movePartySmoothScrollLeft(int speed) { + if (!_smoothScrollingEnabled) + return; + + speed <<= 1; + + gui_drawScene(_sceneDrawPage1); + + for (int i = 88, d = 88; i > 22; i -= 22, d += 22) { + uint32 delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollHorizontalStep(_sceneDrawPage2, 66, d, i); + _screen->copyRegion(112 + i, 0, 112, 0, d, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + } + + if (_sceneDefaultUpdate != 2) { + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + } + + SWAP(_sceneDrawPage1, _sceneDrawPage2); +} + +void LoLEngine::movePartySmoothScrollRight(int speed) { + if (!_smoothScrollingEnabled) + return; + + speed <<= 1; + + gui_drawScene(_sceneDrawPage1); + + uint32 delayTimer = _system->getMillis() + speed * _tickLength; + _screen->copyRegion(112, 0, 222, 0, 66, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + + delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollHorizontalStep(_sceneDrawPage2, 22, 0, 66); + _screen->copyRegion(112, 0, 200, 0, 88, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + + delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollHorizontalStep(_sceneDrawPage2, 44, 0, 22); + _screen->copyRegion(112, 0, 178, 0, 110, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + + if (_sceneDefaultUpdate != 2) { + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + } + + SWAP(_sceneDrawPage1, _sceneDrawPage2); +} + +void LoLEngine::movePartySmoothScrollTurnLeft(int speed) { + if (!_smoothScrollingEnabled) + return; + + speed <<= 1; + + int d = smoothScrollDrawSpecialGuiShape(_sceneDrawPage1); + gui_drawScene(_sceneDrawPage1); + int dp = _sceneDrawPage2 == 2 ? _sceneDrawPage2 : _sceneDrawPage1; + + uint32 delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollTurnStep1(_sceneDrawPage1, _sceneDrawPage2, dp); + if (d) + _screen->copyGuiShapeToSurface(14, dp); + _screen->restoreSceneWindow(dp, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + + delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollTurnStep2(_sceneDrawPage1, _sceneDrawPage2, dp); + if (d) + _screen->copyGuiShapeToSurface(14, dp); + _screen->restoreSceneWindow(dp, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + + delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollTurnStep3(_sceneDrawPage1, _sceneDrawPage2, dp); + if (d) + _screen->copyGuiShapeToSurface(14, dp); + _screen->restoreSceneWindow(dp, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + + if (_sceneDefaultUpdate != 2) { + drawSpecialGuiShape(_sceneDrawPage1); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + } +} + +void LoLEngine::movePartySmoothScrollTurnRight(int speed) { + if (!_smoothScrollingEnabled) + return; + + speed <<= 1; + + int d = smoothScrollDrawSpecialGuiShape(_sceneDrawPage1); + gui_drawScene(_sceneDrawPage1); + int dp = _sceneDrawPage2 == 2 ? _sceneDrawPage2 : _sceneDrawPage1; + + uint32 delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollTurnStep3(_sceneDrawPage2, _sceneDrawPage1, dp); + if (d) + _screen->copyGuiShapeToSurface(14, dp); + _screen->restoreSceneWindow(dp, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + + delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollTurnStep2(_sceneDrawPage2, _sceneDrawPage1, dp); + if (d) + _screen->copyGuiShapeToSurface(14, dp); + _screen->restoreSceneWindow(dp, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + + delayTimer = _system->getMillis() + speed * _tickLength; + _screen->smoothScrollTurnStep1(_sceneDrawPage2, _sceneDrawPage1, dp); + if (d) + _screen->copyGuiShapeToSurface(14, dp); + _screen->restoreSceneWindow(dp, 0); + _screen->updateScreen(); + fadeText(); + delayUntil(delayTimer); + + if (_sceneDefaultUpdate != 2) { + drawSpecialGuiShape(_sceneDrawPage1); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + } +} + +void LoLEngine::pitDropScroll(int numSteps) { + _screen->copyRegionSpecial(0, 320, 200, 112, 0, 6, 176, 120, 0, 0, 176, 120, 0); + uint32 etime = 0; + + for (int i = 0; i < numSteps; i++) { + etime = _system->getMillis() + _tickLength; + int ys = ((30720 / numSteps) * i) >> 8; + _screen->copyRegionSpecial(6, 176, 120, 0, ys, 0, 320, 200, 112, 0, 176, 120 - ys, 0); + _screen->copyRegionSpecial(2, 320, 200, 112, 0, 0, 320, 200, 112, 120 - ys, 176, ys, 0); + _screen->updateScreen(); + + delayUntil(etime); + } + + etime = _system->getMillis() + _tickLength; + + _screen->copyRegionSpecial(2, 320, 200, 112, 0, 0, 320, 200, 112, 0, 176, 120, 0); + _screen->updateScreen(); + + delayUntil(etime); + + updateDrawPage2(); +} + +void LoLEngine::shakeScene(int duration, int width, int height, int restore) { + _screen->copyRegion(112, 0, 112, 0, 176, 120, 0, 6, Screen::CR_NO_P_CHECK); + uint32 endTime = _system->getMillis() + duration * _tickLength; + + while (endTime > _system->getMillis()) { + uint32 delayTimer = _system->getMillis() + 2 * _tickLength; + + int s1 = width ? (_rnd.getRandomNumber(255) % (width << 1)) - width : 0; + int s2 = height ? (_rnd.getRandomNumber(255) % (height << 1)) - height : 0; + + int x1, y1, x2, y2, w, h; + if (s1 >= 0) { + x1 = 112; + x2 = 112 + s1; + w = 176 - s1; + } else { + x1 = 112 - s1; + x2 = 112; + w = 176 + s1; + } + + if (s2 >= 0) { + y1 = 0; + y2 = s2; + h = 120 - s2; + } else { + y1 = -s2; + y2 = 0; + h = 120 + s2; + } + + _screen->copyRegion(x1, y1, x2, y2, w, h, 6, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + + delayUntil(delayTimer); + } + + if (restore) { + _screen->copyRegion(112, 0, 112, 0, 176, 120, 6, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + updateDrawPage2(); + } +} + +void LoLEngine::processGasExplosion(int soundId) { + int cp = _screen->setCurPage(2); + _screen->copyPage(0, 12); + + static const uint8 sounds[] = { 0x62, 0xA7, 0xA7, 0xA8 }; + snd_playSoundEffect(sounds[soundId], -1); + + uint16 targetBlock = 0; + int dist = getSpellTargetBlock(_currentBlock, _currentDirection, 3, targetBlock); + + uint8 *p1 = _screen->getPalette(1).getData(); + uint8 *p2 = _screen->getPalette(3).getData(); + + if (dist) { + WSAMovie_v2 *mov = new WSAMovie_v2(this); + Common::String file = Common::String::format("gasexp%0d.wsa", dist); + mov->open(file.c_str(), 1, 0); + if (!mov->opened()) + error("Gas: Unable to load gasexp.wsa"); + + playSpellAnimation(mov, 0, 6, 1, (176 - mov->width()) / 2 + 112, (120 - mov->height()) / 2, 0, 0, 0, 0, false); + + mov->close(); + delete mov; + + } else { + memcpy(p2, p1, 768); + + for (int i = 1; i < 128; i++) + p2[i * 3] = 0x3F; + + uint32 ctime = _system->getMillis(); + while (_screen->timedPaletteFadeStep(_screen->getPalette(0).getData(), p2, _system->getMillis() - ctime, 10)) + updateInput(); + + ctime = _system->getMillis(); + while (_screen->timedPaletteFadeStep(p2, _screen->getPalette(0).getData(), _system->getMillis() - ctime, 50)) + updateInput(); + } + + _screen->copyPage(12, 2); + _screen->setCurPage(cp); + + updateDrawPage2(); + _sceneUpdateRequired = true; + gui_drawScene(0); +} + +int LoLEngine::smoothScrollDrawSpecialGuiShape(int pageNum) { + if (!_specialGuiShape) + return 0; + + _screen->clearGuiShapeMemory(pageNum); + _screen->drawShape(pageNum, _specialGuiShape, _specialGuiShapeX, _specialGuiShapeY, 2, 0); + _screen->copyGuiShapeFromSceneBackupBuffer(pageNum, 14); + return 1; +} + +void LoLEngine::drawScene(int pageNum) { + if (pageNum && pageNum != _sceneDrawPage1) { + SWAP(_sceneDrawPage1, _sceneDrawPage2); + updateDrawPage2(); + } + + if (pageNum && pageNum != _sceneDrawPage1) { + SWAP(_sceneDrawPage1, _sceneDrawPage2); + updateDrawPage2(); + } + + generateBlockDrawingBuffer(); + drawVcnBlocks(); + drawSceneShapes(); + + if (!pageNum) { + drawSpecialGuiShape(_sceneDrawPage1); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, _sceneDrawPage2, Screen::CR_NO_P_CHECK); + _screen->copyRegion(112, 0, 112, 0, 176, 120, _sceneDrawPage1, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + SWAP(_sceneDrawPage1, _sceneDrawPage2); + } + + updateEnvironmentalSfx(0); + gui_drawCompass(); + + _sceneUpdateRequired = false; +} + + +void LoLEngine::setWallType(int block, int wall, int val) { + if (wall == -1) { + for (int i = 0; i < 4; i++) + _levelBlockProperties[block].walls[i] = val; + if (_wllAutomapData[val] == 17) { + _levelBlockProperties[block].flags &= 0xEF; + _levelBlockProperties[block].flags |= 0x20; + } else { + _levelBlockProperties[block].flags &= 0xDF; + } + } else { + _levelBlockProperties[block].walls[wall] = val; + } + + checkSceneUpdateNeed(block); +} + +void LoLEngine::updateDrawPage2() { + _screen->copyRegion(112, 0, 112, 0, 176, 120, 0, _sceneDrawPage2, Screen::CR_NO_P_CHECK); +} + +void LoLEngine::prepareSpecialScene(int fieldType, int hasDialogue, int suspendGui, int allowSceneUpdate, int controlMode, int fadeFlag) { + resetPortraitsAndDisableSysTimer(); + if (fieldType) { + if (suspendGui) + gui_specialSceneSuspendControls(1); + + if (!allowSceneUpdate) + _sceneDefaultUpdate = 0; + + if (hasDialogue) + initDialogueSequence(fieldType, 0); + + if (fadeFlag) { + if (_flags.use16ColorMode) + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); + else + _screen->fadePalette(_screen->getPalette(3), 10); + _screen->_fadeFlag = 0; + } + + setSpecialSceneButtons(0, 0, 320, 130, controlMode); + + } else { + if (suspendGui) + gui_specialSceneSuspendControls(0); + + if (!allowSceneUpdate) + _sceneDefaultUpdate = 0; + + gui_disableControls(controlMode); + + if (fadeFlag) { + if (_flags.use16ColorMode) { + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); + } else { + _screen->getPalette(3).copy(_screen->getPalette(0), 128); + _screen->loadSpecialColors(_screen->getPalette(3)); + _screen->fadePalette(_screen->getPalette(3), 10); + } + _screen->_fadeFlag = 0; + } + + if (hasDialogue) + initDialogueSequence(fieldType, 0); + + setSpecialSceneButtons(112, 0, 176, 120, controlMode); + } +} + +int LoLEngine::restoreAfterSpecialScene(int fadeFlag, int redrawPlayField, int releaseTimScripts, int sceneUpdateMode) { + if (!_needSceneRestore) + return 0; + + _needSceneRestore = 0; + enableSysTimer(2); + + if (_dialogueField) + restoreAfterDialogueSequence(_currentControlMode); + + if (_specialSceneFlag) + gui_specialSceneRestoreControls(_currentControlMode); + + int l = _currentControlMode; + _currentControlMode = 0; + + gui_specialSceneRestoreButtons(); + calcCharPortraitXpos(); + + _currentControlMode = l; + + if (releaseTimScripts) { + for (int i = 0; i < TIM::kWSASlots; i++) + _tim->freeAnimStruct(i); + + for (int i = 0; i < 10; i++) + _tim->unload(_activeTim[i]); + } + + gui_enableControls(); + + if (fadeFlag) { + if ((_screen->_fadeFlag != 1 && _screen->_fadeFlag != 2) || (_screen->_fadeFlag == 1 && _currentControlMode)) { + if (_currentControlMode) + _screen->fadeToBlack(10); + else + _screen->fadeClearSceneWindow(10); + } + + _currentControlMode = 0; + calcCharPortraitXpos(); + + if (redrawPlayField) + gui_drawPlayField(); + + setPaletteBrightness(_screen->getPalette(0), _brightness, _lampEffect); + + } else { + _currentControlMode = 0; + calcCharPortraitXpos(); + + if (redrawPlayField) + gui_drawPlayField(); + } + + _sceneDefaultUpdate = sceneUpdateMode; + return 1; +} + +void LoLEngine::setSequenceButtons(int x, int y, int w, int h, int enableFlags) { + gui_enableSequenceButtons(x, y, w, h, enableFlags); + _seqWindowX1 = x; + _seqWindowY1 = y; + _seqWindowX2 = x + w; + _seqWindowY2 = y + h; + int offs = _itemInHand ? 10 : 0; + _screen->setMouseCursor(offs, offs, getItemIconShapePtr(_itemInHand)); + _currentFloatingCursor = -1; + if (w == 320) { + setLampMode(0); + _lampStatusSuspended = true; + } +} + +void LoLEngine::setSpecialSceneButtons(int x, int y, int w, int h, int enableFlags) { + gui_enableSequenceButtons(x, y, w, h, enableFlags); + _spsWindowX = x; + _spsWindowY = y; + _spsWindowW = w; + _spsWindowH = h; +} + +void LoLEngine::setDefaultButtonState() { + gui_enableDefaultPlayfieldButtons(); + _seqWindowX1 = _seqWindowY1 = _seqWindowX2 = _seqWindowY2 = _seqTrigger = 0; + if (_lampStatusSuspended) + resetLampStatus(); + _lampStatusSuspended = false; +} + +void LoLEngine::drawSceneShapes(int) { + for (int i = 0; i < 18; i++) { + uint8 t = _dscTileIndex[i]; + uint8 s = _visibleBlocks[t]->walls[_sceneDrawVarDown]; + + _shpDmX1 = 0; + _shpDmX2 = 0; + + int16 dimY1 = 0; + int16 dimY2 = 0; + + setLevelShapesDim(t, _shpDmX1, _shpDmX2, _sceneShpDim); + + if (_shpDmX2 <= _shpDmX1) + continue; + + drawDecorations(t); + + uint16 w = _wllWallFlags[s]; + + if (t == 16) + w |= 0x80; + + drawBlockEffects(t, 0); + + if (_visibleBlocks[t]->assignedObjects && (w & 0x80)) + drawBlockObjects(t); + + drawBlockEffects(t, 1); + + if (!(w & 8)) + continue; + + uint16 v = 20 * (s - (s < 23 ? _dscDoorScaleOffs[s] : 0)); + if (v > 80) + v = 80; + + setDoorShapeDim(t, dimY1, dimY2, _sceneShpDim); + drawDoor(_doorShapes[(s < 23 ? _dscDoorShpIndex[s] : 0)], 0, t, 10, 0, -v, 2); + setLevelShapesDim(t, dimY1, dimY2, _sceneShpDim); + } +} + +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[4 + _dscDimMap[index] * 5] + 2; + if (ovlIndex > 7) + ovlIndex = 7; + + if (!scaleW || !scaleH) + continue; + + uint8 d = (_currentDirection + _dscWalls[s]) & 3; + int8 l = _wllShapeMap[_visibleBlocks[index]->walls[d]]; + + uint8 *shapeData = 0; + + int x = 0; + int y = 0; + int flags = 0; + + while (l > 0) { + if ((_levelDecorationProperties[l].flags & 8) && index != 3 && index != 9 && index != 13) { + l = _levelDecorationProperties[l].next; + continue; + } + + if (_dscOvlMap[shpIx] == 1 && ((_levelDecorationProperties[l].flags & 2) || ((_levelDecorationProperties[l].flags & 4) && _wllProcessFlag))) + ix = -ix; + + int xOffs = 0; + int yOffs = 0; + uint8 *ovl = 0; + + if (_levelDecorationProperties[l].scaleFlag[shpIx] & 1) { + xOffs = _levelDecorationProperties[l].shapeX[shpIx]; + yOffs = _levelDecorationProperties[l].shapeY[shpIx]; + shpIx = _dscOvlMap[shpIx]; + int ov = ovlIndex; + if (_flags.use16ColorMode) { + uint8 bb = _blockBrightness >> 4; + if (ov > bb) + ov -= bb; + else + ov = 0; + } + ovl = _screen->getLevelOverlay(ov); + } else if (_levelDecorationProperties[l].shapeIndex[shpIx] != 0xFFFF) { + scaleW = scaleH = 0x100; + int ov = 7; + if (_flags.use16ColorMode) { + uint8 bb = _blockBrightness >> 4; + if (ov > bb) + ov -= bb; + else + ov = 0; + } + ovl = _screen->getLevelOverlay(ov); + } + + if (_levelDecorationProperties[l].shapeIndex[shpIx] != 0xFFFF) { + shapeData = _levelDecorationShapes[_levelDecorationProperties[l].shapeIndex[shpIx]]; + if (shapeData) { + if (ix < 0) { + x = _dscShapeX[s] + xOffs + ((_levelDecorationProperties[l].shapeX[shpIx] * scaleW) >> 8); + if (ix == _dscShapeIndex[s]) { + x = _dscShapeX[s] - ((_levelDecorationProperties[l].shapeX[shpIx] * scaleW) >> 8) - + _screen->getShapeScaledWidth(shapeData, scaleW) - xOffs; + } + flags = 0x105; + } else { + x = _dscShapeX[s] + xOffs + ((_levelDecorationProperties[l].shapeX[shpIx] * scaleW) >> 8); + flags = 0x104; + } + + y = _dscShapeY[s] + yOffs + ((_levelDecorationProperties[l].shapeY[shpIx] * scaleH) >> 8); + _screen->drawShape(_sceneDrawPage1, shapeData, x + 112, y, _sceneShpDim, flags, ovl, 1, scaleW, scaleH); + + if ((_levelDecorationProperties[l].flags & 1) && shpIx < 4) { + //draw shadow + x += (_screen->getShapeScaledWidth(shapeData, scaleW)); + flags ^= 1; + _screen->drawShape(_sceneDrawPage1, shapeData, x + 112, y, _sceneShpDim, flags, ovl, 1, scaleW, scaleH); + } + } + } + + l = _levelDecorationProperties[l].next; + shpIx = (_dscShapeIndex[s] < 0) ? -_dscShapeIndex[s] : _dscShapeIndex[s]; + } + } +} + +void LoLEngine::drawBlockEffects(int index, int type) { + static const uint16 yOffs[] = { 0xFF, 0xFF, 0x80, 0x80 }; + uint8 flg = _visibleBlocks[index]->flags; + // flags: 0x10 = ice wall, 0x20 = teleporter, 0x40 = blue slime spot, 0x80 = blood spot + if (!(flg & 0xF0)) + return; + + type = (type == 0) ? 2 : 0; + + for (int i = 0; i < 2; i++, type++) { + if (!((0x10 << type) & flg)) + continue; + + uint16 x = 0x80; + uint16 y = yOffs[type]; + uint16 drawFlag = (type == 3) ? 0x80 : 0x20; + uint8 *ovl = (type == 3) ? _screen->_grayOverlay : 0; + + if (_flags.use16ColorMode) { + ovl = 0; + drawFlag = (type == 0 || type == 3) ? 0 : 0x20; + } + + calcCoordinatesAddDirectionOffset(x, y, _currentDirection); + + x |= ((_visibleBlockIndex[index] & 0x1F) << 8); + y |= ((_visibleBlockIndex[index] & 0xFFE0) << 3); + + drawItemOrMonster(_effectShapes[type], ovl, x, y, 0, (type == 1) ? -20 : 0, drawFlag, -1, false); + } +} + +void LoLEngine::drawSpecialGuiShape(int pageNum) { + if (!_specialGuiShape) + return; + + _screen->drawShape(pageNum, _specialGuiShape, _specialGuiShapeX, _specialGuiShapeY, 2, 0); + + if (_specialGuiShapeMirrorFlag & 1) + _screen->drawShape(pageNum, _specialGuiShape, _specialGuiShapeX + _specialGuiShape[3], _specialGuiShapeY, 2, 1); +} + +} // End of namespace Kyra + +#endif // ENABLE_LOL |