diff options
Diffstat (limited to 'engines/kyra/scene_hof.cpp')
-rw-r--r-- | engines/kyra/scene_hof.cpp | 763 |
1 files changed, 763 insertions, 0 deletions
diff --git a/engines/kyra/scene_hof.cpp b/engines/kyra/scene_hof.cpp new file mode 100644 index 0000000000..3fc7947253 --- /dev/null +++ b/engines/kyra/scene_hof.cpp @@ -0,0 +1,763 @@ +/* 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/kyra_hof.h" +#include "kyra/screen_v2.h" +#include "kyra/sound.h" +#include "kyra/wsamovie.h" +#include "kyra/resource.h" + +#include "common/func.h" + +namespace Kyra { + +void KyraEngine_HoF::enterNewScene(uint16 newScene, int facing, int unk1, int unk2, int unk3) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::enterNewScene(%d, %d, %d, %d, %d)", newScene, facing, unk1, unk2, unk3); + if (_newChapterFile != _currentTalkFile) { + _currentTalkFile = _newChapterFile; + if (_flags.isTalkie) { + showMessageFromCCode(265, 150, 0); + _screen->updateScreen(); + openTalkFile(_currentTalkFile); + } + showMessage(0, 207); + _screen->updateScreen(); + } + + _screen->hideMouse(); + + if (!unk3) { + updateWaterFlasks(); + displayInvWsaLastFrame(); + } + + if (unk1) { + int x = _mainCharacter.x1; + int y = _mainCharacter.y1; + + switch (facing) { + case 0: + y -= 6; + break; + + case 2: + x = 335; + break; + + case 4: + y = 147; + break; + + case 6: + x = -16; + break; + + default: + break; + } + + moveCharacter(facing, x, y); + } + + bool newSoundFile = false; + uint32 waitTime = 0; + if (_sceneList[newScene].sound != _lastMusicCommand) { + newSoundFile = true; + waitTime = _system->getMillis() + 1000; + _sound->beginFadeOut(); + } + + _chatAltFlag = false; + + if (!unk3) { + _emc->init(&_sceneScriptState, &_sceneScriptData); + _emc->start(&_sceneScriptState, 5); + while (_emc->isValid(&_sceneScriptState)) + _emc->run(&_sceneScriptState); + } + + Common::for_each(_wsaSlots, _wsaSlots+ARRAYSIZE(_wsaSlots), Common::mem_fun(&WSAMovieV2::close)); + _specialExitCount = 0; + memset(_specialExitTable, -1, sizeof(_specialExitTable)); + + _mainCharacter.sceneId = newScene; + _sceneList[newScene].flags &= ~1; + loadScenePal(); + unloadScene(); + loadSceneMsc(); + + SceneDesc &scene = _sceneList[newScene]; + _sceneExit1 = scene.exit1; + _sceneExit2 = scene.exit2; + _sceneExit3 = scene.exit3; + _sceneExit4 = scene.exit4; + + if (newSoundFile) { + if (_sound->getMusicType() == Sound::kAdlib) { + while (_sound->isPlaying()) + _system->delayMillis(10); + } else { + while (waitTime > _system->getMillis()) + _system->delayMillis(10); + } + snd_loadSoundFile(_sceneList[newScene].sound); + } + + startSceneScript(unk3); + + if (_overwriteSceneFacing) { + facing = _mainCharacter.facing; + _overwriteSceneFacing = false; + } + + enterNewSceneUnk1(facing, unk2, unk3); + + setTimer1DelaySecs(-1); + _sceneScriptState.regs[3] = 1; + enterNewSceneUnk2(unk3); + _screen->showMouse(); + _unk5 = 0; + setNextIdleAnimTimer(); + + _currentScene = newScene; +} + +void KyraEngine_HoF::enterNewSceneUnk1(int facing, int unk1, int unk2) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::enterNewSceneUnk1(%d, %d, %d)", facing, unk1, unk2); + int x = 0, y = 0; + int x2 = 0, y2 = 0; + bool needProc = true; + + if (_mainCharX == -1 && _mainCharY == -1) { + switch (facing+1) { + case 1: case 2: case 8: + x2 = _sceneEnterX3; + y2 = _sceneEnterY3; + break; + + case 3: + x2 = _sceneEnterX4; + y2 = _sceneEnterY4; + break; + + case 4: case 5: case 6: + x2 = _sceneEnterX1; + y2 = _sceneEnterY1; + break; + + case 7: + x2 = _sceneEnterX2; + y2 = _sceneEnterY2; + break; + + default: + x2 = y2 = -1; + break; + } + + if (x2 >= 316) + x2 = 312; + if (y2 >= 141) + y2 = 139; + if (x2 <= 4) + x2 = 8; + } + + if (_mainCharX >= 0) { + x = x2 = _mainCharX; + needProc = false; + } + + if (_mainCharY >= 0) { + y = y2 = _mainCharY; + needProc = false; + } + + _mainCharX = _mainCharY = -1; + + if (unk1 && needProc) { + x = x2; + y = y2; + + switch (facing) { + case 0: + y2 = 147; + break; + + case 2: + x2 = -16; + break; + + case 4: + y2 = y - 4; + break; + + case 6: + x2 = 335; + break; + + default: + break; + } + } + + x2 &= ~3; + x &= ~3; + y2 &= ~1; + y &= ~1; + + _mainCharacter.facing = facing; + _mainCharacter.x1 = _mainCharacter.x2 = x2; + _mainCharacter.y1 = _mainCharacter.y2 = y2; + initSceneAnims(unk2); + + if (!unk2) + snd_playWanderScoreViaMap(_sceneList[_mainCharacter.sceneId].sound, 0); + + if (unk1 && !unk2 && _mainCharacter.animFrame != 32) + moveCharacter(facing, x, y); +} + +void KyraEngine_HoF::enterNewSceneUnk2(int unk1) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::enterNewSceneUnk2(%d)", unk1); + _unk3 = -1; + + if (_flags.isTalkie) { + if (_mainCharX == -1 && _mainCharY == -1 && _mainCharacter.sceneId != 61 && + !queryGameFlag(0x1F1) && !queryGameFlag(0x192) && !queryGameFlag(0x193) && + _mainCharacter.sceneId != 70 && !queryGameFlag(0x159) && _mainCharacter.sceneId != 37) { + _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing]; + updateCharacterAnim(0); + refreshAnimObjectsIfNeed(); + } + } else if (_mainCharX != -1 && _mainCharY != -1) { + if (_characterFrameTable[_mainCharacter.facing] == 25) + _mainCharacter.facing = 5; + _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing]; + updateCharacterAnim(0); + refreshAnimObjectsIfNeed(); + } + + if (!unk1) { + runSceneScript4(0); + zanthSceneStartupChat(); + } + + _unk4 = 0; + _unk3 = -1; +} + +int KyraEngine_HoF::trySceneChange(int *moveTable, int unk1, int updateChar) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::trySceneChange(%p, %d, %d)", (const void*)moveTable, unk1, updateChar); + bool running = true; + bool unkFlag = false; + int8 updateType = -1; + int changedScene = 0; + const int *moveTableStart = moveTable; + _unk4 = 0; + while (running && !_quitFlag) { + if (*moveTable >= 0 && *moveTable <= 7) { + _mainCharacter.facing = getOppositeFacingDirection(*moveTable); + unkFlag = true; + } else { + if (*moveTable == 8) { + running = false; + } else { + ++moveTable; + unkFlag = false; + } + } + + if (checkSceneChange()) { + running = false; + changedScene = 1; + } + + if (unk1) { + if (skipFlag()) { + resetSkipFlag(false); + running = false; + _unk4 = 1; + } + } + + if (!unkFlag || !running) + continue; + + int ret = 0; + if (moveTable == moveTableStart || moveTable[1] == 8) + ret = updateCharPos(0); + else + ret = updateCharPos(moveTable); + + if (ret) + ++moveTable; + + ++updateType; + if (!updateType) { + update(); + } else if (updateType == 1) { + refreshAnimObjectsIfNeed(); + updateType = -1; + } + } + + if (updateChar) + _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing]; + + updateCharacterAnim(0); + refreshAnimObjectsIfNeed(); + + if (!changedScene && !_unk4) { + //XXX + } + return changedScene; +} + +int KyraEngine_HoF::checkSceneChange() { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::checkSceneChange()"); + SceneDesc &curScene = _sceneList[_mainCharacter.sceneId]; + int charX = _mainCharacter.x1, charY = _mainCharacter.y1; + int facing = 0; + int process = 0; + + if (_screen->getLayer(charX, charY) == 1 && _unk3 == -6) { + facing = 0; + process = 1; + } else if (charX >= 316 && _unk3 == -5) { + facing = 2; + process = 1; + } else if (charY >= 142 && _unk3 == -4) { + facing = 4; + process = 1; + } else if (charX <= 4 && _unk3 == -3) { + facing = 6; + process = 1; + } + + if (!process) + return 0; + + uint16 newScene = 0xFFFF; + switch (facing) { + case 0: + newScene = curScene.exit1; + break; + + case 2: + newScene = curScene.exit2; + break; + + case 4: + newScene = curScene.exit3; + break; + + case 6: + newScene = curScene.exit4; + break; + + default: + newScene = _mainCharacter.sceneId; + break; + } + + if (newScene == 0xFFFF) + return 0; + + enterNewScene(newScene, facing, 1, 1, 0); + return 1; +} + +void KyraEngine_HoF::unloadScene() { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::unloadScene()"); + _emc->unload(&_sceneScriptData); + freeSceneShapePtrs(); + freeSceneAnims(); +} + +void KyraEngine_HoF::loadScenePal() { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::loadScenePal()"); + uint16 sceneId = _mainCharacter.sceneId; + memcpy(_screen->getPalette(1), _screen->getPalette(0), 768); + + char filename[14]; + strcpy(filename, _sceneList[sceneId].filename1); + strcat(filename, ".COL"); + _screen->loadBitmap(filename, 3, 3, 0); + memcpy(_screen->getPalette(1), _screen->getCPagePtr(3), 384); + memset(_screen->getPalette(1), 0, 3); + memcpy(_scenePal, _screen->getCPagePtr(3)+336, 432); +} + +void KyraEngine_HoF::loadSceneMsc() { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::loadSceneMsc()"); + uint16 sceneId = _mainCharacter.sceneId; + char filename[14]; + strcpy(filename, _sceneList[sceneId].filename1); + strcat(filename, ".MSC"); + _screen->loadBitmap(filename, 3, 5, 0); +} + +void KyraEngine_HoF::startSceneScript(int unk1) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::startSceneScript(%d)", unk1); + uint16 sceneId = _mainCharacter.sceneId; + char filename[14]; + + strcpy(filename, _sceneList[sceneId].filename1); + if (sceneId == 68 && (queryGameFlag(0x1BC) || queryGameFlag(0x1BD))) + strcpy(filename, "DOORX"); + strcat(filename, ".CPS"); + + _screen->loadBitmap(filename, 3, 3, 0); + resetScaleTable(); + _useCharPal = false; + memset(_charPalTable, 0, sizeof(_charPalTable)); + memset(_layerFlagTable, 0, sizeof(_layerFlagTable)); + memset(_specialSceneScriptState, 0, sizeof(_specialSceneScriptState)); + + _sceneEnterX1 = 160; + _sceneEnterY1 = 0; + _sceneEnterX2 = 296; + _sceneEnterY2 = 72; + _sceneEnterX3 = 160; + _sceneEnterY3 = 128; + _sceneEnterX4 = 24; + _sceneEnterY4 = 72; + + _sceneCommentString = "Undefined scene comment string!"; + _emc->init(&_sceneScriptState, &_sceneScriptData); + + strcpy(filename, _sceneList[sceneId].filename1); + strcat(filename, "."); + strcat(filename, _scriptLangExt[(_flags.platform == Common::kPlatformPC && !_flags.isTalkie) ? 0 : _lang]); + + _res->exists(filename, true); + _emc->load(filename, &_sceneScriptData, &_opcodes); + runSceneScript7(); + + _emc->start(&_sceneScriptState, 0); + _sceneScriptState.regs[0] = sceneId; + _sceneScriptState.regs[5] = unk1; + while (_emc->isValid(&_sceneScriptState)) + _emc->run(&_sceneScriptState); + + memcpy(_gamePlayBuffer, _screen->getCPagePtr(3), 46080); + + for (int i = 0; i < 10; ++i) { + _emc->init(&_sceneSpecialScripts[i], &_sceneScriptData); + _emc->start(&_sceneSpecialScripts[i], i+8); + _sceneSpecialScriptsTimer[i] = 0; + } + + _sceneEnterX1 &= ~3; + _sceneEnterX2 &= ~3; + _sceneEnterX3 &= ~3; + _sceneEnterX4 &= ~3; + _sceneEnterY1 &= ~1; + _sceneEnterY2 &= ~1; + _sceneEnterY3 &= ~1; + _sceneEnterY4 &= ~1; +} + +void KyraEngine_HoF::runSceneScript2() { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::runSceneScript2()"); + _emc->init(&_sceneScriptState, &_sceneScriptData); + _sceneScriptState.regs[4] = _itemInHand; + _emc->start(&_sceneScriptState, 2); + + while (_emc->isValid(&_sceneScriptState)) + _emc->run(&_sceneScriptState); +} + +void KyraEngine_HoF::runSceneScript4(int unk1) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::runSceneScript4(%d)", unk1); + _sceneScriptState.regs[4] = _itemInHand; + _sceneScriptState.regs[5] = unk1; + + _emc->start(&_sceneScriptState, 4); + while (_emc->isValid(&_sceneScriptState)) + _emc->run(&_sceneScriptState); +} + +void KyraEngine_HoF::runSceneScript7() { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::runSceneScript7()"); + int oldPage = _screen->_curPage; + _screen->_curPage = 2; + + _emc->start(&_sceneScriptState, 7); + while (_emc->isValid(&_sceneScriptState)) + _emc->run(&_sceneScriptState); + + _screen->_curPage = oldPage; +} + +void KyraEngine_HoF::initSceneAnims(int unk1) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::initSceneAnims(%d)", unk1); + for (int i = 0; i < ARRAYSIZE(_animObjects); ++i) + _animObjects[i].enabled = 0; + + bool animInit = false; + + AnimObj *animState = &_animObjects[0]; + + if (_mainCharacter.animFrame != 32) + _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing]; + + animState->enabled = 1; + animState->xPos1 = _mainCharacter.x1; + animState->yPos1 = _mainCharacter.y1; + animState->shapePtr = getShapePtr(_mainCharacter.animFrame); + animState->shapeIndex1 = animState->shapeIndex2 = _mainCharacter.animFrame; + + int frame = _mainCharacter.animFrame - 9; + int shapeX = _shapeDescTable[frame].xAdd; + int shapeY = _shapeDescTable[frame].yAdd; + + animState->xPos2 = _mainCharacter.x1; + animState->yPos2 = _mainCharacter.y1; + + _charScale = getScale(_mainCharacter.x1, _mainCharacter.y1); + + int shapeXScaled = (shapeX * _charScale) >> 8; + int shapeYScaled = (shapeY * _charScale) >> 8; + + animState->xPos2 += shapeXScaled; + animState->yPos2 += shapeYScaled; + animState->xPos3 = animState->xPos2; + animState->yPos3 = animState->yPos2; + animState->needRefresh = 1; + animState->specialRefresh = 1; + + _animList = 0; + + AnimObj *charAnimState = animState; + + for (int i = 0; i < 10; ++i) { + animState = &_animObjects[i+1]; + animState->enabled = 0; + animState->needRefresh = 0; + animState->specialRefresh = 0; + + if (_sceneAnims[i].flags & 1) { + animState->enabled = 1; + animState->needRefresh = 1; + animState->specialRefresh = 1; + } + + animState->animFlags = _sceneAnims[i].flags & 8; + + if (_sceneAnims[i].flags & 2) + animState->flags = 0x800; + else + animState->flags = 0; + + if (_sceneAnims[i].flags & 4) + animState->flags |= 1; + + animState->xPos1 = _sceneAnims[i].x; + animState->yPos1 = _sceneAnims[i].y; + + if (_sceneAnims[i].flags & 0x20) + animState->shapePtr = _sceneShapeTable[_sceneAnims[i].shapeIndex]; + else + animState->shapePtr = 0; + + if (_sceneAnims[i].flags & 0x40) { + animState->shapeIndex3 = _sceneAnims[i].shapeIndex; + animState->animNum = i; + } else { + animState->shapeIndex3 = 0xFFFF; + animState->animNum = 0xFFFF; + } + + animState->shapeIndex2 = 0xFFFF; + + animState->xPos3 = animState->xPos2 = _sceneAnims[i].x2; + animState->yPos3 = animState->yPos2 = _sceneAnims[i].y2; + animState->width = _sceneAnims[i].width; + animState->height = _sceneAnims[i].height; + animState->width2 = animState->height2 = _sceneAnims[i].specialSize; + + if (_sceneAnims[i].flags & 1) { + if (animInit) { + _animList = addToAnimListSorted(_animList, animState); + } else { + _animList = initAnimList(_animList, animState); + animInit = true; + } + } + } + + if (animInit) { + _animList = addToAnimListSorted(_animList, charAnimState); + } else { + _animList = initAnimList(_animList, charAnimState); + animInit = true; + } + + for (int i = 0; i < 30; ++i) { + animState = &_animObjects[i+11]; + + uint16 shapeIndex = _itemList[i].id; + if (shapeIndex == 0xFFFF || _itemList[i].sceneId != _mainCharacter.sceneId) { + animState->enabled = 0; + animState->needRefresh = 0; + animState->specialRefresh = 0; + } else { + animState->xPos1 = _itemList[i].x; + animState->yPos1 = _itemList[i].y; + animState->shapePtr = getShapePtr(64+shapeIndex); + animState->shapeIndex1 = animState->shapeIndex2 = shapeIndex+64; + + animState->xPos2 = _itemList[i].x; + animState->yPos2 = _itemList[i].y; + int objectScale = getScale(animState->xPos2, animState->yPos2); + + const uint8 *shape = getShapePtr(animState->shapeIndex1); + animState->xPos2 -= (_screen->getShapeScaledWidth(shape, objectScale) >> 1); + animState->yPos2 -= (_screen->getShapeScaledHeight(shape, objectScale) >> 1); + animState->xPos3 = animState->xPos2; + animState->yPos3 = animState->yPos2; + + animState->enabled = 1; + animState->needRefresh = 1; + animState->specialRefresh = 1; + + if (animInit) { + _animList = addToAnimListSorted(_animList, animState); + } else { + _animList = initAnimList(_animList, animState); + animInit = true; + } + } + } + + _animObjects[0].specialRefresh = 1; + _animObjects[0].needRefresh = 1; + + for (int i = 1; i < 41; ++i) { + if (_animObjects[i].enabled) { + _animObjects[i].needRefresh = 1; + _animObjects[i].specialRefresh = 1; + } + } + + restorePage3(); + drawAnimObjects(); + _screen->hideMouse(); + initSceneScreen(unk1); + _screen->showMouse(); + refreshAnimObjects(0); +} + +void KyraEngine_HoF::initSceneScreen(int unk1) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::initSceneScreen(%d)", unk1); + if (_unkSceneScreenFlag1) { + _screen->copyRegion(0, 0, 0, 0, 320, 144, 2, 0, Screen::CR_NO_P_CHECK); + return; + } + + if (_noScriptEnter) { + memset(_screen->getPalette(0), 0, 384); + _screen->setScreenPalette(_screen->getPalette(0)); + } + + _screen->copyRegion(0, 0, 0, 0, 320, 144, 2, 0, Screen::CR_NO_P_CHECK); + + if (_noScriptEnter) { + _screen->setScreenPalette(_screen->getPalette(1)); + memcpy(_screen->getPalette(0), _screen->getPalette(1), 384); + } + + updateCharPal(0); + + _emc->start(&_sceneScriptState, 3); + _sceneScriptState.regs[5] = unk1; + while (_emc->isValid(&_sceneScriptState)) + _emc->run(&_sceneScriptState); +} + +void KyraEngine_HoF::freeSceneShapePtrs() { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::freeSceneShapePtrs()"); + for (int i = 0; i < ARRAYSIZE(_sceneShapeTable); ++i) + delete [] _sceneShapeTable[i]; + memset(_sceneShapeTable, 0, sizeof(_sceneShapeTable)); +} + +void KyraEngine_HoF::fadeScenePal(int srcIndex, int delayTime) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::fadeScenePal(%d, %d)", srcIndex, delayTime); + uint8 *dst = _screen->getPalette(0) + 336; + const uint8 *src = _scenePal + (srcIndex << 4)*3; + memcpy(dst, src, 48); + + _screen->fadePalette(_screen->getPalette(0), delayTime, &_updateFunctor); +} + +#pragma mark - +#pragma mark - Pathfinder +#pragma mark - + +bool KyraEngine_HoF::lineIsPassable(int x, int y) { + debugC(9, kDebugLevelMain, "KyraEngine_HoF::lineIsPassable(%d, %d)", x, y); + static int unkTable[] = { 1, 1, 1, 1, 1, 2, 4, 6, 8 }; + + if (_pathfinderFlag & 2) { + if (x >= 320) + return false; + } + + if (_pathfinderFlag & 4) { + if (y >= 144) + return false; + } + + if (_pathfinderFlag & 8) { + if (x < 0) + return false; + } + + if (y > 143) + return false; + + int unk1 = unkTable[getScale(x, y) >> 5]; + + if (y < 0) + y = 0; + x -= unk1 >> 1; + if (x < 0) + x = 0; + int x2 = x + unk1; + if (x2 > 320) + x2 = 320; + + for (;x < x2; ++x) + if (!_screen->getShapeFlag1(x, y)) + return false; + + return true; +} + +} // end of namespace Kyra + |