diff options
Diffstat (limited to 'engines/prince')
-rw-r--r-- | engines/prince/draw.cpp | 60 | ||||
-rw-r--r-- | engines/prince/inventory.cpp | 700 | ||||
-rw-r--r-- | engines/prince/module.mk | 4 | ||||
-rw-r--r-- | engines/prince/prince.cpp | 2307 | ||||
-rw-r--r-- | engines/prince/walk.cpp | 1610 |
5 files changed, 2373 insertions, 2308 deletions
diff --git a/engines/prince/draw.cpp b/engines/prince/draw.cpp index 6d330f61cb..a924f99def 100644 --- a/engines/prince/draw.cpp +++ b/engines/prince/draw.cpp @@ -702,4 +702,64 @@ void PrinceEngine::setPalette(const byte *palette) { } } +void PrinceEngine::doTalkAnim(int animNumber, int slot, AnimType animType) { + Text &text = _textSlots[slot]; + int lines = calcTextLines((const char *)_interpreter->getString()); + int time = lines * 30; + if (animType == kNormalAnimation) { + Anim &normAnim = _normAnimList[animNumber]; + if (normAnim._animData != nullptr) { + if (!normAnim._state) { + if (normAnim._currW && normAnim._currH) { + text._color = _flags->getFlagValue(Flags::KOLOR); + text._x = normAnim._currX + normAnim._currW / 2; + text._y = normAnim._currY - 10; + } + } + } + } else if (animType == kBackgroundAnimation) { + if (!_backAnimList[animNumber].backAnims.empty()) { + int currAnim = _backAnimList[animNumber]._seq._currRelative; + Anim &backAnim = _backAnimList[animNumber].backAnims[currAnim]; + if (backAnim._animData != nullptr) { + if (!backAnim._state) { + if (backAnim._currW && backAnim._currH) { + text._color = _flags->getFlagValue(Flags::KOLOR); + text._x = backAnim._currX + backAnim._currW / 2; + text._y = backAnim._currY - 10; + } + } + } + } + } else { + error("doTalkAnim() - wrong animType: %d", animType); + } + text._time = time; + if (getLanguage() == Common::DE_DEU) { + correctStringDEU((char *)_interpreter->getString()); + } + text._str = (const char *)_interpreter->getString(); + _interpreter->increaseString(); +} + +void PrinceEngine::freeNormAnim(int slot) { + if (!_normAnimList.empty()) { + _normAnimList[slot]._state = 1; + if (_normAnimList[slot]._animData != nullptr) { + delete _normAnimList[slot]._animData; + _normAnimList[slot]._animData = nullptr; + } + if (_normAnimList[slot]._shadowData != nullptr) { + delete _normAnimList[slot]._shadowData; + _normAnimList[slot]._shadowData = nullptr; + } + } +} + +void PrinceEngine::freeAllNormAnims() { + for (int i = 0; i < kMaxNormAnims; i++) { + freeNormAnim(i); + } +} + } // End of namespace Prince diff --git a/engines/prince/inventory.cpp b/engines/prince/inventory.cpp new file mode 100644 index 0000000000..509eaceb76 --- /dev/null +++ b/engines/prince/inventory.cpp @@ -0,0 +1,700 @@ +/* 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. + * + */ + +#include "prince/prince.h" + +#include "prince/graphics.h" +#include "prince/hero.h" +#include "prince/script.h" +#include "prince/mhwanh.h" +#include "prince/variatxt.h" +#include "prince/option_text.h" +#include "prince/font.h" + +namespace Prince { + +void PrinceEngine::addInv(int heroId, int item, bool addItemQuiet) { + Hero *hero = nullptr; + if (!heroId) { + hero = _mainHero; + } else if (heroId == 1) { + hero = _secondHero; + } + if (hero != nullptr) { + if (hero->_inventory.size() < kMaxItems) { + if (item != 0x7FFF) { + hero->_inventory.push_back(item); + } + if (!addItemQuiet) { + addInvObj(); + } + _interpreter->setResult(0); + } else { + _interpreter->setResult(1); + } + } +} + +void PrinceEngine::remInv(int heroId, int item) { + Hero *hero = nullptr; + if (!heroId) { + hero = _mainHero; + } else if (heroId == 1) { + hero = _secondHero; + } + if (hero != nullptr) { + for (uint i = 0; i < hero->_inventory.size(); i++) { + if (hero->_inventory[i] == item) { + hero->_inventory.remove_at(i); + _interpreter->setResult(0); + return; + } + } + } + _interpreter->setResult(1); +} + +void PrinceEngine::clearInv(int heroId) { + switch (heroId) { + case 0: + _mainHero->_inventory.clear(); + break; + case 1: + _secondHero->_inventory.clear(); + break; + default: + error("clearInv() - wrong hero slot"); + break; + } +} + +void PrinceEngine::swapInv(int heroId) { + Common::Array<int> tempInv; + Hero *hero = nullptr; + if (!heroId) { + hero = _mainHero; + } else if (heroId == 1) { + hero = _secondHero; + } + if (hero != nullptr) { + for (uint i = 0; i < hero->_inventory.size(); i++) { + tempInv.push_back(hero->_inventory[i]); + } + hero->_inventory.clear(); + for (uint i = 0; i < hero->_inventory2.size(); i++) { + hero->_inventory.push_back(hero->_inventory2[i]); + } + hero->_inventory2.clear(); + for (uint i = 0; i < tempInv.size(); i++) { + hero->_inventory2.push_back(tempInv[i]); + } + tempInv.clear(); + } +} + +void PrinceEngine::addInvObj() { + changeCursor(0); + prepareInventoryToView(); + + _inventoryBackgroundRemember = true; + drawScreen(); + + Graphics::Surface *suitcase = _suitcaseBmp->getSurface(); + + if (!_flags->getFlagValue(Flags::CURSEBLINK)) { + + loadSample(27, "PRZEDMIO.WAV"); + playSample(27, 0); + + _mst_shadow2 = 1; + + while (_mst_shadow2 < 512) { + rememberScreenInv(); + _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); + drawInvItems(); + _graph->update(_graph->_screenForInventory); + _mst_shadow2 += 50; + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + eventMan->pollEvent(event); + if (shouldQuit()) { + return; + } + pausePrinceEngine(); + } + while (_mst_shadow2 > 256) { + rememberScreenInv(); + _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); + drawInvItems(); + _graph->update(_graph->_screenForInventory); + _mst_shadow2 -= 42; + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + eventMan->pollEvent(event); + if (shouldQuit()) { + return; + } + pausePrinceEngine(); + } + } else { + //CURSEBLINK: + for (int i = 0; i < 3; i++) { + _mst_shadow2 = 256; + while (_mst_shadow2 < 512) { + rememberScreenInv(); + _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); + drawInvItems(); + _graph->update(_graph->_screenForInventory); + _mst_shadow2 += 50; + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + eventMan->pollEvent(event); + if (shouldQuit()) { + return; + } + pausePrinceEngine(); + } + while (_mst_shadow2 > 256) { + rememberScreenInv(); + _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); + drawInvItems(); + _graph->update(_graph->_screenForInventory); + _mst_shadow2 -= 50; + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + eventMan->pollEvent(event); + if (shouldQuit()) { + return; + } + pausePrinceEngine(); + } + } + } + _mst_shadow2 = 0; + for (int i = 0; i < 20; i++) { + rememberScreenInv(); + _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); + drawInvItems(); + _graph->update(_graph->_screenForInventory); + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + eventMan->pollEvent(event); + if (shouldQuit()) { + return; + } + pausePrinceEngine(); + } +} + +void PrinceEngine::rememberScreenInv() { + _graph->_screenForInventory->copyFrom(*_graph->_frontScreen); +} + +void PrinceEngine::inventoryFlagChange(bool inventoryState) { + if (inventoryState) { + _showInventoryFlag = true; + _inventoryBackgroundRemember = true; + } else { + _showInventoryFlag = false; + } +} + +void PrinceEngine::prepareInventoryToView() { + _invMobList.clear(); + int invItem = _mainHero->_inventory.size(); + _invLine = invItem / 3; + if (invItem % 3) { + _invLine++; + } + if (_invLine < 4) { + _invLine = 4; + } + _maxInvW = (374 - 2 * _invLine) / _invLine; + _invLineW = _maxInvW - 2; + + int currInvX = _invLineX; + int currInvY = _invLineY; + + Common::MemoryReadStream stream(_invTxt, _invTxtSize); + byte c; + + uint item = 0; + for (int i = 0; i < _invLines; i++) { + for (int j = 0; j < _invLine; j++) { + Mob tempMobItem; + if (item < _mainHero->_inventory.size()) { + int itemNr = _mainHero->_inventory[item]; + tempMobItem._visible = 0; + tempMobItem._mask = itemNr; + tempMobItem._rect = Common::Rect(currInvX + _picWindowX, currInvY, currInvX + _picWindowX + _invLineW - 1, currInvY + _invLineH - 1); + tempMobItem._type = 0; // to work with checkMob() + + tempMobItem._name = ""; + tempMobItem._examText = ""; + int txtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8]); + int examTxtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8 + 4]); + + stream.seek(txtOffset); + while ((c = stream.readByte())) { + tempMobItem._name += c; + } + + stream.seek(examTxtOffset); + while ((c = stream.readByte())) { + tempMobItem._examText += c; + } + _invMobList.push_back(tempMobItem); + } + currInvX += _invLineW + _invLineSkipX; + item++; + } + currInvX = _invLineX; + currInvY += _invLineSkipY + _invLineH; + } +} + +void PrinceEngine::drawInvItems() { + int currInvX = _invLineX; + int currInvY = _invLineY; + uint item = 0; + for (int i = 0; i < _invLines; i++) { + for (int j = 0; j < _invLine; j++) { + if (item < _mainHero->_inventory.size()) { + int itemNr = _mainHero->_inventory[item]; + _mst_shadow = 0; + if (_mst_shadow2) { + if (!_flags->getFlagValue(Flags::CURSEBLINK)) { + if (item + 1 == _mainHero->_inventory.size()) { // last item in inventory + _mst_shadow = 1; + } + } else if (itemNr == 1 || itemNr == 3 || itemNr == 4 || itemNr == 7) { + _mst_shadow = 1; + } + } + + int drawX = currInvX; + int drawY = currInvY; + Graphics::Surface *itemSurface = nullptr; + if (itemNr != 68) { + itemSurface = _allInvList[itemNr].getSurface(); + if (itemSurface->h < _maxInvH) { + drawY += (_maxInvH - itemSurface->h) / 2; + } + } else { + // candle item: + if (_candleCounter == 8) { + _candleCounter = 0; + } + itemNr = _candleCounter; + _candleCounter++; + itemNr &= 7; + itemNr += 71; + itemSurface = _allInvList[itemNr].getSurface(); + drawY += _allInvList[itemNr]._y + (_maxInvH - 76) / 2 - 200; + } + if (itemSurface->w < _maxInvW) { + drawX += (_maxInvW - itemSurface->w) / 2; + } + if (!_mst_shadow) { + _graph->drawTransparentSurface(_graph->_screenForInventory, drawX, drawY, itemSurface); + } else { + _mst_shadow = _mst_shadow2; + _graph->drawTransparentWithBlendSurface(_graph->_screenForInventory, drawX, drawY, itemSurface); + } + } + currInvX += _invLineW + _invLineSkipX; + item++; + } + currInvX = _invLineX; + currInvY += _invLineSkipY + _invLineH; + } +} + +void PrinceEngine::inventoryLeftMouseButton() { + if (!_mouseFlag) { + _textSlots[0]._time = 0; + _textSlots[0]._str = nullptr; + stopSample(28); + } + + if (_optionsFlag == 1) { + if (_selectedMob != -1) { + if (_optionEnabled < _invOptionsNumber) { + _optionsFlag = 0; + } else { + return; + } + } else { + error("PrinceEngine::inventoryLeftMouseButton() - optionsFlag = 1, selectedMob = 0"); + if (_currentPointerNumber == 2) { + changeCursor(1); + _currentPointerNumber = 1; + _selectedMob = -1; + _optionsMob = -1; + return; + } else { + return; + } + } + } else { + if (_selectedMob != -1) { + if (_currentPointerNumber != 2) { + if (_invMobList[_selectedMob]._mask != 29) { + _optionEnabled = 0; + } else { + // map item + _optionEnabled = 1; + } + } else { + //use_item_on_item + int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem); + if (invObjUU == -1) { + int textNr = 80011; // "I can't do it." + if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) { + textNr = 80020; // "Nothing is happening." + } + _interpreter->setCurrentString(textNr); + printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100); + setVoice(0, 28, 1); + playSample(28, 0); + _selectedMob = -1; + _optionsMob = -1; + return; + } else { + _interpreter->storeNewPC(invObjUU); + _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask); + _showInventoryFlag = false; + } + } + } else { + return; + } + } + //do_option + if (_optionEnabled == 0) { + int invObjExamEvent = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjExam); + if (invObjExamEvent == -1) { + // do_standard + printAt(0, 216, (char *)_invMobList[_selectedMob]._examText.c_str(), kNormalWidth / 2, _invExamY); + _interpreter->setCurrentString(_invMobList[_selectedMob]._mask + 70000); + setVoice(0, 28, 1); + playSample(28, 0); + // disableuseuse + changeCursor(0); + _currentPointerNumber = 1; + } else { + _interpreter->storeNewPC(invObjExamEvent); + _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask); + _showInventoryFlag = false; + } + } else if (_optionEnabled == 1) { + // not_examine + int invObjUse = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUse); + if (invObjUse == -1) { + // do_standard_use + _selectedMode = 0; + _selectedItem = _invMobList[_selectedMob]._mask; + makeInvCursor(_invMobList[_selectedMob]._mask); + _currentPointerNumber = 2; + changeCursor(2); + } else { + _interpreter->storeNewPC(invObjUse); + _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask); + _showInventoryFlag = false; + } + } else if (_optionEnabled == 4) { + // do_standard_give + _selectedMode = 1; + _selectedItem = _invMobList[_selectedMob]._mask; + makeInvCursor(_invMobList[_selectedMob]._mask); + _currentPointerNumber = 2; + changeCursor(2); + } else { + // use_item_on_item + int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem); + if (invObjUU == -1) { + int textNr = 80011; // "I can't do it." + if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) { + textNr = 80020; // "Nothing is happening." + } + _interpreter->setCurrentString(textNr); + printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100); + setVoice(0, 28, 1); + playSample(28, 0); + } else { + _interpreter->storeNewPC(invObjUU); + _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask); + _showInventoryFlag = false; + } + } + _selectedMob = -1; + _optionsMob = -1; +} + +void PrinceEngine::inventoryRightMouseButton() { + if (_textSlots[0]._str == nullptr) { + enableOptions(false); + } +} + +void PrinceEngine::enableOptions(bool checkType) { + if (_optionsFlag != 1) { + changeCursor(1); + _currentPointerNumber = 1; + if (_selectedMob != -1) { + if (checkType) { + if (_mobList[_selectedMob]._type & 0x100) { + return; + } + } + Common::Point mousePos = _system->getEventManager()->getMousePos(); + int x1 = mousePos.x - _optionsWidth / 2; + int x2 = mousePos.x + _optionsWidth / 2; + if (x1 < 0) { + x1 = 0; + x2 = _optionsWidth; + } else if (x2 >= kNormalWidth) { + x1 = kNormalWidth - _optionsWidth; + x2 = kNormalWidth; + } + int y1 = mousePos.y - 10; + if (y1 < 0) { + y1 = 0; + } + if (y1 + _optionsHeight >= kNormalHeight) { + y1 = kNormalHeight - _optionsHeight; + } + _optionsMob = _selectedMob; + _optionsX = x1; + _optionsY = y1; + _optionsFlag = 1; + } + } +} + +void PrinceEngine::checkOptions() { + if (_optionsFlag) { + Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _optionsWidth, _optionsY + _optionsHeight); + Common::Point mousePos = _system->getEventManager()->getMousePos(); + if (!optionsRect.contains(mousePos)) { + _optionsFlag = 0; + _selectedMob = -1; + return; + } + _graph->drawAsShadowSurface(_graph->_frontScreen, _optionsX, _optionsY, _optionsPic, _graph->_shadowTable50); + + _optionEnabled = -1; + int optionsYCord = mousePos.y - (_optionsY + 16); + if (optionsYCord >= 0) { + int selectedOptionNr = optionsYCord / _optionsStep; + if (selectedOptionNr < _optionsNumber) { + _optionEnabled = selectedOptionNr; + } + } + int optionsColor; + int textY = _optionsY + 16; + for (int i = 0; i < _optionsNumber; i++) { + if (i != _optionEnabled) { + optionsColor = _optionsColor1; + } else { + optionsColor = _optionsColor2; + } + Common::String optText; + switch(getLanguage()) { + case Common::PL_POL: + optText = optionsTextPL[i]; + break; + case Common::DE_DEU: + optText = optionsTextDE[i]; + break; + case Common::EN_ANY: + optText = optionsTextEN[i]; + break; + default: + break; + }; + uint16 textW = getTextWidth(optText.c_str()); + uint16 textX = _optionsX + _optionsWidth / 2 - textW / 2; + _font->drawString(_graph->_frontScreen, optText, textX, textY, textW, optionsColor); + textY += _optionsStep; + } + } +} + +void PrinceEngine::checkInvOptions() { + if (_optionsFlag) { + Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _invOptionsWidth, _optionsY + _invOptionsHeight); + Common::Point mousePos = _system->getEventManager()->getMousePos(); + if (!optionsRect.contains(mousePos)) { + _optionsFlag = 0; + _selectedMob = -1; + return; + } + _graph->drawAsShadowSurface(_graph->_screenForInventory, _optionsX, _optionsY, _optionsPicInInventory, _graph->_shadowTable50); + + _optionEnabled = -1; + int optionsYCord = mousePos.y - (_optionsY + 16); + if (optionsYCord >= 0) { + int selectedOptionNr = optionsYCord / _invOptionsStep; + if (selectedOptionNr < _invOptionsNumber) { + _optionEnabled = selectedOptionNr; + } + } + int optionsColor; + int textY = _optionsY + 16; + for (int i = 0; i < _invOptionsNumber; i++) { + if (i != _optionEnabled) { + optionsColor = _optionsColor1; + } else { + optionsColor = _optionsColor2; + } + Common::String invText; + switch(getLanguage()) { + case Common::PL_POL: + invText = invOptionsTextPL[i]; + break; + case Common::DE_DEU: + invText = invOptionsTextDE[i]; + break; + case Common::EN_ANY: + invText = invOptionsTextEN[i]; + break; + default: + error("Unknown game language %d", getLanguage()); + break; + }; + uint16 textW = getTextWidth(invText.c_str()); + uint16 textX = _optionsX + _invOptionsWidth / 2 - textW / 2; + _font->drawString(_graph->_screenForInventory, invText, textX, textY, _graph->_screenForInventory->w, optionsColor); + textY += _invOptionsStep; + } + } +} + +void PrinceEngine::displayInventory() { + + _mainHero->freeOldMove(); + _secondHero->freeOldMove(); + + _interpreter->setFgOpcodePC(0); + + stopAllSamples(); + + prepareInventoryToView(); + + while (!shouldQuit()) { + + if (_textSlots[0]._str != nullptr) { + changeCursor(0); + } else { + changeCursor(_currentPointerNumber); + + Common::Rect inventoryRect(_invX1, _invY1, _invX1 + _invWidth, _invY1 + _invHeight); + Common::Point mousePos = _system->getEventManager()->getMousePos(); + + if (!_invCurInside && inventoryRect.contains(mousePos)) { + _invCurInside = true; + } + + if (_invCurInside && !inventoryRect.contains(mousePos)) { + inventoryFlagChange(false); + _invCurInside = false; + break; + } + } + + rememberScreenInv(); + + Graphics::Surface *suitcase = _suitcaseBmp->getSurface(); + _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); + + drawInvItems(); + + showTexts(_graph->_screenForInventory); + + if (!_optionsFlag && _textSlots[0]._str == nullptr) { + _selectedMob = checkMob(_graph->_screenForInventory, _invMobList, false); + } + + checkInvOptions(); + + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + while (eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + keyHandler(event); + break; + case Common::EVENT_LBUTTONDOWN: + inventoryLeftMouseButton(); + break; + case Common::EVENT_RBUTTONDOWN: + inventoryRightMouseButton(); + break; + default: + break; + } + } + + if (!_showInventoryFlag) { + break; + } + + if (shouldQuit()) + return; + + getDebugger()->onFrame(); + _graph->update(_graph->_screenForInventory); + pausePrinceEngine(); + } + + if (_currentPointerNumber == 2) { + _flags->setFlagValue(Flags::SELITEM, _selectedItem); + } else { + _flags->setFlagValue(Flags::SELITEM, 0); + } +} + +void PrinceEngine::openInventoryCheck() { + if (!_optionsFlag) { + if (_mouseFlag == 1 || _mouseFlag == 2) { + if (_mainHero->_visible) { + if (!_flags->getFlagValue(Flags::INVALLOWED)) { + // 29 - Basement, 50 - Map + if (_locationNr != 29 && _locationNr != 50) { + Common::Point mousePos = _system->getEventManager()->getMousePos(); + if (mousePos.y < 4 && !_showInventoryFlag) { + _invCounter++; + } else { + _invCounter = 0; + } + if (_invCounter >= _invMaxCount) { + inventoryFlagChange(true); + } + } + } + } + } + } +} + +} // End of namespace Prince diff --git a/engines/prince/module.mk b/engines/prince/module.mk index 8446d07a12..ecc109a8e6 100644 --- a/engines/prince/module.mk +++ b/engines/prince/module.mk @@ -12,6 +12,7 @@ MODULE_OBJS = \ font.o \ graphics.o \ hero.o \ + inventory.o \ mhwanh.o \ music.o \ mob.o \ @@ -23,7 +24,8 @@ MODULE_OBJS = \ script.o \ sound.o \ variatxt.o \ - videoplayer.o + videoplayer.o \ + walk.o # This module can be built as a plugin ifeq ($(ENABLE_PRINCE), DYNAMIC_PLUGIN) diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp index 654b87ea26..f29b8c2bae 100644 --- a/engines/prince/prince.cpp +++ b/engines/prince/prince.cpp @@ -51,7 +51,6 @@ #include "prince/archive.h" #include "prince/hero.h" #include "prince/animation.h" -#include "prince/option_text.h" #include "prince/curve_values.h" namespace Prince { @@ -696,369 +695,6 @@ void PrinceEngine::pausePrinceEngine(int fps) { _currentTime = _system->getMillis(); } -void PrinceEngine::addInv(int heroId, int item, bool addItemQuiet) { - Hero *hero = nullptr; - if (!heroId) { - hero = _mainHero; - } else if (heroId == 1) { - hero = _secondHero; - } - if (hero != nullptr) { - if (hero->_inventory.size() < kMaxItems) { - if (item != 0x7FFF) { - hero->_inventory.push_back(item); - } - if (!addItemQuiet) { - addInvObj(); - } - _interpreter->setResult(0); - } else { - _interpreter->setResult(1); - } - } -} - -void PrinceEngine::remInv(int heroId, int item) { - Hero *hero = nullptr; - if (!heroId) { - hero = _mainHero; - } else if (heroId == 1) { - hero = _secondHero; - } - if (hero != nullptr) { - for (uint i = 0; i < hero->_inventory.size(); i++) { - if (hero->_inventory[i] == item) { - hero->_inventory.remove_at(i); - _interpreter->setResult(0); - return; - } - } - } - _interpreter->setResult(1); -} - -void PrinceEngine::clearInv(int heroId) { - switch (heroId) { - case 0: - _mainHero->_inventory.clear(); - break; - case 1: - _secondHero->_inventory.clear(); - break; - default: - error("clearInv() - wrong hero slot"); - break; - } -} - -void PrinceEngine::swapInv(int heroId) { - Common::Array<int> tempInv; - Hero *hero = nullptr; - if (!heroId) { - hero = _mainHero; - } else if (heroId == 1) { - hero = _secondHero; - } - if (hero != nullptr) { - for (uint i = 0; i < hero->_inventory.size(); i++) { - tempInv.push_back(hero->_inventory[i]); - } - hero->_inventory.clear(); - for (uint i = 0; i < hero->_inventory2.size(); i++) { - hero->_inventory.push_back(hero->_inventory2[i]); - } - hero->_inventory2.clear(); - for (uint i = 0; i < tempInv.size(); i++) { - hero->_inventory2.push_back(tempInv[i]); - } - tempInv.clear(); - } -} - -void PrinceEngine::addInvObj() { - changeCursor(0); - prepareInventoryToView(); - - _inventoryBackgroundRemember = true; - drawScreen(); - - Graphics::Surface *suitcase = _suitcaseBmp->getSurface(); - - if (!_flags->getFlagValue(Flags::CURSEBLINK)) { - - loadSample(27, "PRZEDMIO.WAV"); - playSample(27, 0); - - _mst_shadow2 = 1; - - while (_mst_shadow2 < 512) { - rememberScreenInv(); - _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); - drawInvItems(); - _graph->update(_graph->_screenForInventory); - _mst_shadow2 += 50; - Common::Event event; - Common::EventManager *eventMan = _system->getEventManager(); - eventMan->pollEvent(event); - if (shouldQuit()) { - return; - } - pausePrinceEngine(); - } - while (_mst_shadow2 > 256) { - rememberScreenInv(); - _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); - drawInvItems(); - _graph->update(_graph->_screenForInventory); - _mst_shadow2 -= 42; - Common::Event event; - Common::EventManager *eventMan = _system->getEventManager(); - eventMan->pollEvent(event); - if (shouldQuit()) { - return; - } - pausePrinceEngine(); - } - } else { - //CURSEBLINK: - for (int i = 0; i < 3; i++) { - _mst_shadow2 = 256; - while (_mst_shadow2 < 512) { - rememberScreenInv(); - _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); - drawInvItems(); - _graph->update(_graph->_screenForInventory); - _mst_shadow2 += 50; - Common::Event event; - Common::EventManager *eventMan = _system->getEventManager(); - eventMan->pollEvent(event); - if (shouldQuit()) { - return; - } - pausePrinceEngine(); - } - while (_mst_shadow2 > 256) { - rememberScreenInv(); - _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); - drawInvItems(); - _graph->update(_graph->_screenForInventory); - _mst_shadow2 -= 50; - Common::Event event; - Common::EventManager *eventMan = _system->getEventManager(); - eventMan->pollEvent(event); - if (shouldQuit()) { - return; - } - pausePrinceEngine(); - } - } - } - _mst_shadow2 = 0; - for (int i = 0; i < 20; i++) { - rememberScreenInv(); - _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); - drawInvItems(); - _graph->update(_graph->_screenForInventory); - Common::Event event; - Common::EventManager *eventMan = _system->getEventManager(); - eventMan->pollEvent(event); - if (shouldQuit()) { - return; - } - pausePrinceEngine(); - } -} - -void PrinceEngine::rememberScreenInv() { - _graph->_screenForInventory->copyFrom(*_graph->_frontScreen); -} - -void PrinceEngine::inventoryFlagChange(bool inventoryState) { - if (inventoryState) { - _showInventoryFlag = true; - _inventoryBackgroundRemember = true; - } else { - _showInventoryFlag = false; - } -} - -void PrinceEngine::prepareInventoryToView() { - _invMobList.clear(); - int invItem = _mainHero->_inventory.size(); - _invLine = invItem / 3; - if (invItem % 3) { - _invLine++; - } - if (_invLine < 4) { - _invLine = 4; - } - _maxInvW = (374 - 2 * _invLine) / _invLine; - _invLineW = _maxInvW - 2; - - int currInvX = _invLineX; - int currInvY = _invLineY; - - Common::MemoryReadStream stream(_invTxt, _invTxtSize); - byte c; - - uint item = 0; - for (int i = 0; i < _invLines; i++) { - for (int j = 0; j < _invLine; j++) { - Mob tempMobItem; - if (item < _mainHero->_inventory.size()) { - int itemNr = _mainHero->_inventory[item]; - tempMobItem._visible = 0; - tempMobItem._mask = itemNr; - tempMobItem._rect = Common::Rect(currInvX + _picWindowX, currInvY, currInvX + _picWindowX + _invLineW - 1, currInvY + _invLineH - 1); - tempMobItem._type = 0; // to work with checkMob() - - tempMobItem._name = ""; - tempMobItem._examText = ""; - int txtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8]); - int examTxtOffset = READ_LE_UINT32(&_invTxt[itemNr * 8 + 4]); - - stream.seek(txtOffset); - while ((c = stream.readByte())) { - tempMobItem._name += c; - } - - stream.seek(examTxtOffset); - while ((c = stream.readByte())) { - tempMobItem._examText += c; - } - _invMobList.push_back(tempMobItem); - } - currInvX += _invLineW + _invLineSkipX; - item++; - } - currInvX = _invLineX; - currInvY += _invLineSkipY + _invLineH; - } -} - -void PrinceEngine::drawInvItems() { - int currInvX = _invLineX; - int currInvY = _invLineY; - uint item = 0; - for (int i = 0; i < _invLines; i++) { - for (int j = 0; j < _invLine; j++) { - if (item < _mainHero->_inventory.size()) { - int itemNr = _mainHero->_inventory[item]; - _mst_shadow = 0; - if (_mst_shadow2) { - if (!_flags->getFlagValue(Flags::CURSEBLINK)) { - if (item + 1 == _mainHero->_inventory.size()) { // last item in inventory - _mst_shadow = 1; - } - } else if (itemNr == 1 || itemNr == 3 || itemNr == 4 || itemNr == 7) { - _mst_shadow = 1; - } - } - - int drawX = currInvX; - int drawY = currInvY; - Graphics::Surface *itemSurface = nullptr; - if (itemNr != 68) { - itemSurface = _allInvList[itemNr].getSurface(); - if (itemSurface->h < _maxInvH) { - drawY += (_maxInvH - itemSurface->h) / 2; - } - } else { - // candle item: - if (_candleCounter == 8) { - _candleCounter = 0; - } - itemNr = _candleCounter; - _candleCounter++; - itemNr &= 7; - itemNr += 71; - itemSurface = _allInvList[itemNr].getSurface(); - drawY += _allInvList[itemNr]._y + (_maxInvH - 76) / 2 - 200; - } - if (itemSurface->w < _maxInvW) { - drawX += (_maxInvW - itemSurface->w) / 2; - } - if (!_mst_shadow) { - _graph->drawTransparentSurface(_graph->_screenForInventory, drawX, drawY, itemSurface); - } else { - _mst_shadow = _mst_shadow2; - _graph->drawTransparentWithBlendSurface(_graph->_screenForInventory, drawX, drawY, itemSurface); - } - } - currInvX += _invLineW + _invLineSkipX; - item++; - } - currInvX = _invLineX; - currInvY += _invLineSkipY + _invLineH; - } -} - -void PrinceEngine::walkTo() { - if (_mainHero->_visible) { - _mainHero->freeHeroAnim(); - _mainHero->freeOldMove(); - _interpreter->storeNewPC(_script->_scriptInfo.usdCode); - int destX, destY; - if (_optionsMob != -1) { - destX = _mobList[_optionsMob]._examPosition.x; - destY = _mobList[_optionsMob]._examPosition.y; - _mainHero->_destDirection = _mobList[_optionsMob]._examDirection; - } else { - Common::Point mousePos = _system->getEventManager()->getMousePos(); - destX = mousePos.x + _picWindowX; - destY = mousePos.y + _picWindowY; - _mainHero->_destDirection = 0; - } - _mainHero->_coords = makePath(kMainHero, _mainHero->_middleX, _mainHero->_middleY, destX, destY); - if (_mainHero->_coords != nullptr) { - _mainHero->_currCoords = _mainHero->_coords; - _mainHero->_dirTab = _directionTable; - _mainHero->_currDirTab = _directionTable; - _directionTable = nullptr; - _mainHero->_state = Hero::kHeroStateMove; - moveShandria(); - } - } -} - -void PrinceEngine::moveRunHero(int heroId, int x, int y, int dir, bool runHeroFlag) { - Hero *hero = nullptr; - if (!heroId) { - hero = _mainHero; - } else if (heroId == 1) { - hero = _secondHero; - } - - if (hero != nullptr) { - if (dir) { - hero->_destDirection = dir; - } - if (x || y) { - hero->freeOldMove(); - hero->_coords = makePath(heroId, hero->_middleX, hero->_middleY, x, y); - if (hero->_coords != nullptr) { - hero->_currCoords = hero->_coords; - hero->_dirTab = _directionTable; - hero->_currDirTab = _directionTable; - _directionTable = nullptr; - if (runHeroFlag) { - hero->_state = Hero::kHeroStateRun; - } else { - hero->_state = Hero::kHeroStateMove; - } - if (heroId == kMainHero && _mouseFlag) { - moveShandria(); - } - } - } else { - hero->freeOldMove(); - hero->_state = Hero::kHeroStateTurn; - } - hero->freeHeroAnim(); - hero->_visible = 1; - } -} - void PrinceEngine::leftMouseButton() { _flags->setFlagValue(Flags::ESCAPED2, 1); // skip intro animation _flags->setFlagValue(Flags::LMOUSE, 1); @@ -1159,351 +795,6 @@ void PrinceEngine::rightMouseButton() { } } -void PrinceEngine::inventoryLeftMouseButton() { - if (!_mouseFlag) { - _textSlots[0]._time = 0; - _textSlots[0]._str = nullptr; - stopSample(28); - } - - if (_optionsFlag == 1) { - if (_selectedMob != -1) { - if (_optionEnabled < _invOptionsNumber) { - _optionsFlag = 0; - } else { - return; - } - } else { - error("PrinceEngine::inventoryLeftMouseButton() - optionsFlag = 1, selectedMob = 0"); - if (_currentPointerNumber == 2) { - changeCursor(1); - _currentPointerNumber = 1; - _selectedMob = -1; - _optionsMob = -1; - return; - } else { - return; - } - } - } else { - if (_selectedMob != -1) { - if (_currentPointerNumber != 2) { - if (_invMobList[_selectedMob]._mask != 29) { - _optionEnabled = 0; - } else { - // map item - _optionEnabled = 1; - } - } else { - //use_item_on_item - int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem); - if (invObjUU == -1) { - int textNr = 80011; // "I can't do it." - if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) { - textNr = 80020; // "Nothing is happening." - } - _interpreter->setCurrentString(textNr); - printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100); - setVoice(0, 28, 1); - playSample(28, 0); - _selectedMob = -1; - _optionsMob = -1; - return; - } else { - _interpreter->storeNewPC(invObjUU); - _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask); - _showInventoryFlag = false; - } - } - } else { - return; - } - } - //do_option - if (_optionEnabled == 0) { - int invObjExamEvent = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjExam); - if (invObjExamEvent == -1) { - // do_standard - printAt(0, 216, (char *)_invMobList[_selectedMob]._examText.c_str(), kNormalWidth / 2, _invExamY); - _interpreter->setCurrentString(_invMobList[_selectedMob]._mask + 70000); - setVoice(0, 28, 1); - playSample(28, 0); - // disableuseuse - changeCursor(0); - _currentPointerNumber = 1; - } else { - _interpreter->storeNewPC(invObjExamEvent); - _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask); - _showInventoryFlag = false; - } - } else if (_optionEnabled == 1) { - // not_examine - int invObjUse = _script->scanMobEvents(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUse); - if (invObjUse == -1) { - // do_standard_use - _selectedMode = 0; - _selectedItem = _invMobList[_selectedMob]._mask; - makeInvCursor(_invMobList[_selectedMob]._mask); - _currentPointerNumber = 2; - changeCursor(2); - } else { - _interpreter->storeNewPC(invObjUse); - _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask); - _showInventoryFlag = false; - } - } else if (_optionEnabled == 4) { - // do_standard_give - _selectedMode = 1; - _selectedItem = _invMobList[_selectedMob]._mask; - makeInvCursor(_invMobList[_selectedMob]._mask); - _currentPointerNumber = 2; - changeCursor(2); - } else { - // use_item_on_item - int invObjUU = _script->scanMobEventsWithItem(_invMobList[_selectedMob]._mask, _script->_scriptInfo.invObjUU, _selectedItem); - if (invObjUU == -1) { - int textNr = 80011; // "I can't do it." - if (_selectedItem == 31 || _invMobList[_selectedMob]._mask == 31) { - textNr = 80020; // "Nothing is happening." - } - _interpreter->setCurrentString(textNr); - printAt(0, 216, (char *)_variaTxt->getString(textNr - 80000), kNormalWidth / 2, 100); - setVoice(0, 28, 1); - playSample(28, 0); - } else { - _interpreter->storeNewPC(invObjUU); - _flags->setFlagValue(Flags::CURRMOB, _invMobList[_selectedMob]._mask); - _showInventoryFlag = false; - } - } - _selectedMob = -1; - _optionsMob = -1; -} - -void PrinceEngine::inventoryRightMouseButton() { - if (_textSlots[0]._str == nullptr) { - enableOptions(false); - } -} - -void PrinceEngine::enableOptions(bool checkType) { - if (_optionsFlag != 1) { - changeCursor(1); - _currentPointerNumber = 1; - if (_selectedMob != -1) { - if (checkType) { - if (_mobList[_selectedMob]._type & 0x100) { - return; - } - } - Common::Point mousePos = _system->getEventManager()->getMousePos(); - int x1 = mousePos.x - _optionsWidth / 2; - int x2 = mousePos.x + _optionsWidth / 2; - if (x1 < 0) { - x1 = 0; - x2 = _optionsWidth; - } else if (x2 >= kNormalWidth) { - x1 = kNormalWidth - _optionsWidth; - x2 = kNormalWidth; - } - int y1 = mousePos.y - 10; - if (y1 < 0) { - y1 = 0; - } - if (y1 + _optionsHeight >= kNormalHeight) { - y1 = kNormalHeight - _optionsHeight; - } - _optionsMob = _selectedMob; - _optionsX = x1; - _optionsY = y1; - _optionsFlag = 1; - } - } -} - -void PrinceEngine::checkOptions() { - if (_optionsFlag) { - Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _optionsWidth, _optionsY + _optionsHeight); - Common::Point mousePos = _system->getEventManager()->getMousePos(); - if (!optionsRect.contains(mousePos)) { - _optionsFlag = 0; - _selectedMob = -1; - return; - } - _graph->drawAsShadowSurface(_graph->_frontScreen, _optionsX, _optionsY, _optionsPic, _graph->_shadowTable50); - - _optionEnabled = -1; - int optionsYCord = mousePos.y - (_optionsY + 16); - if (optionsYCord >= 0) { - int selectedOptionNr = optionsYCord / _optionsStep; - if (selectedOptionNr < _optionsNumber) { - _optionEnabled = selectedOptionNr; - } - } - int optionsColor; - int textY = _optionsY + 16; - for (int i = 0; i < _optionsNumber; i++) { - if (i != _optionEnabled) { - optionsColor = _optionsColor1; - } else { - optionsColor = _optionsColor2; - } - Common::String optText; - switch(getLanguage()) { - case Common::PL_POL: - optText = optionsTextPL[i]; - break; - case Common::DE_DEU: - optText = optionsTextDE[i]; - break; - case Common::EN_ANY: - optText = optionsTextEN[i]; - break; - default: - break; - }; - uint16 textW = getTextWidth(optText.c_str()); - uint16 textX = _optionsX + _optionsWidth / 2 - textW / 2; - _font->drawString(_graph->_frontScreen, optText, textX, textY, textW, optionsColor); - textY += _optionsStep; - } - } -} - -void PrinceEngine::checkInvOptions() { - if (_optionsFlag) { - Common::Rect optionsRect(_optionsX, _optionsY, _optionsX + _invOptionsWidth, _optionsY + _invOptionsHeight); - Common::Point mousePos = _system->getEventManager()->getMousePos(); - if (!optionsRect.contains(mousePos)) { - _optionsFlag = 0; - _selectedMob = -1; - return; - } - _graph->drawAsShadowSurface(_graph->_screenForInventory, _optionsX, _optionsY, _optionsPicInInventory, _graph->_shadowTable50); - - _optionEnabled = -1; - int optionsYCord = mousePos.y - (_optionsY + 16); - if (optionsYCord >= 0) { - int selectedOptionNr = optionsYCord / _invOptionsStep; - if (selectedOptionNr < _invOptionsNumber) { - _optionEnabled = selectedOptionNr; - } - } - int optionsColor; - int textY = _optionsY + 16; - for (int i = 0; i < _invOptionsNumber; i++) { - if (i != _optionEnabled) { - optionsColor = _optionsColor1; - } else { - optionsColor = _optionsColor2; - } - Common::String invText; - switch(getLanguage()) { - case Common::PL_POL: - invText = invOptionsTextPL[i]; - break; - case Common::DE_DEU: - invText = invOptionsTextDE[i]; - break; - case Common::EN_ANY: - invText = invOptionsTextEN[i]; - break; - default: - error("Unknown game language %d", getLanguage()); - break; - }; - uint16 textW = getTextWidth(invText.c_str()); - uint16 textX = _optionsX + _invOptionsWidth / 2 - textW / 2; - _font->drawString(_graph->_screenForInventory, invText, textX, textY, _graph->_screenForInventory->w, optionsColor); - textY += _invOptionsStep; - } - } -} - -void PrinceEngine::displayInventory() { - - _mainHero->freeOldMove(); - _secondHero->freeOldMove(); - - _interpreter->setFgOpcodePC(0); - - stopAllSamples(); - - prepareInventoryToView(); - - while (!shouldQuit()) { - - if (_textSlots[0]._str != nullptr) { - changeCursor(0); - } else { - changeCursor(_currentPointerNumber); - - Common::Rect inventoryRect(_invX1, _invY1, _invX1 + _invWidth, _invY1 + _invHeight); - Common::Point mousePos = _system->getEventManager()->getMousePos(); - - if (!_invCurInside && inventoryRect.contains(mousePos)) { - _invCurInside = true; - } - - if (_invCurInside && !inventoryRect.contains(mousePos)) { - inventoryFlagChange(false); - _invCurInside = false; - break; - } - } - - rememberScreenInv(); - - Graphics::Surface *suitcase = _suitcaseBmp->getSurface(); - _graph->drawTransparentSurface(_graph->_screenForInventory, 0, 0, suitcase); - - drawInvItems(); - - showTexts(_graph->_screenForInventory); - - if (!_optionsFlag && _textSlots[0]._str == nullptr) { - _selectedMob = checkMob(_graph->_screenForInventory, _invMobList, false); - } - - checkInvOptions(); - - Common::Event event; - Common::EventManager *eventMan = _system->getEventManager(); - while (eventMan->pollEvent(event)) { - switch (event.type) { - case Common::EVENT_KEYDOWN: - keyHandler(event); - break; - case Common::EVENT_LBUTTONDOWN: - inventoryLeftMouseButton(); - break; - case Common::EVENT_RBUTTONDOWN: - inventoryRightMouseButton(); - break; - default: - break; - } - } - - if (!_showInventoryFlag) { - break; - } - - if (shouldQuit()) - return; - - getDebugger()->onFrame(); - _graph->update(_graph->_screenForInventory); - pausePrinceEngine(); - } - - if (_currentPointerNumber == 2) { - _flags->setFlagValue(Flags::SELITEM, _selectedItem); - } else { - _flags->setFlagValue(Flags::SELITEM, 0); - } -} - void PrinceEngine::createDialogBox(int dialogBoxNr) { _dialogLines = 0; int amountOfDialogOptions = 0; @@ -1672,66 +963,6 @@ void PrinceEngine::talkHero(int slot) { _interpreter->increaseString(); } -void PrinceEngine::doTalkAnim(int animNumber, int slot, AnimType animType) { - Text &text = _textSlots[slot]; - int lines = calcTextLines((const char *)_interpreter->getString()); - int time = lines * 30; - if (animType == kNormalAnimation) { - Anim &normAnim = _normAnimList[animNumber]; - if (normAnim._animData != nullptr) { - if (!normAnim._state) { - if (normAnim._currW && normAnim._currH) { - text._color = _flags->getFlagValue(Flags::KOLOR); - text._x = normAnim._currX + normAnim._currW / 2; - text._y = normAnim._currY - 10; - } - } - } - } else if (animType == kBackgroundAnimation) { - if (!_backAnimList[animNumber].backAnims.empty()) { - int currAnim = _backAnimList[animNumber]._seq._currRelative; - Anim &backAnim = _backAnimList[animNumber].backAnims[currAnim]; - if (backAnim._animData != nullptr) { - if (!backAnim._state) { - if (backAnim._currW && backAnim._currH) { - text._color = _flags->getFlagValue(Flags::KOLOR); - text._x = backAnim._currX + backAnim._currW / 2; - text._y = backAnim._currY - 10; - } - } - } - } - } else { - error("doTalkAnim() - wrong animType: %d", animType); - } - text._time = time; - if (getLanguage() == Common::DE_DEU) { - correctStringDEU((char *)_interpreter->getString()); - } - text._str = (const char *)_interpreter->getString(); - _interpreter->increaseString(); -} - -void PrinceEngine::freeNormAnim(int slot) { - if (!_normAnimList.empty()) { - _normAnimList[slot]._state = 1; - if (_normAnimList[slot]._animData != nullptr) { - delete _normAnimList[slot]._animData; - _normAnimList[slot]._animData = nullptr; - } - if (_normAnimList[slot]._shadowData != nullptr) { - delete _normAnimList[slot]._shadowData; - _normAnimList[slot]._shadowData = nullptr; - } - } -} - -void PrinceEngine::freeAllNormAnims() { - for (int i = 0; i < kMaxNormAnims; i++) { - freeNormAnim(i); - } -} - void PrinceEngine::getCurve() { _flags->setFlagValue(Flags::TORX1, _curveData[_curvPos]); _flags->setFlagValue(Flags::TORY1, _curveData[_curvPos + 1]); @@ -1905,1544 +1136,6 @@ void PrinceEngine::scrollCredits() { blackPalette(); } -// Modified version of Graphics::drawLine() to allow breaking the loop and return value -int PrinceEngine::drawLine(int x0, int y0, int x1, int y1, int (*plotProc)(int, int, void *), void *data) { - // Bresenham's line algorithm, as described by Wikipedia - const bool steep = ABS(y1 - y0) > ABS(x1 - x0); - - if (steep) { - SWAP(x0, y0); - SWAP(x1, y1); - } - - const int delta_x = ABS(x1 - x0); - const int delta_y = ABS(y1 - y0); - const int delta_err = delta_y; - int x = x0; - int y = y0; - int err = 0; - - const int x_step = (x0 < x1) ? 1 : -1; - const int y_step = (y0 < y1) ? 1 : -1; - - int stopFlag = 0; - if (steep) - stopFlag = (*plotProc)(y, x, data); - else - stopFlag = (*plotProc)(x, y, data); - - while (x != x1 && !stopFlag) { - x += x_step; - err += delta_err; - if (2 * err > delta_x) { - y += y_step; - err -= delta_x; - } - if (steep) - stopFlag = (*plotProc)(y, x, data); - else - stopFlag = (*plotProc)(x, y, data); - } - return stopFlag; -} - -int PrinceEngine::getPixelAddr(byte *pathBitmap, int x, int y) { - int mask = 128 >> (x & 7); - byte value = pathBitmap[x / 8 + y * 80]; - return (mask & value); -} - -void PrinceEngine::findPoint(int x, int y) { - _fpX = x; - _fpY = y; - - if (getPixelAddr(_roomPathBitmap, x, y)) { - return; - } - - int fpL = x; - int fpU = y; - int fpR = x; - int fpD = y; - - while (1) { - if (fpD != kMaxPicHeight) { - if (getPixelAddr(_roomPathBitmap, x, fpD)) { - _fpX = x; - _fpY = fpD; - break; - } - fpD++; - } - if (fpU) { - if (getPixelAddr(_roomPathBitmap, x, fpU)) { - _fpX = x; - _fpY = fpU; - break; - } - fpU--; - } - if (fpL) { - if (getPixelAddr(_roomPathBitmap, fpL, y)) { - _fpX = fpL; - _fpY = y; - break; - } - fpL--; - } - if (fpR != _sceneWidth) { - if (getPixelAddr(_roomPathBitmap, fpR, y)) { - _fpX = fpR; - _fpY = y; - break; - } - fpR++; - } - if (!fpU && (fpD == kMaxPicHeight)) { - if (!fpL && (fpR == _sceneWidth)) { - break; - } - } - } -} - -Direction PrinceEngine::makeDirection(int x1, int y1, int x2, int y2) { - if (x1 != x2) { - if (y1 != y2) { - if (x1 > x2) { - if (y1 > y2) { - if (x1 - x2 >= y1 - y2) { - return kDirLU; - } else { - return kDirUL; - } - } else { - if (x1 - x2 >= y2 - y1) { - return kDirLD; - } else { - return kDirDL; - } - } - } else { - if (y1 > y2) { - if (x2 - x1 >= y1 - y2) { - return kDirRU; - } else { - return kDirUR; - } - } else { - if (x2 - x1 >= y2 - y1) { - return kDirRD; - } else { - return kDirDR; - } - } - } - } else { - if (x1 >= x2) { - return kDirL; - } else { - return kDirR; - } - } - } else { - if (y1 >= y2) { - return kDirU; - } else { - return kDirD; - } - } -} - -void PrinceEngine::specialPlot(int x, int y) { - if (_coords < _coordsBufEnd) { - WRITE_LE_UINT16(_coords, x); - _coords += 2; - WRITE_LE_UINT16(_coords, y); - _coords += 2; - specialPlot2(x, y); - } -} - -void PrinceEngine::specialPlot2(int x, int y) { - int mask = 128 >> (x & 7); - _roomPathBitmapTemp[x / 8 + y * 80] |= mask; -} - -void PrinceEngine::specialPlotInside(int x, int y) { - if (_coords < _coordsBufEnd) { - WRITE_LE_UINT16(_coords, x); - _coords += 2; - WRITE_LE_UINT16(_coords, y); - _coords += 2; - } -} - -int PrinceEngine::plotTraceLine(int x, int y, void *data) { - PrinceEngine *traceLine = (PrinceEngine *)data; - if (!traceLine->_traceLineFirstPointFlag) { - if (!traceLine->getPixelAddr(traceLine->_roomPathBitmapTemp, x, y)) { - if (traceLine->getPixelAddr(traceLine->_roomPathBitmap, x, y)) { - traceLine->specialPlotInside(x, y); - traceLine->_traceLineLen++; - return 0; - } else { - return -1; - } - } else { - return 1; - } - } else { - traceLine->_traceLineFirstPointFlag = false; - return 0; - } -} - -int PrinceEngine::leftDownDir() { - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::leftDir() { - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::leftUpDir() { - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::rightDownDir() { - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::rightDir() { - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::rightUpDir() { - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::upLeftDir() { - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::upDir() { - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::upRightDir() { - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::downLeftDir() { - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::downDir() { - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::downRightDir() { - if (!checkRightDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDownDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkRightUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - if (!checkLeftUpDir()) { - specialPlot(_checkX, _checkY); - return 0; - } - return -1; -} - -int PrinceEngine::cpe() { - if ((*(_checkBitmap - kPBW) & _checkMask)) { - if ((*(_checkBitmap + kPBW) & _checkMask)) { - int value; - switch (_checkMask) { - case 128: - value = READ_LE_UINT16(_checkBitmap - 1); - value &= 0x4001; - if (value != 0x4001) { - return 0; - } - break; - case 64: - value = *_checkBitmap; - value &= 0xA0; - if (value != 0xA0) { - return 0; - } - break; - case 32: - value = *_checkBitmap; - value &= 0x50; - if (value != 0x50) { - return 0; - } - break; - case 16: - value = *_checkBitmap; - value &= 0x28; - if (value != 0x28) { - return 0; - } - break; - case 8: - value = *_checkBitmap; - value &= 0x14; - if (value != 0x14) { - return 0; - } - break; - case 4: - value = *_checkBitmap; - value &= 0xA; - if (value != 0xA) { - return 0; - } - break; - case 2: - value = *_checkBitmap; - value &= 0x5; - if (value != 0x5) { - return 0; - } - break; - case 1: - value = READ_LE_UINT16(_checkBitmap); - value &= 0x8002; - if (value != 0x8002) { - return 0; - } - break; - default: - error("Wrong _checkMask value - cpe()"); - break; - } - _checkX = _rembX; - _checkY = _rembY; - _checkBitmapTemp = _rembBitmapTemp; - _checkBitmap = _rembBitmap; - _checkMask = _rembMask; - return -1; - } - return 0; - } - return 0; -} - -int PrinceEngine::checkLeftDownDir() { - if (_checkX && _checkY != (kMaxPicHeight / 2 - 1)) { - int tempMask = _checkMask; - if (tempMask != 128) { - tempMask <<= 1; - if ((*(_checkBitmap + kPBW) & tempMask)) { - if (!(*(_checkBitmapTemp + kPBW) & tempMask)) { - _checkBitmap += kPBW; - _checkBitmapTemp += kPBW; - _checkMask = tempMask; - } else { - return 1; - } - } else { - return -1; - } - } else { - if ((*(_checkBitmap + kPBW - 1) & 1)) { - if (!(*(_checkBitmapTemp + kPBW - 1) & 1)) { - _checkBitmap += (kPBW - 1); - _checkBitmapTemp += (kPBW - 1); - _checkMask = 1; - } else { - return 1; - } - } else { - return -1; - } - } - _checkX--; - _checkY++; - return cpe(); - } else { - return -1; - } -} - -int PrinceEngine::checkLeftDir() { - if (_checkX) { - int tempMask = _checkMask; - if (tempMask != 128) { - tempMask <<= 1; - if ((*(_checkBitmap) & tempMask)) { - if (!(*(_checkBitmapTemp) & tempMask)) { - _checkMask = tempMask; - } else { - return 1; - } - } else { - return -1; - } - } else { - if ((*(_checkBitmap - 1) & 1)) { - if (!(*(_checkBitmapTemp - 1) & 1)) { - _checkBitmap--; - _checkBitmapTemp--; - _checkMask = 1; - } else { - return 1; - } - } else { - return -1; - } - } - _checkX--; - return cpe(); - } else { - return -1; - } -} - -int PrinceEngine::checkDownDir() { - if (_checkY != (kMaxPicHeight / 2 - 1)) { - if ((*(_checkBitmap + kPBW) & _checkMask)) { - if (!(*(_checkBitmapTemp + kPBW) & _checkMask)) { - _checkBitmap += kPBW; - _checkBitmapTemp += kPBW; - _checkY++; - return cpe(); - } else { - return 1; - } - } else { - return -1; - } - } else { - return -1; - } -} - -int PrinceEngine::checkUpDir() { - if (_checkY) { - if ((*(_checkBitmap - kPBW) & _checkMask)) { - if (!(*(_checkBitmapTemp - kPBW) & _checkMask)) { - _checkBitmap -= kPBW; - _checkBitmapTemp -= kPBW; - _checkY--; - return cpe(); - } else { - return 1; - } - } else { - return -1; - } - } else { - return -1; - } -} - -int PrinceEngine::checkRightDir() { - if (_checkX != (kMaxPicWidth / 2 - 1)) { - int tempMask = _checkMask; - if (tempMask != 1) { - tempMask >>= 1; - if ((*(_checkBitmap) & tempMask)) { - if (!(*(_checkBitmapTemp) & tempMask)) { - _checkMask = tempMask; - } else { - return 1; - } - } else { - return -1; - } - } else { - if ((*(_checkBitmap + 1) & 128)) { - if (!(*(_checkBitmapTemp + 1) & 128)) { - _checkBitmap++; - _checkBitmapTemp++; - _checkMask = 128; - } else { - return 1; - } - } else { - return -1; - } - } - _checkX++; - return cpe(); - } else { - return -1; - } -} - -int PrinceEngine::checkLeftUpDir() { - if (_checkX && _checkY) { - int tempMask = _checkMask; - if (tempMask != 128) { - tempMask <<= 1; - if ((*(_checkBitmap - kPBW) & tempMask)) { - if (!(*(_checkBitmapTemp - kPBW) & tempMask)) { - _checkBitmap -= kPBW; - _checkBitmapTemp -= kPBW; - _checkMask = tempMask; - } else { - return 1; - } - } else { - return -1; - } - } else { - if ((*(_checkBitmap - (kPBW + 1)) & 1)) { - if (!(*(_checkBitmapTemp - (kPBW + 1)) & 1)) { - _checkBitmap -= (kPBW + 1); - _checkBitmapTemp -= (kPBW + 1); - _checkMask = 1; - } else { - return 1; - } - } else { - return -1; - } - } - _checkX--; - _checkY--; - return cpe(); - } else { - return -1; - } -} - -int PrinceEngine::checkRightDownDir() { - if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY != (kMaxPicHeight / 2 - 1)) { - int tempMask = _checkMask; - if (tempMask != 1) { - tempMask >>= 1; - if ((*(_checkBitmap + kPBW) & tempMask)) { - if (!(*(_checkBitmapTemp + kPBW) & tempMask)) { - _checkBitmap += kPBW; - _checkBitmapTemp += kPBW; - _checkMask = tempMask; - } else { - return 1; - } - } else { - return -1; - } - } else { - if ((*(_checkBitmap + kPBW + 1) & 128)) { - if (!(*(_checkBitmapTemp + kPBW + 1) & 128)) { - _checkBitmap += kPBW + 1; - _checkBitmapTemp += kPBW + 1; - _checkMask = 128; - } else { - return 1; - } - } else { - return -1; - } - } - _checkX++; - _checkY++; - return cpe(); - } else { - return -1; - } -} - -int PrinceEngine::checkRightUpDir() { - if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY) { - int tempMask = _checkMask; - if (tempMask != 1) { - tempMask >>= 1; - if ((*(_checkBitmap - kPBW) & tempMask)) { - if (!(*(_checkBitmapTemp - kPBW) & tempMask)) { - _checkBitmap -= kPBW; - _checkBitmapTemp -= kPBW; - _checkMask = tempMask; - } else { - return 1; - } - } else { - return -1; - } - } else { - if ((*(_checkBitmap - kPBW + 1) & 128)) { - if (!(*(_checkBitmapTemp - kPBW + 1) & 128)) { - _checkBitmap -= (kPBW - 1); - _checkBitmapTemp -= (kPBW - 1); - _checkMask = 128; - } else { - return 1; - } - } else { - return -1; - } - } - _checkX++; - _checkY--; - return cpe(); - } else { - return -1; - } -} - -bool PrinceEngine::tracePath(int x1, int y1, int x2, int y2) { - for (uint i = 0; i < kPathBitmapLen; i++) { - _roomPathBitmapTemp[i] = 0; - } - if (x1 != x2 || y1 != y2) { - if (getPixelAddr(_roomPathBitmap, x1, y1)) { - if (getPixelAddr(_roomPathBitmap, x2, y2)) { - _coords = _coordsBuf; - specialPlot(x1, y1); - - int x = x1; - int y = y1; - - while (1) { - int btx = x; - int bty = y; - byte *bcad = _coords; - - _traceLineLen = 0; - _traceLineFirstPointFlag = true; - int drawLineFlag = drawLine(x, y, x2, y2, &this->plotTraceLine, this); - - if (!drawLineFlag) { - return true; - } else if (drawLineFlag == -1 && _traceLineLen >= 2) { - byte *tempCorrds = bcad; - while (tempCorrds != _coords) { - x = READ_LE_UINT16(tempCorrds); - y = READ_LE_UINT16(tempCorrds + 2); - tempCorrds += 4; - specialPlot2(x, y); - } - } else { - _coords = bcad; - x = btx; - y = bty; - } - - Direction dir = makeDirection(x, y, x2, y2); - - _rembBitmapTemp = &_roomPathBitmapTemp[x / 8 + y * 80]; - _rembBitmap = &_roomPathBitmap[x / 8 + y * 80]; - _rembMask = 128 >> (x & 7); - _rembX = x; - _rembY = y; - - _checkBitmapTemp = _rembBitmapTemp; - _checkBitmap = _rembBitmap; - _checkMask = _rembMask; - _checkX = _rembX; - _checkY = _rembY; - - int result; - switch (dir) { - case kDirLD: - result = leftDownDir(); - break; - case kDirL: - result = leftDir(); - break; - case kDirLU: - result = leftUpDir(); - break; - case kDirRD: - result = rightDownDir(); - break; - case kDirR: - result = rightDir(); - break; - case kDirRU: - result = rightUpDir(); - break; - case kDirUL: - result = upLeftDir(); - break; - case kDirU: - result = upDir(); - break; - case kDirUR: - result = upRightDir(); - break; - case kDirDL: - result = downLeftDir(); - break; - case kDirD: - result = downDir(); - break; - case kDirDR: - result = downRightDir(); - break; - default: - result = -1; - error("tracePath: wrong direction %d", dir); - break; - } - - if (result) { - byte *tempCoords = _coords; - tempCoords -= 4; - if (tempCoords > _coordsBuf) { - int tempX = READ_LE_UINT16(tempCoords); - int tempY = READ_LE_UINT16(tempCoords + 2); - if (_checkX == tempX && _checkY == tempY) { - _coords = tempCoords; - } - x = READ_LE_UINT16(tempCoords); - y = READ_LE_UINT16(tempCoords + 2); - } else { - return false; - } - } else { - x = _checkX; - y = _checkY; - } - } - return true; - } else { - error("tracePath: wrong destination point"); - } - } else { - error("tracePath: wrong start point"); - } - } else { - error("tracePath: same point"); - } -} - -void PrinceEngine::specialPlotInside2(int x, int y) { - WRITE_LE_UINT16(_coords2, x); - _coords2 += 2; - WRITE_LE_UINT16(_coords2, y); - _coords2 += 2; -} - -int PrinceEngine::plotTracePoint(int x, int y, void *data) { - PrinceEngine *tracePoint = (PrinceEngine *)data; - if (!tracePoint->_tracePointFirstPointFlag) { - if (tracePoint->getPixelAddr(tracePoint->_roomPathBitmap, x, y)) { - tracePoint->specialPlotInside2(x, y); - return 0; - } else { - return -1; - } - } else { - tracePoint->_tracePointFirstPointFlag = false; - return 0; - } -} - -void PrinceEngine::approxPath() { - byte *oldCoords; - _coords2 = _coordsBuf2; - byte *tempCoordsBuf = _coordsBuf; // first point on path - byte *tempCoords = _coords; - if (tempCoordsBuf != tempCoords) { - tempCoords -= 4; // last point on path - while (tempCoordsBuf != tempCoords) { - int x1 = READ_LE_UINT16(tempCoords); - int y1 = READ_LE_UINT16(tempCoords + 2); - int x2 = READ_LE_UINT16(tempCoordsBuf); - int y2 = READ_LE_UINT16(tempCoordsBuf + 2); - tempCoordsBuf += 4; - //TracePoint - oldCoords = _coords2; - if (_coords2 == _coordsBuf2) { - WRITE_LE_UINT16(_coords2, x1); - WRITE_LE_UINT16(_coords2 + 2, y1); - _coords2 += 4; - } else { - int testX = READ_LE_UINT16(_coords2 - 4); - int testY = READ_LE_UINT16(_coords2 - 2); - if (testX != x1 || testY != y1) { - WRITE_LE_UINT16(_coords2, x1); - WRITE_LE_UINT16(_coords2 + 2, y1); - _coords2 += 4; - } - } - _tracePointFirstPointFlag = true; - bool drawLineFlag = drawLine(x1, y1, x2, y2, &this->plotTracePoint, this); - if (!drawLineFlag) { - tempCoords = tempCoordsBuf - 4; - tempCoordsBuf = _coordsBuf; - } else { - _coords2 = oldCoords; - } - } - } -} - -void PrinceEngine::freeDirectionTable() { - if (_directionTable != nullptr) { - free(_directionTable); - _directionTable = nullptr; - } -} - -int PrinceEngine::scanDirectionsFindNext(byte *tempCoordsBuf, int xDiff, int yDiff) { - - int tempX, tempY, direction; - - tempX = Hero::kHeroDirLeft; - if (xDiff < 0) { - tempX = Hero::kHeroDirRight; - } - - tempY = Hero::kHeroDirUp; - if (yDiff < 0) { - tempY = Hero::kHeroDirDown; - } - - while (1) { - int againPointX1 = READ_LE_UINT16(tempCoordsBuf); - int againPointY1 = READ_LE_UINT16(tempCoordsBuf + 2); - tempCoordsBuf += 4; - - if (tempCoordsBuf == _coords) { - direction = tempX; - break; - } - - int dX = againPointX1 - READ_LE_UINT16(tempCoordsBuf); - int dY = againPointY1 - READ_LE_UINT16(tempCoordsBuf + 2); - - if (dX != xDiff) { - direction = tempY; - break; - } - - if (dY != yDiff) { - direction = tempX; - break; - } - } - return direction; -} - -void PrinceEngine::scanDirections() { - freeDirectionTable(); - byte *tempCoordsBuf = _coordsBuf; - if (tempCoordsBuf != _coords) { - int size = (_coords - tempCoordsBuf) / 4 + 1; // number of coord points plus one for end marker - _directionTable = (byte *)malloc(size); - byte *tempDirTab = _directionTable; - int direction = -1; - int lastDirection = -1; - - while (1) { - int x1 = READ_LE_UINT16(tempCoordsBuf); - int y1 = READ_LE_UINT16(tempCoordsBuf + 2); - tempCoordsBuf += 4; - if (tempCoordsBuf == _coords) { - break; - } - int x2 = READ_LE_UINT16(tempCoordsBuf); - int y2 = READ_LE_UINT16(tempCoordsBuf + 2); - - int xDiff = x1 - x2; - int yDiff = y1 - y2; - - if (xDiff) { - if (yDiff) { - if (lastDirection != -1) { - direction = lastDirection; - if (direction == Hero::kHeroDirLeft) { - if (xDiff < 0) { - direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); - } - } else if (direction == Hero::kHeroDirRight) { - if (xDiff >= 0) { - direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); - } - } else if (direction == Hero::kHeroDirUp) { - if (yDiff < 0) { - direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); - } - } else { - if (yDiff >= 0) { - direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); - } - } - } else { - direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); - } - } else { - direction = Hero::kHeroDirLeft; - if (xDiff < 0) { - direction = Hero::kHeroDirRight; - } - } - } else { - if (yDiff) { - direction = Hero::kHeroDirUp; - if (yDiff < 0) { - direction = Hero::kHeroDirDown; - } - } else { - direction = lastDirection; - } - } - lastDirection = direction; - *tempDirTab = direction; - tempDirTab++; - } - *tempDirTab = *(tempDirTab - 1); - tempDirTab++; - *tempDirTab = 0; - } -} - -void PrinceEngine::moveShandria() { - int shanLen1 = _shanLen; - if (_flags->getFlagValue(Flags::SHANDOG)) { - _secondHero->freeHeroAnim(); - _secondHero->freeOldMove(); - byte *shanCoords = _mainHero->_currCoords + shanLen1 * 4 - 4; - int shanX = READ_LE_UINT16(shanCoords - 4); - int shanY = READ_LE_UINT16(shanCoords - 2); - int xDiff = shanX - _secondHero->_middleX; - if (xDiff < 0) { - xDiff *= -1; - } - int yDiff = shanY - _secondHero->_middleY; - if (yDiff < 0) { - yDiff *= -1; - } - shanCoords -= 4; - if (shanCoords != _mainHero->_currCoords) { - yDiff *= 1.5; - int shanDis = xDiff * xDiff + yDiff * yDiff; - if (shanDis >= kMinDistance) { - while (1) { - shanCoords -= 4; - if (shanCoords == _mainHero->_currCoords) { - break; - } - int x = READ_LE_UINT16(shanCoords); - int y = READ_LE_UINT16(shanCoords + 2); - int pointDiffX = x - shanX; - if (pointDiffX < 0) { - pointDiffX *= -1; - } - int pointDiffY = y - shanY; - if (pointDiffY < 0) { - pointDiffY *= -1; - } - pointDiffY *= 1.5; - int distance = pointDiffX * pointDiffX + pointDiffY * pointDiffY; - if (distance >= kMinDistance) { - break; - } - } - int pathSizeDiff = (shanCoords - _mainHero->_currCoords) / 4; - int destDir = *(_mainHero->_currDirTab + pathSizeDiff); - _secondHero->_destDirection = destDir; - int destX = READ_LE_UINT16(shanCoords); - int destY = READ_LE_UINT16(shanCoords + 2); - _secondHero->_coords = makePath(kSecondHero, _secondHero->_middleX, _secondHero->_middleY, destX, destY); - if (_secondHero->_coords != nullptr) { - _secondHero->_currCoords = _secondHero->_coords; - int delay = shanLen1 - _shanLen; - if (delay < 6) { - delay = 6; - } - _secondHero->_moveDelay = delay / 2; - _secondHero->_state = Hero::kHeroStateDelayMove; - _secondHero->_dirTab = _directionTable; - _secondHero->_currDirTab = _directionTable; - _directionTable = nullptr; - } - } - } - } -} - -byte *PrinceEngine::makePath(int heroId, int currX, int currY, int destX, int destY) { - int realDestX = destX; - int realDestY = destY; - _flags->setFlagValue(Flags::MOVEDESTX, destX); - _flags->setFlagValue(Flags::MOVEDESTY, destY); - - int x1 = currX / 2; - int y1 = currY / 2; - int x2 = destX / 2; - int y2 = destY / 2; - - if ((x1 != x2) || (y1 != y2)) { - findPoint(x1, y1); - if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) { - return nullptr; - } - if ((x1 != _fpX) || (y1 != _fpY)) { - x1 = _fpX; - y1 = _fpY; - } - findPoint(x2, y2); - if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) { - return nullptr; - } - if ((x2 != _fpX) || (y2 != _fpY)) { - x2 = _fpX; - y2 = _fpY; - if (!_flags->getFlagValue(Flags::EXACTMOVE)) { - realDestX = x2 * 2; - realDestY = y2 * 2; - _flags->setFlagValue(Flags::MOVEDESTX, realDestX); - _flags->setFlagValue(Flags::MOVEDESTY, realDestY); - } else { - return nullptr; - } - } - - if ((x1 == x2) && (y1 == y2)) { - if (!heroId) { - _mainHero->freeOldMove(); - _mainHero->_state = Hero::kHeroStateTurn; - } else if (heroId == 1) { - _secondHero->freeOldMove(); - _secondHero->_state = Hero::kHeroStateTurn; - } - return nullptr; - } - - int pathLen1 = 0; - int pathLen2 = 0; - int stX = x1; - int stY = y1; - int sizeCoords2 = 0; - - if (tracePath(x1, y1, x2, y2)) { - allocCoords2(); - approxPath(); - sizeCoords2 = _coords2 - _coordsBuf2; - for (int i = 0; i < sizeCoords2; i++) { - _coordsBuf[i] = _coordsBuf2[i]; - } - _coords = _coordsBuf + sizeCoords2; - approxPath(); - _coordsBuf3 = _coordsBuf2; - _coordsBuf2 = nullptr; - _coords3 = _coords2; - _coords2 = nullptr; - pathLen1 = _coords3 - _coordsBuf3; - } - if (tracePath(x2, y2, x1, y1)) { - allocCoords2(); - approxPath(); - sizeCoords2 = _coords2 - _coordsBuf2; - for (int i = 0; i < sizeCoords2; i++) { - _coordsBuf[i] = _coordsBuf2[i]; - } - _coords = _coordsBuf + sizeCoords2; - approxPath(); - pathLen2 = _coords2 - _coordsBuf2; - } - - byte *chosenCoordsBuf = _coordsBuf2; - byte *choosenCoords = _coords2; - int choosenLength = pathLen1; - if (pathLen1 < pathLen2) { - chosenCoordsBuf = _coordsBuf3; - choosenCoords = _coords3; - choosenLength = pathLen2; - } - - if (choosenLength) { - if (chosenCoordsBuf != nullptr) { - int tempXBegin = READ_LE_UINT16(chosenCoordsBuf); - int tempYBegin = READ_LE_UINT16(chosenCoordsBuf + 2); - if (stX != tempXBegin || stY != tempYBegin) { - SWAP(chosenCoordsBuf, choosenCoords); - chosenCoordsBuf -= 4; - byte *tempCoordsBuf = _coordsBuf; - while (1) { - int cord = READ_LE_UINT32(chosenCoordsBuf); - WRITE_LE_UINT32(tempCoordsBuf, cord); - tempCoordsBuf += 4; - if (chosenCoordsBuf == choosenCoords) { - break; - } - chosenCoordsBuf -= 4; - } - _coords = tempCoordsBuf; - } else { - int sizeChoosen = choosenCoords - chosenCoordsBuf; - for (int i = 0; i < sizeChoosen; i++) { - _coordsBuf[i] = chosenCoordsBuf[i]; - } - _coords = _coordsBuf + sizeChoosen; - } - WRITE_LE_UINT32(_coords, 0xFFFFFFFF); - freeCoords2(); - freeCoords3(); - scanDirections(); - - byte *tempCoordsBuf = _coordsBuf; - byte *tempCoords = _coords; - byte *newCoords; - if (tempCoordsBuf != tempCoords) { - int normCoordsSize = _coords - _coordsBuf + 4; - newCoords = (byte *)malloc(normCoordsSize); - byte *newCoordsBegin = newCoords; - while (tempCoordsBuf != tempCoords) { - int newValueX = READ_LE_UINT16(tempCoordsBuf); - WRITE_LE_UINT16(newCoords, newValueX * 2); - newCoords += 2; - int newValueY = READ_LE_UINT16(tempCoordsBuf + 2); - WRITE_LE_UINT16(newCoords, newValueY * 2); - newCoords += 2; - tempCoordsBuf += 4; - } - WRITE_LE_UINT16(newCoords - 4, realDestX); - WRITE_LE_UINT16(newCoords - 2, realDestY); - WRITE_LE_UINT32(newCoords, 0xFFFFFFFF); - newCoords += 4; - _shanLen = (newCoords - newCoordsBegin); - _shanLen /= 4; - return newCoordsBegin; - } - } - } - _coords = _coordsBuf; - freeCoords2(); - freeCoords3(); - return nullptr; - } else { - if (!heroId) { - _mainHero->freeOldMove(); - _mainHero->_state = Hero::kHeroStateTurn; - } else if (heroId == 1) { - _secondHero->freeOldMove(); - _secondHero->_state = Hero::kHeroStateTurn; - } - return nullptr; - } -} - -void PrinceEngine::allocCoords2() { - if (_coordsBuf2 == nullptr) { - _coordsBuf2 = (byte *)malloc(kTracePts * 4); - _coords2 = _coordsBuf2; - } -} - -void PrinceEngine::freeCoords2() { - if (_coordsBuf2 != nullptr) { - free(_coordsBuf2); - _coordsBuf2 = nullptr; - _coords2 = nullptr; - } -} - -void PrinceEngine::freeCoords3() { - if (_coordsBuf3 != nullptr) { - free(_coordsBuf3); - _coordsBuf3 = nullptr; - _coords3 = nullptr; - } -} - -void PrinceEngine::openInventoryCheck() { - if (!_optionsFlag) { - if (_mouseFlag == 1 || _mouseFlag == 2) { - if (_mainHero->_visible) { - if (!_flags->getFlagValue(Flags::INVALLOWED)) { - // 29 - Basement, 50 - Map - if (_locationNr != 29 && _locationNr != 50) { - Common::Point mousePos = _system->getEventManager()->getMousePos(); - if (mousePos.y < 4 && !_showInventoryFlag) { - _invCounter++; - } else { - _invCounter = 0; - } - if (_invCounter >= _invMaxCount) { - inventoryFlagChange(true); - } - } - } - } - } - } -} - void PrinceEngine::mainLoop() { changeCursor(0); _currentTime = _system->getMillis(); diff --git a/engines/prince/walk.cpp b/engines/prince/walk.cpp new file mode 100644 index 0000000000..0e81c36f3f --- /dev/null +++ b/engines/prince/walk.cpp @@ -0,0 +1,1610 @@ +/* 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. + * + */ + +#include "prince/prince.h" +#include "prince/hero.h" +#include "prince/script.h" + +namespace Prince { + +void PrinceEngine::walkTo() { + if (_mainHero->_visible) { + _mainHero->freeHeroAnim(); + _mainHero->freeOldMove(); + _interpreter->storeNewPC(_script->_scriptInfo.usdCode); + int destX, destY; + if (_optionsMob != -1) { + destX = _mobList[_optionsMob]._examPosition.x; + destY = _mobList[_optionsMob]._examPosition.y; + _mainHero->_destDirection = _mobList[_optionsMob]._examDirection; + } else { + Common::Point mousePos = _system->getEventManager()->getMousePos(); + destX = mousePos.x + _picWindowX; + destY = mousePos.y + _picWindowY; + _mainHero->_destDirection = 0; + } + _mainHero->_coords = makePath(kMainHero, _mainHero->_middleX, _mainHero->_middleY, destX, destY); + if (_mainHero->_coords != nullptr) { + _mainHero->_currCoords = _mainHero->_coords; + _mainHero->_dirTab = _directionTable; + _mainHero->_currDirTab = _directionTable; + _directionTable = nullptr; + _mainHero->_state = Hero::kHeroStateMove; + moveShandria(); + } + } +} + +void PrinceEngine::moveRunHero(int heroId, int x, int y, int dir, bool runHeroFlag) { + Hero *hero = nullptr; + if (!heroId) { + hero = _mainHero; + } else if (heroId == 1) { + hero = _secondHero; + } + + if (hero != nullptr) { + if (dir) { + hero->_destDirection = dir; + } + if (x || y) { + hero->freeOldMove(); + hero->_coords = makePath(heroId, hero->_middleX, hero->_middleY, x, y); + if (hero->_coords != nullptr) { + hero->_currCoords = hero->_coords; + hero->_dirTab = _directionTable; + hero->_currDirTab = _directionTable; + _directionTable = nullptr; + if (runHeroFlag) { + hero->_state = Hero::kHeroStateRun; + } else { + hero->_state = Hero::kHeroStateMove; + } + if (heroId == kMainHero && _mouseFlag) { + moveShandria(); + } + } + } else { + hero->freeOldMove(); + hero->_state = Hero::kHeroStateTurn; + } + hero->freeHeroAnim(); + hero->_visible = 1; + } +} + +// Modified version of Graphics::drawLine() to allow breaking the loop and return value +int PrinceEngine::drawLine(int x0, int y0, int x1, int y1, int (*plotProc)(int, int, void *), void *data) { + // Bresenham's line algorithm, as described by Wikipedia + const bool steep = ABS(y1 - y0) > ABS(x1 - x0); + + if (steep) { + SWAP(x0, y0); + SWAP(x1, y1); + } + + const int delta_x = ABS(x1 - x0); + const int delta_y = ABS(y1 - y0); + const int delta_err = delta_y; + int x = x0; + int y = y0; + int err = 0; + + const int x_step = (x0 < x1) ? 1 : -1; + const int y_step = (y0 < y1) ? 1 : -1; + + int stopFlag = 0; + if (steep) + stopFlag = (*plotProc)(y, x, data); + else + stopFlag = (*plotProc)(x, y, data); + + while (x != x1 && !stopFlag) { + x += x_step; + err += delta_err; + if (2 * err > delta_x) { + y += y_step; + err -= delta_x; + } + if (steep) + stopFlag = (*plotProc)(y, x, data); + else + stopFlag = (*plotProc)(x, y, data); + } + return stopFlag; +} + +int PrinceEngine::getPixelAddr(byte *pathBitmap, int x, int y) { + int mask = 128 >> (x & 7); + byte value = pathBitmap[x / 8 + y * 80]; + return (mask & value); +} + +void PrinceEngine::findPoint(int x, int y) { + _fpX = x; + _fpY = y; + + if (getPixelAddr(_roomPathBitmap, x, y)) { + return; + } + + int fpL = x; + int fpU = y; + int fpR = x; + int fpD = y; + + while (1) { + if (fpD != kMaxPicHeight) { + if (getPixelAddr(_roomPathBitmap, x, fpD)) { + _fpX = x; + _fpY = fpD; + break; + } + fpD++; + } + if (fpU) { + if (getPixelAddr(_roomPathBitmap, x, fpU)) { + _fpX = x; + _fpY = fpU; + break; + } + fpU--; + } + if (fpL) { + if (getPixelAddr(_roomPathBitmap, fpL, y)) { + _fpX = fpL; + _fpY = y; + break; + } + fpL--; + } + if (fpR != _sceneWidth) { + if (getPixelAddr(_roomPathBitmap, fpR, y)) { + _fpX = fpR; + _fpY = y; + break; + } + fpR++; + } + if (!fpU && (fpD == kMaxPicHeight)) { + if (!fpL && (fpR == _sceneWidth)) { + break; + } + } + } +} + +Direction PrinceEngine::makeDirection(int x1, int y1, int x2, int y2) { + if (x1 != x2) { + if (y1 != y2) { + if (x1 > x2) { + if (y1 > y2) { + if (x1 - x2 >= y1 - y2) { + return kDirLU; + } else { + return kDirUL; + } + } else { + if (x1 - x2 >= y2 - y1) { + return kDirLD; + } else { + return kDirDL; + } + } + } else { + if (y1 > y2) { + if (x2 - x1 >= y1 - y2) { + return kDirRU; + } else { + return kDirUR; + } + } else { + if (x2 - x1 >= y2 - y1) { + return kDirRD; + } else { + return kDirDR; + } + } + } + } else { + if (x1 >= x2) { + return kDirL; + } else { + return kDirR; + } + } + } else { + if (y1 >= y2) { + return kDirU; + } else { + return kDirD; + } + } +} + +void PrinceEngine::specialPlot(int x, int y) { + if (_coords < _coordsBufEnd) { + WRITE_LE_UINT16(_coords, x); + _coords += 2; + WRITE_LE_UINT16(_coords, y); + _coords += 2; + specialPlot2(x, y); + } +} + +void PrinceEngine::specialPlot2(int x, int y) { + int mask = 128 >> (x & 7); + _roomPathBitmapTemp[x / 8 + y * 80] |= mask; +} + +void PrinceEngine::specialPlotInside(int x, int y) { + if (_coords < _coordsBufEnd) { + WRITE_LE_UINT16(_coords, x); + _coords += 2; + WRITE_LE_UINT16(_coords, y); + _coords += 2; + } +} + +int PrinceEngine::plotTraceLine(int x, int y, void *data) { + PrinceEngine *traceLine = (PrinceEngine *)data; + if (!traceLine->_traceLineFirstPointFlag) { + if (!traceLine->getPixelAddr(traceLine->_roomPathBitmapTemp, x, y)) { + if (traceLine->getPixelAddr(traceLine->_roomPathBitmap, x, y)) { + traceLine->specialPlotInside(x, y); + traceLine->_traceLineLen++; + return 0; + } else { + return -1; + } + } else { + return 1; + } + } else { + traceLine->_traceLineFirstPointFlag = false; + return 0; + } +} + +int PrinceEngine::leftDownDir() { + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::leftDir() { + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::leftUpDir() { + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::rightDownDir() { + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::rightDir() { + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::rightUpDir() { + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::upLeftDir() { + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::upDir() { + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::upRightDir() { + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::downLeftDir() { + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::downDir() { + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::downRightDir() { + if (!checkRightDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDownDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkRightUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + if (!checkLeftUpDir()) { + specialPlot(_checkX, _checkY); + return 0; + } + return -1; +} + +int PrinceEngine::cpe() { + if ((*(_checkBitmap - kPBW) & _checkMask)) { + if ((*(_checkBitmap + kPBW) & _checkMask)) { + int value; + switch (_checkMask) { + case 128: + value = READ_LE_UINT16(_checkBitmap - 1); + value &= 0x4001; + if (value != 0x4001) { + return 0; + } + break; + case 64: + value = *_checkBitmap; + value &= 0xA0; + if (value != 0xA0) { + return 0; + } + break; + case 32: + value = *_checkBitmap; + value &= 0x50; + if (value != 0x50) { + return 0; + } + break; + case 16: + value = *_checkBitmap; + value &= 0x28; + if (value != 0x28) { + return 0; + } + break; + case 8: + value = *_checkBitmap; + value &= 0x14; + if (value != 0x14) { + return 0; + } + break; + case 4: + value = *_checkBitmap; + value &= 0xA; + if (value != 0xA) { + return 0; + } + break; + case 2: + value = *_checkBitmap; + value &= 0x5; + if (value != 0x5) { + return 0; + } + break; + case 1: + value = READ_LE_UINT16(_checkBitmap); + value &= 0x8002; + if (value != 0x8002) { + return 0; + } + break; + default: + error("Wrong _checkMask value - cpe()"); + break; + } + _checkX = _rembX; + _checkY = _rembY; + _checkBitmapTemp = _rembBitmapTemp; + _checkBitmap = _rembBitmap; + _checkMask = _rembMask; + return -1; + } + return 0; + } + return 0; +} + +int PrinceEngine::checkLeftDownDir() { + if (_checkX && _checkY != (kMaxPicHeight / 2 - 1)) { + int tempMask = _checkMask; + if (tempMask != 128) { + tempMask <<= 1; + if ((*(_checkBitmap + kPBW) & tempMask)) { + if (!(*(_checkBitmapTemp + kPBW) & tempMask)) { + _checkBitmap += kPBW; + _checkBitmapTemp += kPBW; + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap + kPBW - 1) & 1)) { + if (!(*(_checkBitmapTemp + kPBW - 1) & 1)) { + _checkBitmap += (kPBW - 1); + _checkBitmapTemp += (kPBW - 1); + _checkMask = 1; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX--; + _checkY++; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkLeftDir() { + if (_checkX) { + int tempMask = _checkMask; + if (tempMask != 128) { + tempMask <<= 1; + if ((*(_checkBitmap) & tempMask)) { + if (!(*(_checkBitmapTemp) & tempMask)) { + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap - 1) & 1)) { + if (!(*(_checkBitmapTemp - 1) & 1)) { + _checkBitmap--; + _checkBitmapTemp--; + _checkMask = 1; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX--; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkDownDir() { + if (_checkY != (kMaxPicHeight / 2 - 1)) { + if ((*(_checkBitmap + kPBW) & _checkMask)) { + if (!(*(_checkBitmapTemp + kPBW) & _checkMask)) { + _checkBitmap += kPBW; + _checkBitmapTemp += kPBW; + _checkY++; + return cpe(); + } else { + return 1; + } + } else { + return -1; + } + } else { + return -1; + } +} + +int PrinceEngine::checkUpDir() { + if (_checkY) { + if ((*(_checkBitmap - kPBW) & _checkMask)) { + if (!(*(_checkBitmapTemp - kPBW) & _checkMask)) { + _checkBitmap -= kPBW; + _checkBitmapTemp -= kPBW; + _checkY--; + return cpe(); + } else { + return 1; + } + } else { + return -1; + } + } else { + return -1; + } +} + +int PrinceEngine::checkRightDir() { + if (_checkX != (kMaxPicWidth / 2 - 1)) { + int tempMask = _checkMask; + if (tempMask != 1) { + tempMask >>= 1; + if ((*(_checkBitmap) & tempMask)) { + if (!(*(_checkBitmapTemp) & tempMask)) { + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap + 1) & 128)) { + if (!(*(_checkBitmapTemp + 1) & 128)) { + _checkBitmap++; + _checkBitmapTemp++; + _checkMask = 128; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX++; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkLeftUpDir() { + if (_checkX && _checkY) { + int tempMask = _checkMask; + if (tempMask != 128) { + tempMask <<= 1; + if ((*(_checkBitmap - kPBW) & tempMask)) { + if (!(*(_checkBitmapTemp - kPBW) & tempMask)) { + _checkBitmap -= kPBW; + _checkBitmapTemp -= kPBW; + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap - (kPBW + 1)) & 1)) { + if (!(*(_checkBitmapTemp - (kPBW + 1)) & 1)) { + _checkBitmap -= (kPBW + 1); + _checkBitmapTemp -= (kPBW + 1); + _checkMask = 1; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX--; + _checkY--; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkRightDownDir() { + if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY != (kMaxPicHeight / 2 - 1)) { + int tempMask = _checkMask; + if (tempMask != 1) { + tempMask >>= 1; + if ((*(_checkBitmap + kPBW) & tempMask)) { + if (!(*(_checkBitmapTemp + kPBW) & tempMask)) { + _checkBitmap += kPBW; + _checkBitmapTemp += kPBW; + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap + kPBW + 1) & 128)) { + if (!(*(_checkBitmapTemp + kPBW + 1) & 128)) { + _checkBitmap += kPBW + 1; + _checkBitmapTemp += kPBW + 1; + _checkMask = 128; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX++; + _checkY++; + return cpe(); + } else { + return -1; + } +} + +int PrinceEngine::checkRightUpDir() { + if (_checkX != (kMaxPicWidth / 2 - 1) && _checkY) { + int tempMask = _checkMask; + if (tempMask != 1) { + tempMask >>= 1; + if ((*(_checkBitmap - kPBW) & tempMask)) { + if (!(*(_checkBitmapTemp - kPBW) & tempMask)) { + _checkBitmap -= kPBW; + _checkBitmapTemp -= kPBW; + _checkMask = tempMask; + } else { + return 1; + } + } else { + return -1; + } + } else { + if ((*(_checkBitmap - kPBW + 1) & 128)) { + if (!(*(_checkBitmapTemp - kPBW + 1) & 128)) { + _checkBitmap -= (kPBW - 1); + _checkBitmapTemp -= (kPBW - 1); + _checkMask = 128; + } else { + return 1; + } + } else { + return -1; + } + } + _checkX++; + _checkY--; + return cpe(); + } else { + return -1; + } +} + +bool PrinceEngine::tracePath(int x1, int y1, int x2, int y2) { + for (uint i = 0; i < kPathBitmapLen; i++) { + _roomPathBitmapTemp[i] = 0; + } + if (x1 != x2 || y1 != y2) { + if (getPixelAddr(_roomPathBitmap, x1, y1)) { + if (getPixelAddr(_roomPathBitmap, x2, y2)) { + _coords = _coordsBuf; + specialPlot(x1, y1); + + int x = x1; + int y = y1; + + while (1) { + int btx = x; + int bty = y; + byte *bcad = _coords; + + _traceLineLen = 0; + _traceLineFirstPointFlag = true; + int drawLineFlag = drawLine(x, y, x2, y2, &this->plotTraceLine, this); + + if (!drawLineFlag) { + return true; + } else if (drawLineFlag == -1 && _traceLineLen >= 2) { + byte *tempCorrds = bcad; + while (tempCorrds != _coords) { + x = READ_LE_UINT16(tempCorrds); + y = READ_LE_UINT16(tempCorrds + 2); + tempCorrds += 4; + specialPlot2(x, y); + } + } else { + _coords = bcad; + x = btx; + y = bty; + } + + Direction dir = makeDirection(x, y, x2, y2); + + _rembBitmapTemp = &_roomPathBitmapTemp[x / 8 + y * 80]; + _rembBitmap = &_roomPathBitmap[x / 8 + y * 80]; + _rembMask = 128 >> (x & 7); + _rembX = x; + _rembY = y; + + _checkBitmapTemp = _rembBitmapTemp; + _checkBitmap = _rembBitmap; + _checkMask = _rembMask; + _checkX = _rembX; + _checkY = _rembY; + + int result; + switch (dir) { + case kDirLD: + result = leftDownDir(); + break; + case kDirL: + result = leftDir(); + break; + case kDirLU: + result = leftUpDir(); + break; + case kDirRD: + result = rightDownDir(); + break; + case kDirR: + result = rightDir(); + break; + case kDirRU: + result = rightUpDir(); + break; + case kDirUL: + result = upLeftDir(); + break; + case kDirU: + result = upDir(); + break; + case kDirUR: + result = upRightDir(); + break; + case kDirDL: + result = downLeftDir(); + break; + case kDirD: + result = downDir(); + break; + case kDirDR: + result = downRightDir(); + break; + default: + result = -1; + error("tracePath: wrong direction %d", dir); + break; + } + + if (result) { + byte *tempCoords = _coords; + tempCoords -= 4; + if (tempCoords > _coordsBuf) { + int tempX = READ_LE_UINT16(tempCoords); + int tempY = READ_LE_UINT16(tempCoords + 2); + if (_checkX == tempX && _checkY == tempY) { + _coords = tempCoords; + } + x = READ_LE_UINT16(tempCoords); + y = READ_LE_UINT16(tempCoords + 2); + } else { + return false; + } + } else { + x = _checkX; + y = _checkY; + } + } + return true; + } else { + error("tracePath: wrong destination point"); + } + } else { + error("tracePath: wrong start point"); + } + } else { + error("tracePath: same point"); + } +} + +void PrinceEngine::specialPlotInside2(int x, int y) { + WRITE_LE_UINT16(_coords2, x); + _coords2 += 2; + WRITE_LE_UINT16(_coords2, y); + _coords2 += 2; +} + +int PrinceEngine::plotTracePoint(int x, int y, void *data) { + PrinceEngine *tracePoint = (PrinceEngine *)data; + if (!tracePoint->_tracePointFirstPointFlag) { + if (tracePoint->getPixelAddr(tracePoint->_roomPathBitmap, x, y)) { + tracePoint->specialPlotInside2(x, y); + return 0; + } else { + return -1; + } + } else { + tracePoint->_tracePointFirstPointFlag = false; + return 0; + } +} + +void PrinceEngine::approxPath() { + byte *oldCoords; + _coords2 = _coordsBuf2; + byte *tempCoordsBuf = _coordsBuf; // first point on path + byte *tempCoords = _coords; + if (tempCoordsBuf != tempCoords) { + tempCoords -= 4; // last point on path + while (tempCoordsBuf != tempCoords) { + int x1 = READ_LE_UINT16(tempCoords); + int y1 = READ_LE_UINT16(tempCoords + 2); + int x2 = READ_LE_UINT16(tempCoordsBuf); + int y2 = READ_LE_UINT16(tempCoordsBuf + 2); + tempCoordsBuf += 4; + //TracePoint + oldCoords = _coords2; + if (_coords2 == _coordsBuf2) { + WRITE_LE_UINT16(_coords2, x1); + WRITE_LE_UINT16(_coords2 + 2, y1); + _coords2 += 4; + } else { + int testX = READ_LE_UINT16(_coords2 - 4); + int testY = READ_LE_UINT16(_coords2 - 2); + if (testX != x1 || testY != y1) { + WRITE_LE_UINT16(_coords2, x1); + WRITE_LE_UINT16(_coords2 + 2, y1); + _coords2 += 4; + } + } + _tracePointFirstPointFlag = true; + bool drawLineFlag = drawLine(x1, y1, x2, y2, &this->plotTracePoint, this); + if (!drawLineFlag) { + tempCoords = tempCoordsBuf - 4; + tempCoordsBuf = _coordsBuf; + } else { + _coords2 = oldCoords; + } + } + } +} + +void PrinceEngine::freeDirectionTable() { + if (_directionTable != nullptr) { + free(_directionTable); + _directionTable = nullptr; + } +} + +int PrinceEngine::scanDirectionsFindNext(byte *tempCoordsBuf, int xDiff, int yDiff) { + + int tempX, tempY, direction; + + tempX = Hero::kHeroDirLeft; + if (xDiff < 0) { + tempX = Hero::kHeroDirRight; + } + + tempY = Hero::kHeroDirUp; + if (yDiff < 0) { + tempY = Hero::kHeroDirDown; + } + + while (1) { + int againPointX1 = READ_LE_UINT16(tempCoordsBuf); + int againPointY1 = READ_LE_UINT16(tempCoordsBuf + 2); + tempCoordsBuf += 4; + + if (tempCoordsBuf == _coords) { + direction = tempX; + break; + } + + int dX = againPointX1 - READ_LE_UINT16(tempCoordsBuf); + int dY = againPointY1 - READ_LE_UINT16(tempCoordsBuf + 2); + + if (dX != xDiff) { + direction = tempY; + break; + } + + if (dY != yDiff) { + direction = tempX; + break; + } + } + return direction; +} + +void PrinceEngine::scanDirections() { + freeDirectionTable(); + byte *tempCoordsBuf = _coordsBuf; + if (tempCoordsBuf != _coords) { + int size = (_coords - tempCoordsBuf) / 4 + 1; // number of coord points plus one for end marker + _directionTable = (byte *)malloc(size); + byte *tempDirTab = _directionTable; + int direction = -1; + int lastDirection = -1; + + while (1) { + int x1 = READ_LE_UINT16(tempCoordsBuf); + int y1 = READ_LE_UINT16(tempCoordsBuf + 2); + tempCoordsBuf += 4; + if (tempCoordsBuf == _coords) { + break; + } + int x2 = READ_LE_UINT16(tempCoordsBuf); + int y2 = READ_LE_UINT16(tempCoordsBuf + 2); + + int xDiff = x1 - x2; + int yDiff = y1 - y2; + + if (xDiff) { + if (yDiff) { + if (lastDirection != -1) { + direction = lastDirection; + if (direction == Hero::kHeroDirLeft) { + if (xDiff < 0) { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } else if (direction == Hero::kHeroDirRight) { + if (xDiff >= 0) { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } else if (direction == Hero::kHeroDirUp) { + if (yDiff < 0) { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } else { + if (yDiff >= 0) { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } + } else { + direction = scanDirectionsFindNext(tempCoordsBuf, xDiff, yDiff); + } + } else { + direction = Hero::kHeroDirLeft; + if (xDiff < 0) { + direction = Hero::kHeroDirRight; + } + } + } else { + if (yDiff) { + direction = Hero::kHeroDirUp; + if (yDiff < 0) { + direction = Hero::kHeroDirDown; + } + } else { + direction = lastDirection; + } + } + lastDirection = direction; + *tempDirTab = direction; + tempDirTab++; + } + *tempDirTab = *(tempDirTab - 1); + tempDirTab++; + *tempDirTab = 0; + } +} + +void PrinceEngine::moveShandria() { + int shanLen1 = _shanLen; + if (_flags->getFlagValue(Flags::SHANDOG)) { + _secondHero->freeHeroAnim(); + _secondHero->freeOldMove(); + byte *shanCoords = _mainHero->_currCoords + shanLen1 * 4 - 4; + int shanX = READ_LE_UINT16(shanCoords - 4); + int shanY = READ_LE_UINT16(shanCoords - 2); + int xDiff = shanX - _secondHero->_middleX; + if (xDiff < 0) { + xDiff *= -1; + } + int yDiff = shanY - _secondHero->_middleY; + if (yDiff < 0) { + yDiff *= -1; + } + shanCoords -= 4; + if (shanCoords != _mainHero->_currCoords) { + yDiff *= 1.5; + int shanDis = xDiff * xDiff + yDiff * yDiff; + if (shanDis >= kMinDistance) { + while (1) { + shanCoords -= 4; + if (shanCoords == _mainHero->_currCoords) { + break; + } + int x = READ_LE_UINT16(shanCoords); + int y = READ_LE_UINT16(shanCoords + 2); + int pointDiffX = x - shanX; + if (pointDiffX < 0) { + pointDiffX *= -1; + } + int pointDiffY = y - shanY; + if (pointDiffY < 0) { + pointDiffY *= -1; + } + pointDiffY *= 1.5; + int distance = pointDiffX * pointDiffX + pointDiffY * pointDiffY; + if (distance >= kMinDistance) { + break; + } + } + int pathSizeDiff = (shanCoords - _mainHero->_currCoords) / 4; + int destDir = *(_mainHero->_currDirTab + pathSizeDiff); + _secondHero->_destDirection = destDir; + int destX = READ_LE_UINT16(shanCoords); + int destY = READ_LE_UINT16(shanCoords + 2); + _secondHero->_coords = makePath(kSecondHero, _secondHero->_middleX, _secondHero->_middleY, destX, destY); + if (_secondHero->_coords != nullptr) { + _secondHero->_currCoords = _secondHero->_coords; + int delay = shanLen1 - _shanLen; + if (delay < 6) { + delay = 6; + } + _secondHero->_moveDelay = delay / 2; + _secondHero->_state = Hero::kHeroStateDelayMove; + _secondHero->_dirTab = _directionTable; + _secondHero->_currDirTab = _directionTable; + _directionTable = nullptr; + } + } + } + } +} + +byte *PrinceEngine::makePath(int heroId, int currX, int currY, int destX, int destY) { + int realDestX = destX; + int realDestY = destY; + _flags->setFlagValue(Flags::MOVEDESTX, destX); + _flags->setFlagValue(Flags::MOVEDESTY, destY); + + int x1 = currX / 2; + int y1 = currY / 2; + int x2 = destX / 2; + int y2 = destY / 2; + + if ((x1 != x2) || (y1 != y2)) { + findPoint(x1, y1); + if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) { + return nullptr; + } + if ((x1 != _fpX) || (y1 != _fpY)) { + x1 = _fpX; + y1 = _fpY; + } + findPoint(x2, y2); + if (!getPixelAddr(_roomPathBitmap, _fpX, _fpY)) { + return nullptr; + } + if ((x2 != _fpX) || (y2 != _fpY)) { + x2 = _fpX; + y2 = _fpY; + if (!_flags->getFlagValue(Flags::EXACTMOVE)) { + realDestX = x2 * 2; + realDestY = y2 * 2; + _flags->setFlagValue(Flags::MOVEDESTX, realDestX); + _flags->setFlagValue(Flags::MOVEDESTY, realDestY); + } else { + return nullptr; + } + } + + if ((x1 == x2) && (y1 == y2)) { + if (!heroId) { + _mainHero->freeOldMove(); + _mainHero->_state = Hero::kHeroStateTurn; + } else if (heroId == 1) { + _secondHero->freeOldMove(); + _secondHero->_state = Hero::kHeroStateTurn; + } + return nullptr; + } + + int pathLen1 = 0; + int pathLen2 = 0; + int stX = x1; + int stY = y1; + int sizeCoords2 = 0; + + if (tracePath(x1, y1, x2, y2)) { + allocCoords2(); + approxPath(); + sizeCoords2 = _coords2 - _coordsBuf2; + for (int i = 0; i < sizeCoords2; i++) { + _coordsBuf[i] = _coordsBuf2[i]; + } + _coords = _coordsBuf + sizeCoords2; + approxPath(); + _coordsBuf3 = _coordsBuf2; + _coordsBuf2 = nullptr; + _coords3 = _coords2; + _coords2 = nullptr; + pathLen1 = _coords3 - _coordsBuf3; + } + if (tracePath(x2, y2, x1, y1)) { + allocCoords2(); + approxPath(); + sizeCoords2 = _coords2 - _coordsBuf2; + for (int i = 0; i < sizeCoords2; i++) { + _coordsBuf[i] = _coordsBuf2[i]; + } + _coords = _coordsBuf + sizeCoords2; + approxPath(); + pathLen2 = _coords2 - _coordsBuf2; + } + + byte *chosenCoordsBuf = _coordsBuf2; + byte *choosenCoords = _coords2; + int choosenLength = pathLen1; + if (pathLen1 < pathLen2) { + chosenCoordsBuf = _coordsBuf3; + choosenCoords = _coords3; + choosenLength = pathLen2; + } + + if (choosenLength) { + if (chosenCoordsBuf != nullptr) { + int tempXBegin = READ_LE_UINT16(chosenCoordsBuf); + int tempYBegin = READ_LE_UINT16(chosenCoordsBuf + 2); + if (stX != tempXBegin || stY != tempYBegin) { + SWAP(chosenCoordsBuf, choosenCoords); + chosenCoordsBuf -= 4; + byte *tempCoordsBuf = _coordsBuf; + while (1) { + int cord = READ_LE_UINT32(chosenCoordsBuf); + WRITE_LE_UINT32(tempCoordsBuf, cord); + tempCoordsBuf += 4; + if (chosenCoordsBuf == choosenCoords) { + break; + } + chosenCoordsBuf -= 4; + } + _coords = tempCoordsBuf; + } else { + int sizeChoosen = choosenCoords - chosenCoordsBuf; + for (int i = 0; i < sizeChoosen; i++) { + _coordsBuf[i] = chosenCoordsBuf[i]; + } + _coords = _coordsBuf + sizeChoosen; + } + WRITE_LE_UINT32(_coords, 0xFFFFFFFF); + freeCoords2(); + freeCoords3(); + scanDirections(); + + byte *tempCoordsBuf = _coordsBuf; + byte *tempCoords = _coords; + byte *newCoords; + if (tempCoordsBuf != tempCoords) { + int normCoordsSize = _coords - _coordsBuf + 4; + newCoords = (byte *)malloc(normCoordsSize); + byte *newCoordsBegin = newCoords; + while (tempCoordsBuf != tempCoords) { + int newValueX = READ_LE_UINT16(tempCoordsBuf); + WRITE_LE_UINT16(newCoords, newValueX * 2); + newCoords += 2; + int newValueY = READ_LE_UINT16(tempCoordsBuf + 2); + WRITE_LE_UINT16(newCoords, newValueY * 2); + newCoords += 2; + tempCoordsBuf += 4; + } + WRITE_LE_UINT16(newCoords - 4, realDestX); + WRITE_LE_UINT16(newCoords - 2, realDestY); + WRITE_LE_UINT32(newCoords, 0xFFFFFFFF); + newCoords += 4; + _shanLen = (newCoords - newCoordsBegin); + _shanLen /= 4; + return newCoordsBegin; + } + } + } + _coords = _coordsBuf; + freeCoords2(); + freeCoords3(); + return nullptr; + } else { + if (!heroId) { + _mainHero->freeOldMove(); + _mainHero->_state = Hero::kHeroStateTurn; + } else if (heroId == 1) { + _secondHero->freeOldMove(); + _secondHero->_state = Hero::kHeroStateTurn; + } + return nullptr; + } +} + +void PrinceEngine::allocCoords2() { + if (_coordsBuf2 == nullptr) { + _coordsBuf2 = (byte *)malloc(kTracePts * 4); + _coords2 = _coordsBuf2; + } +} + +void PrinceEngine::freeCoords2() { + if (_coordsBuf2 != nullptr) { + free(_coordsBuf2); + _coordsBuf2 = nullptr; + _coords2 = nullptr; + } +} + +void PrinceEngine::freeCoords3() { + if (_coordsBuf3 != nullptr) { + free(_coordsBuf3); + _coordsBuf3 = nullptr; + _coords3 = nullptr; + } +} + +} // End of namespace Prince |