From 05f68b17d4a60ece9e2eed14746eab5b29a3e688 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Sun, 9 Mar 2008 14:46:24 +0000 Subject: - implemented cauldron handling for HoF (needs some more testing though) - fixed bug in updateCharFacing - added 'give' command to HoF debugger, which allows setting the hand item to a specified item svn-id: r31087 --- engines/kyra/animator_v2.cpp | 2 +- engines/kyra/debugger.cpp | 19 ++++ engines/kyra/debugger.h | 1 + engines/kyra/gui_v2.cpp | 99 +++++++++++++++++++ engines/kyra/items_v2.cpp | 9 ++ engines/kyra/kyra_v2.cpp | 220 ++++++++++++++++++++++++++++++++++++++++++- engines/kyra/kyra_v2.h | 32 ++++++- engines/kyra/script_v2.cpp | 5 + engines/kyra/staticres.cpp | 57 ++++++++++- 9 files changed, 438 insertions(+), 6 deletions(-) (limited to 'engines/kyra') diff --git a/engines/kyra/animator_v2.cpp b/engines/kyra/animator_v2.cpp index 0d4bdf3328..9bd9b76dfc 100644 --- a/engines/kyra/animator_v2.cpp +++ b/engines/kyra/animator_v2.cpp @@ -202,7 +202,7 @@ void KyraEngine_v2::updateCharFacing() { else _mainCharacter.facing = 3; - _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.animFrame]; + _mainCharacter.animFrame = _characterFrameTable[_mainCharacter.facing]; updateCharacterAnim(0); refreshAnimObjectsIfNeed(); } diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp index d44fcb3b81..194633ec68 100644 --- a/engines/kyra/debugger.cpp +++ b/engines/kyra/debugger.cpp @@ -234,6 +234,7 @@ Debugger_v2::Debugger_v2(KyraEngine_v2 *vm) : Debugger(vm), _vm(vm) { DCmd_Register("scenes", WRAP_METHOD(Debugger_v2, cmd_listScenes)); DCmd_Register("scene_info", WRAP_METHOD(Debugger_v2, cmd_sceneInfo)); DCmd_Register("scene_to_facing", WRAP_METHOD(Debugger_v2, cmd_sceneToFacing)); + DCmd_Register("give", WRAP_METHOD(Debugger_v2, cmd_giveItem)); } bool Debugger_v2::cmd_enterScene(int argc, const char **argv) { @@ -359,5 +360,23 @@ bool Debugger_v2::cmd_sceneToFacing(int argc, const char **argv) { return true; } +bool Debugger_v2::cmd_giveItem(int argc, const char **argv) { + if (argc == 2) { + int item = atoi(argv[1]); + + // Kyrandia 2 has only 178 items (-1 to 176), otherwise it will crash + if (item < -1 || item > 176) { + DebugPrintf("itemid must be any value between (including) -1 and 176\n"); + return true; + } + + _vm->setHandItem(item); + } else { + DebugPrintf("Syntax: give \n"); + } + + return true; +} + } // End of namespace Kyra diff --git a/engines/kyra/debugger.h b/engines/kyra/debugger.h index 3c4356e880..033044a41e 100644 --- a/engines/kyra/debugger.h +++ b/engines/kyra/debugger.h @@ -81,6 +81,7 @@ protected: bool cmd_sceneInfo(int argc, const char **argv); bool cmd_characterInfo(int argc, const char **argv); bool cmd_sceneToFacing(int argc, const char **argv); + bool cmd_giveItem(int argc, const char **argv); }; } // End of namespace Kyra diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp index d1a3b6c954..c05987e482 100644 --- a/engines/kyra/gui_v2.cpp +++ b/engines/kyra/gui_v2.cpp @@ -751,6 +751,8 @@ void KyraEngine_v2::scrollInventoryWheel() { movie.close(); } +// spellbook specific code + int KyraEngine_v2::bookButton(Button *button) { if (!queryGameFlag(1)) { objectChat(getTableString(0xEB, _cCodeBuffer, 1), 0, 0x83, 0xEB); @@ -982,4 +984,101 @@ int KyraEngine_v2::bookClose(Button *button) { return 0; } +// cauldron specific code + +int KyraEngine_v2::cauldronClearButton(Button *button) { + if (!queryGameFlag(2)) { + updateCharFacing(); + objectChat(getTableString(0xF0, _cCodeBuffer, 1), 0, 0x83, 0xF0); + return 0; + } + + if (queryGameFlag(0xE4)) { + snd_playSoundEffect(0x0D); + return 0; + } + + _screen->hideMouse(); + displayInvWsaLastFrame(); + snd_playSoundEffect(0x25); + loadInvWsa("PULL.WSA", 1, 6, 0, -1, -1, 1); + loadInvWsa("CAULD00.WSA", 1, 7, 0, 0xD4, 0x0F, 1); + showMessage(0, 0xCF); + setCauldronState(0, 0); + clearCauldronTable(); + snd_playSoundEffect(0x57); + loadInvWsa("CAULDFIL.WSA", 1, 7, 0, -1, -1, 1); + _screen->showMouse(); + return 0; +} + +int KyraEngine_v2::cauldronButton(Button *button) { + if (!queryGameFlag(2)) { + objectChat(getTableString(0xF0, _cCodeBuffer, 1), 0, 0x83, 0xF0); + return 0; + } + + if (!_screen->isMouseVisible() || _handItemSet < 0) + return 0; + + if (queryGameFlag(0xE4)) { + snd_playSoundEffect(0x0D); + return 0; + } + + updateCharFacing(); + + for (int i = 0; _cauldronProtectedItems[i] != -1; ++i) { + if (_itemInHand == _cauldronProtectedItems[i]) { + objectChat(getTableString(0xF1, _cCodeBuffer, 1), 0, 0x83, 0xF1); + return 0; + } + } + + if (_itemInHand == -1) { + //sub_33AAE(); + return 0; + } + + for (int i = 0; _cauldronBowlTable[i] != -1; i += 2) { + if (_itemInHand == _cauldronBowlTable[i]) { + addFrontCauldronTable(_itemInHand); + setHandItem(_cauldronBowlTable[i+1]); + if (!updateCauldron()) { + _cauldronState = 0; + cauldronRndPaletteFade(); + } + return 0; + } + } + + if (_itemInHand == 18) { + const int16 *magicTable = (_mainCharacter.sceneId == 77) ? _cauldronMagicTableScene77 : _cauldronMagicTable; + while (magicTable[0] != -1) { + if (_cauldronState == magicTable[0]) { + setHandItem(magicTable[1]); + snd_playSoundEffect(0x6C); + ++_cauldronUseCount; + if (_cauldronStateTable[_cauldronState] <= _cauldronUseCount && _cauldronUseCount) { + showMessage(0, 0xCF); + setCauldronState(0, true); + clearCauldronTable(); + } + return 0; + } + magicTable += 2; + } + } else if (_itemInHand >= 0) { + int item = _itemInHand; + cauldronItemAnim(item); + addFrontCauldronTable(item); + if (!updateCauldron()) { + _cauldronState = 0; + cauldronRndPaletteFade(); + } + } + + return 0; +} + } // end of namespace Kyra diff --git a/engines/kyra/items_v2.cpp b/engines/kyra/items_v2.cpp index 78f6f58f31..72e18846d4 100644 --- a/engines/kyra/items_v2.cpp +++ b/engines/kyra/items_v2.cpp @@ -455,5 +455,14 @@ void KyraEngine_v2::removeHandItem() { _screen->showMouse(); } +bool KyraEngine_v2::itemIsFlask(int item) { + for (int i = 0; _flaskTable[i] != -1; ++i) { + if (_flaskTable[i] == item) + return true; + } + + return false; +} + } // end of namespace Kyra diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp index f5e04f5727..83bc93c2c4 100644 --- a/engines/kyra/kyra_v2.cpp +++ b/engines/kyra/kyra_v2.cpp @@ -129,6 +129,10 @@ KyraEngine_v2::KyraEngine_v2(OSystem *system, const GameFlags &flags) : KyraEngi _bookCurPage = 0; _bookNewPage = 0; _bookBkgd = 0; + + _cauldronState = 0; + _cauldronUseCount = 0; + memset(_cauldronStateTables, 0, sizeof(_cauldronStateTables)); } KyraEngine_v2::~KyraEngine_v2() { @@ -349,8 +353,11 @@ void KyraEngine_v2::startup() { clearAnimObjects(); // XXX - memset(_hiddenItems, -1, sizeof(_hiddenItems)); + clearCauldronTable(); // XXX + memset(_hiddenItems, -1, sizeof(_hiddenItems)); + for (int i = 0; i < 23; ++i) + resetCauldronStateTable(i); _sceneList = new SceneDesc[86]; memset(_sceneList, 0, sizeof(SceneDesc)*86); @@ -1601,6 +1608,14 @@ void KyraEngine_v2::restoreGfxRect24x24(int x, int y) { _screen->copyBlockToPage(_screen->_curPage, x, y, 24, 24, _gfxBackUpRect); } +void KyraEngine_v2::backUpGfxRect32x32(int x, int y) { + _screen->copyRegionToBuffer(_screen->_curPage, x, y, 32, 32, _gfxBackUpRect); +} + +void KyraEngine_v2::restoreGfxRect32x32(int x, int y) { + _screen->copyBlockToPage(_screen->_curPage, x, y, 32, 32, _gfxBackUpRect); +} + #pragma mark - void KyraEngine_v2::openTalkFile(int newFile) { @@ -1783,6 +1798,207 @@ void KyraEngine_v2::displayInvWsaLastFrame() { #pragma mark - +void KyraEngine_v2::setCauldronState(uint8 state, bool paletteFade) { + memcpy(_screen->getPalette(2), _screen->getPalette(0), 768); + Common::SeekableReadStream *file = _res->getFileStream("_POTIONS.PAL"); + if (!file) + error("Couldn't load cauldron palette"); + file->seek(state*18, SEEK_SET); + file->read(_screen->getPalette(2)+723, 18); + delete file; + file = 0; + + if (paletteFade) { + snd_playSoundEffect((state == 0) ? 0x6B : 0x66); + _screen->fadePalette(_screen->getPalette(2), 0x4B, &_updateFunctor); + } else { + _screen->setScreenPalette(_screen->getPalette(2)); + _screen->updateScreen(); + } + + memcpy(_screen->getPalette(0)+723, _screen->getPalette(2)+723, 18); + _cauldronState = state; + _cauldronUseCount = 0; + //if (state == 5) + // sub_27149(); +} + +void KyraEngine_v2::clearCauldronTable() { + Common::set_to(_cauldronTable, _cauldronTable+ARRAYSIZE(_cauldronTable), -1); +} + +void KyraEngine_v2::addFrontCauldronTable(int item) { + for (int i = 23; i >= 0; --i) + _cauldronTable[i+1] = _cauldronTable[i]; + _cauldronTable[0] = item; +} + +void KyraEngine_v2::cauldronItemAnim(int item) { + const int x = 282; + const int y = 135; + const int mouseDstX = (x + 7) & (~1); + const int mouseDstY = (y + 15) & (~1); + int mouseX = _mouseX & (~1); + int mouseY = _mouseY & (~1); + + while (mouseY != mouseDstY) { + if (mouseY < mouseDstY) + mouseY += 2; + else if (mouseY > mouseDstY) + mouseY -= 2; + uint32 waitEnd = _system->getMillis() + _tickLength; + _system->warpMouse(mouseX, mouseY); + delayUntil(waitEnd); + } + + while (mouseX != mouseDstX) { + if (mouseX < mouseDstX) + mouseX += 2; + else if (mouseX > mouseDstX) + mouseX -= 2; + uint32 waitEnd = _system->getMillis() + _tickLength; + _system->warpMouse(mouseX, mouseY); + delayUntil(waitEnd); + } + + if (itemIsFlask(item)) { + setHandItem(19); + delayUntil(_system->getMillis()+_tickLength*30); + setHandItem(18); + } else { + _screen->hideMouse(); + backUpGfxRect32x32(x, y); + uint8 *shape = getShapePtr(item+64); + + int curY = y; + for (int i = 0; i < 12; i += 2, curY += 2) { + restoreGfxRect32x32(x, y); + uint32 waitEnd = _system->getMillis() + _tickLength; + _screen->drawShape(0, shape, x, curY, 0, 0); + _screen->updateScreen(); + delayUntil(waitEnd); + } + + snd_playSoundEffect(0x17); + + for (int i = 16; i > 0; i -= 2, curY += 2) { + _screen->setNewShapeHeight(shape, i); + restoreGfxRect32x32(x, y); + uint32 waitEnd = _system->getMillis() + _tickLength; + _screen->drawShape(0, shape, x, curY, 0, 0); + _screen->updateScreen(); + } + + restoreGfxRect32x32(x, y); + _screen->resetShapeHeight(shape); + removeHandItem(); + _screen->showMouse(); + } +} + +bool KyraEngine_v2::updateCauldron() { + for (int i = 0; i < 23; ++i) { + const int16 *curStateTable = _cauldronStateTables[i]; + if (*curStateTable == -2) + continue; + + int cauldronState = i; + int16 cauldronTable[25]; + memcpy(cauldronTable, _cauldronTable, sizeof(cauldronTable)); + + while (*curStateTable != -2) { + int stateValue = *curStateTable++; + int i = 0; + for (; i < 25; ++i) { + int val = cauldronTable[i]; + + switch (val) { + case 68: + val = 70; + break; + + case 133: + case 167: + val = 119; + break; + + case 130: + case 143: + case 100: + val = 12; + break; + + case 132: + case 65: + case 69: + case 74: + val = 137; + break; + + case 157: + val = 134; + break; + + default: + break; + } + + if (val == stateValue) { + cauldronTable[i] = -1; + i = 26; + } + } + + if (i == 25) + cauldronState = -1; + } + + if (cauldronState >= 0) { + showMessage(0, 0xCF); + setCauldronState(cauldronState, true); + if (cauldronState == 7) + objectChat(getTableString(0xF2, _cCodeBuffer, 1), 0, 0x83, 0xF2); + clearCauldronTable(); + return true; + } + } + + return false; +} + +void KyraEngine_v2::cauldronRndPaletteFade() { + showMessage(0, 0xCF); + int index = _rnd.getRandomNumberRng(0x0F, 0x16); + Common::SeekableReadStream *file = _res->getFileStream("_POTIONS.PAL"); + if (!file) + error("Couldn't load cauldron palette"); + file->seek(index*18, SEEK_SET); + file->read(_screen->getPalette(0)+723, 18); + snd_playSoundEffect(0x6A); + _screen->fadePalette(_screen->getPalette(0), 0x1E, &_updateFunctor); + file->seek(0, SEEK_SET); + file->read(_screen->getPalette(0)+723, 18); + delete file; + _screen->fadePalette(_screen->getPalette(0), 0x1E, &_updateFunctor); +} + +void KyraEngine_v2::resetCauldronStateTable(int idx) { + for (int i = 0; i < 7; ++i) + _cauldronStateTables[idx][i] = -2; +} + +bool KyraEngine_v2::addToCauldronStateTable(int data, int idx) { + for (int i = 0; i < 7; ++i) { + if (_cauldronStateTables[idx][i] == -2) { + _cauldronStateTables[idx][i] = data; + return true; + } + } + return false; +} + +#pragma mark - + void KyraEngine_v2::registerDefaultSettings() { KyraEngine::registerDefaultSettings(); @@ -1951,7 +2167,7 @@ void KyraEngine_v2::setupOpcodeTable() { // 0x78 Opcode(o2_getDlgIndex), Opcode(o2_defineRoom), - OpcodeUnImpl(), + Opcode(o2_addCauldronStateTableEntry), Opcode(o2_setCountDown), // 0x7c Opcode(o2_getCountDown), diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h index a816e21e2e..ac0604ac31 100644 --- a/engines/kyra/kyra_v2.h +++ b/engines/kyra/kyra_v2.h @@ -331,6 +331,8 @@ protected: void backUpGfxRect24x24(int x, int y); void restoreGfxRect24x24(int x, int y); + void backUpGfxRect32x32(int x, int y); + void restoreGfxRect32x32(int x, int y); uint8 *getShapePtr(int index) { return _defaultShapeTable[index]; } uint8 *_defaultShapeTable[250]; @@ -555,6 +557,9 @@ protected: void setHandItem(uint16 item); void removeHandItem(); + static const int16 _flaskTable[]; + bool itemIsFlask(int item); + // inventory static const int _inventoryX[]; static const int _inventoryY[]; @@ -615,8 +620,10 @@ protected: int scrollInventory(Button *button); int buttonInventory(Button *button); int bookButton(Button *button); + int cauldronButton(Button *button); + int cauldronClearButton(Button *button); - // -> book + // book static const int _bookPageYOffset[]; static const byte _bookTextColorMap[]; @@ -637,6 +644,28 @@ protected: int bookNextPage(Button *button); int bookClose(Button *button); + // cauldron + uint8 _cauldronState; + int16 _cauldronUseCount; + int16 _cauldronTable[25]; + int16 _cauldronStateTables[23][7]; + + static const int16 _cauldronProtectedItems[]; + static const int16 _cauldronBowlTable[]; + static const int16 _cauldronMagicTable[]; + static const int16 _cauldronMagicTableScene77[]; + static const uint8 _cauldronStateTable[]; + + void resetCauldronStateTable(int idx); + bool addToCauldronStateTable(int data, int idx); + + void setCauldronState(uint8 state, bool paletteFade); + void clearCauldronTable(); + void addFrontCauldronTable(int item); + void cauldronItemAnim(int item); + void cauldronRndPaletteFade(); + bool updateCauldron(); + // localization void loadCCodeBuffer(const char *file); void loadOptionsBuffer(const char *file); @@ -944,6 +973,7 @@ protected: int o2_setupDialogue(ScriptState *script); int o2_getDlgIndex(ScriptState *script); int o2_defineRoom(ScriptState *script); + int o2_addCauldronStateTableEntry(ScriptState *script); int o2_setCountDown(ScriptState *script); int o2_getCountDown(ScriptState *script); int o2_objectChat(ScriptState *script); diff --git a/engines/kyra/script_v2.cpp b/engines/kyra/script_v2.cpp index c2c0be003c..923abd7133 100644 --- a/engines/kyra/script_v2.cpp +++ b/engines/kyra/script_v2.cpp @@ -686,6 +686,11 @@ int KyraEngine_v2::o2_defineRoom(ScriptState *script) { return 0; } +int KyraEngine_v2::o2_addCauldronStateTableEntry(ScriptState *script) { + debugC(3, kDebugLevelScriptFuncs, "o2_addCauldronStateTableEntry(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1)); + return addToCauldronStateTable(stackPos(0), stackPos(1)) ? 1 : 0; +} + int KyraEngine_v2::o2_setCountDown(ScriptState *script) { debugC(3, kDebugLevelScriptFuncs, "o2_setCountDown(%p) (%d)", (const void *)script, stackPos(0)); _scriptCountDown = _system->getMillis() + stackPos(0) * _tickLength; diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index afaefb6ad5..6ac5322e0d 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -1449,8 +1449,8 @@ void KyraEngine_v2::initMainButtonList() { // note: _buttonDataListPtr static Button mainButtons[] = { { 0, 0x1, 0x4F, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0x00A, 0x95, 0x39, 0x1D, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0, /*&KyraEngine_v2::sub_C9A1*/0 }, - { 0, 0x2, 0x00, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0x104, 0x90, 0x3C, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0, /*&KyraEngine_v2::sub_27037*/0 }, - { 0, 0x5, 0x00, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0x0FA, 0x90, 0x0A, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0, /*&KyraEngine_v2::sub_27032*/0 }, + { 0, 0x2, 0x00, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0x104, 0x90, 0x3C, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0, &KyraEngine_v2::cauldronButton }, + { 0, 0x5, 0x00, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0x0FA, 0x90, 0x0A, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0, &KyraEngine_v2::cauldronClearButton }, { 0, 0x3, 0x00, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0x0CE, 0x90, 0x2C, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0, &KyraEngine_v2::bookButton }, { 0, 0x4, 0x00, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0x0B6, 0x9D, 0x18, 0x1E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0, &KyraEngine_v2::scrollInventory }, { 0, 0x6, 0x00, 0, 0, 0, 0, 0x1100, 0, 0, 0, 0, 0x04D, 0x92, 0x13, 0x15, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0, &KyraEngine_v2::buttonInventory }, @@ -1534,6 +1534,59 @@ const byte KyraEngine_v2::_bookTextColorMap[] = { 0x00, 0xC7, 0xCF, 0x00 }; +const int16 KyraEngine_v2::_cauldronProtectedItems[] = { + 0x07, 0x0D, 0x47, 0x48, + 0x29, 0x1A, 0x1C, 0x6D, + 0x4D, 0x3A, 0x0E, 0x0F, + 0x10, 0x11, 0x26, 0x3E, + 0x35, 0x40, 0x42, 0xA6, + 0xA4, 0xA5, 0x91, 0x95, + 0x99, 0xAC, 0xAE, 0xAF, + 0x8A, 0x79, 0x61, -1 +}; + +const int16 KyraEngine_v2::_cauldronBowlTable[] = { + 0x0027, 0x0029, + 0x0028, 0x0029, + 0x0033, 0x0029, + 0x0049, 0x0029, + 0x004A, 0x0029, + 0x004B, 0x0029, + 0x004C, 0x0029, + 0x003B, 0x0029, + 0x0034, 0x0034, + -1, -1 +}; + +const int16 KyraEngine_v2::_cauldronMagicTable[] = { + 0x0, 0x16, 0x2, 0x1A, + 0x7, 0xA4, 0x5, 0x4D, + 0x1, 0xA5, 0x3, 0xA6, + 0x6, 0x6D, 0x4, 0x91, + 0xA, 0x99, 0xC, 0x95, + 0x9, 0xAC, -1, -1 +}; + +const int16 KyraEngine_v2::_cauldronMagicTableScene77[] = { + 0x0, 0x16, 0x2, 0x1A, + 0x7, 0xAB, 0x5, 0x4D, + 0x1, 0xAE, 0x3, 0xAF, + 0x6, 0x6D, 0x4, 0x91, + 0xA, 0x99, 0xC, 0x95, + 0x9, 0xAC, -1, -1 +}; + +const uint8 KyraEngine_v2::_cauldronStateTable[] = { + 3, 1, 3, 1, 1, 4, 4, 2, + 3, 1, 1, 3, 1, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3 +}; + +const int16 KyraEngine_v2::_flaskTable[] = { + 0x19, 0x14, 0x15, 0x16, 0x17, 0x18, 0x34, + 0x1B, 0x39, 0x1A, 0x3A, 0x4D, 0x72, -1 +}; + // kyra 3 static res const char *KyraEngine_v3::_soundList[] = { -- cgit v1.2.3