aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/chargen.cpp1495
-rw-r--r--engines/kyra/detection.cpp11
-rw-r--r--engines/kyra/detection_tables.h74
-rw-r--r--engines/kyra/eob1.cpp242
-rw-r--r--engines/kyra/eob1.h96
-rw-r--r--engines/kyra/eob2.cpp437
-rw-r--r--engines/kyra/eob2.h119
-rw-r--r--engines/kyra/eobcommon.cpp1845
-rw-r--r--engines/kyra/eobcommon.h977
-rw-r--r--engines/kyra/gui.h8
-rw-r--r--engines/kyra/gui_eob.cpp2165
-rw-r--r--engines/kyra/gui_eob.h130
-rw-r--r--engines/kyra/gui_lol.cpp90
-rw-r--r--engines/kyra/gui_lol.h2
-rw-r--r--engines/kyra/items_eob.cpp614
-rw-r--r--engines/kyra/kyra_hof.cpp2
-rw-r--r--engines/kyra/kyra_hof.h2
-rw-r--r--engines/kyra/kyra_mr.cpp2
-rw-r--r--engines/kyra/kyra_mr.h2
-rw-r--r--engines/kyra/kyra_v1.cpp41
-rw-r--r--engines/kyra/kyra_v1.h2
-rw-r--r--engines/kyra/kyra_v2.h2
-rw-r--r--engines/kyra/lol.cpp410
-rw-r--r--engines/kyra/lol.h328
-rw-r--r--engines/kyra/loleobbase.cpp354
-rw-r--r--engines/kyra/loleobbase.h324
-rw-r--r--engines/kyra/magic_eob.cpp780
-rw-r--r--engines/kyra/module.mk29
-rw-r--r--engines/kyra/resource.cpp4
-rw-r--r--engines/kyra/resource.h319
-rw-r--r--engines/kyra/resource_intern.cpp11
-rw-r--r--engines/kyra/saveload_eob.cpp549
-rw-r--r--engines/kyra/saveload_lol.cpp96
-rw-r--r--engines/kyra/scene_eob.cpp1350
-rw-r--r--engines/kyra/scene_lol.cpp733
-rw-r--r--engines/kyra/screen.cpp58
-rw-r--r--engines/kyra/screen.h45
-rw-r--r--engines/kyra/screen_eob.cpp965
-rw-r--r--engines/kyra/screen_eob.h105
-rw-r--r--engines/kyra/script.cpp2
-rw-r--r--engines/kyra/script.h4
-rw-r--r--engines/kyra/script_eob.cpp1528
-rw-r--r--engines/kyra/script_eob.h121
-rw-r--r--engines/kyra/script_hof.cpp2
-rw-r--r--engines/kyra/script_lok.cpp2
-rw-r--r--engines/kyra/script_lol.cpp80
-rw-r--r--engines/kyra/script_mr.cpp2
-rw-r--r--engines/kyra/script_tim.cpp180
-rw-r--r--engines/kyra/script_tim.h19
-rw-r--r--engines/kyra/sequences_eob1.cpp140
-rw-r--r--engines/kyra/sequences_eob2.cpp1277
-rw-r--r--engines/kyra/sound.cpp2
-rw-r--r--engines/kyra/sound_lol.cpp25
-rw-r--r--engines/kyra/sprites_eob.cpp1249
-rw-r--r--engines/kyra/sprites_lol.cpp77
-rw-r--r--engines/kyra/staticres.cpp16
-rw-r--r--engines/kyra/staticres_eob.cpp1062
-rw-r--r--engines/kyra/staticres_lol.cpp190
-rw-r--r--engines/kyra/text_eob.cpp649
-rw-r--r--engines/kyra/text_eob.h112
-rw-r--r--engines/kyra/text_lol.cpp501
-rw-r--r--engines/kyra/text_lol.h52
-rw-r--r--engines/kyra/timer.cpp2
-rw-r--r--engines/kyra/timer_eob.cpp378
-rw-r--r--engines/kyra/timer_lol.cpp52
65 files changed, 20172 insertions, 2370 deletions
diff --git a/engines/kyra/chargen.cpp b/engines/kyra/chargen.cpp
new file mode 100644
index 0000000000..4a0e035483
--- /dev/null
+++ b/engines/kyra/chargen.cpp
@@ -0,0 +1,1495 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/eobcommon.h"
+#include "kyra/resource.h"
+#include "kyra/sound_intern.h"
+
+namespace Kyra {
+
+class CharacterGenerator {
+public:
+ CharacterGenerator(EobCoreEngine *vm, Screen_Eob *screen);
+ ~CharacterGenerator();
+
+ void start(EobCharacter *characters, uint8 ***faceShapes);
+
+private:
+ void init();
+ void initButtonsFromList(int first, int numButtons);
+ void initButton(int index, int x, int y, int w, int h, int keyCode);
+ void checkForCompleteParty();
+ void toggleSpecialButton(int index, int bodyCustom, int pageNum);
+ void processSpecialButton(int index);
+ void highlightBoxFrame(int index);
+ int viewDeleteCharacter();
+ void createPartyMember();
+ int raceSexMenu();
+ int classMenu(int raceSex);
+ int alignmentMenu(int cClass);
+ void updateMagicShapes();
+ void generateStats(int index);
+ void modifyMenu();
+ void statsAndFacesMenu();
+ void faceSelectMenu();
+ int getNextFreeFaceShape(int shpIndex, int charSex, int step, int8 *selectedPortraits);
+ void processFaceMenuSelection(int index);
+ void printStats(int index, int mode);
+ void processNameInput(int index, int len, int textColor);
+ int rollDice();
+ int modifyStat(int index, int8 *stat1, int8 *stat2);
+ int getMaxHp(int cclass, int constitution, int level1, int level2, int level3);
+ int getMinHp(int cclass, int constitution, int level1, int level2, int level3);
+ void finish();
+
+ uint8 **_chargenMagicShapes;
+ uint8 **_chargenButtonLabels;
+ int _activeBox;
+ int _magicShapesBox;
+ int _updateBoxIndex;
+ int _updateBoxColorIndex;
+ int _updateBoxShapesIndex;
+ int _lastUpdateBoxShapesIndex;
+ uint32 _chargenBoxTimer;
+ uint32 _chargenMagicShapeTimer;
+ int8 _chargenSelectedPortraits[4];
+ int8 _chargenSelectedPortraits2[4];
+
+ uint16 _chargenMinStats[7];
+ uint16 _chargenMaxStats[7];
+
+ const char *const *_chargenStrings1;
+ const char *const *_chargenStrings2;
+ const char *const *_chargenStatStrings;
+ const char *const *_chargenRaceSexStrings;
+ const char *const *_chargenClassStrings;
+ const char *const *_chargenAlignmentStrings;
+ const char *const *_chargenEnterGameStrings;
+
+ const uint8 *_chargenStartLevels;
+ const uint8 *_chargenClassMinStats;
+ const uint8 *_chargenRaceMinStats;
+ const uint16 *_chargenRaceMaxStats;
+
+ static const EobChargenButtonDef _chargenButtonDefs[];
+ static const CreatePartyModButton _chargenModButtons[];
+ static const EobRect8 _chargenButtonBodyCoords[];
+ static const EobRect16 _chargenPortraitBoxFrames[];
+ static const int16 _chargenBoxX[];
+ static const int16 _chargenBoxY[];
+ static const int16 _chargenNameFieldX[];
+ static const int16 _chargenNameFieldY[];
+
+ static const int32 _classMenuMasks[];
+ static const int32 _alignmentMenuMasks[];
+
+ static const int16 _raceModifiers[];
+
+ EobCharacter *_characters;
+ uint8 **_faceShapes;
+
+ EobCoreEngine *_vm;
+ Screen_Eob *_screen;
+};
+
+void EobCoreEngine::startCharacterGeneration() {
+ CharacterGenerator(this, _screen).start(_characters, &_faceShapes);
+}
+
+CharacterGenerator::CharacterGenerator(EobCoreEngine *vm, Screen_Eob *screen) : _vm(vm), _screen(screen),
+ _characters(0), _faceShapes(0), _chargenMagicShapes(0), _chargenButtonLabels(0), _updateBoxIndex(-1),
+ _chargenBoxTimer(0), _chargenMagicShapeTimer(0), _updateBoxColorIndex(0), _updateBoxShapesIndex(0),
+ _lastUpdateBoxShapesIndex(0), _magicShapesBox(6), _activeBox(0) {
+
+ _chargenStatStrings = _vm->_chargenStatStrings;
+ _chargenRaceSexStrings = _vm->_chargenRaceSexStrings;
+ _chargenClassStrings = _vm->_chargenClassStrings;
+ _chargenAlignmentStrings = _vm->_chargenAlignmentStrings;
+
+ memset(_chargenSelectedPortraits, -1, sizeof(_chargenSelectedPortraits));
+ memset(_chargenSelectedPortraits2, 0, sizeof(_chargenSelectedPortraits2));
+ memset(_chargenMinStats, 0, sizeof(_chargenMinStats));
+ memset(_chargenMaxStats, 0, sizeof(_chargenMaxStats));
+
+ int temp;
+ _chargenStrings1 = _vm->staticres()->loadStrings(kEobBaseChargenStrings1, temp);
+ _chargenStrings2 = _vm->staticres()->loadStrings(kEobBaseChargenStrings2, temp);
+ _chargenStartLevels = _vm->staticres()->loadRawData(kEobBaseChargenStartLevels, temp);
+ _chargenEnterGameStrings = _vm->staticres()->loadStrings(kEobBaseChargenEnterGameStrings, temp);
+ _chargenClassMinStats = _vm->staticres()->loadRawData(kEobBaseChargenClassMinStats, temp);
+ _chargenRaceMinStats = _vm->staticres()->loadRawData(kEobBaseChargenRaceMinStats, temp);
+ _chargenRaceMaxStats = _vm->staticres()->loadRawDataBe16(kEobBaseChargenRaceMaxStats, temp);
+}
+
+CharacterGenerator::~CharacterGenerator() {
+ if (_chargenMagicShapes) {
+ for (int i = 0; i < 10; i++)
+ delete[] _chargenMagicShapes[i];
+ delete[] _chargenMagicShapes;
+ }
+
+ if (_chargenButtonLabels) {
+ for (int i = 0; i < 10; i++)
+ delete[] _chargenButtonLabels[i];
+ delete[] _chargenButtonLabels;
+ }
+}
+
+void CharacterGenerator::start(EobCharacter *characters, uint8 ***faceShapes) {
+ if (!characters && !faceShapes)
+ return;
+
+ _characters = characters;
+ _faceShapes = *faceShapes;
+
+ _vm->sound()->playTrack(0);
+
+ _vm->delay(_vm->_tickLength);
+
+ init();
+
+ _screen->setScreenDim(2);
+
+ checkForCompleteParty();
+ initButtonsFromList(0, 5);
+
+ _vm->sound()->playTrack(_vm->game() == GI_EOB1 ? 20 : 13);
+ _activeBox = 0;
+
+ for (bool loop = true; loop && (!_vm->shouldQuit()); ) {
+ highlightBoxFrame(_activeBox + 6);
+ _vm->sound()->process();
+ int inputFlag = _vm->checkInput(_vm->_activeButtons, false, 0);
+ _vm->removeInputTop();
+
+ if (inputFlag) {
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_LEFT] || inputFlag == _vm->_keyMap[Common::KEYCODE_RIGHT])
+ _activeBox ^= 1;
+ else if (inputFlag == _vm->_keyMap[Common::KEYCODE_UP] || inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN])
+ _activeBox ^= 2;
+ highlightBoxFrame(-1);
+ }
+
+ if (inputFlag & 0x8000) {
+ inputFlag = (inputFlag & 0x0f) - 1;
+ if (inputFlag == 4) {
+ loop = false;
+ } else {
+ _activeBox = inputFlag;
+ inputFlag = 43;
+ }
+ }
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN] || inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP5]) {
+ highlightBoxFrame(-1);
+ if (_characters[_activeBox].name[0]) {
+ int b = _activeBox;
+ if (viewDeleteCharacter())
+ loop = false;
+ if (b != _activeBox && !_characters[_activeBox].name[0])
+ createPartyMember();
+ } else {
+ createPartyMember();
+ }
+
+ initButtonsFromList(0, 5);
+ checkForCompleteParty();
+ }
+
+ if (loop == false) {
+ for (int i = 0; i < 4; i++) {
+ if (!_characters[i].name[0])
+ loop = true;
+ }
+ }
+ }
+
+ if (!_vm->shouldQuit()) {
+ processSpecialButton(15);
+ finish();
+ }
+
+ _vm->sound()->playTrack(15);
+
+ *faceShapes = _faceShapes;
+}
+
+void CharacterGenerator::init() {
+ _screen->loadEobBitmap("CHARGENA", 3, 3);
+ if (_faceShapes) {
+ for (int i = 0; i < 44; i++)
+ delete[] _faceShapes[i];
+ delete[] _faceShapes;
+ }
+
+ _faceShapes = new uint8*[44];
+ for (int i = 0; i < 44; i++)
+ _faceShapes[i] = _screen->encodeShape((i % 10) << 2, (i / 10) << 5, 4, 32, true);
+ _screen->_curPage = 0;
+
+ _screen->loadEobCpsFileToPage("CHARGEN", 0, 3, 3, 0);
+ _screen->loadEobBitmap("CHARGENB", 3, 3);
+ if (_chargenMagicShapes) {
+ for (int i = 0; i < 10; i++)
+ delete[] _chargenMagicShapes[i];
+ delete[] _chargenMagicShapes;
+ }
+
+ _chargenMagicShapes = new uint8*[10];
+ for (int i = 0; i < 10; i++)
+ _chargenMagicShapes[i] = _screen->encodeShape(i << 2, 0, 4, 32, true);
+
+ _chargenButtonLabels = new uint8*[17];
+ for (int i = 0; i < 17; i++) {
+ const CreatePartyModButton *c = &_chargenModButtons[i];
+ _chargenButtonLabels[i] = c->labelW? _screen->encodeShape(c->encodeLabelX, c->encodeLabelY, c->labelW, c->labelH, true) : 0;
+ }
+
+ _screen->copyPage(3, 2);
+ _screen->_curPage = 0;
+ _screen->copyRegion(144, 64, 0, 0, 180, 128, 0, 2, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+}
+
+void CharacterGenerator::initButtonsFromList(int first, int numButtons) {
+ _vm->gui_resetButtonList();
+
+ for (int i = 0; i < numButtons; i++) {
+ const EobChargenButtonDef *e = &_chargenButtonDefs[first + i];
+ initButton(i, e->x, e->y, e->w, e->h, e->keyCode);
+ }
+
+ _vm->gui_notifyButtonListChanged();
+}
+
+void CharacterGenerator::initButton(int index, int x, int y, int w, int h, int keyCode) {
+ Button *b = 0;
+ int cnt = 1;
+
+ if (_vm->_activeButtons) {
+ Button *n = _vm->_activeButtons;
+ while (n->nextButton) {
+ ++cnt;
+ n = n->nextButton;
+ }
+
+ ++cnt;
+ b = n->nextButton = &_vm->_activeButtonData[cnt];
+ } else {
+ b = &_vm->_activeButtonData[0];
+ _vm->_activeButtons = b;
+ }
+
+ *b = Button();
+ b->flags = 0x1100;
+ b->data0Val2 = 12;
+ b->data1Val2 = b->data2Val2 = 15;
+ b->data3Val2 = 8;
+
+ b->index = index + 1;
+ b->x = x << 3;
+ b->y = y;
+ b->width = w;
+ b->height = h;
+ b->keyCode = keyCode;
+ b->keyCode2 = keyCode + 0x100;
+}
+
+void CharacterGenerator::checkForCompleteParty() {
+ _screen->copyRegion(0, 0, 160, 0, 160, 128, 2, 2, Screen::CR_NO_P_CHECK);
+ int cp = _screen->setCurPage(2);
+ _screen->printShadedText(_chargenStrings1[8], 168, 16, 15, 0);
+ _screen->setCurPage(cp);
+ _screen->copyRegion(160, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK);
+
+ int numChars = 0;
+ for (int i = 0; i < 4; i++) {
+ if (_characters[i].name[0])
+ numChars++;
+ }
+
+ if (numChars == 4) {
+ _screen->setCurPage(2);
+ _screen->printShadedText(_chargenStrings1[0], 168, 61, 15, 0);
+ _screen->setCurPage(0);
+ _screen->copyRegion(168, 61, 152, 125, 136, 40, 2, 0, Screen::CR_NO_P_CHECK);
+ toggleSpecialButton(15, 0, 0);
+ } else {
+ toggleSpecialButton(14, 0, 0);
+ }
+
+ _screen->updateScreen();
+}
+
+void CharacterGenerator::toggleSpecialButton(int index, int bodyCustom, int pageNum) {
+ if (index >= 17)
+ return;
+
+ const CreatePartyModButton *c = &_chargenModButtons[index];
+ const EobRect8 *p = &_chargenButtonBodyCoords[c->bodyIndex + bodyCustom];
+
+ int x2 = 20;
+ int y2 = 0;
+
+ if (pageNum) {
+ x2 = c->destX + 2;
+ y2 = c->destY - 64;
+ }
+
+ _screen->copyRegion(p->x << 3, p->y, x2 << 3, y2, p->w << 3, p->h, 2, 2, Screen::CR_NO_P_CHECK);
+ if (c->labelW)
+ _screen->drawShape(2, _chargenButtonLabels[index], (x2 << 3) + c->labelX, y2 + c->labelY, 0);
+
+ if (pageNum == 2)
+ return;
+
+ _screen->copyRegion(160, 0, c->destX << 3, c->destY, p->w << 3, p->h, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+}
+
+void CharacterGenerator::processSpecialButton(int index) {
+ toggleSpecialButton(index, 1, 0);
+ _vm->sound()->playSoundEffect(76);
+ _vm->_system->delayMillis(80);
+ toggleSpecialButton(index, 0, 0);
+}
+
+void CharacterGenerator::highlightBoxFrame(int index) {
+ static const uint8 colorTable[] = { 0x0F, 0xB0, 0xB2, 0xB4, 0xB6,
+ 0xB8, 0xBA, 0xBC, 0x0C, 0xBC, 0xBA, 0xB8, 0xB6, 0xB4, 0xB2, 0xB0, 0x00
+ };
+
+ if (_updateBoxIndex == index) {
+ if (_updateBoxIndex == -1)
+ return;
+
+ if (_vm->_system->getMillis() <= _chargenBoxTimer)
+ return;
+
+ if (!colorTable[_updateBoxColorIndex])
+ _updateBoxColorIndex = 0;
+
+ const EobRect16 *r = &_chargenPortraitBoxFrames[_updateBoxIndex];
+ _screen->drawBox(r->x1, r->y1, r->x2, r->y2, colorTable[_updateBoxColorIndex++]);
+ _screen->updateScreen();
+
+ _chargenBoxTimer = _vm->_system->getMillis() + _vm->_tickLength;
+
+ } else {
+ if (_updateBoxIndex != -1) {
+ const EobRect16 *r = &_chargenPortraitBoxFrames[_updateBoxIndex];
+ _screen->drawBox(r->x1, r->y1, r->x2, r->y2, 12);
+ _screen->updateScreen();
+ }
+
+ _updateBoxColorIndex = 0;
+ _updateBoxIndex = index;
+ _chargenBoxTimer = _vm->_system->getMillis();
+ }
+}
+
+int CharacterGenerator::viewDeleteCharacter() {
+ initButtonsFromList(0, 7);
+ _vm->removeInputTop();
+
+ highlightBoxFrame(-1);
+ printStats(_activeBox, 2);
+
+ int res = 0;
+ for (bool loop = true; loop && _characters[_activeBox].name[0] && !_vm->shouldQuit(); ) {
+ highlightBoxFrame(_activeBox + 6);
+ _vm->sound()->process();
+
+ int inputFlag = _vm->checkInput(_vm->_activeButtons, false, 0);
+ int cbx = _activeBox;
+ _vm->removeInputTop();
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN] || inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP5] || inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE]) {
+ processSpecialButton(9);
+ res = 0;
+ loop = false;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_LEFT] || inputFlag == _vm->_keyMap[Common::KEYCODE_RIGHT]) {
+ cbx ^= 1;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_UP] || inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN]) {
+ cbx ^= 2;
+ }
+
+ if (inputFlag & 0x8000) {
+ inputFlag = (inputFlag & 0x0f) - 1;
+ if (inputFlag == 4) {
+ res = 1;
+ loop = false;
+ } else if (inputFlag == 5) {
+ processSpecialButton(9);
+ res = 0;
+ loop = false;
+ } else if (inputFlag == 6) {
+ if (_characters[_activeBox].name[0]) {
+ processSpecialButton(16);
+ _characters[_activeBox].name[0] = 0;
+ processNameInput(_activeBox, 1, 12);
+ processFaceMenuSelection(_activeBox + 50);
+ }
+ } else {
+ cbx = inputFlag;
+ }
+ }
+
+ if (loop == false)
+ highlightBoxFrame(-1);
+
+ if (!_characters[cbx].name[0])
+ loop = false;
+
+ if (cbx != _activeBox) {
+ _activeBox = cbx;
+ highlightBoxFrame(-1);
+ if (loop)
+ printStats(_activeBox, 2);
+ }
+ }
+
+ return res;
+}
+
+void CharacterGenerator::createPartyMember() {
+ _screen->setScreenDim(2);
+ _chargenBoxTimer = 0;
+
+ for (int i = 0; i != 3 && !_vm->shouldQuit(); i++) {
+ bool bck = false;
+
+ switch (i) {
+ case 0:
+ _characters[_activeBox].raceSex = raceSexMenu();
+ break;
+ case 1:
+ _characters[_activeBox].cClass = classMenu(_characters[_activeBox].raceSex);
+ if (_characters[_activeBox].cClass == _vm->_keyMap[Common::KEYCODE_ESCAPE])
+ bck = true;
+ break;
+ case 2:
+ _characters[_activeBox].alignment = alignmentMenu(_characters[_activeBox].cClass);
+ if (_characters[_activeBox].alignment == _vm->_keyMap[Common::KEYCODE_ESCAPE])
+ bck = true;
+ break;
+ default:
+ break;
+ }
+
+ if (bck)
+ i -= 2;
+ };
+
+ if (!_vm->shouldQuit()) {
+ generateStats(_activeBox);
+ statsAndFacesMenu();
+
+ for (_characters[_activeBox].name[0] = 0; _characters[_activeBox].name[0] == 0 && !_vm->shouldQuit(); ) {
+ processFaceMenuSelection(_chargenMinStats[6]);
+ printStats(_activeBox, 0);
+ _screen->printShadedText(_chargenStrings2[11], 149, 100, 9, 0);
+ if (!_vm->shouldQuit())
+ processNameInput(_activeBox, _vm->_gui->getTextInput(_characters[_activeBox].name, 24, 100, 10, 15, 0, 8), 2);
+ }
+ }
+}
+
+int CharacterGenerator::raceSexMenu() {
+ _screen->drawBox(_chargenBoxX[_activeBox], _chargenBoxY[_activeBox], _chargenBoxX[_activeBox] + 32, _chargenBoxY[_activeBox] + 33, 12);
+ _screen->copyRegion(0, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(_chargenStrings2[8], 147, 67, 9, 0);
+ _vm->removeInputTop();
+
+ _vm->_gui->setupMenu(1, 0, _chargenRaceSexStrings, -1, 0, 0);
+ int16 res = -1;
+
+ while (res == -1 && !_vm->shouldQuit()) {
+ res = _vm->_gui->handleMenu(1, _chargenRaceSexStrings, 0, -1, 0);
+ updateMagicShapes();
+ }
+
+ return res;
+}
+
+int CharacterGenerator::classMenu(int raceSex) {
+ int32 itemsMask = -1;
+
+ for (int i = 0; i < 4; i++) {
+ // check for evil characters
+ if (_characters[i].name[0] && _characters[i].alignment > 5)
+ itemsMask = 0xFFFB;
+ }
+
+ _vm->removeInputTop();
+ updateMagicShapes();
+
+ _screen->copyRegion(0, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(_chargenStrings2[9], 147, 67, 9, 0);
+
+ toggleSpecialButton(5, 0, 0);
+
+ itemsMask &=_classMenuMasks[raceSex / 2];
+ _vm->_gui->setupMenu(2, 15, _chargenClassStrings, itemsMask, 0, 0);
+
+ _vm->_mouseX = _vm->_mouseY = 0;
+ int16 res = -1;
+
+ while (res == -1 && !_vm->shouldQuit()) {
+ updateMagicShapes();
+
+ int in = _vm->checkInput(0, false, 0) & 0xff;
+ Common::Point mp = _vm->getMousePos();
+
+ if (in == _vm->_keyMap[Common::KEYCODE_ESCAPE] || _vm->_gui->_menuLastInFlags == _vm->_keyMap[Common::KEYCODE_ESCAPE] || _vm->_gui->_menuLastInFlags == _vm->_keyMap[Common::KEYCODE_b]) {
+ res = _vm->_keyMap[Common::KEYCODE_ESCAPE];
+ } else if (_vm->posWithinRect(mp.x, mp.y, 264, 171, 303, 187)) {
+ if (in == 199 || in == 201)
+ res = _vm->_keyMap[Common::KEYCODE_ESCAPE];
+ else
+ _vm->removeInputTop();
+ } else {
+ res = _vm->_gui->handleMenu(2, _chargenClassStrings, 0, itemsMask, 0);
+ }
+ }
+
+ _vm->removeInputTop();
+
+ if (res == _vm->_keyMap[Common::KEYCODE_ESCAPE])
+ processSpecialButton(5);
+
+ return res;
+}
+
+int CharacterGenerator::alignmentMenu(int cClass) {
+ int32 itemsMask = -1;
+
+ for (int i = 0; i < 4; i++) {
+ // check for paladins
+ if (_characters[i].name[0] && _characters[i].cClass == 2)
+ itemsMask = 0xFE3F;
+ }
+
+ _vm->removeInputTop();
+ updateMagicShapes();
+
+ _screen->copyRegion(0, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(_chargenStrings2[10], 147, 67, 9, 0);
+
+ toggleSpecialButton(5, 0, 0);
+
+ itemsMask &=_alignmentMenuMasks[cClass];
+ _vm->_gui->setupMenu(3, 9, _chargenAlignmentStrings, itemsMask, 0, 0);
+
+ _vm->_mouseX = _vm->_mouseY = 0;
+ int16 res = -1;
+
+ while (res == -1 && !_vm->shouldQuit()) {
+ updateMagicShapes();
+
+ int in = _vm->checkInput(0, false, 0) & 0xff;
+ Common::Point mp = _vm->getMousePos();
+
+ if (in == _vm->_keyMap[Common::KEYCODE_ESCAPE] || _vm->_gui->_menuLastInFlags == _vm->_keyMap[Common::KEYCODE_ESCAPE] || _vm->_gui->_menuLastInFlags == _vm->_keyMap[Common::KEYCODE_b]) {
+ res = _vm->_keyMap[Common::KEYCODE_ESCAPE];
+ } else if (_vm->posWithinRect(mp.x, mp.y, 264, 171, 303, 187)) {
+ if (in == 199 || in == 201)
+ res = _vm->_keyMap[Common::KEYCODE_ESCAPE];
+ else
+ _vm->removeInputTop();
+ } else {
+ res = _vm->_gui->handleMenu(3, _chargenAlignmentStrings, 0, itemsMask, 0);
+ }
+ }
+
+ _vm->removeInputTop();
+
+ if (res == _vm->_keyMap[Common::KEYCODE_ESCAPE])
+ processSpecialButton(5);
+
+ return res;
+}
+
+void CharacterGenerator::updateMagicShapes() {
+ _vm->sound()->process();
+
+ if (_magicShapesBox != _activeBox) {
+ _chargenMagicShapeTimer = 0;
+ _magicShapesBox = _activeBox;
+ }
+
+ if (_chargenMagicShapeTimer < _vm->_system->getMillis()) {
+ if (++_updateBoxShapesIndex > 9)
+ _updateBoxShapesIndex = 0;
+ _chargenMagicShapeTimer = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+ }
+
+ if (_updateBoxShapesIndex == _lastUpdateBoxShapesIndex)
+ return;
+
+ _screen->copyRegion(_activeBox << 5, 128, 288, 128, 32, 32, 2, 2, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(2, _chargenMagicShapes[_updateBoxShapesIndex], 288, 128, 0);
+ _screen->copyRegion(288, 128, _chargenBoxX[_activeBox], _chargenBoxY[_activeBox] + 1, 32, 32, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ _lastUpdateBoxShapesIndex = _updateBoxShapesIndex;
+}
+
+void CharacterGenerator::generateStats(int index) {
+ EobCharacter *c = &_characters[index];
+
+ for (int i = 0; i < 3; i++) {
+ c->level[i] = _chargenStartLevels[(c->cClass << 2) + i];
+ c->experience[i] = (_vm->game() == GI_EOB2 ? 69000 : 5000) / _chargenStartLevels[(c->cClass << 2) + 3];
+ }
+
+ int rc = c->raceSex >> 1;
+ for (int i = 0; i < 6; i++) {
+ _chargenMinStats[i] = MAX(_chargenClassMinStats[c->cClass * 6 + i], _chargenRaceMinStats[rc * 6 + i]);
+ _chargenMaxStats[i] = _chargenRaceMaxStats[rc * 6 + i];
+ }
+
+ if (_vm->_charClassModUnk[c->cClass])
+ _chargenMaxStats[0] = 18;
+
+ uint16 sv[6];
+ for (int i = 0; i < 6; i++) {
+ sv[i] = MAX<uint16>(rollDice() + _raceModifiers[rc * 6 + i], _chargenMinStats[i]);
+ if (!i && sv[i] == 18)
+ sv[i] |= (uint16)(_vm->rollDice(1, 100) << 8);
+ if (sv[i] > _chargenMaxStats[i])
+ sv[i] = _chargenMaxStats[i];
+ }
+
+ c->strengthCur = c->strengthMax = sv[0] & 0xff;
+ c->strengthExtCur = c->strengthExtMax = sv[0] >> 8;
+ c->intelligenceCur = c->intelligenceMax = sv[1] & 0xff;
+ c->wisdomCur = c->wisdomMax = sv[2] & 0xff;
+ c->dexterityCur = c->dexterityMax = sv[3] & 0xff;
+ c->constitutionCur = c->constitutionMax = sv[4] & 0xff;
+ c->charismaCur = c->charismaMax = sv[5] & 0xff;
+ c->armorClass = 10 + _vm->getDexterityArmorClassModifier(sv[3] & 0xff);
+ c->hitPointsCur = 0;
+
+ for (int l = 0; l < 3; l++) {
+ for (int i = 0; i < c->level[l]; i++)
+ c->hitPointsCur += _vm->generateCharacterHitpointsByLevel(index, 1 << l);
+ }
+
+ c->hitPointsMax = c->hitPointsCur;
+}
+
+void CharacterGenerator::modifyMenu() {
+ _vm->removeInputTop();
+ printStats(_activeBox, 3);
+
+ EobCharacter *c = &_characters[_activeBox];
+ int8 hpLO = c->hitPointsCur;
+
+ for (int i = 0; i >= 0 && i < 7; ) {
+ switch (i) {
+ case 0:
+ i = modifyStat(i, &c->strengthCur, &c->strengthExtCur);
+ break;
+ case 1:
+ i = modifyStat(i, &c->intelligenceCur, 0);
+ break;
+ case 2:
+ i = modifyStat(i, &c->wisdomCur, 0);
+ break;
+ case 3:
+ i = modifyStat(i, &c->dexterityCur, 0);
+ break;
+ case 4:
+ i = modifyStat(i, &c->constitutionCur, 0);
+ break;
+ case 5:
+ i = modifyStat(i, &c->charismaCur, 0);
+ break;
+ case 6:
+ hpLO = c->hitPointsCur;
+ i = modifyStat(i, &hpLO, 0);
+ c->hitPointsCur = hpLO;
+ break;
+ default:
+ break;
+ }
+
+ if (i == -2 || _vm->shouldQuit())
+ break;
+ else if (i < 0)
+ i = 6;
+ i %= 7;
+
+ printStats(_activeBox, 3);
+ }
+
+ printStats(_activeBox, 1);
+}
+
+void CharacterGenerator::statsAndFacesMenu() {
+ faceSelectMenu();
+ printStats(_activeBox, 1);
+ initButtonsFromList(27, 4);
+ _vm->removeInputTop();
+ int in = 0;
+
+ while (!in && !_vm->shouldQuit()) {
+ updateMagicShapes();
+ in = _vm->checkInput(_vm->_activeButtons, false, 0);
+ _vm->removeInputTop();
+
+ if (in == 0x8001) {
+ processSpecialButton(4);
+ updateMagicShapes();
+ generateStats(_activeBox);
+ in = -1;
+ } else if (in == 0x8002) {
+ processSpecialButton(7);
+ modifyMenu();
+ in = -1;
+ } else if (in == 0x8003) {
+ processSpecialButton(8);
+ faceSelectMenu();
+ in = -1;
+ } else if (in == 0x8004 || in == _vm->_keyMap[Common::KEYCODE_KP5]) {
+ processSpecialButton(6);
+ in = 1;
+ } else {
+ in = 0;
+ }
+
+ if (in & 0x8000) {
+ printStats(_activeBox, 1);
+ initButtonsFromList(27, 4);
+ in = 0;
+ }
+ }
+
+ highlightBoxFrame(6 + _activeBox);
+ highlightBoxFrame(-1);
+}
+
+void CharacterGenerator::faceSelectMenu() {
+ int8 sp[4];
+ memcpy(sp, _chargenSelectedPortraits2, sizeof(sp));
+ _vm->removeInputTop();
+ initButtonsFromList(21, 6);
+
+ int charSex = _characters[_activeBox].raceSex % 2;
+ int8 shp = charSex ? 26 : 0;
+
+ printStats(_activeBox, 4);
+ toggleSpecialButton(12, 0, 0);
+ toggleSpecialButton(13, 0, 0);
+ highlightBoxFrame(-1);
+
+ shp = getNextFreeFaceShape(shp, charSex, 1, _chargenSelectedPortraits);
+
+ int res = -1;
+ int box = 1;
+
+ while (res == -1 && !_vm->shouldQuit()) {
+ int8 shpOld = shp;
+
+ for (int i = 0; i < 4; i++) {
+ sp[i] = shp;
+ _screen->drawShape(0, _faceShapes[sp[i]], 176 + (i << 5), 66, 0);
+ shp = getNextFreeFaceShape(shp + 1, charSex, 1, _chargenSelectedPortraits);
+ }
+
+ shp = shpOld;
+ int in = 0;
+
+ while (!in && !_vm->shouldQuit()) {
+ updateMagicShapes();
+ in = _vm->checkInput(_vm->_activeButtons, false, 0);
+ _vm->removeInputTop();
+
+ highlightBoxFrame(box + 10);
+
+ if (in == 0x8002 || in == _vm->_keyMap[Common::KEYCODE_RIGHT]) {
+ processSpecialButton(13);
+ in = 2;
+ } else if (in > 0x8002 && in < 0x8007) {
+ box = (in & 7) - 3;
+ in = 3;
+ } else if (in == 0x8001 || in == _vm->_keyMap[Common::KEYCODE_LEFT]) {
+ processSpecialButton(12);
+ in = 1;
+ } else if (in == _vm->_keyMap[Common::KEYCODE_RETURN] || in == _vm->_keyMap[Common::KEYCODE_KP5]) {
+ in = 3;
+ } else if (in & 0x8000) {
+ in &= 0xff;
+ } else {
+ in = 0;
+ }
+ }
+
+ highlightBoxFrame(-1);
+
+ if (in == 1)
+ shp = getNextFreeFaceShape(shp - 1, charSex, -1, _chargenSelectedPortraits);
+ else if (in == 2)
+ shp = getNextFreeFaceShape(shp + 1, charSex, 1, _chargenSelectedPortraits);
+ else if (in == 3)
+ res = box;
+ }
+
+ if (!_vm->shouldQuit()) {
+ highlightBoxFrame(-1);
+ updateMagicShapes();
+
+ _chargenSelectedPortraits[_activeBox] = sp[res];
+ _characters[_activeBox].portrait = sp[res];
+ _characters[_activeBox].faceShape = _faceShapes[sp[res]];
+
+ printStats(_activeBox, 1);
+ }
+}
+
+int CharacterGenerator::getNextFreeFaceShape(int shpIndex, int charSex, int step, int8 *selectedPortraits) {
+ int shpCur = ((shpIndex < 0) ? 43 : shpIndex) % 44;
+ bool notUsable = false;
+
+ do {
+ notUsable = false;
+ for (int i = 0; i < 4; i++) {
+ if (_characters[i].name[0] && selectedPortraits[i] == shpCur)
+ notUsable = true;
+ }
+
+ if ((charSex && (shpCur < 26)) || (!charSex && (shpCur > 28)))
+ notUsable = true;
+
+ if (notUsable) {
+ shpCur += step;
+ shpCur = ((shpCur < 0) ? 43 : shpCur) % 44;
+ }
+ } while (notUsable);
+
+ return shpCur;
+}
+
+void CharacterGenerator::processFaceMenuSelection(int index) {
+ highlightBoxFrame(-1);
+ if (index <= 48)
+ _screen->drawShape(0, _characters[_activeBox].faceShape, _chargenBoxX[_activeBox], _chargenBoxY[_activeBox] + 1, 0);
+ else
+ toggleSpecialButton(index - 50, 0, 0);
+}
+
+void CharacterGenerator::printStats(int index, int mode) {
+ _screen->copyRegion(0, 0, 160, 0, 160, 128, 2, 2, Screen::CR_NO_P_CHECK);
+ _screen->_curPage = 2;
+
+ EobCharacter *c = &_characters[index];
+
+ if (mode != 4)
+ _screen->drawShape(2, c->faceShape, 224, 2, 0);
+
+ _screen->printShadedText(c->name, 160 + ((20 - strlen(c->name)) << 2), 35, 15, 0);
+ _screen->printShadedText(_chargenRaceSexStrings[c->raceSex], 160 + ((20 - strlen(_chargenRaceSexStrings[c->raceSex])) << 2), 45, 15, 0);
+ _screen->printShadedText(_chargenClassStrings[c->cClass], 160 + ((20 - strlen(_chargenClassStrings[c->cClass])) << 2), 54, 15, 0);
+
+ for (int i = 0; i < 6; i++)
+ _screen->printShadedText(_chargenStatStrings[i], 163, (i + 8) << 3, 15, 0);
+
+ _screen->printShadedText(_chargenStrings1[2], 248, 64, 15, 0);
+
+ char str[22];
+ snprintf(str, 22, _chargenStrings1[3], _vm->getCharStrength(c->strengthCur, c->strengthExtCur), c->intelligenceCur, c->wisdomCur, c->dexterityCur, c->constitutionCur, c->charismaCur);
+ _screen->printShadedText(str, 192, 64, 15, 0);
+
+ snprintf(str, 22, _chargenStrings1[4], c->armorClass, c->hitPointsMax);
+ _screen->printShadedText(str, 280, 64, 15, 0);
+
+ const char *lvlStr = c->level[2] ? _chargenStrings1[7] : (c->level[1] ? _chargenStrings1[6] : _chargenStrings1[5]);
+ snprintf(str, 22, lvlStr, c->level[0], c->level[1], c->level[2]);
+ _screen->printShadedText(str, 280, 80, 15, 0);
+
+ switch (mode) {
+ case 1:
+ toggleSpecialButton(4, 0, 2);
+ toggleSpecialButton(7, 0, 2);
+ toggleSpecialButton(8, 0, 2);
+ toggleSpecialButton(6, 0, 2);
+ break;
+
+ case 2:
+ toggleSpecialButton(16, 0, 2);
+ toggleSpecialButton(9, 0, 2);
+ break;
+
+ case 3:
+ toggleSpecialButton(10, 0, 2);
+ toggleSpecialButton(11, 0, 2);
+ toggleSpecialButton(9, 0, 2);
+ break;
+
+ default:
+ break;
+ }
+
+ _screen->copyRegion(160, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK);
+
+ if (mode != 3)
+ _screen->updateScreen();
+
+ _screen->_curPage = 0;
+}
+
+void CharacterGenerator::processNameInput(int index, int len, int textColor) {
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+
+ // WORKAROUND for bug in original code:
+ len = strlen(_characters[index].name);
+
+ int xOffs = (60 - _screen->getFontWidth() * len) >> 1;
+ _screen->printText(_chargenStrings1[1], _chargenNameFieldX[index], _chargenNameFieldY[index], 12, 12);
+ _screen->printText(_characters[index].name, _chargenNameFieldX[index] + xOffs, _chargenNameFieldY[index], textColor, 0);
+ _screen->updateScreen();
+ _screen->setFont(of);
+}
+
+int CharacterGenerator::rollDice() {
+ int res = 0;
+ int min = 10;
+
+ for (int i = 0; i < 4; i++) {
+ int d = _vm->rollDice(1, 6, 0);
+ res += d;
+ if (d < min)
+ min = d;
+ }
+
+ res -= min;
+ return res;
+}
+
+int CharacterGenerator::modifyStat(int index, int8 *stat1, int8 *stat2) {
+ uint8 *s1 = (uint8*) stat1;
+ uint8 *s2 = (uint8*) stat2;
+
+ initButtonsFromList(31, 10);
+ Button *b = _vm->gui_getButton(_vm->_activeButtons, index + 1);
+
+ printStats(_activeBox, 3);
+ _vm->removeInputTop();
+
+ char statStr[6];
+ if (index)
+ snprintf(statStr, 6, "%d", *s1);
+ else
+ snprintf(statStr, 6, "%s", _vm->getCharStrength(*s1, *s2));
+
+ _screen->copyRegion(b->x - 112, b->y - 64, b->x + 32, b->y, 40, b->height, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(statStr, b->x + 32, b->y, 6, 0);
+ _screen->updateScreen();
+
+ EobCharacter *c = &_characters[_activeBox];
+
+ int ci = index;
+ uint8 v2 = s2 ? *s2 : 0;
+
+ if (index == 6) {
+ _chargenMaxStats[6] = getMaxHp(c->cClass, c->constitutionCur, c->level[0], c->level[1], c->level[2]);
+ _chargenMinStats[6] = getMinHp(c->cClass, c->constitutionCur, c->level[0], c->level[1], c->level[2]);
+ }
+
+ for (bool loop = true; loop && !_vm->shouldQuit(); ) {
+ uint8 v1 = *s1;
+ updateMagicShapes();
+ int inputFlag = _vm->checkInput(_vm->_activeButtons, false, 0);
+ _vm->removeInputTop();
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_LEFT] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP4] || inputFlag == _vm->_keyMap[Common::KEYCODE_MINUS] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP_MINUS] || inputFlag == 0x8009) {
+ processSpecialButton(11);
+ v1--;
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_RIGHT] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP6] || inputFlag == _vm->_keyMap[Common::KEYCODE_PLUS] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP_PLUS] || inputFlag == 0x8008) {
+ processSpecialButton(10);
+ v1++;
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_UP] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP8]) {
+ ci = --ci % 7;
+ loop = false;
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP2]) {
+ ci = ++ci % 7;
+ loop = false;
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_o] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP5] || inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE] || inputFlag == 0x800A) {
+ processSpecialButton(9);
+ loop = false;
+ ci = -2;
+
+ } else if (inputFlag & 0x8000) {
+ inputFlag = (inputFlag & 0x0f) - 1;
+ if (index != inputFlag) {
+ ci = inputFlag;
+ loop = false;
+ }
+ }
+
+ if (v1 == *s1)
+ continue;
+
+ if (!index) {
+ while (v1 > 18) {
+ v1--;
+ v2++;
+ }
+ while (v2 > 0 && v1 < 18) {
+ v1++;
+ v2--;
+ }
+
+ v1 = CLIP<uint8>(v1, _chargenMinStats[index], _chargenMaxStats[index] & 0xff);
+ v2 = (v1 == 18 && _chargenMaxStats[index] >= 19) ? CLIP<uint8>(v2, 0, 100) : 0;
+ if (s2)
+ *s2 = v2;
+ else
+ error("CharacterGenerator::modifyStat:...");
+ } else {
+ v1 = CLIP<uint8>(v1, _chargenMinStats[index], _chargenMaxStats[index]);
+ }
+
+ *s1 = v1;
+
+ if (index == 6)
+ _characters[_activeBox].hitPointsMax = v1;
+
+ if (index)
+ snprintf(statStr, 6, "%d", *s1);
+ else
+ snprintf(statStr, 6, "%s", _vm->getCharStrength(*s1, *s2));
+
+ _screen->copyRegion(b->x - 112, b->y - 64, b->x + 32, b->y, 40, b->height, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(statStr, b->x + 32, b->y, 6, 0);
+ _screen->updateScreen();
+
+ if (index == 4) {
+ int oldVal = c->hitPointsCur;
+ _chargenMaxStats[6] = getMaxHp(c->cClass, c->constitutionCur, c->level[0], c->level[1], c->level[2]);
+ _chargenMinStats[6] = getMinHp(c->cClass, c->constitutionCur, c->level[0], c->level[1], c->level[2]);
+ c->hitPointsMax = c->hitPointsCur = CLIP<int16>(c->hitPointsCur, _chargenMinStats[6], _chargenMaxStats[6]);
+
+ if (c->hitPointsCur != oldVal) {
+ snprintf(statStr, 6, "%d", c->hitPointsCur);
+ _screen->copyRegion(120, 72, 264, 136, 40, 8, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(statStr, 264, 136, 15, 0);
+ _screen->updateScreen();
+ }
+
+ } else if (index == 3) {
+ int oldVal = c->armorClass;
+ c->armorClass = _vm->getDexterityArmorClassModifier(v1) + 10;
+
+ if (c->armorClass != oldVal) {
+ snprintf(statStr, 6, "%d", c->armorClass);
+ _screen->copyRegion(120, 64, 264, 128, 40, 8, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(statStr, 264, 128, 15, 0);
+ _screen->updateScreen();
+ }
+ }
+
+ if (loop = false) {
+ if (index)
+ snprintf(statStr, 6, "%d", *s1);
+ else
+ snprintf(statStr, 6, "%s", _vm->getCharStrength(*s1, *s2));
+ _screen->printText(statStr, b->x + 32, b->y, 15, 0);
+ _screen->updateScreen();
+ }
+ }
+
+ return ci;
+}
+
+int CharacterGenerator::getMaxHp(int cclass, int constitution, int level1, int level2, int level3) {
+ int res = 0;
+ constitution = _vm->getClassAndConstHitpointsModifier(cclass, constitution);
+
+ int m = _vm->getClassHpIncreaseType(cclass, 0);
+ if (m != -1)
+ res = _vm->getModifiedHpLimits(m, constitution, level1, false);
+
+ m = _vm->getClassHpIncreaseType(cclass, 1);
+ if (m != -1)
+ res += _vm->getModifiedHpLimits(m, constitution, level2, false);
+
+ m = _vm->getClassHpIncreaseType(cclass, 2);
+ if (m != -1)
+ res += _vm->getModifiedHpLimits(m, constitution, level3, false);
+
+ res /= _vm->_numLevelsPerClass[cclass];
+
+ return res;
+}
+
+int CharacterGenerator::getMinHp(int cclass, int constitution, int level1, int level2, int level3) {
+ int res = 0;
+ constitution = _vm->getClassAndConstHitpointsModifier(cclass, constitution);
+
+ int m = _vm->getClassHpIncreaseType(cclass, 0);
+ if (m != -1)
+ res = _vm->getModifiedHpLimits(m, constitution, level1, true);
+
+ m = _vm->getClassHpIncreaseType(cclass, 1);
+ if (m != -1)
+ res += _vm->getModifiedHpLimits(m, constitution, level2, true);
+
+ m = _vm->getClassHpIncreaseType(cclass, 2);
+ if (m != -1)
+ res += _vm->getModifiedHpLimits(m, constitution, level3, true);
+
+ res /= _vm->_numLevelsPerClass[cclass];
+
+ return res;
+}
+
+void CharacterGenerator::finish() {
+ _screen->copyRegion(0, 0, 160, 0, 160, 128, 2, 2, Screen::CR_NO_P_CHECK);
+ int cp = _screen->setCurPage(2);
+ _screen->printShadedText(_chargenEnterGameStrings[0], 168, 32, 15, 0);
+ _screen->setCurPage(cp);
+ _screen->copyRegion(160, 0, 144, 64, 160, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ if (_vm->game() == GI_EOB1) {
+ static const int8 classDefaultItemsList[] = { 1, 17, 2, 17, 46, -1, 4, -1, 5, -1, 6, 2, 7, -1, 8, -1, 9, 21, 10, 2, 31, 2 };
+ static const int8 classDefaultItemsListIndex[] = { 4, 8, 0, -1, 4, 3, 0, -1, 4, 10, 0, 8, 3, 6, 1, -1, 2, 7, 0, -1,
+ 4, 5, 0, -1, 4, 7, 0, 8, 4, 5, 0, 8, 4, 6, 8, 8, 4, 6, 5, 8, 3, 6, 5, -1, 2, 7, 5, 0, 4, 6, 7, 0, 4, 3, 7, 0, 2, 6, 7, 1 };
+
+ _characters[0].inventory[2] = _vm->duplicateItem(35);
+
+ for (int i = 0; i < 4; i++) {
+ EobCharacter *c = &_characters[i];
+ c->flags = 1;
+ c->food = 100;
+ c->id = i;
+ c->inventory[3] = _vm->duplicateItem(10);
+
+ for (int ii = 0; ii < 4; ii++) {
+ int l = classDefaultItemsListIndex[(c->cClass << 2) + ii] << 1;
+ if (classDefaultItemsList[l] == -1)
+ continue;
+
+ int d = classDefaultItemsList[l];
+ int slot = classDefaultItemsList[l + 1];
+
+ if (slot < 0) {
+ slot = 0;
+ if (c->inventory[slot])
+ slot++;
+ if (c->inventory[slot])
+ slot++;
+ }
+
+ if (slot != 2 && c->inventory[slot])
+ continue;
+
+ if (d == 5 && (c->raceSex >> 1) == 3)
+ d = 36;
+
+ if (slot == 2) {
+ while (c->inventory[slot])
+ slot++;
+ }
+
+ c->inventory[slot] = _vm->duplicateItem(d);
+ }
+
+ _vm->recalcArmorClass(i);
+ }
+
+ } else {
+ static const uint8 classDefaultItemsListIndex[] = { 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 3, 2, 0, 0, 2 };
+ static const int8 itemList0[] = { 3, 36, 0, 17, -1, 0, 0, 56, 1, 17, 31, 0, 1, 23, 1, 17, 31, 1, 1 };
+ static const int8 itemList1[] = { 1, 2, 0, 17, -1, 0, 0 };
+ static const int8 itemList2[] = { 2, 56, 1, 17, 31, 0, 1, 23, 1, 17, 31, 0, 1 };
+ static const int8 itemList3[] = { 2, 1, 1, 17, 31, 1, 1, 1, 0, 17, 31, 2, 1 };
+ static const int8 *itemList[] = { itemList0, itemList1, itemList2, itemList3 };
+
+ for (int i = 0; i < 4; i++) {
+ EobCharacter *c = &_characters[i];
+ c->flags = 1;
+ c->food = 100;
+ c->id = i;
+ const int8 *df = itemList[classDefaultItemsListIndex[c->cClass]];
+ int v1 = _vm->rollDice(1, *df++, -1);
+
+ df = &df[v1 * 6];
+ for (int ii = 0; ii < 2; ii++) {
+ if (df[0] == -1)
+ break;
+ _vm->createInventoryItem(c, df[0], df[1], df[2]);
+ df = &df[3];
+ }
+
+ uint16 m = _vm->_classModifierFlags[c->cClass];
+ v1 = _vm->rollDice(1, 2, -1);
+
+ int ival = 0;
+ int itype = 0;
+
+ if (m & 0x31) {
+ if ((c->raceSex >> 1) == 3) {
+ itype = 22;
+ ival = 1;
+ } else {
+ if (v1 == 0) {
+ itype = 5;
+ ival = 1;
+ } else {
+ itype = 34;
+ }
+ }
+ } else if (m & 0x04) {
+ itype = 26;
+ if (v1 != 0)
+ ival = 1;
+ } else if (m & 0x08) {
+ ival = 1;
+ itype = ((c->raceSex >> 1) == 3) ? 22 : 5;
+ } else {
+ if (v1 == 0) {
+ itype = 3;
+ } else {
+ itype = 4;
+ ival = 1;
+ }
+ }
+
+ _vm->createInventoryItem(c, itype, ival, 0);
+ _vm->createInventoryItem(c, 10, -1, 2);
+ _vm->createInventoryItem(c, 10, -1, 2);
+ _vm->createInventoryItem(c, 24, 2, 2);
+
+ if (_vm->_classModifierFlags[c->cClass] & 2) {
+ _vm->createInventoryItem(c, 7, -1, 1);
+ _vm->createInventoryItem(c, 21, 4, 2);
+ _vm->createInventoryItem(c, 21, 13, 2);
+ }
+
+ if (_vm->_classModifierFlags[c->cClass] & 0x14) {
+ if (c->cClass == 2)
+ _vm->createInventoryItem(c, 27, -1, 1);
+ else
+ _vm->createInventoryItem(c, 8, -1, 1);
+
+ _vm->createInventoryItem(c, 20, 49, 1);
+ }
+
+ if (_vm->_classModifierFlags[c->cClass] & 8)
+ _vm->createInventoryItem(c, 6, -1, 1);
+
+ if (i == 0)
+ _vm->createInventoryItem(c, 93, -1, 2);
+
+ _vm->recalcArmorClass(i);
+ }
+ }
+
+ for (int i = 0; i < 4; i++) {
+ if (_vm->_classModifierFlags[_characters[i].cClass] & 2)
+ _characters[i].mageSpellsAvailabilityFlags = (_vm->game() == GI_EOB2) ? 0x81CB6 : 0x26C;
+
+ if (_vm->_classModifierFlags[_characters[i].cClass] & 0x14 && _vm->game() == GI_EOB2) {
+ // Cleric: Turn Undead
+ _characters[i].clericSpells[0] = 29;
+ }
+ }
+
+ for (int i = 0; i < 4; i++) {
+ EobCharacter *c = &_characters[i];
+ c->strengthMax = c->strengthCur;
+ c->strengthExtMax = c->strengthExtCur;
+ c->intelligenceMax = c->intelligenceCur;
+ c->wisdomMax = c->wisdomCur;
+ c->dexterityMax = c->dexterityCur;
+ c->constitutionMax = c->constitutionCur;
+ c->charismaMax = c->charismaCur;
+ c->hitPointsMax = c->hitPointsCur;
+ }
+
+ _vm->gui_resetButtonList();
+
+ if (_faceShapes) {
+ for (int i = 0; i < 44; i++) {
+ bool del = true;
+ for (int ii = 0; ii < 4; ii++) {
+ if (_characters[ii].faceShape == _faceShapes[i])
+ del = false;
+ }
+ if (del)
+ delete[] _faceShapes[i];
+ }
+ delete[] _faceShapes;
+ _faceShapes = 0;
+ }
+
+ if (_chargenMagicShapes) {
+ for (int i = 0; i < 10; i++)
+ delete[] _chargenMagicShapes[i];
+ delete[] _chargenMagicShapes;
+ _chargenMagicShapes = 0;
+ }
+
+ if (_chargenButtonLabels) {
+ for (int i = 0; i < 10; i++)
+ delete[] _chargenButtonLabels[i];
+ delete[] _chargenButtonLabels;
+ _chargenButtonLabels = 0;
+ }
+}
+
+const EobChargenButtonDef CharacterGenerator::_chargenButtonDefs[] = {
+ { 0x01, 0x37, 0x31, 0x32, 0x70 },
+ { 0x09, 0x37, 0x31, 0x32, 0x71 },
+ { 0x01, 0x77, 0x31, 0x32, 0x72 },
+ { 0x09, 0x77, 0x31, 0x32, 0x73 },
+ { 0x03, 0xB5, 0x53, 0x10, 0x1A },
+ { 0x21, 0xAC, 0x26, 0x10, 0x19 },
+ { 0x1C, 0xAC, 0x26, 0x10, 0x21 },
+ { 0x21, 0xAC, 0x26, 0x10, 0x32 },
+ { 0x13, 0x50, 0x9A, 0x08, 0x00 },
+ { 0x13, 0x58, 0x9A, 0x08, 0x00 },
+ { 0x13, 0x60, 0x9A, 0x08, 0x00 },
+ { 0x13, 0x68, 0x9A, 0x08, 0x00 },
+ { 0x13, 0x70, 0x9A, 0x08, 0x00 },
+ { 0x13, 0x78, 0x9A, 0x08, 0x00 },
+ { 0x13, 0x80, 0x9A, 0x08, 0x00 },
+ { 0x13, 0x88, 0x9A, 0x08, 0x00 },
+ { 0x13, 0x90, 0x9A, 0x08, 0x00 },
+ { 0x13, 0x98, 0x9A, 0x08, 0x00 },
+ { 0x13, 0xA0, 0x9A, 0x08, 0x00 },
+ { 0x13, 0xA8, 0x9A, 0x08, 0x00 },
+ { 0x13, 0xB0, 0x9A, 0x08, 0x00 },
+ { 0x12, 0x42, 0x20, 0x10, 0x00 },
+ { 0x12, 0x52, 0x20, 0x10, 0x00 },
+ { 0x16, 0x42, 0x20, 0x20, 0x00 },
+ { 0x1A, 0x42, 0x20, 0x20, 0x00 },
+ { 0x1E, 0x42, 0x20, 0x20, 0x00 },
+ { 0x22, 0x42, 0x20, 0x20, 0x00 },
+ { 0x1C, 0x9C, 0x26, 0x10, 0x14 },
+ { 0x21, 0x9C, 0x26, 0x10, 0x34 },
+ { 0x1C, 0xAC, 0x26, 0x10, 0x22 },
+ { 0x21, 0xAC, 0x26, 0x10, 0x26 },
+ { 0x12, 0x80, 0x35, 0x08, 0x00 },
+ { 0x12, 0x88, 0x35, 0x08, 0x00 },
+ { 0x12, 0x90, 0x35, 0x08, 0x00 },
+ { 0x12, 0x98, 0x35, 0x08, 0x00 },
+ { 0x12, 0xA0, 0x35, 0x08, 0x00 },
+ { 0x12, 0xA8, 0x35, 0x08, 0x00 },
+ { 0x1D, 0x88, 0x35, 0x08, 0x00 },
+ { 0x1B, 0xAC, 0x15, 0x10, 0x0D },
+ { 0x1E, 0xAC, 0x15, 0x10, 0x0C },
+ { 0x21, 0xAC, 0x25, 0x10, 0x19 }
+};
+
+const CreatePartyModButton CharacterGenerator::_chargenModButtons[] = {
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A, 0x40 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x80 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A, 0x80 },
+ { 0x00, 0xC0, 0x04, 0x05, 0x07, 0x05, 0x08, 0x1C, 0x9C },
+ { 0x04, 0xC0, 0x03, 0x05, 0x0A, 0x05, 0x08, 0x21, 0xAC },
+ { 0x07, 0xC0, 0x03, 0x05, 0x0B, 0x05, 0x08, 0x21, 0xAC },
+ { 0x0A, 0xC0, 0x04, 0x05, 0x06, 0x05, 0x08, 0x21, 0x9C },
+ { 0x18, 0xC0, 0x03, 0x05, 0x09, 0x05, 0x08, 0x1C, 0xAC },
+ { 0x0E, 0xC0, 0x02, 0x05, 0x0F, 0x05, 0x08, 0x21, 0xAC },
+ { 0x10, 0xC0, 0x01, 0x05, 0x09, 0x05, 0x04, 0x1B, 0xAC },
+ { 0x11, 0xC0, 0x01, 0x01, 0x09, 0x07, 0x04, 0x1E, 0xAC },
+ { 0x12, 0xC0, 0x03, 0x07, 0x07, 0x04, 0x06, 0x12, 0x42 },
+ { 0x15, 0xC0, 0x03, 0x07, 0x07, 0x04, 0x06, 0x12, 0x52 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x03, 0xB5 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x03, 0xB5 },
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x1C, 0xAC }
+};
+
+const EobRect8 CharacterGenerator::_chargenButtonBodyCoords[] = {
+ { 0x00, 0x80, 0x04, 0x20 },
+ { 0x04, 0x80, 0x04, 0x20 },
+ { 0x08, 0x80, 0x04, 0x20 },
+ { 0x0C, 0x80, 0x04, 0x20 },
+ { 0x0E, 0xA0, 0x03, 0x10 },
+ { 0x0B, 0xA0, 0x03, 0x10 },
+ { 0x10, 0x80, 0x04, 0x10 },
+ { 0x10, 0x90, 0x04, 0x10 },
+ { 0x11, 0xA0, 0x05, 0x10 },
+ { 0x11, 0xB0, 0x05, 0x10 },
+ { 0x16, 0xA0, 0x05, 0x10 },
+ { 0x16, 0xB0, 0x05, 0x10 },
+ { 0x00, 0xA0, 0x0B, 0x10 },
+ { 0x14, 0x80, 0x0B, 0x10 },
+ { 0x14, 0x90, 0x0B, 0x10 }
+};
+
+const EobRect16 CharacterGenerator::_chargenPortraitBoxFrames[] = {
+ { 0x00B7, 0x0001, 0x00F7, 0x0034 },
+ { 0x00FF, 0x0001, 0x013F, 0x0034 },
+ { 0x00B7, 0x0035, 0x00F7, 0x0068 },
+ { 0x00FF, 0x0035, 0x013F, 0x0068 },
+ { 0x00B7, 0x0069, 0x00F7, 0x009C },
+ { 0x00FF, 0x0069, 0x013F, 0x009C },
+ { 0x0010, 0x003F, 0x0030, 0x0060 },
+ { 0x0050, 0x003F, 0x0070, 0x0060 },
+ { 0x0010, 0x007F, 0x0030, 0x00A0 },
+ { 0x0050, 0x007F, 0x0070, 0x00A0 },
+ { 0x00B0, 0x0042, 0x00D0, 0x0061 },
+ { 0x00D0, 0x0042, 0x00F0, 0x0061 },
+ { 0x00F0, 0x0042, 0x0110, 0x0061 },
+ { 0x0110, 0x0042, 0x0130, 0x0061 },
+ { 0x0004, 0x0018, 0x0024, 0x0039 },
+ { 0x00A3, 0x0018, 0x00C3, 0x0039 },
+ { 0x0004, 0x0040, 0x0024, 0x0061 },
+ { 0x00A3, 0x0040, 0x00C3, 0x0061 },
+ { 0x0004, 0x0068, 0x0024, 0x0089 },
+ { 0x00A3, 0x0068, 0x00C3, 0x0089 }
+};
+
+const int16 CharacterGenerator::_chargenBoxX[] = { 0x10, 0x50, 0x10, 0x50 };
+const int16 CharacterGenerator::_chargenBoxY[] = { 0x3F, 0x3F, 0x7F, 0x7F };
+const int16 CharacterGenerator::_chargenNameFieldX[] = { 0x02, 0x42, 0x02, 0x42 };
+const int16 CharacterGenerator::_chargenNameFieldY[] = { 0x6B, 0x6B, 0xAB, 0xAB };
+
+const int32 CharacterGenerator::_classMenuMasks[] = {
+ 0x003F, 0x07BB, 0x77FB, 0x00F1, 0x08F1, 0x00B1
+};
+
+const int32 CharacterGenerator::_alignmentMenuMasks[] = {
+ 0x01FF, 0x0007, 0x0001, 0x01FF, 0x01FF, 0x01FE, 0x01FF, 0x01FE,
+ 0x01FF, 0x01FE, 0x01FE, 0x01FE, 0x01FF, 0x0007, 0x01FF
+};
+
+const int16 CharacterGenerator::_raceModifiers[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, -1, 0, 1, -1, 0, 0, 0, -1, 0, 0, 1, 0, 0
+};
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index 68eb08210e..44fbc0fe68 100644
--- a/engines/kyra/detection.cpp
+++ b/engines/kyra/detection.cpp
@@ -17,12 +17,15 @@
* 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 "kyra/kyra_lok.h"
#include "kyra/lol.h"
#include "kyra/kyra_hof.h"
#include "kyra/kyra_mr.h"
+#include "kyra/eob1.h"
+#include "kyra/eob2.h"
#include "common/config-manager.h"
#include "common/system.h"
@@ -129,6 +132,14 @@ bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGame
*engine = new Kyra::LoLEngine(syst, flags);
break;
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+ case Kyra::GI_EOB1:
+ *engine = new Kyra::EobEngine(syst, flags);
+ break;
+ case Kyra::GI_EOB2:
+ *engine = new Kyra::DarkMoonEngine(syst, flags);
+ break;
+#endif // ENABLE_EOB
default:
res = false;
warning("Kyra engine: unknown gameID");
diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index ebf7c8eee7..50a154dcf3 100644
--- a/engines/kyra/detection_tables.h
+++ b/engines/kyra/detection_tables.h
@@ -57,6 +57,9 @@ namespace {
#define LOL_DEMO_FLAGS FLAGS(true, true, false, false, false, false, false, false, Kyra::GI_LOL)
#define LOL_KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, false, Kyra::GI_KYRA2)
+#define EOB_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_EOB1)
+#define EOB2_FLAGS FLAGS(false, false, false, false, false, false, false, false, Kyra::GI_EOB2)
+
const KYRAGameDescription adGameDescs[] = {
/* disable these targets until they get supported
{
@@ -1439,6 +1442,73 @@ const KYRAGameDescription adGameDescs[] = {
LOL_KYRA2_DEMO_FLAGS
},
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+
+ {
+ {
+ "eob",
+ 0,
+ {
+ { "EOBDATA2.PAK", 0, "feaf0345086b3a1d931352f4b0ad8feb", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK)
+ },
+ EOB_FLAGS
+ },
+
+ {
+ {
+ "eob",
+ 0,
+ {
+ { "SHINDIA.CPS", 0, "383b0c7ba0903eae5d04cad28ce90aaf", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK)
+ },
+ EOB_FLAGS
+ },
+
+ {
+ {
+ "eob2",
+ 0,
+ {
+ { "LEVEL15.INF", 0, "10f19eab75c73d0476dc58bcf70fff7a", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK)
+ },
+ EOB2_FLAGS
+ },
+
+ {
+ {
+ "eob2",
+ 0,
+ {
+ { "LEVEL15.INF", 0, "ce54243ad1ca4447f521340428da2c91", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ ADGF_NO_FLAGS,
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK)
+ },
+ EOB2_FLAGS
+ },
+#endif // ENABLE_EOB
+
{ AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0) }
};
@@ -1449,6 +1519,10 @@ const PlainGameDescriptor gameList[] = {
#ifdef ENABLE_LOL
{ "lol", "Lands of Lore: The Throne of Chaos" },
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+ { "eob", "Eye of the Beholder" },
+ { "eob2", "Eye of the Beholder II: The Legend of Darkmoon" },
+#endif // ENABLE_EOB
{ 0, 0 }
};
diff --git a/engines/kyra/eob1.cpp b/engines/kyra/eob1.cpp
new file mode 100644
index 0000000000..993d06a56b
--- /dev/null
+++ b/engines/kyra/eob1.cpp
@@ -0,0 +1,242 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/eob1.h"
+#include "kyra/resource.h"
+
+namespace Kyra {
+
+EobEngine::EobEngine(OSystem *system, const GameFlags &flags) : EobCoreEngine(system, flags) {
+ _numSpells = 53;
+}
+
+EobEngine::~EobEngine() {
+ delete[] _itemsOverlay;
+}
+
+Common::Error EobEngine::init() {
+ Common::Error err = EobCoreEngine::init();
+ if (err.getCode() != Common::kNoError)
+ return err;
+
+ initStaticResource();
+
+ _itemsOverlay = _res->fileData("ITEMRMP.VGA", 0);
+
+ _bkgColor_1 = 132;
+ _color1_1 = 135;
+ _color2_1 = 130;
+ _color4 = 133;
+ _color5 = 133;
+ _color6 = 180;
+ _color7 = 177;
+ _color8 = 184;
+
+ _color14 = _color8;
+ _color13 = _color7;
+ _color12 = _color6;
+
+ _screen->modifyScreenDim(7, 0x01, 0xB3, 0x22, 0x12);
+ _screen->modifyScreenDim(9, 0x01, 0x7D, 0x26, 0x3F);
+ _screen->modifyScreenDim(12, 0x01, 0x04, 0x14, 0xA0);
+
+ _scriptTimersCount = 1;
+
+ return Common::kNoError;
+}
+
+void EobEngine::startupNew() {
+ _currentLevel = 1;
+ _currentSub = 0;
+ loadLevel(1, 0);
+ _currentBlock = 490;
+ _currentDirection = 0;
+ setHandItem(0);
+}
+
+void EobEngine::startupLoad() {
+ updateHandItemCursor();
+ loadLevel(_currentLevel, _currentSub);
+ _saveLoadMode = 0;
+}
+
+void EobEngine::npcSequence(int npcIndex) {
+
+
+}
+
+void EobEngine::updateUsedCharacterHandItem(int charIndex, int slot) {
+ EobItem *itm = &_items[_characters[charIndex].inventory[slot]];
+ if (itm->type == 48) {
+ int charges = itm->flags & 0x3f;
+ if (--charges)
+ --itm->flags;
+ else
+ deleteInventoryItem(charIndex, slot);
+ } else if (itm->type == 34 || itm->type == 35) {
+ deleteInventoryItem(charIndex, slot);
+ }
+}
+
+void EobEngine::replaceMonster(int unit, uint16 block, int pos, int dir, int type, int shpIndex, int mode, int h2, int randItem, int fixedItem) {
+ if (_levelBlockProperties[block].flags & 7)
+ return;
+
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].hitPointsCur <= 0) {
+ initMonster(i, unit, block, pos, dir, type, shpIndex, mode, h2, randItem, fixedItem);;
+ break;
+ }
+ }
+}
+
+void EobEngine::loadDoorShapes(int doorType1, int shapeId1, int doorType2, int shapeId2) {
+ _screen->loadEobBitmap("DOOR", 5, 3);
+ _screen->_curPage = 2;
+
+ if (doorType1 != 0xff) {
+ for (int i = 0; i < 3; i++) {
+ const uint8 *enc = &_doorShapeEncodeDefs[(doorType1 * 3 + i) << 2];
+ _doorShapes[shapeId1 + i] = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3]);
+ enc = &_doorSwitchShapeEncodeDefs[(doorType1 * 3 + i) << 2];
+ _doorSwitches[shapeId1 + i].shp = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3]);
+ _doorSwitches[shapeId1 + i].x = _doorSwitchCoords[doorType1 << 1];
+ _doorSwitches[shapeId1 + i].y = _doorSwitchCoords[(doorType1 << 1) + 1];
+ }
+ }
+
+ if (doorType2 != 0xff) {
+ for (int i = 0; i < 3; i++) {
+ const uint8 *enc = &_doorShapeEncodeDefs[(doorType2 * 3 + i) << 2];
+ _doorShapes[shapeId2 + i] = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3]);
+ enc = &_doorSwitchShapeEncodeDefs[(doorType2 * 3 + i) << 2];
+ _doorSwitches[shapeId2 + i].shp = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3]);
+ _doorSwitches[shapeId2 + i].x = _doorSwitchCoords[doorType2 << 1];
+ _doorSwitches[shapeId2 + i].y = _doorSwitchCoords[(doorType2 << 1) + 1];
+ }
+ }
+
+ _screen->_curPage = 0;
+}
+
+void EobEngine::drawDoorIntern(int type, int index, int x, int y, int w, int wall, int mDim, int16 y1, int16 y2) {
+ int shapeIndex = type + 2 - mDim;
+ uint8 *shp = _doorShapes[shapeIndex];
+
+ int d1 = 0;
+ int d2 = 0;
+ int v = 0;
+ const ScreenDim *td = _screen->getScreenDim(5);
+
+ switch (_currentLevel) {
+ case 4:
+ case 5:
+ case 6:
+ y = _dscDoorY2[mDim] - shp[1];
+ d1 = _dscDoorCoordsExt[index << 1] >> 3;
+ d2 = _dscDoorCoordsExt[(index << 1) + 1] >> 3;
+ if (_shpDmX1 > d1)
+ d1 = _shpDmX1;
+ if (_shpDmX2 < d2)
+ d2 = _shpDmX2;
+ _screen->modifyScreenDim(5, d1, td->sy, d2 - d1, td->h);
+ v = ((wall < 30) ? (wall - _dscDoorScaleOffs[wall]) * _dscDoorScaleMult3[mDim] : _dscDoorScaleMult4[mDim]) * -1;
+ v -= (shp[2] << 3);
+ drawBlockObject(0, 2, shp, x + v, y, 5);
+ v += (shp[2] << 3);
+ drawBlockObject(1, 2, shp, x - v, y, 5);
+ if (_wllShapeMap[wall] == -1)
+ drawBlockObject(0, 2, _doorSwitches[shapeIndex].shp, _doorSwitches[shapeIndex].x + w - v, _doorSwitches[shapeIndex].y, 5);
+ break;
+
+ case 7:
+ case 8:
+ case 9:
+ y = _dscDoorY3[mDim] - _doorShapes[shapeIndex + 3][1];
+ d1 = x - (_doorShapes[shapeIndex + 3][2] << 2);
+ x -= (shp[2] << 2);
+ drawBlockObject(0, 2, _doorShapes[shapeIndex + 3], d1, y, 5);
+ scaleLevelShapesDim(index, y1, y2, 5);
+ y = _dscDoorY3[mDim] - ((wall < 30) ? (wall - _dscDoorScaleOffs[wall]) * _dscDoorScaleMult1[mDim] : _dscDoorScaleMult2[mDim]);
+ drawBlockObject(0, 2, shp, x, y, 5);
+ if (_wllShapeMap[wall] == -1)
+ drawBlockObject(0, 2, _doorSwitches[shapeIndex].shp, _doorSwitches[shapeIndex].x + w, _doorSwitches[shapeIndex].y, 5);
+ break;
+
+ case 10:
+ case 11:
+ v = ((wall < 30) ? (wall - _dscDoorScaleOffs[wall]) * _dscDoorScaleMult5[mDim] : _dscDoorScaleMult6[mDim]) * -1;
+ x -= (shp[2] << 2);
+ y = _dscDoorY3[mDim] + v;
+ drawBlockObject(0, 2, shp, x, y + v, 5);
+ v >>= 4;
+ y = _dscDoorY5[mDim];
+ drawBlockObject(0, 2, _doorShapes[shapeIndex + 3], x, y - v, 5);
+ if (_wllShapeMap[wall] == -1)
+ drawBlockObject(0, 2, _doorSwitches[shapeIndex].shp, _doorSwitches[shapeIndex].x + w, _doorSwitches[shapeIndex].y, 5);
+ break;
+
+ default:
+ y = (_currentLevel == 12 ? _dscDoorY6[mDim] : _dscDoorY1[mDim]) - shp[1];
+ x -= (shp[2] << 2);
+ y -= (wall >= 30 ? _dscDoorScaleMult2[mDim] : (wall - _dscDoorScaleOffs[wall]) * _dscDoorScaleMult1[mDim]);
+ drawBlockObject(0, 2, shp, x, y, 5);
+
+ if (_wllShapeMap[wall] == -1)
+ drawBlockObject(0, 2, _doorSwitches[shapeIndex].shp, _doorSwitches[shapeIndex].x + w, _doorSwitches[shapeIndex].y, 5);
+ break;
+ }
+}
+
+uint32 EobEngine::convertSpellFlagToEob2Format(uint32 flag, int ignoreInvisibility) {
+ uint32 res = 0;
+ if (flag & 0x01)
+ res |= 0x20;
+ if (flag & 0x02)
+ res |= 0x400;
+ if (flag & 0x04)
+ res |= 0x80;
+ if (flag & 0x08)
+ res |= 0x40;
+ if (ignoreInvisibility)
+ res |= 0x100;
+ return res;
+}
+
+uint32 EobEngine::convertCharacterEffectFlagToEob2Format(uint32 flag) {
+ uint32 res = 0;
+ if (flag & 0x02)
+ res |= 0x08;
+ if (flag & 0x04)
+ res |= 0x40;
+ if (flag & 0x80)
+ res |= 0x2000;
+ if (flag & 0x100)
+ res |= 0x4000;
+ return res;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/eob1.h b/engines/kyra/eob1.h
new file mode 100644
index 0000000000..27a060f65c
--- /dev/null
+++ b/engines/kyra/eob1.h
@@ -0,0 +1,96 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#ifndef KYRA_EOB1_H
+#define KYRA_EOB1_H
+
+#include "kyra/eobcommon.h"
+
+namespace Kyra {
+
+class EobEngine : public EobCoreEngine {
+friend class GUI_Eob;
+public:
+ EobEngine(OSystem *system, const GameFlags &flags);
+ ~EobEngine();
+
+private:
+ // Init / Release
+ Common::Error init();
+ void initStaticResource();
+ void initSpells();
+
+ // Main Menu
+ int mainMenu();
+ int mainMenuLoop();
+
+ // Main loop
+ void startupNew();
+ void startupLoad();
+
+ // Intro/Outro
+ void seq_playOpeningCredits();
+ void seq_playIntro();
+ void seq_playFinale();
+
+ // characters
+ void npcSequence(int npcIndex);
+
+ //const char *const *_npc1Strings;
+ //const char *const *_npc2Strings;
+
+ // items
+ void updateUsedCharacterHandItem(int charIndex, int slot);
+
+ // Monsters
+ void replaceMonster(int unit, uint16 block, int d, int dir, int type, int shpIndex, int mode, int h2, int randItem, int fixedItem);
+
+ // Level
+ void loadDoorShapes(int doorType1, int shapeId1, int doorType2, int shapeId2);
+ void drawDoorIntern(int type, int index, int x, int y, int w, int wall, int mDim, int16 y1, int16 y2);
+
+ const int16 *_dscDoorCoordsExt;
+ const uint8 *_dscDoorScaleMult4;
+ const uint8 *_dscDoorScaleMult5;
+ const uint8 *_dscDoorScaleMult6;
+ const uint8 *_dscDoorY3;
+ const uint8 *_dscDoorY4;
+ const uint8 *_dscDoorY5;
+ const uint8 *_dscDoorY6;
+
+ const uint8 *_doorShapeEncodeDefs;
+ const uint8 *_doorSwitchShapeEncodeDefs;
+ const uint8 *_doorSwitchCoords;
+
+ // Misc
+ uint32 convertSpellFlagToEob2Format(uint32 flag, int ignoreInvisibility);
+ uint32 convertCharacterEffectFlagToEob2Format(uint32 flag);
+};
+
+
+} // End of namespace Kyra
+
+#endif
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/eob2.cpp b/engines/kyra/eob2.cpp
new file mode 100644
index 0000000000..120ad157d0
--- /dev/null
+++ b/engines/kyra/eob2.cpp
@@ -0,0 +1,437 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/eob2.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+namespace Kyra {
+
+DarkMoonEngine::DarkMoonEngine(OSystem *system, const GameFlags &flags) : EobCoreEngine(system, flags) {
+ _seqIntro = _seqFinale = 0;
+ _shapesIntro = _shapesFinale = 0;
+ _dscDoorType5Offs = 0;
+ _numSpells = 70;
+}
+
+DarkMoonEngine::~DarkMoonEngine() {
+ delete[] _seqIntro;
+ delete[] _seqFinale;
+ delete[] _shapesIntro;
+ delete[] _shapesFinale;
+}
+
+Common::Error DarkMoonEngine::init() {
+ Common::Error err = EobCoreEngine::init();
+ if (err.getCode() != Common::kNoError)
+ return err;
+
+ initStaticResource();
+
+ _monsterProps = new EobMonsterProperty[10];
+
+ _bkgColor_1 = 183;
+ _color1_1 = 186;
+ _color2_1 = 181;
+ _color4 = 133;
+ _color5 = 184;
+ _color6 = 183;
+ _color7 = 181;
+ _color8 = 186;
+ _color12 = 180;
+ _color13 = 177;
+ _color14 = 182;
+
+ return Common::kNoError;
+}
+
+void DarkMoonEngine::startupNew() {
+ _currentLevel = 4;
+ _currentSub = 0;
+ loadLevel(4, 0);
+ _currentBlock = 171;
+ _currentDirection = 2;
+ setHandItem(0);
+}
+
+void DarkMoonEngine::startupLoad() {
+ updateHandItemCursor();
+ loadLevel(_currentLevel, _currentSub);
+ _saveLoadMode = 0;
+}
+
+void DarkMoonEngine::npcSequence(int npcIndex) {
+ _screen->loadEobBitmap("OUTTAKE", 5, 3);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 0, 6, Screen::CR_NO_P_CHECK);
+ const uint8 *shpDef = &_npcShpData[npcIndex << 3];
+
+ for (int i = npcIndex; i != 255; i = shpDef[7]) {
+ shpDef = &_npcShpData[i << 3];
+ _screen->_curPage = 2;
+ const uint8 *shp = _screen->encodeShape(READ_LE_UINT16(shpDef), shpDef[2], shpDef[3], shpDef[4]);
+ _screen->_curPage = 0;
+ _screen->drawShape(0, shp, 88 + shpDef[5] - (shp[2] << 2), 104 + shpDef[6] - shp[1], 5);
+ delete[] shp;
+ }
+
+ Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT");
+ _screen->loadFileDataToPage(s, 5, 32000);
+ delete s;
+
+ gui_drawBox(0, 121, 320, 79, _color1_1, _color2_1, _bkgColor_1);
+ _txt->setupField(9, true);
+ _txt->resetPageBreakString();
+
+ if (npcIndex == 0) {
+ snd_playSoundEffect(57);
+ if (npcJoinDialogue(0, 1, 3, 2))
+ setScriptFlag(0x40);
+ } else if (npcIndex == 1) {
+ snd_playSoundEffect(53);
+ gui_drawDialogueBox();
+
+ _txt->printDialogueText(4, 0);
+ int r = runDialogue(-1, 0, _npc1Strings[0], _npc1Strings[1]) - 1;
+
+ if (r == 0) {
+ _sound->playTrack(0);
+ delay(3 * _tickLength);
+ snd_playSoundEffect(91);
+ npcJoinDialogue(1, 5, 6, 7);
+ } else if (r == 1) {
+ setScriptFlag(0x20);
+ }
+
+ } else if (npcIndex == 2) {
+ snd_playSoundEffect(55);
+ gui_drawDialogueBox();
+
+ _txt->printDialogueText(8, 0);
+ int r = runDialogue(-1, 0, _npc2Strings[0], _npc2Strings[1]) - 1;
+
+ if (r == 0) {
+ if (rollDice(1, 2, -1))
+ _txt->printDialogueText(9, _okStrings[0]);
+ else
+ npcJoinDialogue(2, 102, 103, 104);
+ setScriptFlag(8);
+ } else if (r == 1) {
+ _currentDirection = 0;
+ }
+ }
+
+ _txt->removePageBreakFlag();
+ gui_restorePlayField();
+}
+
+void DarkMoonEngine::updateUsedCharacterHandItem(int charIndex, int slot) {
+ EobItem *itm = &_items[_characters[charIndex].inventory[slot]];
+ if (itm->type == 48 || itm->type == 62) {
+ if (itm->value == 5)
+ return;
+ int charges = itm->flags & 0x3f;
+ if (--charges)
+ --itm->flags;
+ else
+ deleteInventoryItem(charIndex, slot);
+ } else if (itm->type == 26 || itm->type == 34 || itm->type == 35) {
+ deleteInventoryItem(charIndex, slot);
+ }
+}
+
+void DarkMoonEngine::generateMonsterPalettes(const char *file, int16 monsterIndex) {
+ int cp = _screen->setCurPage(2);
+ _screen->loadEobBitmap(file, 3, 3);
+ uint8 tmpPal[16];
+ uint8 newPal[16];
+
+ for (int i = 0; i < 6; i++) {
+ int dci = monsterIndex + i;
+ memcpy(tmpPal, _monsterShapes[dci] + 4, 16);
+ int colx = 302 + 3 * i;
+
+ for (int ii = 0; ii < 16; ii++) {
+ uint8 col = _screen->getPagePixel(_screen->_curPage, colx, 184 + ii);
+
+ int iii = 0;
+ for (; iii < 16; iii++) {
+ if (tmpPal[iii] == col) {
+ newPal[ii] = iii;
+ break;
+ }
+ }
+
+ if (iii == 16)
+ newPal[ii] = 0;
+ }
+
+ for (int ii = 1; ii < 3; ii++) {
+ memcpy(tmpPal, _monsterShapes[dci] + 4, 16);
+
+ for (int iii = 0; iii < 16; iii++) {
+ uint8 col = _screen->getPagePixel(_screen->_curPage, colx + ii, 184 + iii);
+ if (newPal[iii])
+ tmpPal[newPal[iii]] = col;
+ }
+
+ int c = i;
+ if (monsterIndex >= 18)
+ c += 6;
+
+ c = (c << 1) + (ii - 1);
+ memcpy(_monsterPalettes[c], tmpPal, 16);
+ }
+ }
+
+ _screen->setCurPage(cp);
+}
+
+void DarkMoonEngine::loadMonsterDecoration(const char *file, int16 monsterIndex) {
+ char filename[13];
+ snprintf(filename, 13, "%s.dcr", file);
+
+ Common::SeekableReadStream *s = _res->createReadStream(filename);
+ if (!s)
+ return;
+
+ int len = s->readUint16LE();
+
+ for (int i = 0; i < len; i++) {
+ for (int ii = 0; ii < 6; ii++) {
+ uint8 dc[6];
+ s->read(dc, 6);
+ if (!dc[2] || !dc[3])
+ continue;
+
+ SpriteDecoration *m = &_monsterDecorations[i * 6 + ii + monsterIndex];
+
+ m->shp = _screen->encodeShape(dc[0], dc[1], dc[2], dc[3]);
+ m->x = dc[4];
+ m->y = dc[5];
+ }
+ }
+
+ delete s;
+}
+
+void DarkMoonEngine::replaceMonster(int unit, uint16 block, int pos, int dir, int type, int shpIndex, int mode, int h2, int randItem, int fixedItem) {
+ uint8 flg = _levelBlockProperties[block].flags & 7;
+
+ if (flg == 7 || _currentBlock == block || (flg && (_monsterProps[type].u30 || pos == 4)))
+ return;
+
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].block != block)
+ continue;
+ if (_monsters[i].pos == 4 || _monsterProps[_monsters[i].type].u30)
+ return;
+ }
+
+ int index = -1;
+ int maxDist = 0;
+
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].hitPointsCur <= 0) {
+ index = i;
+ break;
+ }
+
+ if (_monsters[i].flags & 0x40)
+ continue;
+
+ int dist = getBlockDistance(_monsters[i].block, _currentBlock);
+
+ if (dist > maxDist) {
+ maxDist = dist;
+ index = i;
+ }
+ }
+
+ if (index == -1)
+ return;
+
+ if (_monsters[index].hitPointsCur > 0)
+ killMonster(&_monsters[index], false);
+
+ initMonster(index, unit, block, pos, dir, type, shpIndex, mode, h2, randItem, fixedItem);
+}
+
+const uint8 *DarkMoonEngine::loadDoorShapes(const char *filename, int doorIndex, const uint8 *shapeDefs) {
+ _screen->loadEobBitmap(filename, 3, 3);
+ for (int i = 0; i < 3; i++) {
+ _doorShapes[doorIndex * 3 + i] = _screen->encodeShape(READ_LE_UINT16(shapeDefs), READ_LE_UINT16(shapeDefs + 2), READ_LE_UINT16(shapeDefs + 4), READ_LE_UINT16(shapeDefs + 6));
+ shapeDefs += 8;
+ }
+
+ for (int i = 0; i < 2; i++) {
+ _doorSwitches[doorIndex * 3 + i].shp = _screen->encodeShape(READ_LE_UINT16(shapeDefs), READ_LE_UINT16(shapeDefs + 2), READ_LE_UINT16(shapeDefs + 4), READ_LE_UINT16(shapeDefs + 6));
+ shapeDefs += 8;
+ _doorSwitches[doorIndex * 3 + i].x = *shapeDefs;
+ shapeDefs += 2;
+ _doorSwitches[doorIndex * 3 + i]. y= *shapeDefs;
+ shapeDefs += 2;
+ }
+ _screen->_curPage = 0;
+ return shapeDefs;
+}
+
+void DarkMoonEngine::drawDoorIntern(int type, int, int x, int y, int w, int wall, int mDim, int16, int16) {
+ int shapeIndex = type * 3 + 2 - mDim;
+ uint8 *shp = _doorShapes[shapeIndex];
+
+ if ((_doorType[type] == 0) || (_doorType[type] == 1)) {
+ y = _dscDoorY1[mDim] - shp[1];
+ x -= (shp[2] << 2);
+
+ if (_doorType[type] == 1) {
+ drawBlockObject(0, 2, shp, x, y, 5);
+ shp = _doorShapes[3 + shapeIndex];
+ }
+
+ y -= ((wall - _dscDoorScaleOffs[wall]) * _dscDoorScaleMult1[mDim]);
+
+ if (_specialWallTypes[wall] == 5)
+ y -= _dscDoorType5Offs[shapeIndex];
+
+ } else if (_doorType[type] == 2) {
+ x -= (shp[2] << 2);
+ y = _dscDoorY2[mDim] - ((wall - _dscDoorScaleOffs[wall]) * _dscDoorScaleMult3[mDim]);
+ }
+
+ drawBlockObject(0, 2, shp, x, y, 5);
+
+ if (_wllShapeMap[wall] == -1 && !_noDoorSwitch[type])
+ drawBlockObject(0, 2, _doorSwitches[shapeIndex].shp, _doorSwitches[shapeIndex].x + w, _doorSwitches[shapeIndex].y, 5);
+}
+
+void DarkMoonEngine::drawLightningColumn() {
+ int f = rollDice(1, 2, -1);
+ int y = 0;
+
+ for (int i = 0; i < 6; i++) {
+ f ^= 1;
+ drawBlockObject(f, 2, _lightningColumnShape, 72, y, 5);
+ y += 64;
+ }
+}
+
+int DarkMoonEngine::resurrectionSelectDialogue() {
+ int cnt = 0;
+ const char *namesList[10];
+ memset(namesList, 0, 10 * sizeof(const char*));
+ int8 indexList[10];
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ if (_characters[i].hitPointsCur != -10)
+ continue;
+
+ namesList[cnt] = _characters[i].name;
+ indexList[cnt++] = i;
+ }
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+
+ for (int ii = 0; ii < 27; ii++) {
+ uint16 inv = _characters[i].inventory[ii];
+ if (!inv)
+ continue;
+
+ if (_items[inv].type != 33)
+ continue;
+
+ namesList[cnt] = _npcPreset[_items[inv].value - 1].name;
+ indexList[cnt++] = -_items[inv].value;
+ }
+ }
+
+ if (_itemInHand) {
+ if (_items[_itemInHand].type == 33) {
+ namesList[cnt] = _npcPreset[_items[_itemInHand].value - 1].name;
+ indexList[cnt++] = -_items[_itemInHand].value;
+ }
+ }
+
+ namesList[cnt] = _abortStrings[0];
+ indexList[cnt++] = 99;
+
+ int r = indexList[runDialogue(-1, 1, namesList[0], namesList[1], namesList[2], namesList[3], namesList[4], namesList[5], namesList[6], namesList[7], namesList[8]) - 1];
+ if (r == 99)
+ return 0;
+
+ if (r < 0) {
+ r = -r;
+ if (prepareForNewPartyMember(33, r))
+ initNpc(r - 1);
+ } else {
+ _characters[r].hitPointsCur = 1;
+ }
+
+ return 1;
+}
+
+int DarkMoonEngine::charSelectDialogue() {
+ int cnt = 0;
+ const char *namesList[7];
+ memset(namesList, 0, 7 * sizeof(const char*));
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 3))
+ continue;
+ namesList[cnt++] = _characters[i].name;
+ }
+
+ namesList[cnt++] = _abortStrings[0];
+
+ int r = runDialogue(-1, 1, namesList[0], namesList[1], namesList[2], namesList[3], namesList[4], namesList[5], namesList[6], 0) - 1;
+ if (r == cnt - 1)
+ return 99;
+
+ for (cnt = 0; cnt < 6; cnt++) {
+ if (!testCharacter(cnt, 3))
+ continue;
+ if (--r < 0)
+ break;
+ }
+ return cnt;
+}
+
+void DarkMoonEngine::characterLevelGain(int charIndex) {
+ EobCharacter *c = &_characters[charIndex];
+ int s = _numLevelsPerClass[c->cClass];
+ for (int i = 0; i < s; i++) {
+ uint32 er = getRequiredExperience(c->cClass, i, c->level[i] + 1);
+ if (er == 0xffffffff)
+ continue;
+
+ increaseCharacterExperience(charIndex, er - c->experience[i]);
+ }
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/eob2.h b/engines/kyra/eob2.h
new file mode 100644
index 0000000000..a36ec0e466
--- /dev/null
+++ b/engines/kyra/eob2.h
@@ -0,0 +1,119 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#ifndef KYRA_EOB2_H
+#define KYRA_EOB2_H
+
+#include "kyra/eobcommon.h"
+
+namespace Kyra {
+
+class DarkmoonSequenceHelper;
+
+struct EobSequenceStep {
+ uint8 command;
+ uint8 obj;
+ int16 x1;
+ uint8 y1;
+ uint8 delay;
+ uint8 pal;
+ uint8 x2;
+ uint8 y2;
+ uint8 w;
+ uint8 h;
+};
+
+class DarkMoonEngine : public EobCoreEngine {
+friend class GUI_Eob;
+friend class DarkmoonSequenceHelper;
+public:
+ DarkMoonEngine(OSystem *system, const GameFlags &flags);
+ ~DarkMoonEngine();
+
+private:
+ // Init / Release
+ Common::Error init();
+ void initStaticResource();
+ void initSpells();
+
+ // Main Menu
+ int mainMenu();
+ int mainMenuLoop();
+
+ // Main loop
+ void startupNew();
+ void startupLoad();
+
+ // Intro/Outro
+ void seq_playIntro();
+ void seq_playFinale();
+ void seq_playCredits(DarkmoonSequenceHelper *sq, const uint8 *data, int sd, int backupPage, int tempPage, int speed);
+
+ const char * const*_introStrings;
+ const char * const *_cpsFilesIntro;
+ const EobSequenceStep **_seqIntro;
+ const EobShapeDef **_shapesIntro;
+
+ const char * const*_finaleStrings;
+ const uint8 *_creditsData;
+ const char * const *_cpsFilesFinale;
+ const EobSequenceStep **_seqFinale;
+ const EobShapeDef **_shapesFinale;
+
+ static const char *_palFilesIntro[];
+ static const char *_palFilesFinale[];
+
+ // characters
+ void npcSequence(int npcIndex);
+
+ const uint8 *_npcShpData;
+ const char *const *_npc1Strings;
+ const char *const *_npc2Strings;
+
+ // items
+ void updateUsedCharacterHandItem(int charIndex, int slot);
+
+ // Monsters
+ void generateMonsterPalettes(const char *file, int16 monsterIndex);
+ void loadMonsterDecoration(const char *file, int16 monsterIndex);
+ void replaceMonster(int unit, uint16 block, int d, int dir, int type, int shpIndex, int mode, int h2, int randItem, int fixedItem);
+
+ // Level
+ const uint8 *loadDoorShapes(const char *filename, int doorIndex, const uint8 *shapeDefs);
+ void drawDoorIntern(int type, int, int x, int y, int w, int wall, int mDim, int16, int16);
+
+ const uint8 *_dscDoorType5Offs;
+
+ // misc
+ void drawLightningColumn();
+ int resurrectionSelectDialogue();
+ int charSelectDialogue();
+ void characterLevelGain(int charIndex);
+};
+
+} // End of namespace Kyra
+
+#endif
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/eobcommon.cpp b/engines/kyra/eobcommon.cpp
new file mode 100644
index 0000000000..d82a3dd012
--- /dev/null
+++ b/engines/kyra/eobcommon.cpp
@@ -0,0 +1,1845 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "common/config-manager.h"
+
+#include "audio/mididrv.h"
+#include "audio/mixer.h"
+
+#include "kyra/loleobbase.h"
+#include "kyra/resource.h"
+#include "kyra/sound_intern.h"
+#include "kyra/script_eob.h"
+#include "kyra/timer.h"
+
+namespace Kyra {
+
+EobCoreEngine::EobCoreEngine(OSystem *system, const GameFlags &flags) : LolEobBaseEngine(system, flags), _numLargeItemShapes(flags.gameID == GI_EOB1 ? 14 : 11),
+ _numSmallItemShapes(flags.gameID == GI_EOB1 ? 23 : 26), _numThrownItemShapes(flags.gameID == GI_EOB1 ? 12 : 9), _numItemIconShapes(flags.gameID == GI_EOB1 ? 89 : 112),
+ _teleporterWallId(flags.gameID == GI_EOB1 ? 52 : 44) {
+ _screen = 0;
+ _gui = 0;
+
+ //_runLoopUnk2 = 0;
+ //_runLoopTimerUnk = 0;
+ _playFinale = false;
+ _runFlag = true;
+ _saveLoadMode = 0;
+ _updateHandItemCursor = false;
+
+ _largeItemShapes = _smallItemShapes = _thrownItemShapes = _spellShapes = _firebeamShapes = _itemIconShapes =
+ _wallOfForceShapes = _teleporterShapes = _sparkShapes = _compassShapes = 0;
+ _redSplatShape = _greenSplatShape = _deadCharShape = _disabledCharGrid = _blackBoxSmallGrid =
+ _weaponSlotGrid = _blackBoxWideGrid = _lightningColumnShape = 0;
+ _tempIconShape = 0;
+
+ _monsterDustStrings = 0;
+ _monsterDistAttType10 = 0;
+ _monsterDistAttSfx10 = 0;
+ _monsterDistAttType17 = 0;
+ _monsterDistAttSfx17 = 0;
+
+ _faceShapes = 0;
+ _characters = 0;
+ _items = 0;
+ _itemTypes = 0;
+ _itemNames = 0;
+ _itemInHand = -1;
+ _numItems = _numItemNames = 0;
+
+ _castScrollSlot = 0;
+ _currentSub = 0;
+
+ _itemsOverlay = 0;
+
+ _partyEffectFlags = 0;
+ _lastUsedItem = 0;
+
+ _levelDecorationRects = 0;
+ _doorSwitches = 0;
+ _monsterProps = 0;
+ _monsterDecorations = 0;
+ _monsterOvl1 = _monsterOvl2 = 0;
+ _monsters = 0;
+ _dstMonsterIndex = 0;
+ _inflictMonsterDamageUnk = 0;
+
+ _teleporterPulse = 0;
+
+ _dscShapeCoords = 0;
+ _dscItemPosIndex = 0;
+ _dscItemShpX = 0;
+ _dscItemScaleIndex = 0;
+ _dscItemTileIndex = 0;
+ _dscItemShapeMap = 0;
+ _dscDoorScaleOffs = 0;
+ _dscDoorScaleMult1 = 0;
+ _dscDoorScaleMult2 = 0;
+ _dscDoorScaleMult3 = 0;
+ _dscDoorY1 = 0;
+
+ _color9 = 17;
+ _color10 = 23;
+ _color11 = 20;
+
+ _exchangeCharacterId = -1;
+ _charExchangeSwap = 0;
+ _hpBarGraphs = true;
+
+ memset(_dialogueLastBitmap, 0, 13);
+ _dlgUnk1 = 0;
+ _moveCounter = 0;
+ _partyResting = false;
+
+ _flyingObjects = 0;
+
+ _inf = 0;
+ _stepCounter = 0;
+ _stepsUntilScriptCall = 0;
+ _scriptTimersMode = 3;
+ _currentDirection = 0;
+
+ _openBookSpellLevel = 0;
+ _openBookSpellSelectedItem = 0;
+ _openBookSpellListOffset = 0;
+ _openBookChar = _openBookCharBackup = 0;
+ _openBookType = _openBookTypeBackup = 0;
+ _openBookSpellList = 0;
+ _openBookAvailableSpells = 0;
+ _activeSpellCaster = 0;
+ _activeSpellCasterPos = 0;
+ _activeSpell = 0;
+ _returnAfterSpellCallback = false;
+ _spells = 0;
+ _spellAnimBuffer = 0;
+ _clericSpellOffset = 0;
+}
+
+EobCoreEngine::~EobCoreEngine() {
+ releaseItemsAndDecorationsShapes();
+ releaseTempData();
+
+ if (_faceShapes) {
+ for (int i = 0; i < 44; i++) {
+ if (_characters) {
+ for (int ii = 0; ii < 6; ii++) {
+ if (_characters[ii].faceShape == _faceShapes[i])
+ _characters[ii].faceShape = 0;
+ }
+ }
+ delete[] _faceShapes[i];
+ _faceShapes[i] = 0;
+ }
+ delete[] _faceShapes;
+ }
+
+ if (_characters) {
+ for (int i = 0; i < 6; i++)
+ delete[] _characters[i].faceShape;
+ }
+
+ delete[] _characters;
+ delete[] _items;
+ delete[] _itemTypes;
+ if (_itemNames) {
+ for (int i = 0; i < 130; i++)
+ delete _itemNames[i];
+ }
+ delete[] _itemNames;
+ delete[] _flyingObjects;
+
+ delete[] _monsterOvl1;
+ delete[] _monsterOvl2;
+ delete[] _monsters;
+
+ if (_monsterDecorations) {
+ releaseMonsterShapes(0, 36);
+ delete[] _monsterShapes;
+ delete[] _monsterDecorations;
+
+ for (int i = 0; i < 24; i++)
+ delete[] _monsterPalettes[i];
+ delete[] _monsterPalettes;
+ }
+
+ delete[] _monsterProps;
+
+ if (_doorSwitches) {
+ releaseDoorShapes();
+ delete[] _doorSwitches;
+ }
+
+ releaseDecorations();
+ delete[] _levelDecorationRects;
+
+ delete[] _spells;
+ delete[] _spellAnimBuffer;
+
+ delete _gui;
+ _gui = 0;
+ delete _inf;
+ delete _timer;
+ _timer = 0;
+}
+
+Common::Error EobCoreEngine::init() {
+ // In EOB the timer proc is directly invoked via interrupt 0x1c, 18.2 times per second.
+ // This makes a tick length of 54.94.
+ _tickLength = 55;
+
+ _screen = new Screen_Eob(this, _system);
+
+ assert(_screen);
+ _screen->setResolution();
+
+ // Setup mixer
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
+
+ //MidiDriverType midiDriver = MidiDriver::detectDevice(MDT_PCSPK | MDT_ADLIB);
+ _sound = new SoundAdLibPC(this, _mixer);
+ assert(_sound);
+
+ if (_sound)
+ _sound->updateVolumeSettings();
+
+ _res = new Resource(this);
+ assert(_res);
+ _res->reset();
+
+ if (!screen()->init())
+ error("screen()->init() failed");
+
+ if (ConfMan.hasKey("save_slot")) {
+ _gameToLoad = ConfMan.getInt("save_slot");
+ if (!saveFileLoadable(_gameToLoad))
+ _gameToLoad = -1;
+ }
+
+ setupKeyMap();
+ _gui = new GUI_Eob(this);
+ _txt = new TextDisplayer_Eob(this, _screen);
+ _inf = new EobInfProcessor(this, _screen);
+
+ _screen->loadFont(Screen::FID_6_FNT, "FONT6.FNT");
+ _screen->loadFont(Screen::FID_8_FNT, "FONT8.FNT");
+
+ _activeButtons = 0;
+
+ _staticres = new StaticResource(this);
+ assert(_staticres);
+ if (!_staticres->init())
+ error("_staticres->init() failed");
+
+ Common::Error err = LolEobBaseEngine::init();
+ if (err.getCode() != Common::kNoError)
+ return err;
+
+ initButtonData();
+ initStaticResource();
+ initSpells();
+
+ _timer = new TimerManager(this, _system);
+ assert(_timer);
+ setupTimers();
+
+ _wllVmpMap[1] = 1;
+ _wllVmpMap[2] = 2;
+ memset(&_wllVmpMap[3], 3, 20);
+ _wllVmpMap[23] = 4;
+ _wllVmpMap[24] = 5;
+
+ memcpy(_wllWallFlags, _wllFlagPreset, _wllFlagPresetSize);
+
+ memset(&_specialWallTypes[3], 1, 5);
+ memset(&_specialWallTypes[13], 1, 5);
+ _specialWallTypes[8] = _specialWallTypes[18] = 6;
+
+ memset(&_wllShapeMap[3], -1, 5);
+ memset(&_wllShapeMap[13], -1, 5);
+
+ _wllVcnOffset = 16;
+
+ _monsters = new EobMonsterInPlay[30];
+ memset(_monsters, 0, 30 * sizeof(EobMonsterInPlay));
+
+ _characters = new EobCharacter[6];
+ memset(_characters, 0, sizeof(EobCharacter) * 6);
+
+ _items = new EobItem[600];
+ memset(_items, 0, sizeof(EobItem) * 600);
+
+ _itemNames = new char*[130];
+ for (int i = 0; i < 130; i++) {
+ _itemNames[i] = new char[35];
+ memset(_itemNames[i], 0, 35);
+ }
+
+ _flyingObjects = new EobFlyingObject[10];
+ memset(_flyingObjects, 0, 10 * sizeof(EobFlyingObject));
+
+ _spellAnimBuffer = new uint8[4096];
+ memset(_spellAnimBuffer, 0, 4096);
+
+ memset(_doorType, 0, sizeof(_doorType));
+ memset(_noDoorSwitch, 0, sizeof(_noDoorSwitch));
+
+ _monsterShapes = new uint8*[36];
+ memset(_monsterShapes, 0, 36 * sizeof(uint8*));
+ _monsterDecorations = new SpriteDecoration[36];
+ memset(_monsterDecorations, 0, 36 * sizeof(SpriteDecoration));
+ _monsterPalettes = new uint8*[24];
+ for (int i = 0; i < 24; i++)
+ _monsterPalettes[i] = new uint8[16];
+
+ _doorSwitches = new SpriteDecoration[6];
+ memset(_doorSwitches, 0, 6 * sizeof(SpriteDecoration));
+
+ _monsterOvl1 = new uint8[16];
+ _monsterOvl2 = new uint8[16];
+ memset(_monsterOvl1, 15, 16 * sizeof(uint8));
+ memset(_monsterOvl2, 13, 16 * sizeof(uint8));
+ _monsterOvl1[0] = _monsterOvl2[0] = 0;
+
+ return Common::kNoError;
+}
+
+Common::Error EobCoreEngine::go() {
+ _txt->removePageBreakFlag();
+ _screen->loadPalette("palette.col", _screen->getPalette(0));
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->setFont(Screen::FID_8_FNT);
+
+ loadItemsAndDecorationsShapes();
+ _screen->setMouseCursor(0, 0, _itemIconShapes[0]);
+ _screen->showMouse();
+
+ //initPlayBuffers
+
+ loadItemDefs();
+
+ int action = 0;
+
+ if (_gameToLoad != -1) {
+ if (loadGameState(_gameToLoad).getCode() != Common::kNoError)
+ error("Couldn't load game slot %d on startup", _gameToLoad);
+ _gameToLoad = -1;
+ } else {
+ action = mainMenu();
+ }
+
+ if (action == -1) {
+ // load game
+ _saveLoadMode = -1;
+ startupLoad();
+ } else if (action == -2) {
+ // new game
+ startCharacterGeneration();
+ startupNew();
+ } else if (action == -3) {
+ // transfer party
+ }
+
+ if (!shouldQuit() && action > -3) {
+ runLoop();
+
+ if (_playFinale)
+ seq_playFinale();
+ }
+
+ return Common::kNoError;
+}
+
+void EobCoreEngine::runLoop() {
+ _envAudioTimer = _system->getMillis() + (rollDice(1, 10, 3) * 18 * _tickLength);
+ ///
+ // startupSub1
+ //
+ //
+ _updateFlags = 0;
+ //_unkCharacterId = 0;
+ _flashShapeTimer = 0;
+ _drawSceneTimer = _system->getMillis();
+ //_unkBBBBBBBBBBBBBBBB = 1;
+ gui_setPlayFieldButtons();
+ //
+
+ _screen->_curPage = 0;
+ gui_drawPlayField(0);
+
+ _screen->setFont(Screen::FID_6_FNT);
+
+ _screen->_curPage = 0;
+ gui_drawAllCharPortraitsWithStats();
+
+ drawScene(1);
+
+ _screen->setScreenDim(7);
+
+ //_runLoopUnk2 = _currentBlock;
+ _runFlag = true;
+
+ while (!shouldQuit() && _runFlag) {
+ //_runLoopUnk2 = _currentBlock;
+ updateCharacterEvents(true);
+ checkInput(_activeButtons, true);
+ removeInputTop();
+
+ if (_updateHandItemCursor) {
+ _updateHandItemCursor = false;
+ setHandItem(_itemInHand);
+ }
+
+ _timer->update();
+ updateScriptTimers();
+
+ if (_sceneUpdateRequired)
+ drawScene(1);
+
+ if (_envAudioTimer >= _system->getMillis())
+ continue;
+
+ _envAudioTimer = _system->getMillis() + (rollDice(1, 10, 3) * 18 * _tickLength);
+ snd_processEnvironmentalSoundEffect(rollDice(1, 2, -1) ? 27 : 28, _currentBlock + rollDice(1, 12, -1));
+ updateEnvironmentalSfx(0);
+ }
+}
+
+bool EobCoreEngine::updateCharacterEvents(bool a) {
+ int numChars = 0;
+ for (int i = 0; i < 6; i++)
+ numChars += testCharacter(i, 13);
+
+ if (numChars)
+ return false;
+
+ if (!a)
+ return true;
+
+
+ gui_drawAllCharPortraitsWithStats();
+
+ /// TODO
+ /// if (checkScriptFlag(0x10))
+ /// j_dranThoseFools()
+
+ /// TODO
+
+ /// TODO
+
+
+ return false;
+}
+
+void EobCoreEngine::loadItemsAndDecorationsShapes() {
+ releaseItemsAndDecorationsShapes();
+ _screen->setCurPage(2);
+
+ _screen->loadBitmap("ITEML1.CPS", 5, 3, 0);
+ _largeItemShapes = new const uint8*[_numLargeItemShapes];
+ int div = (_flags.gameID == GI_EOB1) ? 3 : 8;
+ int mul = (_flags.gameID == GI_EOB1) ? 64 : 24;
+
+ for (int i = 0; i < _numLargeItemShapes; i++)
+ _largeItemShapes[i] = _screen->encodeShape((i / div) << 3, (i % div) * mul, 8, 24);
+
+ _screen->loadBitmap("ITEMS1.CPS", 5, 3, 0);
+ _smallItemShapes = new const uint8*[_numSmallItemShapes];
+ for (int i = 0; i < _numSmallItemShapes; i++)
+ _smallItemShapes[i] = _screen->encodeShape((i / div) << 2, (i % div) * mul, 4, 24);
+
+ _screen->loadBitmap("THROWN.CPS", 5, 3, 0);
+ _thrownItemShapes = new const uint8*[_numThrownItemShapes];
+ for (int i = 0; i < _numThrownItemShapes; i++)
+ _thrownItemShapes[i] = _screen->encodeShape((i / div) << 2, (i % div) * mul, 4, 24);
+
+ _spellShapes = new const uint8*[4];
+ for (int i = 0; i < 4; i++)
+ _spellShapes[i] = _screen->encodeShape(8, i << 5, 6, 32);
+
+ _firebeamShapes = new const uint8*[3];
+ _firebeamShapes[0] = _screen->encodeShape(16, 0, 4, 24);
+ _firebeamShapes[1] = _screen->encodeShape(16, 24, 4, 24);
+ _firebeamShapes[2] = _screen->encodeShape(16, 48, 3, 24);
+ _redSplatShape = _screen->encodeShape(16, _flags.gameID == GI_EOB1 ? 144 : 72, 5, 24);
+ _greenSplatShape = _screen->encodeShape(16, _flags.gameID == GI_EOB1 ? 168 : 96, 5, 16);
+
+ _screen->loadBitmap("ITEMICN.CPS", 5, 3, 0);
+ _itemIconShapes = new const uint8*[_numItemIconShapes];
+ for (int i = 0; i < _numItemIconShapes; i++)
+ _itemIconShapes[i] = _screen->encodeShape((i % 0x14) << 1, (i / 0x14) << 4, 2, 0x10);
+ _tempIconShape = new uint8[300];
+
+ _screen->loadBitmap("DECORATE.CPS", 5, 3, 0);
+
+ if (_flags.gameID == GI_EOB2) {
+ _lightningColumnShape = _screen->encodeShape(18, 88, 4, 64);
+ _wallOfForceShapes = new const uint8*[6];
+ for (int i = 0; i < 6; i++)
+ _wallOfForceShapes[i] = _screen->encodeShape(_wallOfForceShapeDefs[(i << 2)], _wallOfForceShapeDefs[(i << 2) + 1], _wallOfForceShapeDefs[(i << 2) + 2], _wallOfForceShapeDefs[(i << 2) + 3]);
+ }
+
+ _teleporterShapes = new const uint8*[6];
+ for (int i = 0; i < 6; i++)
+ _teleporterShapes[i] = _screen->encodeShape(_teleporterShapeDefs[(i << 2)], _teleporterShapeDefs[(i << 2) + 1], _teleporterShapeDefs[(i << 2) + 2], _teleporterShapeDefs[(i << 2) + 3]);
+ _sparkShapes = new const uint8*[3];
+ _sparkShapes[0] = _screen->encodeShape(29, 0, 2, 16);
+ _sparkShapes[1] = _screen->encodeShape(31, 0, 2, 16);
+ _sparkShapes[2] = _screen->encodeShape(33, 0, 2, 16);
+ _deadCharShape = _screen->encodeShape(0, 88, 4, 32);
+ _disabledCharGrid = _screen->encodeShape(4, 88, 4, 32);
+ _blackBoxSmallGrid = _screen->encodeShape(9, 88, 2, 8);
+ _weaponSlotGrid = _screen->encodeShape(8, 88, 4, 16);
+ _blackBoxWideGrid = _screen->encodeShape(8, 104, 4, 8);
+
+ static const uint8 dHeight[] = { 17, 10, 10 };
+ static const uint8 dY[] = { 120, 137, 147 };
+
+ _compassShapes = new const uint8*[12];
+ for (int y = 0; y < 3; y++) {
+ for (int x = 0; x < 4; x++)
+ _compassShapes[(y << 2) + x] = _screen->encodeShape(x * 3, dY[y], 3, dHeight[y]);
+ }
+}
+
+void EobCoreEngine::releaseItemsAndDecorationsShapes() {
+ if (_largeItemShapes) {
+ for (int i = 0; i < _numLargeItemShapes; i++) {
+ if (_largeItemShapes[i])
+ delete[] _largeItemShapes[i];
+ }
+ delete[] _largeItemShapes;
+ }
+
+ if (_smallItemShapes) {
+ for (int i = 0; i < _numSmallItemShapes; i++) {
+ if (_smallItemShapes[i])
+ delete[] _smallItemShapes[i];
+ }
+ delete[] _smallItemShapes;
+ }
+
+ if (_thrownItemShapes) {
+ for (int i = 0; i < _numThrownItemShapes; i++) {
+ if (_thrownItemShapes[i])
+ delete[] _thrownItemShapes[i];
+ }
+ delete[] _thrownItemShapes;
+ }
+
+ if (_spellShapes) {
+ for (int i = 0; i < 4; i++) {
+ if (_spellShapes[i])
+ delete [] _spellShapes[i];
+ }
+ delete[] _spellShapes;
+ }
+
+ if (_itemIconShapes) {
+ for (int i = 0; i < _numItemIconShapes; i++) {
+ if (_itemIconShapes[i])
+ delete[] _itemIconShapes[i];
+ }
+ delete[] _itemIconShapes;
+ }
+ delete[] _tempIconShape;
+
+ if (_sparkShapes) {
+ for (int i = 0; i < 3; i++) {
+ if (_sparkShapes[i])
+ delete[] _sparkShapes[i];
+ }
+ delete[] _sparkShapes;
+ }
+
+ if (_wallOfForceShapes) {
+ for (int i = 0; i < 6; i++) {
+ if (_wallOfForceShapes[i])
+ delete[] _wallOfForceShapes[i];
+ }
+ delete[] _wallOfForceShapes;
+ }
+
+ if (_teleporterShapes) {
+ for (int i = 0; i < 6; i++) {
+ if (_teleporterShapes[i])
+ delete[] _teleporterShapes[i];
+ }
+ delete[] _teleporterShapes;
+ }
+
+ if (_compassShapes) {
+ for (int i = 0; i < 12; i++) {
+ if (_compassShapes[i])
+ delete[] _compassShapes[i];
+ }
+ delete[] _compassShapes;
+ }
+
+ if (_firebeamShapes) {
+ for (int i = 0; i < 3; i++) {
+ if (_firebeamShapes[i])
+ delete[] _firebeamShapes[i];
+ }
+ delete []_firebeamShapes;
+ }
+
+ delete[] _deadCharShape;
+ delete[] _disabledCharGrid;
+ delete[] _blackBoxSmallGrid;
+ delete[] _weaponSlotGrid;
+ delete[] _blackBoxWideGrid;
+ delete[] _lightningColumnShape;
+}
+
+void EobCoreEngine::setHandItem(Item itemIndex) {
+ if (itemIndex == -1)
+ return;
+
+ if (_screen->curDimIndex() == 7 && itemIndex) {
+ printFullItemName(itemIndex);
+ _txt->printMessage(_takenStrings[0]);
+ }
+
+ _itemInHand = itemIndex;
+ int icon = _items[_itemInHand].icon;
+ const uint8 *shp = _itemIconShapes[icon];
+
+ if (icon && (_items[_itemInHand].flags & 0x80) && ((_flags.gameID == GI_EOB2 && (_partyEffectFlags & 2)) || (_flags.gameID == GI_EOB1 && (_partyEffectFlags & 0x10000)))) {
+ memcpy(_tempIconShape, shp, 300);
+ if (_flags.gameID == GI_EOB1)
+ _screen->replaceShapePalette(_tempIconShape, &_itemsOverlay[icon << 4]);
+ else
+ _screen->applyShapeOverlay(_tempIconShape, 3);
+ shp = _tempIconShape;
+ }
+
+ int mouseOffs = itemIndex ? 8 : 0;
+ _screen->setMouseCursor(mouseOffs, mouseOffs, shp);
+}
+
+int EobCoreEngine::getDexterityArmorClassModifier(int dexterity) {
+ static const int mod[] = { 5, 5, 5, 4, 3, 2, 1, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, -2, -3, -4, -4, -5, -5, -5, -6, -6 };
+ return mod[dexterity];
+}
+
+int EobCoreEngine::generateCharacterHitpointsByLevel(int charIndex, int levelIndex) {
+ EobCharacter *c = &_characters[charIndex];
+ int m = getClassAndConstHitpointsModifier(c->cClass, c->constitutionCur);
+
+ int h = 0;
+
+ for (int i = 0; i < 3; i++) {
+ if (!(levelIndex & (1 << i)))
+ continue;
+
+ int d = getClassHpIncreaseType(c->cClass, i);
+
+ if (c->level[i] <= _hpIncrPerLevel[6 + i])
+ h += rollDice(1, (d >= 0) ? _hpIncrPerLevel[d] : 0);
+ else
+ h += _hpIncrPerLevel[12 + i];
+
+ h += m;
+ }
+
+ h /= _numLevelsPerClass[c->cClass];
+
+ if (h < 1)
+ h = 1;
+
+ return h;
+}
+
+int EobCoreEngine::getClassAndConstHitpointsModifier(int cclass, int constitution) {
+ int res = _hpConstModifiers[constitution];
+
+ if (res <= 2 || (_classModifierFlags[cclass] & 0x31))
+ return res;
+
+ return 2;
+}
+
+int EobCoreEngine::getClassHpIncreaseType(int cclass, int levelIndex) {
+ return _classHpIncreaseType[cclass * 3 + levelIndex];
+}
+
+int EobCoreEngine::getModifiedHpLimits(int hpModifier, int constModifier, int level, bool mode) {
+ int s = _hpIncrPerLevel[6 + hpModifier] > level ? level : _hpIncrPerLevel[6 + hpModifier];
+ int res = s;
+
+ if (!mode)
+ res *= (hpModifier >= 0 ? _hpIncrPerLevel[hpModifier] : 0);
+
+ if (level > s) {
+ s = level - s;
+ res += (s * _hpIncrPerLevel[12 + hpModifier]);
+ }
+
+ if (!mode || (constModifier > 0))
+ res += (level * constModifier);
+
+ return res;
+}
+
+const char *EobCoreEngine::getCharStrength(int str, int strExt) {
+ if (strExt) {
+ if (strExt == 100)
+ strExt = 0;
+ snprintf(_strenghtStr, 6, "%d/%02d", str, strExt);
+ } else {
+ snprintf(_strenghtStr, 6, "%d", str);
+ }
+
+ return _strenghtStr;
+}
+
+int EobCoreEngine::testCharacter(int index, int flags) {
+ if (index == -1)
+ return 0;
+
+ EobCharacter *c = &_characters[index];
+ int res = 1;
+
+ if (flags & 1)
+ res &= (c->flags & 1);
+
+ if (flags & 2)
+ res &= ((c->hitPointsCur <= -10) || (c->flags & 8)) ? 0 : 1;
+
+ if (flags & 4)
+ res &= ((c->hitPointsCur <= 0) || (c->flags & 8)) ? 0 : 1;
+
+ if (flags & 8)
+ res &= (c->flags & 12) ? 0 : 1;
+
+ if (flags & 0x20)
+ res &= (c->flags & 4) ? 0 : 1;
+
+ if (flags & 0x10)
+ res &= (c->flags & 2) ? 0 : 1;
+
+ if (flags & 0x40)
+ res &= (c->food <= 0) ? 0 : 1;
+
+ return res;
+}
+
+int EobCoreEngine::getNextValidCharIndex(int curCharIndex, int searchStep) {
+ do {
+ curCharIndex += searchStep;
+ if (curCharIndex < 0)
+ curCharIndex = 5;
+ if (curCharIndex > 5)
+ curCharIndex = 0;
+ } while (!testCharacter(curCharIndex, 1));
+
+ return curCharIndex;
+}
+
+void EobCoreEngine::recalcArmorClass(int index) {
+ EobCharacter *c = &_characters[index];
+ int acm = getDexterityArmorClassModifier(c->dexterityCur);
+ c->armorClass = 10 + acm;
+
+ static uint8 slot[] = { 17, 0, 1, 18 };
+ for (int i = 0; i < 4; i++) {
+ int itm = c->inventory[slot[i]];
+ if (!itm)
+ continue;
+
+ if (i == 2) {
+ if (!validateWeaponSlotItem(index, 1))
+ continue;
+ }
+
+ int tp = _items[itm].type;
+
+ if (!(_itemTypes[tp].allowedClasses & _classModifierFlags[c->cClass]) || (_itemTypes[tp].extraProperties & 0x7f) || (i >= 1 && i <= 2 && tp != 27 && !(_flags.gameID == GI_EOB2 && tp == 57)))
+ continue;
+
+ c->armorClass += _itemTypes[tp].armorClass;
+ c->armorClass -= _items[itm].value;
+ }
+
+ if (!_items[c->inventory[17]].value) {
+ int8 m1 = 0;
+ int8 m2 = 0;
+
+ if (c->inventory[25]) {
+ if (!(_itemTypes[_items[c->inventory[25]].type].extraProperties & 0x7f))
+ m1 = _items[c->inventory[25]].value;
+ }
+
+ if (c->inventory[26]) {
+ if (!(_itemTypes[_items[c->inventory[26]].type].extraProperties & 0x7f))
+ m2 = _items[c->inventory[26]].value;
+ }
+
+ c->armorClass -= MAX(m1, m2);
+ }
+
+ if (c->effectsRemainder[0] > 0) {
+ if (c->armorClass <= (acm + 6))
+ c->effectsRemainder[0] = 0;
+ else
+ c->armorClass = (acm + 6);
+ }
+
+ // shield
+ if ((c->effectFlags & 8) && (c->armorClass > 4))
+ c->armorClass = 4;
+
+ // magical vestment
+ if (c->effectFlags & 0x4000) {
+ int8 m1 = 5;
+
+ if (getCharacterClericPaladinLevel(index) > 5)
+ m1 += ((getCharacterClericPaladinLevel(index) - 5) / 3);
+
+ if (c->armorClass > m1)
+ c->armorClass = m1;
+ }
+
+ if (c->armorClass < -10)
+ c->armorClass = -10;
+}
+
+int EobCoreEngine::validateWeaponSlotItem(int index, int slot) {
+ EobCharacter *c = &_characters[index];
+ int itm1 = c->inventory[0];
+ int r = itemUsableByCharacter(index, itm1);
+ int tp1 = _items[itm1].type;
+
+ if (!slot)
+ return (!itm1 || r) ? 1 : 0;
+
+ int itm2 = c->inventory[1];
+ r = itemUsableByCharacter(index, itm2);
+ int tp2 = _items[itm2].type;
+
+ if (itm1 && _itemTypes[tp1].requiredHands == 2)
+ return 0;
+
+ if (!itm2)
+ return 1;
+
+ int f = (_itemTypes[tp2].extraProperties & 0x7f);
+ if (f <= 0 || f > 3)
+ return r;
+
+ if (_itemTypes[tp2].requiredHands)
+ return 0;
+
+ return r;
+}
+
+int EobCoreEngine::getCharacterClericPaladinLevel(int index) {
+ if (_castScrollSlot)
+ return 9;
+
+ if (index == -1)
+ return (_currentLevel < 7) ? 5 : 9;
+
+ int l = getLevelIndexForHpIncType(2, _characters[index].cClass);
+ if (l > -1)
+ return _characters[index].level[l];
+
+ l = getLevelIndexForHpIncType(4, _characters[index].cClass);
+ if (l > -1) {
+ if (_characters[index].level[l] > 8)
+ return _characters[index].level[l] - 8;
+ }
+
+ return 1;
+}
+
+int EobCoreEngine::getCharacterMageLevel(int index) {
+ if (_castScrollSlot)
+ return 9;
+
+ if (index == -1)
+ return (_currentLevel < 7) ? 5 : 9;
+
+ int l = getLevelIndexForHpIncType(1, _characters[index].cClass);
+ return (l > -1) ? _characters[index].level[l] : 1;
+}
+
+int EobCoreEngine::getLevelIndexForHpIncType(int hpIncType, int cClass) {
+ if (getClassHpIncreaseType(cClass, 0) == hpIncType)
+ return 0;
+
+ if (getClassHpIncreaseType(cClass, 1) == hpIncType)
+ return 1;
+
+ if (getClassHpIncreaseType(cClass, 2) == hpIncType)
+ return 2;
+
+ return -1;
+}
+
+int EobCoreEngine::countCharactersWithSpecificItems(int16 itemType, int16 itemValue) {
+ int res = 0;
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ if (checkCharacterInventoryForItem(i, itemType, itemValue) != -1)
+ res++;
+ }
+ return res;
+}
+
+int EobCoreEngine::checkCharacterInventoryForItem(int character, int16 itemType, int16 itemValue) {
+ for (int i = 0; i < 27; i++) {
+ uint16 inv = _characters[character].inventory[i];
+ if (!inv)
+ continue;
+ if (_items[inv].type != itemType && itemType != -1)
+ continue;
+ if (_items[inv].value == itemValue || itemValue == -1)
+ return i;
+ }
+ return -1;
+}
+
+void EobCoreEngine::modifyCharacterHitpoints(int character, int16 points) {
+ if (!testCharacter(character, 3))
+ return;
+
+ EobCharacter *c = &_characters[character];
+ c->hitPointsCur += points;
+ if (c->hitPointsCur > c->hitPointsMax)
+ c->hitPointsCur = c->hitPointsMax;
+
+ gui_drawHitpoints(character);
+ gui_drawCharPortraitWithStats(character);
+}
+
+void EobCoreEngine::neutralizePoison(int character) {
+ _characters[character].flags &= ~2;
+ _characters[character].effectFlags &= ~0x2000;
+ deleteCharEventTimer(character, -34);
+ gui_drawCharPortraitWithStats(character);
+}
+
+void EobCoreEngine::initNpc(int npcIndex) {
+ EobCharacter *c = _characters;
+ int i = 0;
+ for (; i < 6; i++) {
+ if (!(_characters[i].flags & 1)) {
+ c = &_characters[i];
+ break;
+ }
+ }
+
+ delete[] c->faceShape;
+ memcpy(c, &_npcPreset[npcIndex], sizeof(EobCharacter));
+ recalcArmorClass(i);
+
+ for (i = 0; i < 25; i++) {
+ if (!c->inventory[i])
+ continue;
+ c->inventory[i] = duplicateItem(c->inventory[i]);
+ }
+
+ _screen->loadEobBitmap(_flags.gameID == GI_EOB2 ? "OUTPORTS" : "OUTTAKE", 3, 3);
+ _screen->_curPage = 2;
+ c->faceShape = _screen->encodeShape(npcIndex << 2, _flags.gameID == GI_EOB2 ? 0 : 160, 4, 32, true);
+ _screen->_curPage = 0;
+}
+
+int EobCoreEngine::npcJoinDialogue(int npcIndex, int queryJoinTextId, int confirmJoinTextId, int noJoinTextId) {
+ gui_drawDialogueBox();
+ _txt->printDialogueText(queryJoinTextId, 0);
+
+ int r = runDialogue(-1, 0, _yesNoStrings[0], _yesNoStrings[1]) - 1;
+ if (r == 0) {
+ if (confirmJoinTextId == -1) {
+ char tmp[35];
+ snprintf(tmp, 35, _npcJoinStrings[0], _npcPreset[npcIndex].name);
+ _txt->printDialogueText(tmp, true);
+ } else {
+ _txt->printDialogueText(confirmJoinTextId, _okStrings[0]);
+ }
+
+ if (prepareForNewPartyMember(33, npcIndex + 1))
+ initNpc(npcIndex);
+
+ } else if (r == 1) {
+ _txt->printDialogueText(noJoinTextId, _okStrings[0]);
+ }
+
+ return r ^ 1;
+}
+
+int EobCoreEngine::prepareForNewPartyMember(int16 itemType, int16 itemValue) {
+ int numChars = 0;
+ for (int i = 0; i < 6; i++)
+ numChars += (_characters[i].flags & 1);
+
+ if (numChars < 6) {
+ deletePartyItem(itemType, itemValue);
+ } else {
+ gui_drawDialogueBox();
+ _txt->printDialogueText(_npcMaxStrings[0]);
+ int r = runDialogue(-1, 1, _characters[0].name, _characters[1].name, _characters[2].name, _characters[3].name,
+ _characters[4].name, _characters[5].name, _abortStrings[0], 0, 0) - 1;
+
+ if (r == 6)
+ return 0;
+
+ deletePartyItem(itemType, itemValue);
+ removeCharacterFromParty(r);
+ }
+
+ return 1;
+}
+
+void EobCoreEngine::removeCharacterFromParty(int charIndex) {
+ EobCharacter *c = &_characters[charIndex];
+ c->flags = 0;
+
+ for (int i = 0; i < 27; i++) {
+ if (i == 16 || !c->inventory[i])
+ continue;
+
+ setItemPosition((Item*)&_levelBlockProperties[_currentBlock & 0x3ff].drawObjects, _currentBlock, c->inventory[i], _dropItemDirIndex[(_currentDirection << 2) + rollDice(1, 2, -1)]);
+ c->inventory[i] = 0;
+ }
+
+ while (c->inventory[16])
+ setItemPosition((Item*)&_levelBlockProperties[_currentBlock & 0x3ff].drawObjects, _currentBlock, getQueuedItem(&c->inventory[16], 0, -1), _dropItemDirIndex[(_currentDirection << 2) + rollDice(1, 2, -1)]);
+
+ c->inventory[16] = 0;
+
+ if (_updateCharNum == charIndex)
+ _updateCharNum = 0;
+
+ setupCharacterTimers();
+}
+
+void EobCoreEngine::increasePartyExperience(int16 points) {
+ int cnt = 0;
+ for (int i = 0; i < 6; i++) {
+ if (testCharacter(i, 3))
+ cnt++;
+ }
+
+ if (cnt <= 0)
+ return;
+
+ points /= cnt;
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 3))
+ continue;
+ increaseCharacterExperience(i, points);
+ }
+}
+
+void EobCoreEngine::increaseCharacterExperience(int charIndex, int32 points) {
+ int cl = _characters[charIndex].cClass;
+ points /= _numLevelsPerClass[cl];
+
+ for (int i = 0; i < 3; i++) {
+ if (getClassHpIncreaseType(cl, i) == -1)
+ continue;
+ _characters[charIndex].experience[i] += points;
+
+ uint32 er = getRequiredExperience(cl, i, _characters[charIndex].level[i] + 1);
+ if (er == 0xffffffff)
+ continue;
+
+ if (_characters[charIndex].experience[i] >= er)
+ increaseCharacterLevel(charIndex, i);
+ }
+}
+
+uint32 EobCoreEngine::getRequiredExperience(int cClass, int levelIndex, int level) {
+ cClass = getClassHpIncreaseType(cClass, levelIndex);
+ if (cClass == -1)
+ return 0xffffffff;
+
+ const uint32 *tbl = _expRequirementTables[cClass];
+ return tbl[level - 1];
+}
+
+void EobCoreEngine::increaseCharacterLevel(int charIndex, int levelIndex) {
+ _characters[charIndex].level[levelIndex]++;
+ int hpInc = generateCharacterHitpointsByLevel(charIndex, levelIndex);
+ _characters[charIndex].hitPointsCur += hpInc;
+ _characters[charIndex].hitPointsMax += hpInc;
+
+ gui_drawCharPortraitWithStats(charIndex);
+ _txt->printMessage(_levelGainStrings[0], -1, _characters[charIndex].name);
+ snd_playSoundEffect(23);
+}
+
+void EobCoreEngine::setWeaponSlotStatus(int charIndex, int mode, int slot) {
+ if (mode == 0 || mode == 2)
+ _characters[charIndex].disabledSlots ^= (1 << slot);
+ else if (mode != 1)
+ return;
+
+ _characters[charIndex].slotStatus[slot] = 0;
+ gui_drawCharPortraitWithStats(charIndex);
+}
+
+void EobCoreEngine::setupDialogueButtons(int presetfirst, int numStr, const char *str1, ...) {
+ _dialogueNumButtons = numStr;
+ _dialogueButtonString[0] = str1;
+ _dialogueHighlightedButton = 0;
+
+ va_list args;
+ va_start(args, str1);
+ const char **s5p = va_arg(args, const char**);
+ va_end(args);
+ for (int i = 1; i < numStr; i++) {
+ if (s5p[i - 1])
+ _dialogueButtonString[i] = s5p[i - 1];
+ else
+ _dialogueNumButtons = numStr = i;
+ }
+
+ static const uint16 prsX[] = { 59, 166, 4, 112, 220, 4, 112, 220, 4, 112, 220, 4, 112, 220 };
+ static const uint8 prsY[] = { 0, 0, 0, 0, 0, 12, 12, 12, 24, 24, 24, 36, 36, 36 };
+
+ const ScreenDim *dm = screen()->_curDim;
+ int yOffs = (_txt->lineCount() + 1) * _screen->getFontHeight() + dm->sy + 4;
+
+ _dialogueButtonPosX = &prsX[presetfirst];
+ _dialogueButtonPosY = &prsY[presetfirst];
+ _dialogueButtonYoffs = yOffs;
+
+ drawDialogueButtons();
+
+ if (!shouldQuit())
+ removeInputTop();
+}
+
+void EobCoreEngine::initDialogueSequence() {
+ _dlgUnk1 = -1;
+ _txt->setWaitButtonMode(0);
+ _dialogueField = true;
+
+ _dialogueLastBitmap[0] = 0;
+
+ _txt->resetPageBreakString();
+ gui_updateControls();
+
+ _sound->playTrack(0);
+ Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT");
+ _screen->loadFileDataToPage(s, 5, 32000);
+ _txt->setupField(9, 0);
+ delete s;
+}
+
+void EobCoreEngine::restoreAfterDialogueSequence() {
+ _txt->allowPageBreak(false);
+ _dialogueField = false;
+
+ _dialogueLastBitmap[0] = 0;
+
+ gui_restorePlayField();
+ _screen->setScreenDim(7);
+
+ if (_flags.gameID == GI_EOB2)
+ _sound->playTrack(2);
+
+ _sceneUpdateRequired = true;
+}
+
+void EobCoreEngine::drawSequenceBitmap(const char *file, int destRect, int x1, int y1, int flags) {
+ static const uint8 frameX[] = { 1, 0 };
+ static const uint8 frameY[] = { 8, 0 };
+ static const uint8 frameW[] = { 20, 40 };
+ static const uint8 frameH[] = { 96, 121 };
+
+ int page = ((flags & 2) || destRect) ? 0 : 6;
+
+ if (scumm_stricmp(_dialogueLastBitmap, file)) {
+ if (!destRect) {
+ if (!(flags & 1)) {
+ _screen->loadEobCpsFileToPage("BORDER", 0, 3, 3, 2);
+ _screen->copyRegion(0, 0, 0, 0, 184, 121, 2, page, Screen::CR_NO_P_CHECK);
+ } else {
+ _screen->copyRegion(0, 0, 0, 0, 184, 121, 0, page, Screen::CR_NO_P_CHECK);
+ }
+
+ if (!page)
+ _screen->copyRegion(0, 0, 0, 0, 184, 121, 2, 6, Screen::CR_NO_P_CHECK);
+ }
+
+ _screen->loadEobCpsFileToPage(file, 0, 3, 3, 2);
+ strcpy(_dialogueLastBitmap, file);
+ }
+
+ if (flags & 2)
+ _screen->crossFadeRegion(x1 << 3, y1, frameX[destRect] << 3, frameY[destRect], frameW[destRect] << 3, frameH[destRect], 2, page);
+ else
+ _screen->copyRegion(x1 << 3, y1, frameX[destRect] << 3, frameY[destRect], frameW[destRect] << 3, frameH[destRect], 2, page, Screen::CR_NO_P_CHECK);
+
+ if (page == 6)
+ _screen->copyRegion(0, 0, 0, 0, 184, 121, 6, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->updateScreen();
+}
+
+int EobCoreEngine::runDialogue(int dialogueTextId, int style, const char *button1, ...) {
+ if (dialogueTextId != -1)
+ txt()->printDialogueText(dialogueTextId, 0);
+
+ va_list args;
+ va_start(args, button1);
+ if (style)
+ setupDialogueButtons(2, 9, button1, args);
+ else
+ setupDialogueButtons(0, 2, button1, args);
+ va_end(args);
+
+ int res = 0;
+ while (res == 0 && !shouldQuit())
+ res = processDialogue();
+
+ gui_drawDialogueBox();
+
+ return res;
+}
+
+void EobCoreEngine::delay(uint32 millis, bool, bool) {
+ while (millis && !shouldQuit() && !skipFlag()) {
+ updateInput();
+ uint32 step = MIN<uint32>(millis, (_tickLength / 5));
+ _system->delayMillis(step);
+ millis -= step;
+ }
+}
+
+void EobCoreEngine::displayParchment(int id) {
+ _txt->setWaitButtonMode(1);
+ _txt->resetPageBreakString();
+ gui_updateControls();
+
+ if (id >= 0) {
+ // display text
+ Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT");
+ _screen->loadFileDataToPage(s, 5, 32000);
+ gui_drawBox(0, 0, 176, 175, _color1_1, _color2_1, _bkgColor_1);
+ _txt->setupField(12, 1);
+ if (_flags.gameID == GI_EOB2)
+ id++;
+ _txt->printDialogueText(id, _okStrings[0]);
+
+ } else {
+ // display bitmap
+ id = -id - 1;
+ static const uint8 x[] = { 0, 20, 0 };
+ static const uint8 y[] = { 0, 0, 96 };
+ drawSequenceBitmap("MAP", 0, x[id], y[id], 0);
+
+ removeInputTop();
+ while (!shouldQuit()) {
+ delay(_tickLength);
+ if (checkInput(0) & 0xff)
+ break;
+ removeInputTop();
+ }
+ removeInputTop();
+ }
+
+ restoreAfterDialogueSequence();
+}
+
+void EobCoreEngine::useSlotWeapon(int charIndex, int slotIndex, int item) {
+ EobCharacter *c = &_characters[charIndex];
+ int tp = item ? _items[item].type : 0;
+
+ if (c->effectFlags & 0x40)
+ removeCharacterEffect(10, charIndex, 1); // remove invisibility effect
+
+ int ep = _itemTypes[tp].extraProperties & 0x7f;
+ int8 inflict = 0;
+
+ if (ep == 1) {
+ inflict = closeDistanceAttack(charIndex, item);
+ if (!inflict)
+ inflict = -1;
+ snd_playSoundEffect(32);
+ } else if (ep == 2) {
+ inflict = thrownAttack(charIndex, slotIndex, item);
+ } else if (ep == 3) {
+ inflict = bowAttack(charIndex, item);
+ gui_drawCharPortraitWithStats(charIndex);
+ }
+
+ if (inflict > 0) {
+ if (_items[item].flags & 8) {
+ c->hitPointsCur += inflict;
+ gui_drawCharPortraitWithStats(charIndex);
+ }
+
+ if (_items[item].flags & 0x10)
+ c->inventory[slotIndex] = 0;
+
+ inflictMonsterDamage(&_monsters[_dstMonsterIndex], inflict, true);
+ }
+
+ c->disabledSlots ^= (1 << slotIndex);
+ c->slotStatus[slotIndex] = inflict;
+
+ gui_drawCharPortraitWithStats(charIndex);
+ setCharEventTimer(charIndex, 18, inflict >= -2 ? slotIndex + 2 : slotIndex, 1);
+}
+
+int EobCoreEngine::closeDistanceAttack(int charIndex, int item) {
+ if (charIndex > 1)
+ return -3;
+
+ uint16 d = calcNewBlockPosition(_currentBlock, _currentDirection);
+ int r = getClosestMonsterPos(charIndex, d);
+
+ if (r == -1) {
+ uint8 w = _specialWallTypes[_levelBlockProperties[d].walls[_sceneDrawVarDown]];
+ if (w == 0xff) {
+ if (_flags.gameID == GI_EOB1) {
+ _levelBlockProperties[d].walls[_sceneDrawVarDown]++;
+ _levelBlockProperties[d].walls[_sceneDrawVarDown ^ 2]++;
+
+ } else {
+ for (int i = 0; i < 4; i++) {
+ if (_specialWallTypes[_levelBlockProperties[d].walls[i]] == 0xff)
+ _levelBlockProperties[d].walls[i]++;
+ }
+ }
+ _sceneUpdateRequired = true;
+
+ } else if ((_flags.gameID == GI_EOB1) || (_flags.gameID == GI_EOB2 && w != 8 && w != 9)) {
+ return -1;
+ }
+
+ return (_flags.gameID == GI_EOB2 && ((_itemTypes[_items[item].type].allowedClasses & 4) || !item)) ? -5 : -2;
+
+ } else {
+ if (_monsters[r].flags & 0x20) {
+ killMonster(&_monsters[r], 1);
+ _txt->printMessage(_monsterDustStrings[0]);
+ return -2;
+ }
+
+ if (!characterAttackHitTest(charIndex, r, item, 1))
+ return -1;
+
+ uint16 flg = 0x100;
+
+ if ((_flags.gameID == GI_EOB1 && _items[item].type > 51 && _items[item].type < 57) || (_flags.gameID == GI_EOB2 && isMagicWeapon(item)))
+ flg |= 1;
+
+ _dstMonsterIndex = r;
+ return calcCloseDistanceMonsterDamage(&_monsters[r], charIndex, item, 1, flg, 5, 3);
+ }
+
+ return 0;
+}
+
+int EobCoreEngine::thrownAttack(int charIndex, int slotIndex, int item) {
+ int d = charIndex > 3 ? charIndex - 2 : charIndex;
+ if (!launchObject(charIndex, item, _currentBlock, _dropItemDirIndex[(_currentDirection << 2) + d], _currentDirection, _items[item].type))
+ return 0;
+
+ snd_playSoundEffect(11);
+ _characters[charIndex].inventory[slotIndex] = 0;
+ reloadWeaponSlot(charIndex, slotIndex, -1, 0);
+ _sceneUpdateRequired = true;
+ return 0;
+}
+
+int EobCoreEngine::bowAttack(int charIndex, int item) {
+ return 0;
+}
+
+void EobCoreEngine::inflictMonsterDamage(EobMonsterInPlay *m, int damage, bool giveExperience) {
+ m->hitPointsCur -= damage;
+ m->flags = (m->flags & 0xf7) | 1;
+
+ if (_monsterProps[m->type].flags & 0x2000) {
+ inflictMonsterDamage_s1(m);
+ checkSceneUpdateNeed(m->block);
+ m->hitPointsCur = 0;
+ } else {
+ if (checkSceneUpdateNeed(m->block)) {
+ m->flags |= 2;
+ if (_inflictMonsterDamageUnk)
+ return;
+ flashMonsterShape(m);
+ }
+ }
+
+ if (m->hitPointsCur <= 0)
+ killMonster(m, giveExperience);
+ else if (getBlockDistance(m->block, _currentBlock) < 4)
+ m->dest = _currentBlock;
+}
+
+void EobCoreEngine::calcAndInflictMonsterDamage(EobMonsterInPlay *m, int times, int pips, int offs, int flags, int b, int damageType) {
+ int dmg = calcCloseDistanceMonsterDamage(m, times, pips, offs, flags, b, damageType);
+ if (dmg > 0)
+ inflictMonsterDamage(m, dmg, flags & 0x800 ? true : false);
+}
+
+void EobCoreEngine::calcAndInflictCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flg, int a, int damageType) {
+ int dmg = calcCharacterDamage(charIndex, times, itemOrPips, useStrModifierOrBase, flg, a, damageType);
+ if (dmg)
+ inflictCharacterDamage(charIndex, dmg);
+}
+
+int EobCoreEngine::calcCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flg, int a, int damageType) {
+ int s = (flg & 0x100) ? calcDamageModifers(times, 0, itemOrPips, _items[itemOrPips].type, useStrModifierOrBase) : rollDice(times, itemOrPips, useStrModifierOrBase);
+ EobCharacter *c = &_characters[charIndex];
+
+ if (a != 5) {
+ if (checkUnkConstModifiers(c, _charClassModUnk[c->cClass], c->level[0], a, c->raceSex))
+ s = recalcDamageModifier(damageType, s);
+ }
+
+ if ((flg & 0x110) == 0x110) {
+ if (!calcDamageCheckItemType(_items[itemOrPips].type))
+ s = 1;
+ }
+
+ if (flg & 4) {
+ if (checkInventoryForRings(charIndex, 3))
+ s = 0;
+ }
+
+ if (flg & 0x400) {
+ if (c->effectFlags & 0x2000)
+ s = 0;
+ else
+ _txt->printMessage(_characterStatusStrings8[0], -1, c->name);
+ }
+
+ return s;
+}
+
+void EobCoreEngine::inflictCharacterDamage(int charIndex, int damage) {
+ EobCharacter *c = &_characters[charIndex];
+ if (!testCharacter(charIndex, 3))
+ return;
+
+ if (c->effectsRemainder[3])
+ c->effectsRemainder[3] = (damage < c->effectsRemainder[3]) ? (c->effectsRemainder[3] - damage) : 0;
+
+ c->hitPointsCur -= damage;
+ c->damageTaken = damage;
+
+ if (c->hitPointsCur > -10) {
+ snd_playSoundEffect(21);
+ } else {
+ c->hitPointsCur = -10;
+ c->flags &= 1;
+ c->food = 0;
+ removeAllCharacterEffects(charIndex);
+ snd_playSoundEffect(22);
+ }
+
+ if (c->effectsRemainder[0]) {
+ c->effectsRemainder[0] = (damage < c->effectsRemainder[0]) ? (c->effectsRemainder[0] - damage) : 0;
+ if (!c->effectsRemainder[0])
+ removeCharacterEffect(1, charIndex, 1);
+ }
+
+ if (_currentControlMode)
+ gui_drawFaceShape(charIndex);
+ else
+ gui_drawCharPortraitWithStats(charIndex);
+
+ if (c->hitPointsCur <= 0 && _updateFlags == 1 && charIndex == _openBookChar) {
+ Button b;
+ clickedSpellbookAbort(&b);
+ }
+
+ setCharEventTimer(charIndex, 18, 6, 1);
+}
+
+bool EobCoreEngine::characterAttackHitTest(int charIndex, int monsterIndex, int item, int attackType) {
+ if (charIndex < 0)
+ return true;
+
+ int p = item ? (_flags.gameID == GI_EOB1 ? _items[item].type : (_itemTypes[_items[item].type].extraProperties & 0x7f)) : 0;
+
+ if (_monsters[monsterIndex].flags & 0x20)
+ return true;// EOB 2 only ?
+
+ int t = _monsters[monsterIndex].type;
+ int d = (p < 1 || p > 3) ? 0 : _items[item].value;
+
+ if (_flags.gameID == GI_EOB2) {
+ if ((p > 0 && p < 4) || !item ){
+ if (((_monsterProps[t].statusFlags & 0x200) && (d <= 0)) || ((_monsterProps[t].statusFlags & 0x1000) && (d <= 1)))
+ return false;
+ }
+ }
+
+ d += (attackType ? getStrHitChanceModifier(charIndex) : getDexHitChanceModifier(charIndex));
+
+ int m = getMonsterAcHitChanceModifier(charIndex, _monsterProps[t].armorClass) - d;
+ int s = rollDice(1, 20);
+
+ _monsters[monsterIndex].flags |= 1;
+
+ if (_flags.gameID == GI_EOB1) {
+ if (_partyEffectFlags & 0x30)
+ s++;
+ if (_characters[charIndex].effectFlags & 0x40)
+ s++;
+ } else if ((_partyEffectFlags & 0x8400) || (_characters[charIndex].effectFlags & 0x1000)) {
+ s++;
+ }
+
+ s = CLIP(s, 1, 20);
+
+ return s < m ? false : true;
+}
+
+bool EobCoreEngine::monsterAttackHitTest(EobMonsterInPlay *m, int charIndex) {
+ int tp = m->type;
+ EobMonsterProperty *p = &_monsterProps[tp];
+
+ int r = rollDice(1, 20);
+ if (r != 20) {
+ if (_characters[charIndex].effectFlags & 0x800)
+ r -= 2;
+ if (_characters[charIndex].effectFlags & 0x10)
+ r -= 2;
+ if (_partyEffectFlags & 0x8000)
+ r--;
+ }
+
+ return ((r == 20) || (r >= (p->hitChance - _characters[charIndex].armorClass)));
+}
+
+bool EobCoreEngine::flyingObjectMonsterHit(EobFlyingObject *fo, int monsterIndex) {
+ if (fo->attackerId != -1) {
+ if (!characterAttackHitTest(fo->attackerId, monsterIndex, fo->item, 0))
+ return false;
+ }
+ calcAndInflictMonsterDamage(&_monsters[monsterIndex], fo->attackerId, fo->item, 0, (fo->attackerId == -1) ? 0x110: 0x910, 5, 3);
+ return true;
+}
+
+bool EobCoreEngine::flyingObjectPartyHit(EobFlyingObject *fo) {
+ int ps = _dscItemPosIndex[(_currentDirection << 2) + (_items[fo->item].pos & 3)];
+ bool res = false;
+
+ bool b = ((_currentDirection == fo->direction || _currentDirection == (fo->direction ^ 2)) && ps > 2);
+ int s = ps << 1;
+ if (ps > 2)
+ s += rollDice(1, 2, -1);
+
+ static const int8 charId[] = { 0, -1, 1, -1, 2, 4, 3, 5 };
+
+ for (int i = 0; i < 2; i++) {
+ int c = charId[s];
+ s ^= 1;
+ if (!testCharacter(c, 3))
+ continue;
+ calcAndInflictCharacterDamage(c, -1, fo->item, 0, 0x110, 5, 3);
+ res = true;
+ if (ps < 2 || b == 0)
+ break;
+ }
+
+ return res;
+}
+
+void EobCoreEngine::monsterCloseAttack(EobMonsterInPlay *m) {
+ int first = _monsterCloseAttDstTable1[(_currentDirection << 2) + m->dir] * 12;
+ int v = (m->pos == 4) ? rollDice(1, 2, -1) : _monsterCloseAttChkTable2[(m->dir << 2) + m->pos];
+ if (!v)
+ first += 6;
+
+ int last = first + 6;
+ for (int i = first; i < last; i++) {
+ int c = _monsterCloseAttDstTable2[i];
+ if (!testCharacter(c, 3))
+ continue;
+
+ // Character Invisibility
+ if ((_characters[c].effectFlags & 0x140) && (rollDice(1, 20) >= 5))
+ continue;
+
+ int dmg = 0;
+ for (int ii = 0; ii < _monsterProps[m->type].attacksPerRound; ii++) {
+ if (!monsterAttackHitTest(m, c))
+ continue;
+ dmg += rollDice(_monsterProps[m->type].dmgDc[ii].times, _monsterProps[m->type].dmgDc[ii].pips, _monsterProps[m->type].dmgDc[ii].base);
+ }
+
+ if (dmg > 0) {
+ if ((_monsterProps[m->type].flags & 0x80) && rollDice(1, 4, -1) != 3) {
+ int slot = rollDice(1, 27, -1);
+ for (int iii = 0; iii < 27; iii++) {
+ Item itm = _characters[c].inventory[slot];
+ if (!itm || !(_itemTypes[_items[itm].type].extraProperties & 0x80)) {
+ if (++slot == 27)
+ slot = 0;
+ continue;
+ }
+
+ _characters[c].inventory[slot] = 0;
+ _txt->printMessage(_itemExtraStrings[(_characters[c].raceSex & 1) ^ 1], -1, _characters[c].name);
+ printFullItemName(itm);
+ _txt->printMessage(_itemExtraStrings[2]);
+ }
+ gui_drawCharPortraitWithStats(c);
+ }
+
+ inflictCharacterDamage(c, dmg);
+
+ if (_monsterProps[m->type].flags & 0x10) {
+ statusAttack(c, 2, _monsterSpecAttStrings[_flags.gameID == GI_EOB1 ? 3 : 2], 0, 1, 8, 1);
+ _characters[c].effectFlags &= ~0x2000;
+ }
+
+ if (_monsterProps[m->type].flags & 0x20)
+ statusAttack(c, 4, _monsterSpecAttStrings[_flags.gameID == GI_EOB1 ? 4 : 3], 2, 5, 9, 1);
+
+ if (_monsterProps[m->type].flags & 0x8000)
+ statusAttack(c, 8, _monsterSpecAttStrings[4], 2, 0, 0, 1);
+
+ }
+
+ if (!(_monsterProps[m->type].flags & 0x4000))
+ return;
+ }
+}
+
+void EobCoreEngine::monsterSpellCast(EobMonsterInPlay *m, int type) {
+ launchMagicObject(-1, type, m->block, m->pos, m->dir);
+ snd_processEnvironmentalSoundEffect(_spells[_magicFlightObjectProperties[type << 2]].sound, m->block);
+}
+
+void EobCoreEngine::statusAttack(int charIndex, int attackStatusFlags, const char *attackStatusString, int a, uint32 effectDuration, int restoreEvent, int noRefresh) {
+ EobCharacter *c = &_characters[charIndex];
+ if ((c->flags & attackStatusFlags) && noRefresh)
+ return;
+ if (!testCharacter(charIndex, 3))
+ return;
+
+ if (a != 5 && specialAttackConstTest(charIndex, a))
+ return;
+
+ if (attackStatusFlags & 8) {
+ removeAllCharacterEffects(charIndex);
+ c->flags = (c->flags & 1) | 8;
+ } else {
+ c->flags |= attackStatusFlags;
+ }
+
+ if ((attackStatusFlags & 0x0c) && (_openBookChar == charIndex) && _updateFlags) {
+ Button b;
+ clickedSpellbookAbort(&b);
+ }
+
+ if (effectDuration)
+ setCharEventTimer(charIndex, effectDuration * 546, restoreEvent, 1);
+
+ gui_drawCharPortraitWithStats(charIndex);
+ _txt->printMessage(_characterStatusStrings13[0], -1, c->name, attackStatusString);
+}
+
+int EobCoreEngine::calcCloseDistanceMonsterDamage(EobMonsterInPlay *m, int times, int pips, int offs, int flags, int b, int damageType) {
+ int s = flags & 0x100 ? calcDamageModifers(times, m, pips, _items[pips].type, offs) : rollDice(times, pips, offs);
+ EobMonsterProperty *p = &_monsterProps[m->type];
+
+ if (b == 5) {
+ if (checkUnkConstModifiers(m, 0, p->level, b, 6))
+ s = recalcDamageModifier(damageType, s);
+ }
+
+ if ((flags & 0x110) == 0x110) {
+ if (!calcDamageCheckItemType(_items[pips].type))
+ s = 1;
+ }
+
+ if ((flags & 0x100) && ((_flags.gameID == GI_EOB2 && (p->statusFlags & 0x100)) || (_flags.gameID == GI_EOB1 && (p->flags & 4))) && (!(_itemTypes[_items[pips].type].allowedClasses & 4 /* bug in original code ??*/)))
+ s >>= 1;
+
+ if (p->statusFlags & 0x2000) {
+ if (flags & 0x100) {
+ if (_items[pips].value < 3)
+ s >>= 2;
+ if (_items[pips].value == 3)
+ s >>= 1;
+ if (s == 0)
+ s = _items[pips].value;
+
+ } else {
+ s >>= 1;
+ }
+ }
+
+ if (flags & 1) {
+ if (checkMonsterDamageEvasion(m))
+ s = 0;
+ }
+
+ if (_flags.gameID == GI_EOB1)
+ return s;
+
+ static const uint16 damageImmunityFlags[] = { 0x01, 0x10, 0x02, 0x20, 0x80, 0x400, 0x20, 0x800, 0x40, 0x80, 0x400, 0x40 };
+ for (int i = 0; i < 12; i += 2) {
+ if ((flags & damageImmunityFlags[i]) && (p->statusFlags & damageImmunityFlags[i + 1]))
+ s = 0;
+ }
+
+ return s;
+}
+
+int EobCoreEngine::calcDamageModifers(int charIndex, EobMonsterInPlay *m, int item, int itemType, int useStrModifier) {
+ int s = (useStrModifier && (charIndex != -1)) ? getStrDamageModifier(charIndex) : 0;
+ if (item) {
+ EobItemType *p = &_itemTypes[itemType];
+ int t = m ? m->type : 0;
+ s += ((m && (_monsterProps[t].flags & 1)) ? rollDice(p->dmgNumDiceL, p->dmgNumPipsL, p->dmgIncS /* bug in original code ? */) :
+ rollDice(p->dmgNumDiceS, p->dmgNumPipsS, p->dmgIncS));
+ s += _items[item].value;
+ } else {
+ s += rollDice(1, 2);
+ }
+
+ return (s < 0) ? 0 : s;
+}
+
+bool EobCoreEngine::checkUnkConstModifiers(void *target, int hpModifier, int level, int b, int race) {
+ static const int8 constMod[] = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5 };
+
+ if (b == 5)
+ return false;
+
+ int s = getConstModifierTableValue(hpModifier, level, b);
+ if (((race == 3 || race == 5) && (b == 4 || b == 1 || b == 0)) || (race == 4 && (b == 4 || b == 1))) {
+ EobCharacter *c = (EobCharacter*)target;
+ s -= constMod[c->constitutionCur];
+ }
+
+ return rollDice(1, 20) < s ? false : true;
+}
+
+bool EobCoreEngine::specialAttackConstTest(int charIndex, int b) {
+ return checkUnkConstModifiers(&_characters[charIndex], _charClassModUnk[_characters[charIndex].cClass], _characters[charIndex].level[0], b, _characters[charIndex].raceSex >> 1);
+}
+
+int EobCoreEngine::getConstModifierTableValue(int hpModifier, int level, int b) {
+ const uint8 *tbl = _constModTables[hpModifier];
+ if (_constModLevelIndex[hpModifier] < level)
+ level = _constModLevelIndex[hpModifier];
+ level /= _constModDiv[hpModifier];
+ level += (_constModExt[hpModifier] * b);
+
+ return tbl[level];
+}
+
+bool EobCoreEngine::calcDamageCheckItemType(int itemType) {
+ itemType = _itemTypes[itemType].extraProperties & 0x7f;
+ return (itemType == 2 || itemType == 3) ? true : false;
+}
+
+int EobCoreEngine::recalcDamageModifier(int damageType, int dmgModifier) {
+ if (damageType == 3)
+ return 0;
+
+ if (damageType == 0 || damageType == 1)
+ return dmgModifier >> 1;
+
+ return dmgModifier;
+}
+
+bool EobCoreEngine::checkMonsterDamageEvasion(EobMonsterInPlay *m) {
+ return rollDice(1, 100) < _monsterProps[m->type].dmgModifierEvade ? true : false;
+}
+
+int EobCoreEngine::getStrHitChanceModifier(int charIndex) {
+ static const int8 strExtLimit[] = { 1, 51, 76, 91, 100 };
+ static const int8 strExtMod[] = { 1, 2, 2, 2, 3 };
+ static const int8 strMod[] = { -4, -3, -3, -2, -2, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 3, 4, 4, 5, 6, 7 };
+
+ int r = strMod[_characters[charIndex].strengthCur - 1];
+ if (_characters[charIndex].strengthExtCur) {
+ for (int i = 0; i < 5; i++) {
+ if (_characters[charIndex].strengthExtCur >= strExtLimit[i])
+ r = strExtMod[i];
+ }
+ }
+
+ return r;
+}
+
+int EobCoreEngine::getStrDamageModifier(int charIndex) {
+ static const int8 strExtLimit[] = { 1, 51, 76, 91, 100 };
+ static const int8 strExtMod[] = { 3, 3, 4, 5, 6 };
+ static const int8 strMod[] = { -3, -2, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 7, 8, 9, 10, 11, 12, 14 };
+
+ int r = strMod[_characters[charIndex].strengthCur - 1];
+ if (_characters[charIndex].strengthExtCur) {
+ for (int i = 0; i < 5; i++) {
+ if (_characters[charIndex].strengthExtCur >= strExtLimit[i])
+ r = strExtMod[i];
+ }
+ }
+
+ return r;
+}
+
+int EobCoreEngine::getDexHitChanceModifier(int charIndex) {
+ static const int8 dexMod[] = { -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 3, 4, 4, 4 };
+ return dexMod[_characters[charIndex].dexterityCur - 1];
+}
+
+int EobCoreEngine::getMonsterAcHitChanceModifier(int charIndex, int monsterAc) {
+ static const uint8 mod1[] = { 1, 3, 3, 2 };
+ static const uint8 mod2[] = { 1, 1, 2, 1 };
+
+ int l = _characters[charIndex].level[0] - 1;
+ int cm = _charClassModUnk[_characters[charIndex].cClass];
+
+ return (20 - ((l / mod1[cm]) * mod2[cm])) - monsterAc;
+}
+
+void EobCoreEngine::inflictMonsterDamage_s1(EobMonsterInPlay *m) {
+
+}
+
+void EobCoreEngine::snd_playSoundEffect(int id, int volume) {
+ if (id < 1 || id > 119 || shouldQuit())
+ return;
+
+ _sound->playSoundEffect(id, volume);
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/eobcommon.h b/engines/kyra/eobcommon.h
new file mode 100644
index 0000000000..201c1dfa11
--- /dev/null
+++ b/engines/kyra/eobcommon.h
@@ -0,0 +1,977 @@
+/* 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.
+ *
+ */
+
+#ifndef KYRA_EOBCOMMON_H
+#define KYRA_EOBCOMMON_H
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+#include "kyra/loleobbase.h"
+#endif // (ENABLE_EOB || ENABLE_LOL)
+
+#ifdef ENABLE_EOB
+
+namespace Kyra {
+
+struct EobShapeDef {
+ int16 index;
+ uint8 x, y, w, h;
+};
+
+struct CreatePartyModButton {
+ uint8 encodeLabelX;
+ uint8 encodeLabelY;
+ uint8 labelW;
+ uint8 labelH;
+ uint8 labelX;
+ uint8 labelY;
+ uint8 bodyIndex;
+ uint8 destX;
+ uint8 destY;
+};
+
+struct EobRect8 {
+ uint8 x;
+ uint8 y;
+ uint8 w;
+ uint8 h;
+};
+
+struct EobRect16 {
+ int16 x1;
+ int16 y1;
+ uint16 x2;
+ uint16 y2;
+};
+
+struct EobChargenButtonDef {
+ uint8 x;
+ uint8 y;
+ uint8 w;
+ uint8 h;
+ uint8 keyCode;
+};
+
+struct EobGuiButtonDef {
+ uint8 keyCode;
+ uint8 keyCode2;
+ uint16 flags;
+ uint16 x;
+ uint8 y;
+ uint16 w;
+ uint8 h;
+ Button::Callback buttonCallback;
+ uint16 arg;
+};
+
+struct EobCharacter {
+ uint8 id;
+ uint8 flags;
+ char name[11];
+ int8 strengthCur;
+ int8 strengthMax;
+ int8 strengthExtCur;
+ int8 strengthExtMax;
+ int8 intelligenceCur;
+ int8 intelligenceMax;
+ int8 wisdomCur;
+ int8 wisdomMax;
+ int8 dexterityCur;
+ int8 dexterityMax;
+ int8 constitutionCur;
+ int8 constitutionMax;
+ int8 charismaCur;
+ int8 charismaMax;
+ int16 hitPointsCur;
+ int16 hitPointsMax;
+ int8 armorClass;
+ uint8 disabledSlots;
+ uint8 raceSex;
+ uint8 cClass;
+ uint8 alignment;
+ int8 portrait;
+ uint8 food;
+ uint8 level[3];
+ uint32 experience[3];
+ uint8 *faceShape;
+
+ int8 mageSpells[80];
+ int8 clericSpells[80];
+ uint32 mageSpellsAvailabilityFlags;
+
+ Item inventory[27];
+ uint32 timers[10];
+ int8 events[10];
+ uint8 effectsRemainder[4];
+ uint32 effectFlags;
+ uint8 damageTaken;
+ int8 slotStatus[5];
+};
+
+struct EobItem {
+ uint8 nameUnid;
+ uint8 nameId;
+ uint8 flags;
+ int8 icon;
+ int8 type;
+ int8 pos;
+ int16 block;
+ Item next;
+ Item prev;
+ uint8 level;
+ int8 value;
+};
+
+struct EobItemType {
+ uint16 invFlags;
+ uint16 handFlags;
+ int8 armorClass;
+ int8 allowedClasses;
+ int8 requiredHands;
+ int8 dmgNumDiceS;
+ int8 dmgNumPipsS;
+ int8 dmgIncS;
+ int8 dmgNumDiceL;
+ int8 dmgNumPipsL;
+ int8 dmgIncL;
+ uint8 unk1;
+ uint16 extraProperties;
+};
+
+struct SpriteDecoration {
+ uint8 *shp;
+ uint8 x;
+ uint8 y;
+};
+
+struct EobMonsterProperty {
+ int8 armorClass;
+ int8 hitChance;
+ uint8 level;
+ uint8 hpDcTimes;
+ uint8 hpDcPips;
+ uint8 hpDcBase;
+ uint8 attacksPerRound;
+ struct DmgDc {
+ uint8 times;
+ uint8 pips;
+ int8 base;
+ } dmgDc[3];
+ uint16 statusFlags;
+ uint16 flags;
+ int32 u22;
+ int32 experience;
+
+ uint8 u30;
+ uint8 sound1;
+ uint8 sound2;
+ uint8 numRemoteAttacks;
+ uint8 remoteWeaponChangeMode;
+ uint8 numRemoteWeapons;
+
+ int8 remoteWeapons[5];
+
+ uint8 u41;
+ uint8 dmgModifierEvade;
+
+ uint8 decorations[3];
+};
+
+struct EobMonsterInPlay {
+ uint8 type;
+ uint8 unit;
+ uint16 block;
+ uint8 pos;
+ int8 dir;
+ uint8 animStep;
+ uint8 shpIndex;
+ int8 mode;
+ int8 f_9;
+ int8 curAttackFrame;
+ uint8 f_b;
+ int16 hitPointsMax;
+ int16 hitPointsCur;
+ uint16 dest;
+ uint16 randItem;
+ uint16 fixedItem;
+ uint8 flags;
+ uint8 idleAnimState;
+ uint8 curRemoteWeapon;
+ uint8 numRemoteAttacks;
+ int8 palette;
+ uint8 directionChanged;
+ uint8 stepsTillRemoteAttack;
+ uint8 sub;
+};
+
+struct ScriptTimer {
+ uint16 func;
+ uint16 ticks;
+ uint32 next;
+};
+
+struct EobFlyingObject {
+ uint8 enable;
+ uint8 objectType;
+ int16 attackerId;
+ Item item;
+ uint16 curBlock;
+ uint16 u2;
+ uint8 u1;
+ uint8 direction;
+ uint8 distance;
+ int8 callBackIndex;
+ uint8 curPos;
+ uint8 flags;
+ uint8 unused;
+};
+
+class EobInfProcessor;
+
+class EobCoreEngine : public LolEobBaseEngine {
+friend class TextDisplayer_Eob;
+friend class GUI_Eob;
+friend class EobInfProcessor;
+friend class DarkmoonSequenceHelper;
+friend class CharacterGenerator;
+public:
+ EobCoreEngine(OSystem *system, const GameFlags &flags);
+ virtual ~EobCoreEngine();
+
+ Screen *screen() { return _screen; }
+ GUI *gui() const { return _gui; }
+
+protected:
+ // Startup
+ virtual Common::Error init();
+ Common::Error go();
+
+ // Main Menu, Intro, Finale
+ virtual int mainMenu() = 0;
+ virtual void seq_playFinale() = 0;
+ bool _playFinale;
+
+ //Init
+ void loadItemsAndDecorationsShapes();
+ void releaseItemsAndDecorationsShapes();
+
+ void initButtonData();
+ void initStaticResource();
+ virtual void initSpells();
+
+ const uint8 **_largeItemShapes;
+ const uint8 **_smallItemShapes;
+ const uint8 **_thrownItemShapes;
+ const int _numLargeItemShapes;
+ const int _numSmallItemShapes;
+ const int _numThrownItemShapes;
+ const int _numItemIconShapes;
+
+ const uint8 **_spellShapes;
+ const uint8 **_firebeamShapes;
+ const uint8 *_redSplatShape;
+ const uint8 *_greenSplatShape;
+ const uint8 **_wallOfForceShapes;
+ const uint8 **_teleporterShapes;
+ const uint8 **_sparkShapes;
+ const uint8 *_deadCharShape;
+ const uint8 *_disabledCharGrid;
+ const uint8 *_blackBoxSmallGrid;
+ const uint8 *_weaponSlotGrid;
+ const uint8 *_blackBoxWideGrid;
+ const uint8 *_lightningColumnShape;
+
+ uint8 *_tempIconShape;
+ uint8 *_itemsOverlay;
+
+ static const uint8 _teleporterShapeDefs[];
+ static const uint8 _wallOfForceShapeDefs[];
+
+ const char *const *_mainMenuStrings;
+
+ // Main loop
+ virtual void startupNew() = 0;
+ virtual void startupLoad() = 0;
+ void runLoop();
+ void update() { screen()->updateScreen(); }
+ bool updateCharacterEvents(bool a);
+
+ bool _runFlag;
+ //int _runLoopUnk2;
+
+ // Create Party
+ void startCharacterGeneration();
+
+ uint8 **_faceShapes;
+
+ static const int8 _classHpIncreaseType[];
+ static const uint8 _hpIncrPerLevel[];
+ static const uint8 _numLevelsPerClass[];
+ static const int16 _hpConstModifiers[];
+ static const uint8 _charClassModUnk[];
+
+ const uint8 *_classModifierFlags;
+
+ // timers
+ void setupTimers();
+ void setCharEventTimer(int charIndex, uint32 countdown, int evnt, int updateExistingTimer);
+ void deleteCharEventTimer(int charIndex, int evnt);
+ void setupCharacterTimers();
+
+ void timerProcessMonsters(int timerNum);
+ void timerSpecialCharacterUpdate(int timerNum);
+ void timerProcessFlyingObjects(int timerNum);
+ void timerProcessCharacterExchange(int timerNum);
+ void timerUpdateTeleporters(int timerNum);
+ void timerUpdateFoodStatus(int timerNum);
+ void timerUpdateMonsterIdleAnim(int timerNum);
+
+ uint8 getClock2Timer(int index) { return index < _numClock2Timers ? _clock2Timers[index] : 0; }
+ uint8 getNumClock2Timers() { return _numClock2Timers; }
+
+ static const uint8 _clock2Timers[];
+ static const uint8 _numClock2Timers;
+
+ // Mouse
+ void setHandItem(Item itemIndex);
+ void updateHandItemCursor() { _updateHandItemCursor = true; }
+ bool _updateHandItemCursor;
+
+ // Characters
+ int getDexterityArmorClassModifier(int dexterity);
+ int generateCharacterHitpointsByLevel(int charIndex, int levelIndex);
+ int getClassAndConstHitpointsModifier(int cclass, int constitution);
+ int getClassHpIncreaseType(int cclass, int levelIndex);
+ int getModifiedHpLimits(int hpModifier, int constModifier, int level, bool mode);
+ const char *getCharStrength(int str, int strExt);
+ int testCharacter(int index, int flags);
+ int getNextValidCharIndex(int curCharIndex, int searchStep);
+
+ void recalcArmorClass(int index);
+ int validateWeaponSlotItem(int index, int slot);
+ int getCharacterClericPaladinLevel(int index);
+ int getCharacterMageLevel(int index);
+ int getLevelIndexForHpIncType(int unk, int cClass);
+
+ int countCharactersWithSpecificItems(int16 itemType, int16 itemValue);
+ int checkCharacterInventoryForItem(int character, int16 itemType, int16 itemValue);
+ void modifyCharacterHitpoints(int character, int16 points);
+ void neutralizePoison(int character);
+
+ virtual void npcSequence(int npcIndex) = 0;
+ void initNpc(int npcIndex);
+ int npcJoinDialogue(int npcIndex, int queryJoinTextId, int confirmJoinTextId, int noJoinTextId);
+ int prepareForNewPartyMember(int16 itemType, int16 itemValue);
+ void removeCharacterFromParty(int charIndex);
+
+ void increasePartyExperience(int16 points);
+ void increaseCharacterExperience(int charIndex, int32 points);
+ uint32 getRequiredExperience(int cClass, int levelIndex, int level);
+ void increaseCharacterLevel(int charIndex, int levelIndex);
+
+ void setWeaponSlotStatus(int charIndex, int mode, int slot);
+
+ EobCharacter *_characters;
+ char _strenghtStr[6];
+ int _castScrollSlot;
+ int _exchangeCharacterId;
+
+ const char *const *_levelGainStrings;
+ const uint32 *_expRequirementTables[6];
+
+ const uint8 *_constModTables[6];
+ const uint8 *_constModLevelIndex;
+ const uint8 *_constModDiv;
+ const uint8 *_constModExt;
+
+ const EobCharacter *_npcPreset;
+ bool _partyResting;
+
+ // Items
+ void loadItemDefs();
+ Item duplicateItem(Item itemIndex);
+ void setItemPosition(Item *itemQueue, int block, Item item, int pos);
+ void createInventoryItem(EobCharacter *c, Item itemIndex, int itemValue, int preferedInventorySlot);
+ int deleteInventoryItem(int charIndex, int slot);
+ void deleteBlockItem(uint16 block, int type);
+ int validateInventorySlotForItem(Item item, int charIndex, int slot);
+ void deletePartyItem(Item itemType, int16 itemValue);
+ virtual void updateUsedCharacterHandItem(int charIndex, int slot) = 0;
+ int itemUsableByCharacter(int charIndex, Item item);
+ int countQueuedItems(Item itemQueue, int16 id, int16 type, int count, int includeFlyingItems);
+ int getQueuedItem(Item *items, int pos, int id);
+ void printFullItemName(Item item);
+ void identifyQueuedItems(Item itemQueue);
+ void drawItemIconShape(int pageNum, Item itemId, int x, int y);
+ bool isMagicWeapon(Item itemIndex);
+ bool checkInventoryForRings(int charIndex, int itemValue);
+ void eatItemInHand(int charIndex);
+
+ bool launchObject(int charIndex, Item item, uint16 startBlock, int startPos, int dir, int type);
+ void launchMagicObject(int charIndex, int type, uint16 startBlock, int startPos, int dir);
+ bool updateObjectFlight(EobFlyingObject *fo, int block, int pos);
+ bool updateFlyingObjectHitTest(EobFlyingObject *fo, int block, int pos);
+ void updateFlyingObject_s3(EobFlyingObject *fo);
+ void endObjectFlight(EobFlyingObject *fo);
+ void checkFlyingObjects();
+
+ void reloadWeaponSlot(int charIndex, int slotIndex, int itemType, int arrowOrDagger);
+
+ EobItem *_items;
+ uint16 _numItems;
+ EobItemType *_itemTypes;
+ char **_itemNames;
+ uint16 _numItemNames;
+ uint32 _partyEffectFlags;
+ Item _lastUsedItem;
+
+ const uint16 *_slotValidationFlags;
+
+ EobFlyingObject *_flyingObjects;
+ const uint8 *_drawObjPosIndex;
+ const uint8 *_flightObjFlipIndex;
+ const int8 *_flightObjShpMap;
+ const int8 *_flightObjSclIndex;
+
+ // Monsters
+ void loadMonsterShapes(const char *filename, int monsterIndex, bool hasDecorations, int encodeTableIndex);
+ void releaseMonsterShapes(int first, int num);
+ virtual void generateMonsterPalettes(const char *file, int16 monsterIndex) {}
+ virtual void loadMonsterDecoration(const char *file, int16 monsterIndex) {}
+ const uint8 *loadMonsterProperties(const uint8 *data);
+ const uint8 *loadActiveMonsterData(const uint8 *data, int level);
+ void initMonster(int index, int unit, uint16 block, int pos, int dir, int type, int shpIndex, int mode, int i, int randItem, int fixedItem);
+ void placeMonster(EobMonsterInPlay *m, uint16 block, int dir);
+ virtual void replaceMonster(int b, uint16 block, int pos, int dir, int type, int shpIndex, int mode, int h2, int randItem, int fixedItem) = 0;
+ void killMonster(EobMonsterInPlay *m, bool giveExperience);
+ int countSpecificMonsters(int type);
+ void updateAttackingMonsterFlags();
+
+ const int8 *getMonsterBlockPositions(uint16 block);
+ int getClosestMonsterPos(int charIndex, int block);
+
+ bool blockHasMonsters(uint16 block);
+ bool isMonsterOnPos(EobMonsterInPlay *m, uint16 block, int pos, int checkPos4);
+ const int16 *findBlockMonsters(uint16 block, int pos, int dir, int blockDamage, int singleTargetCheckAdjacent);
+
+ void drawBlockObject(int flipped, int page, const uint8 *shape, int x, int y, int sd, uint8 *ovl = 0);
+ void drawMonsterShape(const uint8 *shape, int x, int y, int flipped, int flags, int palIndex);
+ void flashMonsterShape(EobMonsterInPlay *m);
+ void updateAllMonsterShapes();
+ void drawBlockItems(int index);
+ void drawDoor(int index);
+ virtual void drawDoorIntern(int type, int index, int x, int y, int w, int wall, int mDim, int16 y1, int16 y2) = 0;
+ void drawMonsters(int index);
+ void drawWallOfForce(int index);
+ void drawFlyingObjects(int index);
+ void drawTeleporter(int index);
+
+ void updateMonsters(int unit);
+ void updateMonsterDest(EobMonsterInPlay *m);
+ void updateMonsterDest2(EobMonsterInPlay *m);
+ void turnFriendlyMonstersHostile();
+ int getNextMonsterDirection(int curBlock, int destBlock);
+ int getNextMonsterPos(EobMonsterInPlay *m, int block);
+ int findFreeMonsterPos(int block, int size);
+ void updateMoveMonster(EobMonsterInPlay *m);
+ bool updateMonsterTryDistanceAttack(EobMonsterInPlay *m);
+ bool updateMonsterTryCloseAttack(EobMonsterInPlay *m, int block);
+ void walkMonster(EobMonsterInPlay *m, int destBlock);
+ bool walkMonsterNextStep(EobMonsterInPlay *m, int destBlock, int direction);
+ void updateMonsterFollowPath(EobMonsterInPlay *m, int turnSteps);
+ void updateMonstersStraying(EobMonsterInPlay *m, int a);
+ void updateMonsters_mode710(EobMonsterInPlay *m);
+ void setBlockMonsterDirection(int block, int dir);
+
+ uint8 *_monsterOvl1;
+ uint8 *_monsterOvl2;
+
+ SpriteDecoration *_monsterDecorations;
+ EobMonsterProperty *_monsterProps;
+
+ EobMonsterInPlay *_monsters;
+
+ const int8 *_monsterStepTable0;
+ const int8 *_monsterStepTable1;
+ const int8 *_monsterStepTable2;
+ const int8 *_monsterStepTable3;
+ const uint8 *_monsterCloseAttPosTable1;
+ const uint8 *_monsterCloseAttPosTable2;
+ const int8 *_monsterCloseAttUnkTable;
+ const uint8 *_monsterCloseAttChkTable1;
+ const uint8 *_monsterCloseAttChkTable2;
+ const uint8 *_monsterCloseAttDstTable1;
+ const uint8 *_monsterCloseAttDstTable2;
+
+ const uint8 *_monsterProximityTable;
+ const uint8 *_findBlockMonstersTable;
+ const char *const *_monsterDustStrings;
+
+ const uint8 *_monsterDistAttType10;
+ const uint8 *_monsterDistAttSfx10;
+ const uint8 *_monsterDistAttType17;
+ const uint8 *_monsterDistAttSfx17;
+ const char *const *_monsterSpecAttStrings;
+
+ const int8 *_monsterFrmOffsTable1;
+ const int8 *_monsterFrmOffsTable2;
+
+ const uint16 *_encodeMonsterShpTable;
+ const uint8 _teleporterWallId;
+
+ const int8 *_monsterDirChangeTable;
+
+ // Level
+ void loadLevel(int level, int func);
+ const char *initLevelData(int func);
+ void addLevelItems();
+ void loadVcnData(const char *file, const char */*nextFile*/);
+ void loadBlockProperties(const char *mazFile);
+ void loadDecorations(const char *cpsFile, const char *decFile);
+ void assignWallsAndDecorations(int wallIndex, int vmpIndex, int decDataIndex, int specialType, int flags);
+ void releaseDecorations();
+ void releaseDoorShapes();
+ void toggleWallState(int wall, int flags);
+ virtual void loadDoorShapes(int doorType1, int shapeId1, int doorType2, int shapeId2) {}
+ virtual const uint8 *loadDoorShapes(const char *filename, int doorIndex, const uint8*shapeDefs) { return (const uint8*)filename; }
+
+ void drawScene(int update);
+ void drawSceneShapes();
+ void drawDecorations(int index);
+
+ int calcNewBlockPositionAndTestPassability(uint16 curBlock, uint16 direction);
+ void notifyBlockNotPassable();
+ void moveParty(uint16 block);
+
+ int clickedDoorSwitch(uint16 block, uint16 direction);
+ int clickedDoorPry(uint16 block, uint16 direction);
+ int clickedDoorNoPry(uint16 block, uint16 direction);
+ int clickedNiche(uint16 block, uint16 direction);
+
+ int specialWallAction(int block, int direction);
+
+ void openDoor(int block);
+ void closeDoor(int block);
+
+ int16 _doorType[2];
+ int16 _noDoorSwitch[2];
+
+ EobRect8 *_levelDecorationRects;
+ SpriteDecoration *_doorSwitches;
+
+ int8 _currentSub;
+ char _curGfxFile[13];
+
+ uint32 _drawSceneTimer;
+ uint32 _flashShapeTimer;
+ uint32 _envAudioTimer;
+ uint16 _teleporterPulse;
+
+ const int16 *_dscShapeCoords;
+
+ const uint8 *_dscItemPosIndex;
+ const int16 *_dscItemShpX;
+ const uint8 *_dscItemScaleIndex;
+ const uint8 *_dscItemTileIndex;
+ const uint8 *_dscItemShapeMap;
+
+ const uint8 *_dscDoorScaleOffs;
+ const uint8 *_dscDoorScaleMult1;
+ const uint8 *_dscDoorScaleMult2;
+ const uint8 *_dscDoorScaleMult3;
+ const uint8 *_dscDoorY1;
+
+ const uint8 *_wllFlagPreset;
+ int _wllFlagPresetSize;
+ const uint8 *_teleporterShapeCoords;
+
+ // Script
+ void runLevelScript(int block, int flags);
+ void setScriptFlag(int flag);
+ bool checkScriptFlag(int flag);
+
+ const uint8 *initScriptTimers(const uint8 *pos);
+ void updateScriptTimers();
+
+ EobInfProcessor *_inf;
+ int _stepCounter;
+ int _stepsUntilScriptCall;
+ ScriptTimer _scriptTimers[5];
+ int _scriptTimersCount;
+ uint8 _scriptTimersMode;
+
+ // Gui
+ void gui_drawPlayField(int pageNum);
+ void gui_restorePlayField();
+ void gui_drawAllCharPortraitsWithStats();
+ void gui_drawCharPortraitWithStats(int index);
+ void gui_drawFaceShape(int index);
+ void gui_drawWeaponSlot(int charIndex, int slot);
+ void gui_drawWeaponSlotStatus(int x, int y, int status);
+ void gui_drawHitpoints(int index);
+ void gui_drawFoodStatusGraph(int index);
+ void gui_drawHorizontalBarGraph(int x, int y, int w, int h, int32 curVal, int32 maxVal, int col1, int col2);
+ void gui_drawCharPortraitStatusFrame(int index);
+ void gui_drawInventoryItem(int slot, int special, int pageNum);
+ void gui_drawCompass(bool force);
+ void gui_drawDialogueBox();
+ void gui_drawSpellbook();
+ void gui_drawSpellbookScrollArrow(int x, int y, int direction);
+ void gui_updateSlotAfterScrollUse();
+ void gui_updateControls();
+ void gui_toggleButtons();
+ void gui_setPlayFieldButtons();
+ void gui_setInventoryButtons();
+ void gui_setStatsListButtons();
+ void gui_setSwapCharacterButtons();
+ void gui_setCastOnWhomButtons();
+ void gui_initButton(int index, int x = -1, int y = -1, int val = -1);
+ Button *gui_getButton(Button *buttonList, int index);
+
+ int clickedInventoryNextPage(Button *button);
+ int clickedPortraitRestore(Button *button);
+ int clickedCharPortraitDefault(Button *button);
+ int clickedCamp(Button *button);
+ int clickedSceneDropPickupItem(Button *button);
+ int clickedCharPortrait2(Button *button);
+ int clickedWeaponSlot(Button *button);
+ int clickedCharNameLabelRight(Button *button);
+ int clickedInventorySlot(Button *button);
+ int clickedEatItem(Button *button);
+ int clickedInventoryPrevChar(Button *button);
+ int clickedInventoryNextChar(Button *button);
+ int clickedSpellbookTab(Button *button);
+ int clickedSpellbookList(Button *button);
+ int clickedCastSpellOnCharacter(Button *button);
+ int clickedUpArrow(Button *button);
+ int clickedDownArrow(Button *button);
+ int clickedLeftArrow(Button *button);
+ int clickedRightArrow(Button *button);
+ int clickedTurnLeftArrow(Button *button);
+ int clickedTurnRightArrow(Button *button);
+ int clickedAbortCharSwitch(Button *button);
+ int clickedSceneThrowItem(Button *button);
+ int clickedSceneSpecial(Button *button);
+ int clickedSpellbookAbort(Button *button);
+ int clickedSpellbookScroll(Button *button);
+ int clickedUnk(Button *button);
+
+ void gui_processCharPortraitClick(int index);
+ void gui_processWeaponSlotClickLeft(int charIndex, int slotIndex);
+ void gui_processWeaponSlotClickRight(int charIndex, int slotIndex);
+ void gui_processInventorySlotClick(int slot);
+
+ static const int16 _buttonList1[];
+ int _buttonList1Size;
+ static const int16 _buttonList2[];
+ int _buttonList2Size;
+ static const int16 _buttonList3[];
+ int _buttonList3Size;
+ static const int16 _buttonList4[];
+ int _buttonList4Size;
+ static const int16 _buttonList5[];
+ int _buttonList5Size;
+ static const int16 _buttonList6[];
+ int _buttonList6Size;
+ static const int16 _buttonList7[];
+ int _buttonList7Size;
+ static const int16 _buttonList8[];
+ int _buttonList8Size;
+
+ const EobGuiButtonDef *_buttonDefs;
+ const char *const *_characterGuiStringsHp;
+ const char *const *_characterGuiStringsWp;
+ const char *const *_characterGuiStringsWr;
+ const char *const *_characterGuiStringsSt;
+ const char *const *_characterGuiStringsIn;
+
+ const char *const *_characterStatusStrings7;
+ const char *const *_characterStatusStrings8;
+ const char *const *_characterStatusStrings9;
+ const char *const *_characterStatusStrings12;
+ const char *const *_characterStatusStrings13;
+
+ const uint16 *_inventorySlotsX;
+ const uint8 *_inventorySlotsY;
+ const uint8 **_compassShapes;
+ uint8 _charExchangeSwap;
+ bool _hpBarGraphs;
+
+ // text
+ void setupDialogueButtons(int presetfirst, int numStr, const char *str1, ...);
+ void initDialogueSequence();
+ void restoreAfterDialogueSequence();
+ void drawSequenceBitmap(const char *file, int destRect, int x1, int y1, int flags);
+ int runDialogue(int dialogueTextId, int style, const char *button1, ...);
+
+ char _dialogueLastBitmap[13];
+ int _dlgUnk1;
+ int _moveCounter;
+
+ uint8 _color4;
+ uint8 _color5;
+ uint8 _color6;
+ uint8 _color7;
+ uint8 _color8;
+ uint8 _color9;
+ uint8 _color10;
+ uint8 _color11;
+ uint8 _color12;
+ uint8 _color13;
+ uint8 _color14;
+
+ const char *const *_chargenStatStrings;
+ const char *const *_chargenRaceSexStrings;
+ const char *const *_chargenClassStrings;
+ const char *const *_chargenAlignmentStrings;
+
+ const char *const *_pryDoorStrings;
+ const char *const *_warningStrings;
+ const char *const *_itemExtraStrings;
+ const char *const *_itemSuffixStrings;
+ const char *const *_takenStrings;
+ const char *const *_potionEffectStrings;
+
+ const char *const *_yesNoStrings;
+ const char *const *_npcMaxStrings;
+ const char *const *_okStrings;
+ const char *const *_npcJoinStrings;
+ const char *const *_cancelStrings;
+ const char *const *_abortStrings;
+
+ // misc
+ void delay(uint32 millis, bool doUpdate = false, bool isMainLoop = false);
+ void displayParchment(int id);
+
+ virtual void drawLightningColumn() {}
+ virtual int resurrectionSelectDialogue() { return -1; }
+ virtual int charSelectDialogue() { return -1; }
+ virtual void characterLevelGain(int charIndex) {}
+
+ Common::Error loadGameState(int slot);
+ Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail);
+
+ void *generateMonsterTempData(LevelTempData *tmp);
+ void *generateFlyingObjectTempData(LevelTempData *tmp);
+ void restoreMonsterTempData(LevelTempData *tmp);
+ void restoreFlyingObjectTempData(LevelTempData *tmp);
+ void releaseMonsterTempData(LevelTempData *tmp);
+ void releaseFlyingObjectTempData(LevelTempData *tmp);
+
+ int _saveLoadMode;
+
+ Screen_Eob *_screen;
+ GUI_Eob *_gui;
+
+ // fight
+ void useSlotWeapon(int charIndex, int slotIndex, int item);
+ int closeDistanceAttack(int charIndex, int item);
+ int thrownAttack(int charIndex, int slotIndex, int item);
+ int bowAttack(int charIndex, int item);
+
+ void inflictMonsterDamage(EobMonsterInPlay *m, int damage, bool giveExperience);
+ void calcAndInflictMonsterDamage(EobMonsterInPlay *m, int times, int pips, int offs, int flags, int b, int damageType);
+ void calcAndInflictCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flg, int a, int damageType);
+ int calcCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flg, int a, int damageType) ;
+ void inflictCharacterDamage(int charIndex, int damage);
+
+ bool characterAttackHitTest(int charIndex, int monsterIndex, int item, int attackType);
+ bool monsterAttackHitTest(EobMonsterInPlay *m, int charIndex);
+ bool flyingObjectMonsterHit(EobFlyingObject *fo, int monsterIndex);
+ bool flyingObjectPartyHit(EobFlyingObject *fo);
+
+ void monsterCloseAttack(EobMonsterInPlay *m);
+ void monsterSpellCast(EobMonsterInPlay *m, int type);
+ void statusAttack(int charIndex, int attackStatusFlags, const char *attackStatusString, int a, uint32 effectDuration, int restoreEvent, int noRefresh);
+
+ int calcCloseDistanceMonsterDamage(EobMonsterInPlay *m, int times, int pips, int offs, int flags, int b, int damageType);
+ int calcDamageModifers(int charIndex, EobMonsterInPlay *m, int item, int itemType, int useStrModifier);
+ bool checkUnkConstModifiers(void *target, int hpModifier, int level, int b, int race);
+ bool specialAttackConstTest(int charIndex, int b);
+ int getConstModifierTableValue(int hpModifier, int level, int b);
+ bool calcDamageCheckItemType(int itemType);
+ int recalcDamageModifier(int damageType, int dmgModifier);
+ bool checkMonsterDamageEvasion(EobMonsterInPlay *m);
+ int getStrHitChanceModifier(int charIndex);
+ int getStrDamageModifier(int charIndex);
+ int getDexHitChanceModifier(int charIndex);
+ int getMonsterAcHitChanceModifier(int charIndex, int monsterAc);
+ void inflictMonsterDamage_s1(EobMonsterInPlay *m);
+
+ int _dstMonsterIndex;
+ int _inflictMonsterDamageUnk;
+ int16 _foundMonstersArray[5];
+
+ // magic
+ void useMagicBookOrSymbol(int charIndex, int type);
+ void useMagicScroll(int charIndex, int type, int weaponSlot);
+ void usePotion(int charIndex, int weaponSlot);
+
+ void castSpell(int spell, int weaponSlot);
+ void removeCharacterEffect(int spell, int charIndex, int showWarning);
+ void removeAllCharacterEffects(int charIndex);
+ void castOnWhomDialogue();
+ void startSpell(int spell);
+
+ void sparkEffectDefensive(int charIndex);
+ void sparkEffectOffensive();
+ void setSpellEventTimer(int spell, int timerBaseFactor, int timerLength, int timerLevelFactor, int updateExistingTimer);
+
+ bool magicObjectHit(EobFlyingObject *fo, int dcTimes, int dcPips, int dcOffs, int level);
+
+ void spellCallback_start_empty() {}
+ bool spellCallback_end_empty(EobFlyingObject *fo) { return true; }
+ void spellCallback_start_armor();
+ void spellCallback_start_burningHands();
+ void spellCallback_start_detectMagic();
+ bool spellCallback_end_detectMagic(EobFlyingObject *fo);
+ void spellCallback_start_magicMissile();
+ bool spellCallback_end_magicMissile(EobFlyingObject *fo);
+ void spellCallback_start_shockingGrasp();
+ bool spellCallback_end_shockingGraspFlameBlade(EobFlyingObject *fo);
+ void spellCallback_start_improvedIdentify();
+ void spellCallback_start_melfsAcidArrow();
+ bool spellCallback_end_melfsAcidArrow(EobFlyingObject *fo);
+ void spellCallback_start_dispelMagic();
+ void spellCallback_start_fireball();
+ bool spellCallback_end_fireball(EobFlyingObject *fo);
+ void spellCallback_start_flameArrow();
+ bool spellCallback_end_flameArrow(EobFlyingObject *fo);
+ void spellCallback_start_holdPerson();
+ bool spellCallback_end_holdPerson(EobFlyingObject *fo);
+ void spellCallback_start_lightningBolt();
+ bool spellCallback_end_lightningBolt(EobFlyingObject *fo);
+ void spellCallback_start_vampiricTouch();
+ bool spellCallback_end_vampiricTouch(EobFlyingObject *fo);
+ void spellCallback_start_fear();
+ void spellCallback_start_iceStorm();
+ bool spellCallback_end_iceStorm(EobFlyingObject *fo);
+ void spellCallback_start_removeCurse();
+ void spellCallback_start_coneOfCold();
+ void spellCallback_start_holdMonster();
+ bool spellCallback_end_holdMonster(EobFlyingObject *fo);
+ void spellCallback_start_wallOfForce();
+ void spellCallback_start_disintegrate();
+ void spellCallback_start_fleshToStone();
+ void spellCallback_start_stoneToFlesh();
+ void spellCallback_start_trueSeeing();
+ bool spellCallback_end_trueSeeing(EobFlyingObject *fo);
+ void spellCallback_start_slayLiving();
+ void spellCallback_start_powerWordStun();
+ void spellCallback_start_causeLightWounds();
+ void spellCallback_start_cureLightWounds();
+ void spellCallback_start_aid();
+ bool spellCallback_end_aid(EobFlyingObject *fo);
+ void spellCallback_start_flameBlade();
+ void spellCallback_start_slowPoison();
+ bool spellCallback_end_slowPoison(EobFlyingObject *fo);
+ void spellCallback_start_createFood();
+ void spellCallback_start_removeParalysis();
+ void spellCallback_start_causeSeriousWounds();
+ void spellCallback_start_cureSeriousWounds();
+ void spellCallback_start_neutralizePoison();
+ void spellCallback_start_causeCriticalWounds();
+ void spellCallback_start_cureCriticalWounds();
+ void spellCallback_start_flameStrike();
+ bool spellCallback_end_flameStrike(EobFlyingObject *fo);
+ void spellCallback_start_raiseDead();
+ void spellCallback_start_harm();
+ void spellCallback_start_heal();
+ void spellCallback_start_layOnHands();
+ void spellCallback_start_turnUndead();
+ bool spellCallback_end_unk1Passive(EobFlyingObject *fo);
+ bool spellCallback_end_unk2Passive(EobFlyingObject *fo);
+ bool spellCallback_end_deathSpellPassive(EobFlyingObject *fo);
+ bool spellCallback_end_disintegratePassive(EobFlyingObject *fo);
+ bool spellCallback_end_causeCriticalWoundsPassive(EobFlyingObject *fo);
+ bool spellCallback_end_fleshToStonePassive(EobFlyingObject *fo);
+
+ int8 _openBookSpellLevel;
+ int8 _openBookSpellSelectedItem;
+ int8 _openBookSpellListOffset;
+ uint8 _openBookChar;
+ uint8 _openBookType;
+ uint8 _openBookCharBackup;
+ uint8 _openBookTypeBackup;
+ const char *const *_openBookSpellList;
+ int8 *_openBookAvailableSpells;
+ uint8 _activeSpellCaster;
+ uint8 _activeSpellCasterPos;
+ uint8 _activeSpell;
+ bool _returnAfterSpellCallback;
+
+ typedef void (EobCoreEngine::*SpellStartCallback)();
+ typedef bool (EobCoreEngine::*SpellEndCallback)(EobFlyingObject *fo);
+
+ struct EobSpell {
+ const char *name;
+ SpellStartCallback startCallback;
+ uint16 flags;
+ const uint16 *timingPara;
+ SpellEndCallback endCallback;
+ uint8 sound;
+ uint32 effectFlags;
+ uint16 damageFlags;
+ };
+
+ EobSpell *_spells;
+ int _numSpells;
+
+ const char *const *_bookNumbers;
+ const char *const *_mageSpellList;
+ int _mageSpellListSize;
+ int _clericSpellOffset;
+ const char *const *_clericSpellList;
+ const char *const *_spellNames;
+ const char *const *_magicStrings1;
+ const char *const *_magicStrings2;
+ const char *const *_magicStrings3;
+ const char *const *_magicStrings4;
+ const char *const *_magicStrings5;
+ const char *const *_magicStrings6;
+ const char *const *_magicStrings7;
+ const char *const *_magicStrings8;
+
+ uint8 *_spellAnimBuffer;
+
+ const uint8 *_sparkEffectDefSteps;
+ const uint8 *_sparkEffectDefSubSteps;
+ const uint8 *_sparkEffectDefShift;
+ const uint8 *_sparkEffectDefAdd;
+ const uint8 *_sparkEffectDefX;
+ const uint8 *_sparkEffectDefY;
+ const uint32 *_sparkEffectOfFlags1;
+ const uint32 *_sparkEffectOfFlags2;
+ const uint8 *_sparkEffectOfShift;
+ const uint8 *_sparkEffectOfX;
+ const uint8 *_sparkEffectOfY;
+
+ const uint8 *_magicFlightObjectProperties;
+
+ // sound
+ void snd_playSoundEffect(int id, int volume=0xFF);
+};
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
+
+#endif \ No newline at end of file
diff --git a/engines/kyra/gui.h b/engines/kyra/gui.h
index 6e9606f1de..04fc9b5523 100644
--- a/engines/kyra/gui.h
+++ b/engines/kyra/gui.h
@@ -40,10 +40,10 @@ struct Button {
typedef Common::Functor1<Button *, int> CallbackFunctor;
typedef Common::SharedPtr<CallbackFunctor> Callback;
- Button() : nextButton(0), index(0), keyCode(0), keyCode2(0), data0Val1(0), data1Val1(0), data2Val1(0), flags(0),
+ Button() : nextButton(0), index(0), keyCode(0), keyCode2(0), data0Val1(0), data1Val1(0), data2Val1(0), data3Val1(0), flags(0),
data0ShapePtr(0), data1ShapePtr(0), data2ShapePtr(0), data0Callback(), data1Callback(), data2Callback(),
dimTableIndex(0), x(0), y(0), width(0), height(0), data0Val2(0), data0Val3(0), data1Val2(0), data1Val3(0),
- data2Val2(0), data2Val3(0), flags2(0), mouseWheel(0), buttonCallback(), arg(0) {}
+ data2Val2(0), data2Val3(0), data3Val2(0), data3Val3(0), flags2(0), mouseWheel(0), buttonCallback(), arg(0) {}
Button *nextButton;
uint16 index;
@@ -54,6 +54,7 @@ struct Button {
byte data0Val1;
byte data1Val1;
byte data2Val1;
+ byte data3Val1;
uint16 flags;
@@ -78,6 +79,9 @@ struct Button {
uint8 data2Val2;
uint8 data2Val3;
+ uint8 data3Val2;
+ uint8 data3Val3;
+
uint16 flags2;
int8 mouseWheel;
diff --git a/engines/kyra/gui_eob.cpp b/engines/kyra/gui_eob.cpp
new file mode 100644
index 0000000000..9aafb76189
--- /dev/null
+++ b/engines/kyra/gui_eob.cpp
@@ -0,0 +1,2165 @@
+/* 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.
+ *
+ */
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#include "kyra/eobcommon.h"
+#include "kyra/gui_eob.h"
+#include "kyra/timer.h"
+#include "kyra/util.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void LolEobBaseEngine::removeInputTop() {
+ if (!_eventList.empty()) {
+ if (_eventList.begin()->event.type == Common::EVENT_LBUTTONDOWN)
+ _mouseClick = 1;
+ else if (_eventList.begin()->event.type == Common::EVENT_RBUTTONDOWN)
+ _mouseClick = 2;
+ else
+ _mouseClick = 0;
+
+ _eventList.erase(_eventList.begin());
+ }
+}
+
+void LolEobBaseEngine::gui_drawBox(int x, int y, int w, int h, int frameColor1, int frameColor2, int fillColor) {
+ w--; h--;
+ if (fillColor != -1)
+ screen()->fillRect(x + 1, y + 1, x + w - 1, y + h - 1, fillColor);
+
+ screen()->drawClippedLine(x + 1, y, x + w, y, frameColor2);
+ screen()->drawClippedLine(x + w, y, x + w, y + h - 1, frameColor2);
+ screen()->drawClippedLine(x, y, x, y + h, frameColor1);
+ screen()->drawClippedLine(x, y + h, x + w, y + h, frameColor1);
+}
+
+void LolEobBaseEngine::gui_drawHorizontalBarGraph(int x, int y, int w, int h, int32 cur, int32 max, int col1, int col2) {
+ if (max < 1)
+ return;
+ if (cur < 0)
+ cur = 0;
+
+ int32 e = MIN(cur, max);
+
+ if (!--w)
+ return;
+ if (!--h)
+ return;
+
+ int32 t = (e * w) / max;
+
+ if (!t && e)
+ t++;
+
+ if (t)
+ screen()->fillRect(x, y, x + t - 1, y + h, col1);
+
+ if (t < w && col2)
+ screen()->fillRect(x + t, y, x + w, y + h, col2);
+}
+
+void LolEobBaseEngine::gui_initButtonsFromList(const int16 *list) {
+ while (*list != -1)
+ gui_initButton(*list++);
+}
+
+void LolEobBaseEngine::gui_resetButtonList() {
+ for (uint i = 0; i < ARRAYSIZE(_activeButtonData); ++i)
+ _activeButtonData[i].nextButton = 0;
+
+ gui_notifyButtonListChanged();
+ _activeButtons = 0;
+}
+
+void LolEobBaseEngine::gui_notifyButtonListChanged() {
+ if (gui()) {
+ if (!_buttonListChanged && !_preserveEvents)
+ removeInputTop();
+ _buttonListChanged = true;
+ }
+}
+
+bool LolEobBaseEngine::clickedShape(int shapeIndex) {
+ if (_clickedSpecialFlag != 0x40)
+ return true;
+
+ for (; shapeIndex; shapeIndex = _levelDecorationProperties[shapeIndex].next) {
+ if (_flags.gameID != GI_LOL)
+ shapeIndex--;
+
+ uint16 s = _levelDecorationProperties[shapeIndex].shapeIndex[1];
+
+ if (s == 0xffff)
+ continue;
+
+ int w = _flags.gameID == GI_LOL ? _levelDecorationShapes[s][3] : (_levelDecorationShapes[s][2] << 3);
+ int h = _levelDecorationShapes[s][_flags.gameID == GI_LOL ? 2 : 1];
+ int x = _levelDecorationProperties[shapeIndex].shapeX[1] + _clickedShapeXOffs;
+ int y = _levelDecorationProperties[shapeIndex].shapeY[1] + _clickedShapeYOffs;
+
+ if (_levelDecorationProperties[shapeIndex].flags & 1) {
+ if (_flags.gameID == GI_LOL)
+ w <<= 1;
+ else
+ x = 176 - x - w;
+ }
+
+ if (posWithinRect(_mouseX, _mouseY, x - 4, y - 4, x + w + 8, y + h + 8))
+ return true;
+ }
+
+ return false;
+}
+
+#ifdef ENABLE_EOB
+
+Button *EobCoreEngine::gui_getButton(Button *buttonList, int index) {
+ while (buttonList) {
+ if (buttonList->index == index)
+ return buttonList;
+ buttonList = buttonList->nextButton;
+ }
+
+ return 0;
+}
+
+void EobCoreEngine::gui_drawPlayField(int pageNum) {
+ _screen->loadEobCpsFileToPage("PLAYFLD", 0, 5, 3, 2);
+ int cp = _screen->setCurPage(2);
+ gui_drawCompass(true);
+
+ if (pageNum && !_sceneDrawPage1)
+ drawScene(0);
+
+ _screen->setCurPage(cp);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ _screen->loadEobCpsFileToPage("INVENT", 0, 5, 3, 2);
+}
+
+void EobCoreEngine::gui_restorePlayField() {
+ loadVcnData(0, 0);
+ _screen->_curPage = 0;
+ gui_drawPlayField(1);
+ gui_drawAllCharPortraitsWithStats();
+}
+
+void EobCoreEngine::gui_drawAllCharPortraitsWithStats() {
+ for (int i = 0; i < 6; i++)
+ gui_drawCharPortraitWithStats(i);
+}
+
+void EobCoreEngine::gui_drawCharPortraitWithStats(int index) {
+ if (!testCharacter(index, 1))
+ return;
+
+ static const uint16 charPortraitPosX[] = { 8, 80, 184, 256 };
+ static const uint16 charPortraitPosY[] = { 2, 54, 106 };
+
+ EobCharacter *c = &_characters[index];
+ int txtCol1 = 12;
+ int txtCol2 = 15;
+
+ if ((_flags.gameID == GI_EOB1 && c->flags & 6) || (_flags.gameID == GI_EOB2 && c->flags & 0x0e)) {
+ txtCol1 = 8;
+ txtCol2 = 6;
+ }
+
+ char tmpStr[10];
+
+ if (_currentControlMode == 0) {
+ int x2 = charPortraitPosX[index & 1];
+ int y2 = charPortraitPosY[index >> 1];
+ Screen::FontId cf = _screen->setFont(Screen::FID_6_FNT);
+
+ _screen->copyRegion(176, 168, x2 , y2, 64, 24, 2, 2, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(240, 168, x2, y2 + 24, 64, 26, 2, 2, Screen::CR_NO_P_CHECK);
+ int cp = _screen->setCurPage(2);
+
+ if (index == _exchangeCharacterId)
+ _screen->printText(_characterGuiStringsSt[0], x2 + 2, y2 + 2, 8, _bkgColor_1);
+ else
+ _screen->printText(c->name, x2 + 2, y2 + 2, txtCol1, _bkgColor_1);
+
+ gui_drawFaceShape(index);
+ gui_drawWeaponSlot(index, 0);
+ gui_drawWeaponSlot(index, 1);
+ gui_drawHitpoints(index);
+
+ if (testCharacter(index, 2))
+ gui_drawCharPortraitStatusFrame(index);
+
+ if (c->damageTaken > 0) {
+ _screen->drawShape(2, _redSplatShape, x2 + 13, y2 + 30, 0);
+ sprintf(tmpStr, "%d", c->damageTaken);
+ _screen->printText(tmpStr, x2 + 34 - (strlen(tmpStr) * 3), y2 + 42, 15, 0);
+ }
+
+ _screen->setCurPage(cp);
+ _screen->setFont(cf);
+
+ if (!cp) {
+ _screen->copyRegion(x2, y2, charPortraitPosX[2 + (index & 1)], y2, 64, 50, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ }
+ } else if ((_currentControlMode == 1 || _currentControlMode == 2) && index == _updateCharNum) {
+ _screen->copyRegion(176, 0, 0, 0, 144, 168, 2, 2, Screen::CR_NO_P_CHECK);
+ _screen->_curPage = 2;
+ gui_drawFaceShape(index);
+ _screen->printShadedText(c->name, 219, 6, txtCol2, _bkgColor_1);
+ gui_drawHitpoints(index);
+ gui_drawFoodStatusGraph(index);
+
+ if (_currentControlMode == 1) {
+ if (c->hitPointsCur == -10)
+ _screen->printShadedText(_characterGuiStringsSt[1], 247, 158, 6, _color6);
+ else if (c->hitPointsCur < 1)
+ _screen->printShadedText(_characterGuiStringsSt[2], 226, 158, 6, _color6);
+ else if (c->effectFlags & (_flags.gameID == GI_EOB1 ? 0x80 : 0x2000))
+ _screen->printShadedText(_characterGuiStringsSt[3], 220, 158, 6, _color6);
+ else if (c->flags & 2)
+ _screen->printShadedText(_characterGuiStringsSt[4], 235, 158, 6, _color6);
+ else if (c->flags & 4)
+ _screen->printShadedText(_characterGuiStringsSt[5], 232, 158, 6, _color6);
+ else if (c->flags & 8)
+ _screen->printShadedText(_characterGuiStringsSt[6], 232, 158, 6, _color6);
+
+ for (int i = 0; i < 27; i++)
+ gui_drawInventoryItem(i, 0, 2);
+ gui_drawInventoryItem(16, 1, 2);
+
+ } else {
+ static const uint16 cm2X1[] = { 179, 272, 301 };
+ static const uint16 cm2Y1[] = { 36, 51, 51 };
+ static const uint16 cm2X2[] = { 271, 300, 318 };
+ static const uint16 cm2Y2[] = { 165, 165, 147 };
+
+ for (int i = 0; i < 3; i++)
+ _screen->fillRect(cm2X1[i], cm2Y1[i], cm2X2[i], cm2Y2[i], _color6);
+
+ _screen->printShadedText(_characterGuiStringsIn[0], 183, 42, 15, _color6);
+ _screen->printText(_chargenClassStrings[c->cClass], 183, 55, 12, _color6);
+ _screen->printText(_chargenAlignmentStrings[c->alignment], 183, 62, 12, _color6);
+ _screen->printText(_chargenRaceSexStrings[c->raceSex], 183, 69, 12, _color6);
+
+ for (int i = 0; i < 6; i++)
+ _screen->printText(_chargenStatStrings[6 + i], 183, 82 + i * 7, 12, _color6);
+
+ _screen->printText(_characterGuiStringsIn[1], 183, 124, 12, _color6);
+ _screen->printText(_characterGuiStringsIn[2], 239, 138, 12, _color6);
+ _screen->printText(_characterGuiStringsIn[3], 278, 138, 12, _color6);
+
+ _screen->printText(getCharStrength(c->strengthCur, c->strengthExtCur), 275, 82, 15, _color6);
+ sprintf(tmpStr, "%d", c->intelligenceCur);
+ _screen->printText(tmpStr, 275, 89, 15, _color6);
+ sprintf(tmpStr, "%d", c->wisdomCur);
+ _screen->printText(tmpStr, 275, 96, 15, _color6);
+ sprintf(tmpStr, "%d", c->dexterityCur);
+ _screen->printText(tmpStr, 275, 103, 15, _color6);
+ sprintf(tmpStr, "%d", c->constitutionCur);
+ _screen->printText(tmpStr, 275, 110, 15, _color6);
+ sprintf(tmpStr, "%d", c->charismaCur);
+ _screen->printText(tmpStr, 275, 117, 15, _color6);
+ sprintf(tmpStr, "%d", c->armorClass);
+ _screen->printText(tmpStr, 275, 124, 15, _color6);
+
+ for (int i = 0; i < 3; i++) {
+ int t = getClassHpIncreaseType(c->cClass, i);
+ if (t == -1)
+ continue;
+
+ _screen->printText(_chargenClassStrings[t + 15], 180, 145 + 7 * i, 12, _color6);
+ sprintf(tmpStr, "%d", c->experience[i]);
+ _screen->printText(tmpStr, 251 - strlen(tmpStr) * 3, 145 + 7 * i, 15, _color6);
+ sprintf(tmpStr, "%d", c->level[i]);
+ _screen->printText(tmpStr, 286 - strlen(tmpStr) * 3, 145 + 7 * i, 15, _color6);
+ }
+ }
+
+ _screen->_curPage = 0;
+ _screen->copyRegion(176, 0, 176, 0, 144, 168, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 176, 0, 144, 168, 2, 2, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ }
+}
+
+void EobCoreEngine::gui_drawFaceShape(int index) {
+ if (!testCharacter(index, 1))
+ return;
+
+ static const uint8 xCoords[] = { 8, 80 };
+ static const uint8 yCoords[] = { 11, 63, 115 };
+
+ int x = xCoords[index & 1];
+ int y = yCoords[index >> 1];
+
+ if (!_screen->_curPage)
+ x += 176;
+
+ if (_currentControlMode) {
+ if (_updateCharNum != index)
+ return;
+
+ x = 181;
+ y = 3;
+ }
+
+ EobCharacter *c = &_characters[index];
+
+ if (c->hitPointsCur == -10) {
+ _screen->drawShape(_screen->_curPage, _deadCharShape, x, y, 0);
+ return;
+ }
+
+ if (_flags.gameID == GI_EOB1) {
+ if (c->effectFlags & 4) {
+ _screen->fillRect(x, y, x + 31, y + 31, 12);
+ return;
+ }
+ } else {
+ if (c->effectFlags & 0x140) {
+ _screen->setFadeTableIndex(1);
+ _screen->setShapeFadeMode(1, true);
+ }
+
+ if (c->flags & 2) {
+ _screen->setFadeTableIndex(0);
+ _screen->setShapeFadeMode(1, true);
+ }
+
+ if (c->flags & 8) {
+ _screen->setFadeTableIndex(2);
+ _screen->setShapeFadeMode(1, true);
+ }
+ }
+
+ _screen->drawShape(_screen->_curPage, c->faceShape, x, y, 0);
+
+ if (c->hitPointsCur < 1)
+ _screen->drawShape(_screen->_curPage, _disabledCharGrid, x, y, 0);
+
+ //if ((c->flags & 2) || (c->flags & 8) || (c->effectFlags & 0x140)) {
+ _screen->setFadeTableIndex(4);
+ _screen->setShapeFadeMode(1, false);
+ //}
+}
+
+void EobCoreEngine::gui_drawWeaponSlot(int charIndex, int slot) {
+ static const uint8 xCoords[] = { 40, 112 };
+ static const uint8 yCoords[] = { 11, 27, 63, 79, 115, 131 };
+
+ int x = xCoords[charIndex & 1];
+ int y = yCoords[(charIndex & 6) + slot];
+
+ if (!_screen->_curPage)
+ x += 176;
+
+ int itm = _characters[charIndex].inventory[slot];
+ gui_drawBox(x, y, 31, 16, _color1_1, _color2_1, _bkgColor_1);
+
+ if (_characters[charIndex].slotStatus[slot]) {
+ gui_drawWeaponSlotStatus(x, y, _characters[charIndex].slotStatus[slot]);
+ return;
+ }
+
+ if (itm)
+ drawItemIconShape(_screen->_curPage, itm, x + 8, y);
+ else if (!slot && checkScriptFlag(0x8000))
+ _screen->drawShape(_screen->_curPage, _itemIconShapes[103], x + 8, y, 0);
+ else
+ _screen->drawShape(_screen->_curPage, _itemIconShapes[85], x + 8, y, 0);
+
+ if ((_characters[charIndex].disabledSlots & (1 << slot)) || !validateWeaponSlotItem(charIndex, slot) || (_characters[charIndex].hitPointsCur <= 0) || (_characters[charIndex].flags & 0x0c))
+ _screen->drawShape(_screen->_curPage, _weaponSlotGrid, x, y, 0);
+}
+
+void EobCoreEngine::gui_drawWeaponSlotStatus(int x, int y, int status) {
+ char tmpStr[6];
+ char tmpStr2[6];
+ tmpStr2[0] = 0;
+
+ if (status > -3 || status == -5)
+ _screen->drawShape(_screen->_curPage, _greenSplatShape, x - 1, y, 0);
+ else
+ gui_drawBox(x, y, 31, 16, _color9, _color10, _color11);
+
+ switch (status + 5) {
+ case 0:
+ strcpy(tmpStr, _characterGuiStringsWp[2]);
+ break;
+ case 1:
+ strcpy(tmpStr, _characterGuiStringsWr[2]);
+ strcpy(tmpStr2, _characterGuiStringsWr[3]);
+ break;
+ case 2:
+ strcpy(tmpStr, _characterGuiStringsWr[0]);
+ strcpy(tmpStr2, _characterGuiStringsWr[1]);
+ break;
+ case 3:
+ strcpy(tmpStr, _characterGuiStringsWp[1]);
+ break;
+ case 4:
+ strcpy(tmpStr, _characterGuiStringsWp[0]);
+ break;
+ default:
+ snprintf(tmpStr, 6, "%d", status);
+ break;
+ }
+
+ if (tmpStr2[0]) {
+ _screen->printText(tmpStr, x + (16 - strlen(tmpStr) * 3), y + 2, 15, 0);
+ _screen->printText(tmpStr2, x + (16 - strlen(tmpStr) * 3), y + 9, 15, 0);
+ } else {
+ _screen->printText(tmpStr, x + (16 - strlen(tmpStr) * 3), y + 5, 15, 0);
+ }
+}
+
+void EobCoreEngine::gui_drawHitpoints(int index) {
+ if (!testCharacter(index, 1))
+ return;
+
+ if (_currentControlMode && (index != _updateCharNum))
+ return;
+
+ static const uint8 xCoords[] = { 23, 95 };
+ static const uint8 yCoords[] = { 46, 98, 150 };
+ static const uint8 barColor[] = { 3, 5, 8 };
+
+ int x = xCoords[index & 1];
+ int y = yCoords[index >> 1];
+ int w = 38;
+ int h = 3;
+
+ if (!_screen->_curPage)
+ x += 176;
+
+ if (_currentControlMode) {
+ x = 250;
+ y = 16;
+ w = 51;
+ h = 5;
+ }
+
+ EobCharacter *c = &_characters[index];
+
+ if (_hpBarGraphs) {
+ int bgCur = c->hitPointsCur + 10;
+ int bgMax = c->hitPointsMax + 10;
+ int col = ((bgMax / 3) > bgCur) ? 1 : 0;
+ if (bgCur <= 10)
+ col = 2;
+
+ if (!_currentControlMode)
+ _screen->printText(_characterGuiStringsHp[0], x - 13, y - 1, 12, 0);
+
+
+ gui_drawHorizontalBarGraph(x, y, w, h, bgCur, bgMax, barColor[col], _color5);
+
+ } else {
+ char tmpString[12];
+ snprintf(tmpString, 12, _characterGuiStringsHp[1], c->hitPointsCur, c->hitPointsMax);
+
+ if (!_currentControlMode) {
+ x -= 13;
+ y -= 1;
+ }
+
+ _screen->printText(tmpString, x, y, 12, _bkgColor_1);
+ }
+}
+
+void EobCoreEngine::gui_drawFoodStatusGraph(int index) {
+ if (!_currentControlMode)
+ return;
+
+ if (!testCharacter(index, 1))
+ return;
+
+ EobCharacter *c = &_characters[index];
+ if (!(c->flags & 1))
+ return;
+
+ if (index != _updateCharNum)
+ return;
+
+ uint8 col = c->food < 20 ? 8 : (c->food < 33 ? 5 : 3);
+ gui_drawHorizontalBarGraph(250, 25, 51, 5, c->food, 100, col, _color5);
+}
+
+void EobCoreEngine::gui_drawHorizontalBarGraph(int x, int y, int w, int h, int32 curVal, int32 maxVal, int col1, int col2) {
+ gui_drawBox(x - 1, y - 1, w + 3, h + 2, _color2_1, _color1_1, -1);
+ LolEobBaseEngine::gui_drawHorizontalBarGraph(x, y, w + 2, h, curVal, maxVal, col1, col2);
+}
+
+void EobCoreEngine::gui_drawCharPortraitStatusFrame(int index) {
+ uint8 boxColor = ((_partyEffectFlags & 0x20000) | (_partyEffectFlags & 0xffff)) ? 4 : 6;
+
+ static const uint8 xCoords[] = { 8, 80 };
+ static const uint8 yCoords[] = { 2, 54, 106 };
+ int x = xCoords[index & 1];
+ int y = yCoords[index >> 1];
+
+ if (!_screen->_curPage)
+ x += 176;
+
+ EobCharacter *c = &_characters[index];
+
+ int v8 = (_flags.gameID == GI_EOB2 && ((c->effectFlags & 0x4818) || c->effectsRemainder[0] || c->effectsRemainder[1] || ((_partyEffectFlags & 0x20000) | (_partyEffectFlags & 0xffff)))) ||
+ (_flags.gameID == GI_EOB1 && ((c->effectFlags & 0x302) || c->effectsRemainder[0] || c->effectsRemainder[1])) ? 1 : 0;
+ int vA = (_flags.gameID == GI_EOB2 && ((((c->effectFlags & 0x3000) | (c->effectFlags & 0x10000)) || (_partyEffectFlags & 0x8420)))) ||
+ (_flags.gameID == GI_EOB1 && ((c->effectFlags & 0x4c8) || _partyEffectFlags & 300000))? 1 : 0;
+
+ if (v8 || vA) {
+ if (v8 && !vA) {
+ _screen->drawBox(x, y, x + 63, y + 49, boxColor);
+ return;
+ }
+
+ if (vA && !v8) {
+ _screen->drawBox(x, y, x + 63, y + 49, 5);
+ return;
+ }
+
+ int iX= x;
+ int iY= y;
+
+ for (int i = 0; i < 64; i += 16) {
+ x = iX + i;
+ if (v8) {
+ _screen->drawClippedLine(x, y, x + 7, y, boxColor);
+ _screen->drawClippedLine(x + 8, y + 49, x + 15, y + 49, boxColor);
+ }
+ if (vA) {
+ _screen->drawClippedLine(x + 8, y, x + 15, y, 5);
+ _screen->drawClippedLine(x, y + 49, x + 7, y + 49, 5);
+ }
+ }
+
+ x = iX;
+
+ for (int i = 1; i < 48; i += 12) {
+ y = iY + i - 1;
+
+ if (vA) {
+ _screen->drawClippedLine(x, y + 1, x, y + 6, 5);
+ _screen->drawClippedLine(x + 63, y + 7, x + 63, y + 12, 5);
+ }
+ if (v8) {
+ _screen->drawClippedLine(x, y + 7, x, y + 12, boxColor);
+ _screen->drawClippedLine(x + 63, y + 1, x + 63, y + 6, boxColor);
+ }
+ }
+
+ } else {
+ _screen->drawClippedLine(x, y, x + 62, y, _color1_1);
+ _screen->drawClippedLine(x, y + 49, x + 62, y + 49, _color2_1);
+ _screen->drawClippedLine(x - 1, y, x - 1, y + 50, 12);
+ _screen->drawClippedLine(x + 63, y, x + 63, y + 50, 12);
+ }
+}
+
+void EobCoreEngine::gui_drawInventoryItem(int slot, int special, int pageNum) {
+ int x = _inventorySlotsX[slot];
+ int y = _inventorySlotsY[slot];
+
+ int item = _characters[_updateCharNum].inventory[slot];
+ int cp = _screen->setCurPage(pageNum);
+
+ if (special) {
+ int wh = (slot == 25 || slot == 26) ? 10 : 18;
+ gui_drawBox(x - 1, y - 1, wh, wh, _color1_1, _color2_1, slot == 16 ? -1 : _bkgColor_1);
+
+ if (slot == 16) {
+ _screen->fillRect(227, 65, 238, 69, 12);
+ int cnt = countQueuedItems(_characters[_updateCharNum].inventory[slot], -1, -1, 1, 1);
+ x = cnt >= 10 ? 227 : 233;
+ char str[3];
+ snprintf(str, 3, "%d", cnt);
+ _screen->printText(str, x, 65, 15, 0);
+ }
+ }
+
+ if (slot != 16 && item) {
+ if (slot == 25 || slot == 26) {
+ x -= 4;
+ y -= 4;
+ }
+ drawItemIconShape(pageNum, item, x, y);
+ }
+ _screen->_curPage = cp;
+ _screen->updateScreen();
+}
+
+void EobCoreEngine::gui_drawCompass(bool force) {
+ if (_currentDirection == _compassDirection && !force)
+ return;
+
+ static const uint8 shpX[2][3] = { { 0x70, 0x4D, 0x95 }, { 0x72, 0x4F, 0x97 } };
+ static const uint8 shpY[2][3] = { { 0x7F, 0x9A, 0x9A }, { 0x83, 0x9E, 0x9E } };
+ int g = _flags.gameID == GI_EOB1 ? 0 : 1;
+
+ for (int i = 0; i < 3; i++)
+ _screen->drawShape(_screen->_curPage, _compassShapes[(i << 2) + _currentDirection], shpX[g][i], shpY[g][i], 0);
+
+ _compassDirection = _currentDirection;
+}
+
+void EobCoreEngine::gui_drawDialogueBox() {
+ gui_drawBox(0, 121, 320, 79, _color1_1, _color2_1, _bkgColor_1);
+ txt()->clearCurDim();
+}
+
+void EobCoreEngine::gui_drawSpellbook() {
+ _screen->setCurPage(2);
+ int numTab = (_flags.gameID == GI_EOB1) ? 5 : 6;
+ _screen->copyRegion(64, 121, 64, 121, 112, 56, 0, 2, Screen::CR_NO_P_CHECK);
+
+ for (int i = 0; i < numTab; i++) {
+ int col1 = _color14;
+ int col2 = _color13;
+ int col3 = _color12;
+
+ if (i == _openBookSpellLevel) {
+ col1 = _color1_1;
+ col2 = _color2_1;
+ col3 = _bkgColor_1;
+ }
+
+ if (_flags.gameID == GI_EOB1) {
+ gui_drawBox(i * 21 + 71, 122, 21, 9, col1, col2, col3);
+ _screen->printText(_magicStrings7[i], i * 21 + 73, 123, 12, 0);
+ } else {
+ gui_drawBox(i * 18 + 68, 121, 18, 9, col1, col2, col3);
+ char val[3];
+ sprintf(val, "%d", i + 1);
+ _screen->printText(val, i * 18 + 75, 123, 12, 0);
+ }
+ }
+
+ if (_flags.gameID == GI_EOB1)
+ gui_drawBox(71, 131, 105, 44, _color1_1, _color2_1, _bkgColor_1);
+ else {
+ gui_drawBox(68, 130, 108, 47, _color1_1, _color2_1, _bkgColor_1);
+ gui_drawBox(68, 168, 78, 9, _color8, _color7, _color6);
+ gui_drawBox(146, 168, 14, 9, _color8, _color7, _color6);
+ gui_drawBox(160, 168, 16, 9, _color8, _color7, _color6);
+ gui_drawSpellbookScrollArrow(150, 169, 0);
+ gui_drawSpellbookScrollArrow(165, 169, 1);
+ }
+
+ int textCol1 = 15;
+ int textCol2 = 8;
+ int textXa = 74;
+ int textXs = 71;
+ int textY = 170;
+ int col3 = _bkgColor_1;
+
+ if (_flags.gameID == GI_EOB1) {
+ textCol2 = 11;
+ textXa = textXs = 73;
+ textY = 168;
+ }
+
+ for (int i = 0; i < 7; i++) {
+ int d = _openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellListOffset + i];
+ if (_openBookSpellSelectedItem == i) {
+ if (d >= 0 && i < 6 && (i + _openBookSpellListOffset) < 9) {
+ _screen->printText(_openBookSpellList[d], textXs, 132 + 6 * i, textCol1, textCol2);
+ } else if (i == 6) {
+ if (_flags.gameID == GI_EOB2)
+ _screen->fillRect(69, 169, 144, 175, textCol2);
+ _screen->printText(_magicStrings1[0], textXa, textY, textCol1, textCol2);
+ }
+ } else {
+ if (d >= 0 && i < 6 && (i + _openBookSpellListOffset) < 9)
+ _screen->printText(_openBookSpellList[d], textXs, 132 + 6 * i, textCol1, col3);
+ else
+ _screen->printText(_magicStrings1[0], textXa, textY, 12, _color6);
+ }
+ }
+
+ if (_characters[_openBookChar].disabledSlots & 4) {
+ static const uint8 xpos[] = { 0x44, 0x62, 0x80, 0x90 };
+ static const uint8 ypos[] = { 0x82, 0x92, 0x98 };
+ for (int yc = 0; yc < 3; yc++) {
+ for (int xc = 0; xc < 4; xc++)
+ _screen->drawShape(_screen->_curPage, _weaponSlotGrid, xpos[xc], ypos[yc], 0);
+ }
+ }
+
+ if (_openBookAvailableSpells[_openBookSpellLevel * 10 + 6] <= 0)
+ _screen->drawShape(2, _blackBoxWideGrid, 146, 168, 0);
+
+ _screen->setCurPage(0);
+ _screen->copyRegion(64, 121, 64, 121, 112, 56, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+}
+
+void EobCoreEngine::gui_drawSpellbookScrollArrow(int x, int y, int direction) {
+ static const uint8 x1[] = { 0, 2, 1, 0, 2, 2 };
+ static const uint8 x2[] = { 2, 4, 5, 6, 4, 4 };
+ if (direction) {
+ _screen->setPagePixel(_screen->_curPage, x + 3, y + 5, 12);
+ for (int i = 1; i < 6; i++)
+ _screen->drawClippedLine(x + x1[i], (5 - i) + y, x + x2[i], (5 - i) + y, 12);
+ } else {
+ _screen->setPagePixel(_screen->_curPage, x + 3, y, 12);
+ for (int i = 1; i < 6; i++)
+ _screen->drawClippedLine(x + x1[i], y + i, x + x2[i], y + i, 12);
+ }
+}
+
+void EobCoreEngine::gui_updateSlotAfterScrollUse() {
+ _characters[_openBookChar].disabledSlots ^= (1 << (--_castScrollSlot));
+ setCharEventTimer(_openBookChar, 18, _castScrollSlot + 2, 1);
+ gui_drawCharPortraitWithStats(_openBookChar);
+ _openBookChar = _openBookCharBackup;
+ _openBookType = _openBookTypeBackup;
+ _castScrollSlot = 0;
+ gui_toggleButtons();
+}
+
+void EobCoreEngine::gui_updateControls() {
+ Button b;
+ if (_currentControlMode)
+ clickedPortraitRestore(&b);
+ if (_updateFlags)
+ clickedSpellbookAbort(&b);
+}
+
+void EobCoreEngine::gui_toggleButtons() {
+ if (_currentControlMode == 0)
+ gui_setPlayFieldButtons();
+ else if (_currentControlMode == 1)
+ gui_setInventoryButtons();
+ else if (_currentControlMode == 2)
+ gui_setStatsListButtons();
+}
+
+void EobCoreEngine::gui_setPlayFieldButtons() {
+ gui_resetButtonList();
+ gui_initButtonsFromList(_updateFlags ? _buttonList2 : _buttonList1);
+}
+
+void EobCoreEngine::gui_setInventoryButtons() {
+ gui_resetButtonList();
+ gui_initButtonsFromList(_updateFlags ? _buttonList5 : _buttonList3);
+}
+
+void EobCoreEngine::gui_setStatsListButtons() {
+ gui_resetButtonList();
+ gui_initButtonsFromList(_updateFlags ? _buttonList6 : _buttonList4);
+}
+
+void EobCoreEngine::gui_setSwapCharacterButtons() {
+ gui_resetButtonList();
+ gui_initButtonsFromList(_buttonList7);
+}
+
+void EobCoreEngine::gui_setCastOnWhomButtons() {
+ gui_resetButtonList();
+ gui_initButtonsFromList(_buttonList8);
+}
+
+void EobCoreEngine::gui_initButton(int index, int, int, int) {
+ Button *b = 0;
+ int cnt = 1;
+
+ if (_flags.gameID == GI_EOB1 && index > 92)
+ return;
+
+ if (_activeButtons) {
+ Button *n = _activeButtons;
+ while (n->nextButton) {
+ ++cnt;
+ n = n->nextButton;
+ }
+
+ ++cnt;
+ b = n->nextButton = &_activeButtonData[cnt];
+ } else {
+ b = &_activeButtonData[0];
+ _activeButtons = b;
+ }
+
+ *b = Button();
+ b->data0Val2 = 12;
+ b->data1Val2 = b->data2Val2 = 15;
+ b->data3Val2 = 8;
+
+ b->index = index + 1;
+
+ const EobGuiButtonDef *d = &_buttonDefs[index];
+
+ if (_flags.gameID == GI_EOB1) {
+ // EOB1 spellbook modifications
+ if (index > 61 && index < 67)
+ d = &_buttonDefs[index + 33];
+ if (index == 88)
+ d = &_buttonDefs[index + 12];
+ }
+
+ b->x = d->x;
+ b->y = d->y;
+ b->width = d->w;
+ b->height = d->h;
+
+ // EOB1 spellbook modifications
+ if (_flags.gameID == GI_EOB1 && ((index > 66 && index < 73) || (index > 76 && index < 79)))
+ b->y++;
+
+ b->flags = d->flags;
+ b->keyCode = d->keyCode;
+ b->keyCode2 = d->keyCode2;
+ b->arg = d->arg;
+ b->buttonCallback = d->buttonCallback;
+}
+
+int EobCoreEngine::clickedCharPortraitDefault(Button *button) {
+ if (!testCharacter(button->arg, 1))
+ return 1;
+
+ gui_processCharPortraitClick(button->arg);
+ return 0;
+}
+
+int EobCoreEngine::clickedCamp(Button *button) {
+ return button->arg;
+}
+
+int EobCoreEngine::clickedSceneDropPickupItem(Button *button) {
+ uint16 block = _currentBlock;
+ if (button->arg > 1) {
+ block = calcNewBlockPosition(_currentBlock, _currentDirection);
+ int f = _wllWallFlags[_levelBlockProperties[block].walls[_sceneDrawVarDown]];
+ if (!(f & 0x0b))
+ return 1;
+ }
+ int d = _dropItemDirIndex[(_currentDirection << 2) + button->arg];
+
+ if (_itemInHand) {
+ setItemPosition((Item*)&_levelBlockProperties[block & 0x3ff].drawObjects, block, _itemInHand, d);
+ setHandItem(0);
+ runLevelScript(block, 4);
+ } else {
+ d = getQueuedItem((Item*)&_levelBlockProperties[block].drawObjects, d, -1);
+ if (!d)
+ return 1;
+ setHandItem(d);
+ runLevelScript(block, 8);
+ }
+
+ _sceneUpdateRequired = true;
+ return 1;
+}
+
+int EobCoreEngine::clickedCharPortrait2(Button *button) {
+ if (!_gui->_progress) {
+ if (!testCharacter(button->arg, 1))
+ return button->index;
+ }
+
+ _currentControlMode = 1;
+ if (!_gui->_progress)
+ _updateCharNum = button->arg;
+
+ _screen->copyRegion(176, 0, 0, 0, 144, 168, 0, 5, Screen::CR_NO_P_CHECK);
+ gui_drawCharPortraitWithStats(_updateCharNum);
+ gui_setInventoryButtons();
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedWeaponSlot(Button *button) {
+ if (!testCharacter(button->arg, 1))
+ return 1;
+
+ static const uint8 sY[] = { 24, 24, 80, 80, 136, 136 };
+ int slot = sY[button->arg] > _mouseY ? 0 : 1;
+
+ if ((_gui->_flagsMouseLeft & 0x7f) == 1)
+ gui_processWeaponSlotClickLeft(button->arg, slot);
+ else
+ gui_processWeaponSlotClickRight(button->arg, slot);
+
+ return 1;
+}
+
+int EobCoreEngine::clickedCharNameLabelRight(Button *button) {
+ if (!testCharacter(button->arg, 1))
+ return button->index;
+
+ if (_updateFlags) {
+ Button b;
+ clickedSpellbookAbort(&b);
+ }
+
+ if (_exchangeCharacterId == -1) {
+ _exchangeCharacterId = button->arg;
+ gui_setSwapCharacterButtons();
+ gui_drawCharPortraitWithStats(_exchangeCharacterId);
+ enableTimer(0);
+ } else {
+ int d = _exchangeCharacterId;
+ _exchangeCharacterId = -1;
+
+ EobCharacter temp;
+ memcpy(&temp, &_characters[d], sizeof(EobCharacter));
+ memcpy(&_characters[d], &_characters[button->arg], sizeof(EobCharacter));
+ memcpy(&_characters[button->arg], &temp, sizeof(EobCharacter));
+
+ _timer->disable(0);
+ gui_drawCharPortraitWithStats(d);
+ gui_processCharPortraitClick(button->arg);
+ gui_drawCharPortraitWithStats(button->arg);
+ gui_setPlayFieldButtons();
+ setupCharacterTimers();
+ }
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedInventorySlot(Button *button) {
+ gui_processInventorySlotClick(button->arg);
+ return button->index;
+}
+
+int EobCoreEngine::clickedEatItem(Button *button) {
+ eatItemInHand(_updateCharNum);
+ return button->index;
+}
+
+int EobCoreEngine::clickedInventoryPrevChar(Button *button) {
+ if (_gui->_progress == 1)
+ _updateCharNum = 0;
+ else if (_gui->_progress == 2)
+ _updateCharNum = 1;
+ else
+ _updateCharNum = getNextValidCharIndex(_updateCharNum, -1);
+
+ gui_drawCharPortraitWithStats(_updateCharNum);
+ return button->index;
+}
+
+int EobCoreEngine::clickedInventoryNextChar(Button *button) {
+ int oldVal = _updateCharNum;
+ int v = button->arg == 2 ? 2 : 0;
+
+ if (_gui->_progress == 1)
+ _updateCharNum = v + 2;
+ else if (_gui->_progress == 2)
+ _updateCharNum = v + 3;
+ else
+ _updateCharNum = getNextValidCharIndex(_updateCharNum, 1);
+
+ if (!testCharacter(_updateCharNum, 1)) {
+ _updateCharNum = oldVal;
+ return 1;
+ }
+
+ gui_drawCharPortraitWithStats(_updateCharNum);
+ return button->index;
+}
+
+int EobCoreEngine::clickedSpellbookTab(Button *button) {
+ _openBookSpellLevel = button->arg;
+ _openBookSpellListOffset = 0;
+
+ for (_openBookSpellSelectedItem = 0; _openBookSpellSelectedItem < 6; _openBookSpellSelectedItem++) {
+ if (_openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellSelectedItem] > 0)
+ break;
+ }
+
+ gui_drawSpellbook();
+
+ _characters[_openBookChar].slotStatus[3] = _openBookSpellLevel;
+ _characters[_openBookChar].slotStatus[2] = _openBookSpellSelectedItem;
+ _characters[_openBookChar].slotStatus[4] = _openBookSpellListOffset;
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedSpellbookList(Button *button) {
+ int listIndex = button->arg;
+ bool spellLevelAvailable = false;
+
+ if (listIndex == 6) {
+ for (int i = 0; i < 10; i++) {
+ if (_openBookAvailableSpells[_openBookSpellLevel * 10 + i] > 0) {
+ spellLevelAvailable = true;
+ break;
+ }
+ }
+ if (!spellLevelAvailable)
+ return button->index;
+
+ int v = (_gui->_progress == 1) ? -1 : ((_gui->_progress == 2) ? 1 : 0);
+
+ _openBookSpellSelectedItem += _openBookSpellListOffset;
+ if (_openBookSpellSelectedItem == 12 || (_openBookSpellSelectedItem == 6 && _openBookSpellListOffset == 0))
+ _openBookSpellSelectedItem = 9;
+
+ do {
+ _openBookSpellSelectedItem += v;
+ int s = (_openBookSpellSelectedItem >= 0) ? _openBookSpellSelectedItem : 9;
+ _openBookSpellSelectedItem = (s <= 9) ? s : 0;
+ } while (_openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellSelectedItem] <= 0 && _openBookSpellSelectedItem != 9);
+
+ if (_openBookSpellSelectedItem >= 6) {
+ _openBookSpellListOffset = 6;
+ if (_openBookSpellSelectedItem == 9)
+ _openBookSpellSelectedItem = 6;
+ else
+ _openBookSpellSelectedItem -= 6;
+ } else {
+ _openBookSpellListOffset = 0;
+ }
+
+ if (_openBookSpellListOffset == 6 && _openBookAvailableSpells[_openBookSpellLevel * 10 + 6] <= 0)
+ _openBookSpellListOffset = 0;
+
+ gui_drawSpellbook();
+
+ } else {
+ if (listIndex == 7 || _openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellListOffset + listIndex] > 0) {
+ if (listIndex < 6) {
+ if (_openBookSpellListOffset + listIndex < 9)
+ _openBookSpellSelectedItem= listIndex;
+ else if (listIndex != 7)
+ return button->index;
+ } else if (listIndex != 7) {
+ return button->index;
+ }
+
+ if (_openBookSpellSelectedItem < 6 && ((_openBookSpellSelectedItem + _openBookSpellListOffset) < 9)) {
+ if (_characters[_openBookChar].disabledSlots & 4)
+ return button->index;
+
+ gui_drawSpellbook();
+
+ int s = _openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellListOffset + _openBookSpellSelectedItem];
+ if (_openBookType == 1)
+ s += _mageSpellListSize;
+
+ castSpell(s, 0);
+
+ } else if ((_openBookSpellSelectedItem == 6 && listIndex == 7) || (_openBookSpellSelectedItem != 6 && listIndex == 6) ) {
+ Button b;
+ clickedSpellbookAbort(&b);
+ }
+ }
+ }
+
+ _characters[_openBookChar].slotStatus[2] = _openBookSpellSelectedItem;
+ _characters[_openBookChar].slotStatus[4] = _openBookSpellListOffset;
+ return button->index;
+}
+
+int EobCoreEngine::clickedCastSpellOnCharacter(Button *button) {
+ _activeSpellCaster = button->arg;
+
+ if (_activeSpellCaster == 255) {
+ _txt->printMessage(_magicStrings3[1]);
+ snd_playSoundEffect(79);
+ if (_castScrollSlot) {
+ gui_updateSlotAfterScrollUse();
+ } else {
+ gui_toggleButtons();
+ gui_drawSpellbook();
+ }
+ } else {
+ if (_characters[_activeSpellCaster].flags & 1)
+ startSpell(_activeSpell);
+ }
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedInventoryNextPage(Button *button) {
+ if (_currentControlMode == 2) {
+ gui_setInventoryButtons();
+ _currentControlMode = 1;
+ } else {
+ gui_setStatsListButtons();
+ _currentControlMode = 2;
+ }
+
+ gui_drawCharPortraitWithStats(_updateCharNum);
+ return button->index;
+}
+
+int EobCoreEngine::clickedPortraitRestore(Button *button) {
+ _currentControlMode = 0;
+ _screen->_curPage = 2;
+ _screen->copyRegion(0, 0, 0, 0, 144, 168, 5, _screen->_curPage, Screen::CR_NO_P_CHECK);
+ gui_drawAllCharPortraitsWithStats();
+ _screen->_curPage = 0;
+ _screen->copyRegion(0, 0, 176, 0, 144, 168, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ gui_setPlayFieldButtons();
+ return button->index;
+}
+
+int EobCoreEngine::clickedUpArrow(Button *button) {
+ int b = calcNewBlockPositionAndTestPassability(_currentBlock, _currentDirection);
+
+ if (b == -1) {
+ notifyBlockNotPassable();
+ } else {
+ moveParty(b);
+ _sceneDefaultUpdate = 1;
+ }
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedDownArrow(Button *button) {
+ int b = calcNewBlockPositionAndTestPassability(_currentBlock, (_currentDirection + 2) & 3);
+
+ if (b == -1) {
+ notifyBlockNotPassable();
+ } else {
+ moveParty(b);
+ _sceneDefaultUpdate = 1;
+ }
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedLeftArrow(Button *button) {
+ int b = calcNewBlockPositionAndTestPassability(_currentBlock, (_currentDirection - 1) & 3);
+
+ if (b == -1) {
+ notifyBlockNotPassable();
+ } else {
+ moveParty(b);
+ _sceneDefaultUpdate = 1;
+ }
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedRightArrow(Button *button) {
+ int b = calcNewBlockPositionAndTestPassability(_currentBlock, (_currentDirection + 1) & 3);
+
+ if (b == -1) {
+ notifyBlockNotPassable();
+ } else {
+ moveParty(b);
+ _sceneDefaultUpdate = 1;
+ }
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedTurnLeftArrow(Button *button) {
+ _currentDirection = (_currentDirection - 1) & 3;
+ //_keybControlUnk = -1;
+ _sceneDefaultUpdate = 1;
+ _sceneUpdateRequired = true;
+ return button->index;
+}
+
+int EobCoreEngine::clickedTurnRightArrow(Button *button) {
+ _currentDirection = (_currentDirection + 1) & 3;
+ //_keybControlUnk = -1;
+ _sceneDefaultUpdate = 1;
+ _sceneUpdateRequired = true;
+ return button->index;
+}
+
+int EobCoreEngine::clickedAbortCharSwitch(Button *button) {
+ _timer->disable(0);
+ int c = _exchangeCharacterId;
+ _exchangeCharacterId = -1;
+ gui_drawCharPortraitWithStats(c);
+ gui_setPlayFieldButtons();
+ return button->index;
+}
+
+int EobCoreEngine::clickedSceneThrowItem(Button *button) {
+ if (!_itemInHand)
+ return button->index;
+
+ if (launchObject(_updateCharNum, _itemInHand, _currentBlock, _dropItemDirIndex[(_currentDirection << 2) + button->arg], _currentDirection, _items[_itemInHand].type)) {
+ setHandItem(0);
+ _sceneUpdateRequired = true;
+ }
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedSceneSpecial(Button *button) {
+ _clickedSpecialFlag = 0x40;
+ return specialWallAction(calcNewBlockPosition(_currentBlock, _currentDirection), _currentDirection);
+}
+
+int EobCoreEngine::clickedSpellbookAbort(Button *button) {
+ _updateFlags = 0;
+ _screen->copyRegion(0, 0, 64, 121, 112, 56, 10, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ gui_drawCompass(true);
+ gui_toggleButtons();
+ return button->index;
+}
+
+int EobCoreEngine::clickedSpellbookScroll(Button *button) {
+ if (_openBookAvailableSpells[_openBookSpellLevel * 10] > 0) {
+ _openBookSpellListOffset ^= 6;
+ _openBookSpellSelectedItem = 0;
+ } else {
+ _openBookSpellListOffset = 6;
+ }
+
+ _characters[_openBookChar].slotStatus[2] = _openBookSpellSelectedItem;
+ _characters[_openBookChar].slotStatus[4] = _openBookSpellListOffset;
+
+ gui_drawSpellbook();
+
+ return button->index;
+}
+
+int EobCoreEngine::clickedUnk(Button *button) {
+ return button->index;
+}
+
+void EobCoreEngine::gui_processCharPortraitClick(int index) {
+ if (index == _updateCharNum)
+ return;
+
+ int a = _updateCharNum;
+ _updateCharNum = index;
+
+ gui_drawCharPortraitWithStats(a);
+ gui_drawCharPortraitWithStats(index);
+}
+
+void EobCoreEngine::gui_processWeaponSlotClickLeft(int charIndex, int slotIndex) {
+ int itm = _characters[charIndex].inventory[slotIndex];
+ if (_items[itm].flags & 0x20)
+ return;
+
+ int ih = _itemInHand;
+ int t = _items[ih].type;
+ uint16 v = (ih) ? _itemTypes[t].invFlags : 0xffff;
+
+ if (v & _slotValidationFlags[slotIndex]) {
+ setHandItem(itm);
+ _characters[charIndex].inventory[slotIndex] = ih;
+ gui_drawCharPortraitWithStats(charIndex);
+ }
+
+ recalcArmorClass(charIndex);
+}
+
+void EobCoreEngine::gui_processWeaponSlotClickRight(int charIndex, int slotIndex) {
+ const char * const *strs = &_itemExtraStrings[_flags.gameID == GI_EOB1 ? 17 : (_flags.lang == Common::DE_DEU ? 26 : 22)];
+
+ if (!testCharacter(charIndex, 0x0d))
+ return;
+
+ uint16 itm = _characters[charIndex].inventory[slotIndex];
+ int wslot = slotIndex < 2 ? slotIndex : -1;
+
+ if (slotIndex < 2 && (!validateWeaponSlotItem(charIndex, slotIndex) || (!_currentControlMode && (_characters[charIndex].disabledSlots & (1 << slotIndex)))))
+ return;
+
+ if (!itemUsableByCharacter(charIndex, itm))
+ _txt->printMessage(strs[0], -1, _characters[charIndex].name);
+
+ if (!itm && slotIndex > 1)
+ return;
+
+ int8 tp = _items[itm].type;
+ int8 vl = _items[itm].value;
+ uint8 ep = _itemTypes[tp].extraProperties & 0x7f;
+
+ switch (ep) {
+ case 0:
+ case 16:
+ // Item automatically used when worn
+ _txt->printMessage(strs[1]);
+ break;
+
+ case 1:
+ case 2:
+ case 3:
+ // Weapons
+ if (!_currentControlMode)
+ useSlotWeapon(charIndex, slotIndex, itm);
+ break;
+
+ case 4:
+ case 8:
+ case 12:
+ case 13:
+ case 15:
+ // Item not used that way
+ _txt->printMessage(strs[2]);
+ break;
+
+ case 5:
+ case 6:
+ // Cleric holy symbol / mage spell book
+ if (!_currentControlMode)
+ useMagicBookOrSymbol(charIndex, ep == 6 ? 1 : 0);
+ break;
+
+ case 7:
+ // Food ration
+ /* don't do anything if mouse control is enabled */
+ //eatItemInHand(charIndex);
+ break;
+
+ case 10:
+ if (_flags.gameID == GI_EOB1)
+ vl += _clericSpellOffset;
+ case 9:
+ // Mage/Cleric Scroll
+ if (!_currentControlMode)
+ useMagicScroll(charIndex, vl, wslot);
+ break;
+
+ case 11:
+ // Letters, Notes, Maps
+ displayParchment(vl);
+ break;
+
+ case 14:
+ // Potion
+ usePotion(charIndex, wslot);
+ break;
+
+ case 18:
+ ep = ep;
+ break;
+
+ case 19:
+ // eob2 horn
+ ep = ep;
+ break;
+
+ case 20:
+ if (vl == 1)
+ inflictCharacterDamage(charIndex, 200);
+ else
+ useMagicScroll(charIndex, 55, wslot);
+ deleteInventoryItem(charIndex, wslot);
+ break;
+
+ default:
+ break;
+ }
+
+ if (ep == 1 && charIndex >= 2)
+ return;
+
+ _lastUsedItem = itm;
+ runLevelScript(calcNewBlockPosition(_currentBlock, _currentDirection), 0x100);
+ _lastUsedItem = 0;
+}
+
+void EobCoreEngine::gui_processInventorySlotClick(int slot) {
+ int itm = _characters[_updateCharNum].inventory[slot];
+ int ih = _itemInHand;
+ if (!validateInventorySlotForItem(ih, _updateCharNum, slot))
+ return;
+
+ if (slot == 16) {
+ if (ih) {
+ setItemPosition(&_characters[_updateCharNum].inventory[16], -2, ih, 0);
+ gui_drawInventoryItem(slot, 1, 0);
+ setHandItem(0);
+
+ } else {
+ itm = getQueuedItem(&_characters[_updateCharNum].inventory[16], 0, -1);
+ gui_drawInventoryItem(slot, 1, 0);
+ setHandItem(itm);
+ }
+
+ } else {
+ setHandItem(itm);
+ _characters[_updateCharNum].inventory[slot] = ih;
+ gui_drawInventoryItem(slot, 1, 0);
+ recalcArmorClass(_updateCharNum);
+ }
+}
+
+GUI_Eob::GUI_Eob(EobCoreEngine *vm) : GUI(vm), _vm(vm), _screen(vm->_screen) {
+ _scrollUpFunctor = _scrollDownFunctor = BUTTON_FUNCTOR(GUI_Eob, this, 0);
+
+ _redrawButtonFunctor = BUTTON_FUNCTOR(GUI, this, &GUI::redrawButtonCallback);
+ _redrawShadedButtonFunctor = BUTTON_FUNCTOR(GUI, this, &GUI::redrawShadedButtonCallback);
+
+ _specialProcessButton = _backupButtonList = 0;
+ _flagsMouseLeft = _flagsMouseRight = _flagsModifier = 0;
+ _backupButtonList = 0;
+ _progress = 0;
+ _prcButtonUnk3 = 1;
+ _cflag = 0xffff;
+
+ _menuLineSpacing = 0;
+ _menuUnk1 = 0;
+ _menuLastInFlags = 0;
+ _menuCur = 0;
+ _menuNumItems = 0;
+}
+
+void GUI_Eob::processButton(Button *button) {
+ if (!button->data0Val1 && !button->data2Val1 && !button->data1Val1)
+ return;
+
+ if ((button->flags & 0x18) == 0x18)
+ return;
+
+ int sd = button->dimTableIndex;
+ const ScreenDim *dm = _screen->getScreenDim(sd);
+
+ int fx = button->x;
+ if (fx < 0)
+ fx += (dm->w << 3);
+
+ int sx = fx + (dm->sx << 3);
+
+ int fy = button->y;
+ if (fy < 0)
+ fy += dm->h;
+
+ int sy = fy + dm->sy;
+
+ uint16 fw = button->width;
+ uint16 fh = button->height;
+
+ uint8 col1 = button->data1Val1;
+ uint8 col2 = button->data1Val3;
+
+ int fx2 = sx + fw - 1;
+ int fy2 = sy + fh - 1;
+
+ if (button->flags2 & 1) {
+ if (button->data1Val1 == 1) {
+ if (button->data0Val1 == 1) {
+ _screen->drawShape(_screen->_curPage, button->data1ShapePtr, fx, fy, sd);
+ } else if (button->data0Val1 == 2) {
+ if (!(button->flags2 & 4))
+ _screen->printText((const char*) button->data1ShapePtr, sx, sy, col1, col2);
+ } else if (button->data0Val1 == 3) {
+ // nullsub (at least EOBII)
+ } else if (button->data0Val1 == 4) {
+ if (button->data1Callback)
+ (*button->data1Callback.get())(button);
+ }
+ } else if (button->data1Val1 == 2) {
+ if (!(button->flags2 & 4))
+ _screen->drawBox(sx, sy, fx2, fy2, col1);
+ } else if (button->data1Val1 == 3) {
+ // nullsub (at least EOBII)
+ } else if (button->data1Val1 == 4) {
+ if (button->data1Callback)
+ (*button->data1Callback.get())(button);
+ }
+ }
+
+ if (button->flags2 & 4) {
+ if (button->data2Val1 == 1) {
+ if (button->data0Val1 == 1) {
+ _screen->drawShape(_screen->_curPage, button->data2ShapePtr, fx, fy, sd);
+ } else if (button->data0Val1 == 2) {
+ if (button->flags2 & 1)
+ _screen->printText((const char*) button->data2ShapePtr, sx, sy, button->data3Val2, button->data3Val3);
+ else
+ _screen->printText((const char*) button->data2ShapePtr, sx, sy, button->data2Val2, button->data2Val3);
+ } else if (button->data0Val1 == 3) {
+ // nullsub (at least EOBII)
+ } else if (button->data0Val1 == 4) {
+ if (button->data2Callback)
+ (*button->data2Callback.get())(button);
+ }
+ } else if (button->data2Val1 == 2) {
+ _screen->drawBox(sx, sy, fx2, fy2, (button->flags2 & 1) ? button->data3Val2 : button->data2Val2);
+ } else if (button->data2Val1 == 3) {
+ // nullsub (at least EOBII)
+ } else if (button->data2Val1 == 4) {
+ if (button->data2Callback)
+ (*button->data2Callback.get())(button);
+ }
+ }
+
+ if (!(button->flags2 & 5)) {
+ if (button->data0Val1 == 1) {
+ _screen->drawShape(_screen->_curPage, button->data0ShapePtr, fx, fy, sd);
+ } else if (button->data0Val1 == 2) {
+ _screen->printText((const char*) button->data0ShapePtr, sx, sy, button->data0Val2, button->data0Val3);
+ } else if (button->data0Val1 == 3) {
+ // nullsub (at least EOBII)
+ } else if (button->data0Val1 == 4) {
+ if (button->data0Callback)
+ (*button->data0Callback.get())(button);
+ } else if (button->data0Val1 == 5) {
+ _screen->drawBox(sx, sy, fx2, fy2, button->data0Val2);
+ } else {
+ if (!button->data0Val1) {
+ if(button->data1Val1 == 2 || button->data2Val1 == 2) {
+ _screen->drawBox(sx, sy, fx2, fy2, button->data0Val2);
+ } else {
+ // nullsub (at least EOBII)
+ }
+ }
+ }
+ }
+}
+
+int GUI_Eob::processButtonList(Kyra::Button *buttonList, uint16 inputFlags, int8 mouseWheel) {
+ _progress = 0;
+ uint16 in = inputFlags & 0xff;
+ uint16 buttonReleaseFlag = 0;
+ bool clickEvt = false;
+
+ _flagsMouseLeft = (_vm->_mouseClick == 1) ? 2 : 4;
+ _flagsMouseRight = (_vm->_mouseClick == 2) ? 2 : 4;
+ _vm->_mouseClick = 0;
+
+ if (in >= 199 && in <= 202) {
+ buttonReleaseFlag = (inputFlags & 0x800) ? 3 : 1;
+ if (in < 201)
+ _flagsMouseLeft = buttonReleaseFlag;
+ else
+ _flagsMouseRight = buttonReleaseFlag;
+
+ ////////////////////////////
+ if (!buttonList && !(inputFlags & 0x800))
+ return inputFlags & 0xff;
+ ////////////////////////////
+
+ inputFlags = 0;
+ clickEvt = true;
+ } else {
+ inputFlags &= 0xff;
+ }
+
+ uint16 result = 0;
+ bool runLoop = true;
+
+ if (!buttonList)
+ return inputFlags;
+
+ if (_vm->_buttonListChanged || (buttonList != _backupButtonList)) {
+ _backupButtonList = buttonList;
+ _flagsModifier = 0;
+
+ while (runLoop) {
+ processButton(buttonList);
+ _flagsModifier |= (buttonList->flags & 0xAA04);
+
+ // UNUSED
+ //if (buttonList->flags2 & 0x20) {
+ // if (_processButtonListExtraCallback)
+ // this->*_processButtonListExtraCallback(buttonList);
+ //}
+
+ if (buttonList->nextButton)
+ buttonList = buttonList->nextButton;
+ else
+ runLoop = false;
+ }
+
+ _vm->_buttonListChanged = false;
+
+ _specialProcessButton = 0;
+ _prcButtonUnk3 = 1;
+ _cflag = 0xffff;
+ }
+
+ int sd = 0;
+ const ScreenDim *dm = _screen->getScreenDim(sd);
+
+ int x1 = dm->sx << 3;
+ int y1 = dm->sy;
+ int w1 = dm->w << 3;
+ int h1 = dm->h;
+
+ uint16 v8 = 0;
+ uint16 v18 = 0;
+ uint16 v16 = 0;
+
+ if (_specialProcessButton)
+ buttonList = _specialProcessButton;
+
+ while (runLoop) {
+ if (buttonList->flags & 8) {
+ buttonList = buttonList->nextButton;
+ runLoop = buttonList ? true : false;
+ continue;
+ }
+
+ int vc = 0;
+ int v6 = 0;
+ uint16 iFlag = buttonList->index | 0x8000;
+ uint16 flgs2 = buttonList->flags2;
+ uint16 flgs = buttonList->flags;
+
+ if (flgs2 & 1)
+ flgs2 |= 8;
+ else
+ flgs2 &= 0xfff7;
+
+ if (flgs2 & 4)
+ flgs2 |= 0x10;
+ else
+ flgs2 &= 0xffef;
+
+ uint16 vL = 0;
+ uint16 vR = 0;
+
+ if (inputFlags) {
+ if (buttonList->keyCode == in) {
+ _progress = 1;
+ _flagsMouseLeft = 1;
+ flgs2 ^= 1;
+ result = iFlag;
+ v6 = 1;
+ } else if (buttonList->keyCode2 == in) {
+ _progress = 2;
+ _flagsMouseRight = 1;
+ result = iFlag;
+ v6 = 1;
+ }
+ } else if (_flagsModifier || clickEvt) {
+ vL = flgs & 0xf00;
+ vR = flgs & 0xf000;
+
+ if (_prcButtonUnk3) {
+ if (sd != buttonList->dimTableIndex) {
+ sd = buttonList->dimTableIndex;
+ dm = _screen->getScreenDim(sd);
+ x1 = dm->sx << 3;
+ y1 = dm->sy;
+ w1 = dm->w << 3;
+ h1 = dm->h;
+ }
+
+ int x2 = x1;
+ if (buttonList->x < 0)
+ x2 += w1;
+ x2 += buttonList->x;
+
+ int y2 = y1;
+ if (buttonList->y < 0)
+ y2 += h1;
+ y2 += buttonList->y;
+
+ if (_vm->_mouseX >= x2 && _vm->_mouseX <= (x2 + buttonList->width) && _vm->_mouseY >= y2 && _vm->_mouseY <= (y2 + buttonList->height)) {
+ flgs2 |= 2;
+
+ if (vL) {
+ switch (_flagsMouseLeft - 1) {
+ case 0:
+ v18 = 1;
+
+ if ((flgs & 4) && buttonList->data2Val1) {
+ flgs2 |= 4;
+ vc = 1;
+ } else {
+ flgs2 &= 0xfffb;
+ }
+
+ if (flgs & 0x100) {
+ v6 = 1;
+ if (!(flgs & 1)) {
+ flgs2 ^= 1;
+ result = iFlag;
+ }
+ }
+
+ if (flgs & 0x40) {
+ _specialProcessButton = buttonList;
+ v8 = 1;
+ }
+
+ _cflag = flgs;
+ break;
+
+ case 1:
+ if (flgs != _cflag)
+ break;
+
+ if ((flgs & 4) && buttonList->data2Val1) {
+ flgs2 |= 4;
+ vc = 1;
+ } else {
+ flgs2 &= 0xfffb;
+ }
+
+ if (!(flgs & 0x200))
+ break;
+
+ v6 = 1;
+
+ if (flgs & 1)
+ break;
+
+ flgs2 |= 1;
+ result = iFlag;
+ break;
+
+ case 2:
+ if (_cflag != flgs)
+ break;
+
+ if (flgs & 0x400) {
+ v6 = 1;
+ if (flgs & 1) {
+ flgs2 ^= 1;
+ result = iFlag;
+ }
+ }
+
+ if ((flgs & 2) && (flgs2 & 1))
+ flgs2 &= 0xfffe;
+ break;
+
+ case 3:
+ if ((flgs & 4) || (!buttonList->data2Val1))
+ flgs2 &= 0xfffb;
+ else
+ flgs2 |= 4;
+
+ if (flgs & 0x800) {
+ v6 = 1;
+ break;
+ }
+
+ if ((flgs & 2) && (flgs2 & 1))
+ flgs2 &= 0xfffe;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (vR && !v6 && !vc) {
+ switch (_flagsMouseRight - 1) {
+ case 0:
+ v18 = 1;
+
+ if ((flgs & 4) && buttonList->data2Val1)
+ flgs2 |= 4;
+ else
+ flgs2 &= 0xfffb;
+
+ if (flgs & 0x1000) {
+ v6 = 1;
+ if (!(flgs & 1)) {
+ flgs2 ^= 1;
+ result = iFlag;
+ }
+ }
+
+ if (flgs & 0x40) {
+ _specialProcessButton = buttonList;
+ v8 = 1;
+ }
+
+ _cflag = flgs;
+ break;
+
+ case 1:
+ if (flgs != _cflag)
+ break;
+
+ if ((flgs & 4) && buttonList->data2Val1)
+ flgs2 |= 4;
+ else
+ flgs2 &= 0xfffb;
+
+ if (!(flgs & 0x2000))
+ break;
+
+ v6 = 1;
+
+ if (flgs & 1)
+ break;
+
+ flgs2 |= 1;
+ result = iFlag;
+ break;
+ case 2:
+ if (_cflag != flgs)
+ break;
+
+ if (flgs & 0x4000) {
+ v6 = 1;
+ if (flgs & 1) {
+ flgs2 ^= 1;
+ result = iFlag;
+ }
+ }
+
+ if ((flgs & 2) && (flgs2 & 1))
+ flgs2 &= 0xfffe;
+ break;
+
+ case 3:
+ if ((flgs & 4) || (!buttonList->data2Val1))
+ flgs2 &= 0xfffb;
+ else
+ flgs2 |= 4;
+
+ if (flgs & 0x8000) {
+ v6 = 1;
+ break;
+ }
+
+ if ((flgs & 2) && (flgs2 & 1))
+ flgs2 &= 0xfffe;
+ break;
+
+ default:
+ break;
+ }
+ }
+ } else { // if (_vm->_mouseX >= x2 && _vm->_mouseX <= (x2 + buttonList->width)....)
+ flgs2 &= 0xfff9;
+
+ if ((flgs & 0x40) && (!(flgs & 0x80)) && _specialProcessButton && !v8) {
+ static const uint16 flagsTable[] = { 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000 };
+
+ if (vL) {
+ v16 = flagsTable[_flagsMouseLeft - 1];
+ if (v16 & flgs)
+ v6 = 1;
+ }
+
+ if (vR && !v6) {
+ v16 = flagsTable[_flagsMouseRight + 3];
+ if (v16 & flgs)
+ v6 = 1;
+ }
+
+ if (!v6) {
+ _specialProcessButton = 0;
+ _prcButtonUnk3 = 1;
+ }
+ }
+
+ if ((flgs & 2) && (flgs2 & 1))
+ flgs2 &= 0xfffe;
+ } // end if (_vm->_mouseX >= x2 && _vm->_mouseX <= (x2 + buttonList->width)....)
+ } // end if (_prcButtonUnk3)
+ } // end if (_flagsModifier || clickEvt)
+
+ buttonList->flags = flgs;
+ buttonList->flags2 = flgs2;
+
+ bool f21 = (flgs2 & 8) ? true : false;
+ bool f22 = (flgs2 & 1) ? true : false;
+ bool f23 = (flgs2 & 0x10) ? true : false;
+ bool f24 = (flgs2 & 4) ? true : false;
+
+ if (f21 != f22 || f23 != f24)
+ processButton(buttonList);
+
+ if (v6 && buttonList->buttonCallback)
+ runLoop = ((*buttonList->buttonCallback.get())(buttonList)) ? false : true;
+
+ if ((flgs2 & 2) && (flgs & 0x20))
+ runLoop = false;
+
+ if (_specialProcessButton && ((vL && _flagsMouseLeft == 3) || (vR && _flagsMouseRight == 3))) {
+ _specialProcessButton = 0;
+ _prcButtonUnk3 = 1;
+ runLoop = false;
+ }
+
+ if (_specialProcessButton && !v8)
+ runLoop = false;
+
+ buttonList = buttonList->nextButton;
+ if (!buttonList)
+ runLoop = false;
+ };
+
+ if ((_flagsMouseLeft == 1 || _flagsMouseRight == 1) && !v18)
+ _cflag = 0xffff;
+
+ if (!result)
+ result = inputFlags;
+
+ return result;
+}
+
+void GUI_Eob::setupMenu(int sd, int maxItem, const char *const *strings, int32 menuItemsMask, int unk, int lineSpacing) {
+ initMenuItemsMask(sd, maxItem, menuItemsMask, unk);
+
+ const ScreenDim *dm = _screen->getScreenDim(19 + sd);
+ int x = (_screen->_curDim->sx + dm->sx) << 3;
+ int y = _screen->_curDim->sy + dm->sy;
+
+ int v = getMenuItem(_menuCur, menuItemsMask, unk);
+
+ for (int i = 0; i < _menuNumItems; i++) {
+ int item = getMenuItem(i, menuItemsMask, unk);
+ int ty = y + i * (lineSpacing + _screen->getFontHeight());
+ _screen->printShadedText(strings[item], x, ty, dm->unkA, 0);
+ if (item == v)
+ _screen->printText(strings[item], x, ty, dm->unkC, 0);
+ }
+
+ _screen->updateScreen();
+ _menuLineSpacing = lineSpacing;
+ _menuUnk1 = 0;
+ _menuLastInFlags = 0;
+ _vm->removeInputTop();
+}
+
+int GUI_Eob::handleMenu(int sd, const char *const *strings, void *b, int32 menuItemsMask, int unk) {
+ const ScreenDim *dm = _screen->getScreenDim(19 + sd);
+ int h = _menuNumItems - 1;
+ int currentItem = _menuCur % _menuNumItems;
+ int newItem = currentItem;
+ int result = -1;
+ int lineH = (_menuLineSpacing + _screen->getFontHeight());
+ int lineS1 = _menuLineSpacing >> 1;
+ int x = (_screen->_curDim->sx + dm->sx) << 3;
+ int y = _screen->_curDim->sy + dm->sy;
+
+ int inFlag = _vm->checkInput(0, false, 0) & 0x8ff;
+ _vm->removeInputTop();
+ Common::Point mousePos = _vm->getMousePos();
+
+ int x1 = (_screen->_curDim->sx << 3) + (dm->sx * _screen->getFontWidth());
+ int y1 = _screen->_curDim->sy + dm->sy - lineS1;
+ int x2 = x1 + (dm->w * _screen->getFontWidth()) - 1;
+ int y2 = y1 + _menuNumItems * lineH - 1;
+ if (_vm->posWithinRect(mousePos.x, mousePos.y, x1, y1, x2, y2))
+ newItem = (mousePos.y - y1) / lineH;
+
+ if (inFlag == 199 || inFlag == 201) {
+ if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, x1, y1, x2, y2))
+ result = newItem = (_vm->_mouseY - y1) / lineH;
+ } else if (inFlag == _vm->_keyMap[Common::KEYCODE_RETURN] || inFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inFlag == _vm->_keyMap[Common::KEYCODE_KP5]) {
+ result = newItem;
+ } else if (inFlag == _vm->_keyMap[Common::KEYCODE_HOME] || inFlag == _vm->_keyMap[Common::KEYCODE_KP7] || inFlag == _vm->_keyMap[Common::KEYCODE_PAGEUP] || inFlag == _vm->_keyMap[Common::KEYCODE_KP9]) {
+ newItem = 0;
+ } else if (inFlag == _vm->_keyMap[Common::KEYCODE_END] || inFlag == _vm->_keyMap[Common::KEYCODE_KP1] || inFlag == _vm->_keyMap[Common::KEYCODE_PAGEDOWN] || inFlag == _vm->_keyMap[Common::KEYCODE_KP3]) {
+ newItem = h;
+ } else if (inFlag == _vm->_keyMap[Common::KEYCODE_UP] || inFlag == _vm->_keyMap[Common::KEYCODE_KP8]) {
+ if (--newItem < 0)
+ newItem = h;
+ } else if (inFlag == _vm->_keyMap[Common::KEYCODE_DOWN] || inFlag == _vm->_keyMap[Common::KEYCODE_KP2]) {
+ if (++newItem > h)
+ newItem = 0;
+ } else {
+ _menuLastInFlags = inFlag;
+ }
+
+ if (newItem != currentItem) {
+ _screen->printText(strings[getMenuItem(currentItem, menuItemsMask, unk)], x, y + currentItem * lineH , dm->unkA, 0);
+ _screen->printText(strings[getMenuItem(newItem, menuItemsMask, unk)], x, y + newItem * lineH , dm->unkC, 0);
+ _screen->updateScreen();
+ }
+
+ if (result != -1) {
+ result = getMenuItem(result, menuItemsMask, unk);
+ menuFlashSelection(strings[result], x, y + newItem * lineH, dm->unkA, dm->unkC, 0);
+ }
+
+ _menuCur = newItem;
+
+ return result;
+}
+
+void GUI_Eob::initMenuItemsMask(int menuId, int maxItem, int32 menuItemsMask, int unk) {
+ if (menuItemsMask == -1) {
+ _menuNumItems = _screen->getScreenDim(19 + menuId)->h;
+ _menuCur = _screen->getScreenDim(19 + menuId)->unk8;
+ return;
+ }
+
+ _menuNumItems = 0;
+
+ for (int i = 0; i < maxItem; i++) {
+ if (menuItemsMask & (1 << (i + unk)))
+ _menuNumItems++;
+ }
+
+ _menuCur = 0;
+}
+
+int GUI_Eob::getMenuItem(int index, int32 menuItemsMask, int unk) {
+ if (menuItemsMask == -1)
+ return index;
+
+ int res = 0;
+ int i = index;
+
+ for (; i; res++) {
+ if (menuItemsMask & (1 << (res + unk)))
+ i--;
+ }
+
+ while (!(menuItemsMask & (1 << (res + unk))))
+ res++;
+
+ return res;
+}
+
+void GUI_Eob::menuFlashSelection(const char *str, int x, int y, int color1, int color2, int color3) {
+ for (int i = 0; i < 3; i++) {
+ _screen->printText(str, x, y, color2, color3);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(32);
+ _screen->printText(str, x, y, color1, color3);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(32);
+ }
+}
+
+int GUI_Eob::getTextInput(char *dest, int x, int y, int destMaxLen, int textColor1, int textColor2, int cursorColor) {
+ uint8 cursorState = 1;
+ char sufx[] = " ";
+
+ int len = strlen(dest);
+ if (len > destMaxLen) {
+ len = destMaxLen;
+ dest[destMaxLen] = 0;
+ }
+
+ int pos = len;
+ if (len >= destMaxLen)
+ pos--;
+
+ _screen->copyRegion((x - 1) << 3, y, 0, 191, (destMaxLen + 2) << 3, 9, 0, 2, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(dest, x << 3, y, textColor1, textColor2);
+
+ uint32 next = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+ sufx[0] = (pos < len) ? dest[pos] : 32;
+ _screen->printText(sufx, (x + pos) << 3, y, textColor1, cursorColor);
+
+ int in = 0;
+
+ do {
+ in = 0;
+ _keyPressed.reset();
+
+ while (!in) {
+ if (next <= _vm->_system->getMillis()) {
+ if (cursorState) {
+ _screen->copyRegion((pos + 1) << 3, 191, (x + pos) << 3, y, 8, 9, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(sufx, (x + pos) << 3, y, textColor1, textColor2);
+ } else {
+ _screen->printText(sufx, (x + pos) << 3, y, textColor1, cursorColor);
+ }
+
+ _screen->updateScreen();
+ cursorState ^= 1;
+ next = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+ }
+
+ _vm->updateInput();
+ for (Common::List<KyraEngine_v1::Event>::const_iterator evt = _vm->_eventList.begin(); evt != _vm->_eventList.end(); ++evt) {
+ if (evt->event.type == Common::EVENT_KEYDOWN) {
+ _keyPressed = evt->event.kbd;
+ in = _keyPressed.ascii;
+ }
+ }
+ _vm->removeInputTop();
+ }
+
+ if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE) {
+ if (pos >= len && len > 0) {
+ dest[--len] = 0;
+ pos--;
+
+ } else if (pos > 0) {
+ for (int i = pos; i < destMaxLen; i++)
+ dest[i - 1] = dest[i];
+ dest[--len] = 0;
+ pos--;
+ }
+
+ } else if (_keyPressed.keycode == Common::KEYCODE_LEFT || _keyPressed.keycode == Common::KEYCODE_KP4) {
+ if (pos > 0)
+ pos--;
+
+ } else if (_keyPressed.keycode == Common::KEYCODE_RIGHT || _keyPressed.keycode == Common::KEYCODE_KP6) {
+ if (pos < len && pos < (destMaxLen - 1))
+ pos++;
+
+ } else if (in > 31 && in < 126) {
+ if (!(in == 32 && pos == 0)) {
+ if (in >= 97 && in <= 122)
+ in -=32;
+
+ if (pos < len) {
+ for (int i = destMaxLen - 1; i >= pos; i--)
+ dest[i + 1] = dest[i];
+
+ dest[pos++] = in;
+
+ if (len == destMaxLen)
+ dest[len] = 0;
+
+ } else {
+ if (pos == destMaxLen) {
+ pos--;
+ len--;
+ }
+
+ dest[pos++] = in;
+ dest[pos] = 0;
+ }
+
+ if (++len > destMaxLen)
+ len = destMaxLen;
+
+ if (pos > (destMaxLen - 1))
+ pos = (destMaxLen - 1);
+ }
+ }
+
+ _screen->copyRegion(0, 191, (x - 1) << 3, y, (destMaxLen + 2) << 3, 9, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(dest, x << 3, y, textColor1, textColor2);
+ sufx[0] = (pos < len) ? dest[pos] : 32;
+
+ if (cursorState)
+ _screen->printText(sufx, (x + pos) << 3, y, textColor1, cursorColor);
+ else
+ _screen->printShadedText(sufx, (x + pos) << 3, y, textColor1, textColor2);
+ _screen->updateScreen();
+
+ } while (_keyPressed.keycode != Common::KEYCODE_RETURN && _keyPressed.keycode != Common::KEYCODE_ESCAPE);
+
+ return _keyPressed.keycode == Common::KEYCODE_ESCAPE ? -1 : len;
+}
+
+#endif // ENABLE_EOB
+
+} // End of namespace Kyra
+
+#endif // defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
diff --git a/engines/kyra/gui_eob.h b/engines/kyra/gui_eob.h
new file mode 100644
index 0000000000..82e9476fe0
--- /dev/null
+++ b/engines/kyra/gui_eob.h
@@ -0,0 +1,130 @@
+/* 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.
+ *
+ */
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#ifndef KYRA_GUI_EOB_H
+#define KYRA_GUI_EOB_H
+
+#include "kyra/gui.h"
+
+#ifdef ENABLE_EOB
+
+namespace Kyra {
+
+class DarkMoonEngine;
+class Screen_Eob;
+
+class GUI_Eob : public GUI {
+ friend class EobCoreEngine;
+ friend class CharacterGenerator;
+public:
+ GUI_Eob(EobCoreEngine *vm);
+
+ void initStaticData() {}
+
+ // button specific
+ void processButton(Button *button);
+ int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel);
+
+ int redrawShadedButtonCallback(Button *button) { return 0; }
+ int redrawButtonCallback(Button *button) { return 0; }
+
+ void setupMenu(int sd, int maxItem, const char *const *strings, int32 menuItemsMask, int unk, int lineSpacing);
+ int handleMenu(int sd, const char *const *strings, void *b, int32 menuItemsMask, int unk);
+ int getMenuItem(int index, int32 menuItemsMask, int unk);
+ void menuFlashSelection(const char *str, int x, int y, int color1, int color2, int color3);
+
+ int getTextInput(char *dest, int x, int y, int destMaxLen, int textColor1, int textColor2, int cursorColor);
+
+ //int runMenu(Menu &menu);
+
+ // utilities for thumbnail creation
+ void createScreenThumbnail(Graphics::Surface &dst) {}
+
+private:
+ void initMenuItemsMask(int menuId, int maxItem, int32 menuItemsMask, int unk);
+
+ //void backupPage0();
+ //void restorePage0();
+
+ //void setupSavegameNames(Menu &menu, int num);
+ //void printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 flags);
+
+ //int getMenuCenterStringX(const char *str, int x1, int x2);
+
+ int getInput();
+
+ Button *getButtonListData() { return _menuButtons; }
+ Button *getScrollUpButton() { return &_scrollUpButton; }
+ Button *getScrollDownButton() { return &_scrollDownButton; }
+
+ Button::Callback getScrollUpButtonHandler() const { return _scrollUpFunctor; }
+ Button::Callback getScrollDownButtonHandler() const { return _scrollDownFunctor; }
+
+ uint8 defaultColor1() const { return 0xFE; }
+ uint8 defaultColor2() const { return 0x00; }
+
+ const char *getMenuTitle(const Menu &menu) { return 0; }
+ const char *getMenuItemTitle(const MenuItem &menuItem) { return 0; }
+ const char *getMenuItemLabel(const MenuItem &menuItem) { return 0; }
+
+ Button _menuButtons[10];
+ Button _scrollUpButton;
+ Button _scrollDownButton;
+ //Menu _mainMenu, _gameOptions, _audioOptions, _choiceMenu, _loadMenu, _saveMenu, _deleteMenu, _savenameMenu, _deathMenu;
+ //Menu *_currentMenu, *_lastMenu, *_newMenu;
+ //int _menuResult;
+ //char *_saveDescription;
+
+ EobCoreEngine *_vm;
+ Screen_Eob *_screen;
+
+ bool _pressFlag;
+
+ Button *_specialProcessButton;
+ Button *_backupButtonList;
+ uint16 _flagsMouseLeft;
+ uint16 _flagsMouseRight;
+ uint16 _flagsModifier;
+ uint16 _progress;
+ uint16 _prcButtonUnk3; /// ALWAYS 1?? REMOVE ??
+ uint16 _cflag;
+
+ Button::Callback _scrollUpFunctor;
+ Button::Callback _scrollDownFunctor;
+
+ int _menuLineSpacing;
+ int _menuUnk1;
+ int _menuLastInFlags;
+
+ int _menuCur;
+ int _menuNumItems;
+};
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
+
+#endif
+
+#endif // ENABLE_EOB || ENABLE_LOL
diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp
index 5bef3cd5b5..08ce0bdadd 100644
--- a/engines/kyra/gui_lol.cpp
+++ b/engines/kyra/gui_lol.cpp
@@ -32,6 +32,7 @@
#include "common/savefile.h"
#include "common/system.h"
#include "common/config-manager.h"
+
#include "graphics/scaler.h"
#include "base/version.h"
@@ -213,9 +214,9 @@ void LoLEngine::gui_displayCharInventory(int charNum) {
}
if (_flags.use16ColorMode)
- gui_drawBarGraph(154, 66 + i * 8, 34, 5, b, e, 0x88, 0);
+ gui_drawHorizontalBarGraph(154, 66 + i * 8, 34, 5, b, e, 0x88, 0);
else
- gui_drawBarGraph(154, 64 + i * 10, 34, 5, b, e, 132, 0);
+ gui_drawHorizontalBarGraph(154, 64 + i * 10, 34, 5, b, e, 132, 0);
}
_screen->drawClippedLine(14, 120, 194, 120, 1);
@@ -343,31 +344,6 @@ void LoLEngine::gui_drawCharInventoryItem(int itemIndex) {
_screen->drawShape(_screen->_curPage, getItemIconShapePtr(i), x + 1, y + 1, 0, 0);
}
-void LoLEngine::gui_drawBarGraph(int x, int y, int w, int h, int32 cur, int32 max, int col1, int col2) {
- if (max < 1)
- return;
- if (cur < 0)
- cur = 0;
-
- int32 e = MIN(cur, max);
-
- if (!--w)
- return;
- if (!--h)
- return;
-
- int32 t = (e * w) / max;
-
- if (!t && e)
- t++;
-
- if (t)
- _screen->fillRect(x, y, x + t - 1, y + h, col1);
-
- if (t < w && col2)
- _screen->fillRect(x + t, y, x + w, y + h, col2);
-}
-
void LoLEngine::gui_drawAllCharPortraitsWithStats() {
int numChars = countActiveCharacters();
if (!numChars)
@@ -460,17 +436,6 @@ void LoLEngine::gui_drawCharPortraitWithStats(int charNum) {
_screen->setFont(tmpFid);
}
-void LoLEngine::gui_drawBox(int x, int y, int w, int h, int frameColor1, int frameColor2, int fillColor) {
- w--; h--;
- if (fillColor != -1)
- _screen->fillRect(x + 1, y + 1, x + w - 1, y + h - 1, fillColor);
-
- _screen->drawClippedLine(x + 1, y, x + w, y, frameColor2);
- _screen->drawClippedLine(x + w, y, x + w, y + h - 1, frameColor2);
- _screen->drawClippedLine(x, y, x, y + h, frameColor1);
- _screen->drawClippedLine(x, y + h, x + w, y + h, frameColor1);
-}
-
void LoLEngine::gui_drawCharFaceShape(int charNum, int x, int y, int pageNum) {
if (_characters[charNum].curFaceFrame < 7 && _characters[charNum].tempFaceFrame)
_characters[charNum].curFaceFrame = _characters[charNum].tempFaceFrame;
@@ -853,19 +818,6 @@ void LoLEngine::gui_triggerEvent(int eventType) {
_preserveEvents = true;
}
-void LoLEngine::removeInputTop() {
- if (!_eventList.empty()) {
- if (_eventList.begin()->event.type == Common::EVENT_LBUTTONDOWN)
- _gui->_mouseClick = 1;
- else if (_eventList.begin()->event.type == Common::EVENT_RBUTTONDOWN)
- _gui->_mouseClick = 2;
- else
- _gui->_mouseClick = 0;
-
- _eventList.erase(_eventList.begin());
- }
-}
-
void LoLEngine::gui_enableDefaultPlayfieldButtons() {
gui_resetButtonList();
gui_initButtonsFromList(_buttonList1);
@@ -911,19 +863,6 @@ void LoLEngine::gui_enableCharInventoryButtons(int charNum) {
gui_setFaceFramesControlButtons(21, 0);
}
-void LoLEngine::gui_resetButtonList() {
- for (uint i = 0; i < ARRAYSIZE(_activeButtonData); ++i)
- _activeButtonData[i].nextButton = 0;
-
- gui_notifyButtonListChanged();
- _activeButtons = 0;
-}
-
-void LoLEngine::gui_initButtonsFromList(const int16 *list) {
- while (*list != -1)
- gui_initButton(*list++);
-}
-
void LoLEngine::gui_setFaceFramesControlButtons(int index, int xOffs) {
int c = countActiveCharacters();
for (int i = 0; i < c; i++)
@@ -1009,14 +948,6 @@ void LoLEngine::gui_initButton(int index, int x, int y, int val) {
b->buttonCallback = _buttonCallbacks[index];
}
-void LoLEngine::gui_notifyButtonListChanged() {
- if (_gui) {
- if (!_gui->_buttonListChanged && !_preserveEvents)
- removeInputTop();
- _gui->_buttonListChanged = true;
- }
-}
-
int LoLEngine::clickedUpArrow(Button *button) {
if (button->arg && !_floatingCursorsEnabled)
return 0;
@@ -1333,7 +1264,6 @@ int LoLEngine::clickedExitCharInventory(Button *button) {
int LoLEngine::clickedSceneDropItem(Button *button) {
static const uint8 offsX[] = { 0x40, 0xC0, 0x40, 0xC0 };
static const uint8 offsY[] = { 0x40, 0x40, 0xC0, 0xC0 };
- static const uint8 dirIndex[] = { 0, 1, 2, 3, 1, 3, 0, 2, 3, 2, 1, 0, 2, 0, 3, 1 };
if ((_updateFlags & 1) || !_itemInHand)
return 0;
@@ -1348,7 +1278,7 @@ int LoLEngine::clickedSceneDropItem(Button *button) {
uint16 x = 0;
uint16 y = 0;
- int i = dirIndex[(_currentDirection << 2) + button->arg];
+ int i = _dropItemDirIndex[(_currentDirection << 2) + button->arg];
calcCoordinates(x, y, block, offsX[i], offsY[i]);
setItemPosition(_itemInHand, x, y, 0, 1);
@@ -1917,9 +1847,7 @@ GUI_LoL::GUI_LoL(LoLEngine *vm) : GUI(vm), _vm(vm), _screen(vm->_screen) {
_specialProcessButton = _backUpButtonList = 0;
_flagsModifier = 0;
- _mouseClick = 0;
_sliderSfx = 11;
- _buttonListChanged = false;
_savegameList = 0;
_savegameListSize = 0;
}
@@ -2015,18 +1943,18 @@ int GUI_LoL::processButtonList(Button *buttonList, uint16 inputFlag, int8 mouseW
if (!buttonList)
return inputFlag & 0x7FFF;
- if (_backUpButtonList != buttonList || _buttonListChanged) {
+ if (_backUpButtonList != buttonList || _vm->_buttonListChanged) {
_specialProcessButton = 0;
_flagsModifier = 0;
- if (_mouseClick == 1)
+ if (_vm->_mouseClick == 1)
_flagsModifier |= 0x200;
- if (_mouseClick == 2)
+ if (_vm->_mouseClick == 2)
_flagsModifier |= 0x2000;
- _mouseClick = 0;
+ _vm->_mouseClick = 0;
_backUpButtonList = buttonList;
- _buttonListChanged = false;
+ _vm->_buttonListChanged = false;
while (buttonList) {
processButton(buttonList);
diff --git a/engines/kyra/gui_lol.h b/engines/kyra/gui_lol.h
index af487402f6..9c0c4e2bfe 100644
--- a/engines/kyra/gui_lol.h
+++ b/engines/kyra/gui_lol.h
@@ -162,9 +162,7 @@ private:
Button *_specialProcessButton;
Button *_backUpButtonList;
- bool _buttonListChanged;
uint16 _flagsModifier;
- uint8 _mouseClick;
int _savegameOffset;
int _sliderSfx;
diff --git a/engines/kyra/items_eob.cpp b/engines/kyra/items_eob.cpp
new file mode 100644
index 0000000000..4f6982abff
--- /dev/null
+++ b/engines/kyra/items_eob.cpp
@@ -0,0 +1,614 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/eobcommon.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+namespace Kyra {
+
+void EobCoreEngine::loadItemDefs() {
+ Common::SeekableReadStream *s = _res->createReadStream("item.dat");
+ _numItems = s->readUint16LE();
+
+ for (int i = 0; i < 600; i++)
+ _items[i].block = -1;
+
+ for (int i = 0; i < _numItems; i++) {
+ _items[i].nameUnid = s->readByte();
+ _items[i].nameId = s->readByte();
+ _items[i].flags = s->readByte();
+ _items[i].icon = s->readSByte();
+ _items[i].type = s->readSByte();
+ _items[i].pos = s->readSByte();
+ _items[i].block = s->readSint16LE();
+ _items[i].next = s->readSint16LE();
+ _items[i].prev = s->readSint16LE();
+ _items[i].level = s->readSByte();
+ _items[i].value = s->readSByte();
+ }
+
+ _numItemNames = s->readUint16LE();
+ for (int i = 0; i < _numItemNames; i++)
+ s->read(_itemNames[i], 35);
+
+ delete s;
+
+ s = _res->createReadStream("itemtype.dat");
+ uint16 numTypes = s->readUint16LE();
+
+ _itemTypes = new EobItemType[numTypes];
+ memset(_itemTypes, 0, sizeof(EobItemType) * numTypes);
+
+ for (int i = 0; i < numTypes; i++) {
+ _itemTypes[i].invFlags = s->readUint16LE();
+ _itemTypes[i].handFlags = s->readUint16LE();
+ _itemTypes[i].armorClass = s->readSByte();
+ _itemTypes[i].allowedClasses = s->readSByte();
+ _itemTypes[i].requiredHands = s->readSByte();
+ _itemTypes[i].dmgNumDiceS = s->readSByte();
+ _itemTypes[i].dmgNumPipsS = s->readSByte();
+ _itemTypes[i].dmgIncS = s->readSByte();
+ _itemTypes[i].dmgNumDiceL = s->readSByte();
+ _itemTypes[i].dmgNumPipsL = s->readSByte();
+ _itemTypes[i].dmgIncL = s->readSByte();
+ _itemTypes[i].unk1 = s->readByte();
+ _itemTypes[i].extraProperties = s->readUint16LE();
+ }
+
+ delete s;
+}
+
+Kyra::Item EobCoreEngine::duplicateItem(Item itemIndex) {
+ EobItem *itm = &_items[itemIndex];
+
+ if (itm->block == -1)
+ return 0;
+
+ Item i = 1;
+ bool foundSlot = false;
+
+ for (; i < 600; i++) {
+ if (_items[i].block == -1) {
+ foundSlot = true;
+ break;
+ }
+ }
+
+ if (!foundSlot)
+ return 0;
+
+ memcpy(&_items[i], &_items[itemIndex], sizeof(EobItem));
+ return i;
+}
+
+void EobCoreEngine::setItemPosition(Item *itemQueue, int block, Item item, int pos) {
+ if (!item)
+ return;
+
+ EobItem *itm = &_items[item];
+ itm->pos = pos;
+ itm->block = block;
+ itm->level = block < 0 ? 0xff : _currentLevel;
+
+ if (!*itemQueue) {
+ *itemQueue = itm->next = itm->prev = item;
+ } else {
+ EobItem *itmQ = &_items[*itemQueue];
+ EobItem *itmQN = &_items[itmQ->next];
+ itm->prev = itmQN->prev;
+ itm->next = itmQ->next;
+ *itemQueue = itmQN->prev = itmQ->next = item;
+ }
+}
+
+void EobCoreEngine::createInventoryItem(EobCharacter *c, Item itemIndex, int itemValue, int preferedInventorySlot) {
+ if (itemIndex <= 0)
+ return;
+
+ itemIndex = duplicateItem(itemIndex);
+ _items[itemIndex].flags |= 0x40;
+
+ if (itemValue != -1)
+ _items[itemIndex].value = itemValue;
+
+ if (itemValue && ((_itemTypes[_items[itemIndex].type].extraProperties & 0x7f) < 4))
+ _items[itemIndex].flags |= 0x80;
+
+ if (c->inventory[preferedInventorySlot]) {
+ for (int i = 2; i < 16; i++) {
+ if (!c->inventory[i]) {
+ c->inventory[i] = itemIndex;
+ return;
+ }
+ }
+ } else {
+ c->inventory[preferedInventorySlot] = itemIndex;
+ }
+}
+
+int EobCoreEngine::deleteInventoryItem(int charIndex, int slot) {
+ int itm = (slot == -1) ? _itemInHand : _characters[charIndex].inventory[slot];
+ _items[itm].block = -1;
+
+ if (slot == -1) {
+ setHandItem(0);
+ } else {
+ _characters[charIndex].inventory[slot] = 0;
+
+ if (_currentControlMode == 1)
+ gui_drawInventoryItem(slot, 1, 0);
+
+ if (_currentControlMode == 0)
+ gui_drawCharPortraitWithStats(charIndex);
+ }
+
+ return _items[itm].value;
+}
+
+void EobCoreEngine::deleteBlockItem(uint16 block, int type) {
+ uint16 itm = _levelBlockProperties[block].drawObjects;
+ if (!itm)
+ return;
+
+ for (uint16 i2 = itm, i = 0; itm != i2 || !i; i++ ) {
+ if (type == _items[itm].type || type == -1) {
+ _items[itm].block = -1;
+ _items[itm].level = 0;
+ uint16 i3 = itm;
+ itm = _items[itm].prev;
+ _items[i3].prev = _items[i3].next = 0;
+ } else {
+ uint16 i3 = itm;
+ itm = _items[itm].prev;
+ _items[i3].prev = _items[i3].next = 0;
+ setItemPosition((Item*)&_levelBlockProperties[block].drawObjects, block, i3, _items[i3].pos);
+ }
+ }
+}
+
+int EobCoreEngine::validateInventorySlotForItem(Item item, int charIndex, int slot) {
+ if (item < 0)
+ return 0;
+
+ int offset = (_flags.gameID == GI_EOB1) ? 11 : (_flags.lang == Common::DE_DEU ? 16 : 12);
+
+ if (slot == 17 && item && !itemUsableByCharacter(charIndex, item)) {
+ _txt->printMessage(_itemExtraStrings[offset], -1, _characters[charIndex].name);
+ return 0;
+ }
+
+ int itm = _characters[charIndex].inventory[slot];
+ int ex = _itemTypes[_items[itm].type].extraProperties & 0x7f;
+
+ if (slot < 2 && _items[itm].flags & 0x20 && ex > 0 && ex < 4) {
+ _txt->printMessage(_itemExtraStrings[offset + 1], -1, _characters[charIndex].name);
+ return 0;
+ }
+
+ uint16 v = item ? _itemTypes[_items[item].type].invFlags : 0xffff;
+ if (v & _slotValidationFlags[slot])
+ return 1;
+
+ _txt->printMessage(_itemExtraStrings[offset + (_flags.gameID == GI_EOB1 ? 1 : 2)]);
+ return 0;
+}
+
+void EobCoreEngine::deletePartyItem(Item itemType, int16 itemValue) {
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+
+ EobCharacter *c = &_characters[i];
+ int slot = checkCharacterInventoryForItem(i, itemType, itemValue);
+
+ if (slot == -1)
+ continue;
+
+ int itm = c->inventory[slot];
+ _items[itm].block = -1;
+ c->inventory[slot] = 0;
+
+ if (_currentControlMode == 0 && slot < 2 && i < 5)
+ gui_drawWeaponSlot(i, slot);
+
+ if (_currentControlMode == 1 && i == _updateCharNum)
+ gui_drawInventoryItem(slot, 1, 0);
+ }
+}
+
+int EobCoreEngine::itemUsableByCharacter(int charIndex, Item item) {
+ if (!item)
+ return 1;
+
+ return (_itemTypes[_items[item].type].allowedClasses & _classModifierFlags[_characters[charIndex].cClass]);
+}
+
+int EobCoreEngine::countQueuedItems(Item itemQueue, int16 id, int16 type, int count, int includeFlyingItems) {
+ uint16 o1 = itemQueue;
+ uint16 o2 = o1;
+
+ if (!o1)
+ return 0;
+
+ int res = 0;
+
+ for (bool forceLoop = true; o1 != o2 || forceLoop; o1 = _items[o1].prev) {
+ EobItem *itm = &_items[o1];
+ forceLoop = false;
+ if (id != -1 || type != -1) {
+ if ((id != -1 || (id == -1 && type != itm->type)) && (type != -1) || (id != o1))
+ continue;
+ }
+
+ if (!includeFlyingItems) {
+ if (itm->pos > 3 && itm->pos < 8)
+ continue;
+ }
+
+ if (!count)
+ return o1;
+
+ res++;
+ }
+
+ return res;
+}
+
+int EobCoreEngine::getQueuedItem(Item *items, int pos, int id) {
+ Item o1 = *items;
+ Item o2 = o1;
+
+ if (!o1)
+ return 0;
+
+ EobItem *itm = &_items[o1];
+
+ for (bool forceLoop = true; o1 != o2 || forceLoop; o1 = itm->prev) {
+ itm = &_items[o1];
+ forceLoop = false;
+ if ((id != -1 || (id == -1 && itm->pos != pos)) && id != o1)
+ continue;
+
+ Item n = itm->next;
+ Item p = itm->prev;
+ _items[n].prev = p;
+ _items[p].next = n;
+ itm->next = itm->prev = itm->block = 0;
+ itm->level = 0;
+ if (o1 == *items)
+ *items = p;
+ if (o1 == *items)
+ *items = 0;
+
+ return o1;
+ }
+
+ return 0;
+}
+
+void EobCoreEngine::printFullItemName(Item item) {
+ EobItem *itm = &_items[item];
+ const char *nameUnid = _itemNames[itm->nameUnid];
+ const char *nameId = _itemNames[itm->nameId];
+ uint8 f = _itemTypes[itm->type].extraProperties & 0x7f;
+ int8 v = itm->value;
+
+ const char *tstr2 = 0;
+ const char *tstr3 = 0;
+ int e = 0;
+
+ char tmpString[61];
+
+ if ((itm->flags & 0x40) && !strlen(nameId)) {
+ switch (f) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ if (v == 0)
+ strcpy(tmpString, nameUnid);
+ else if (v < 0)
+ sprintf(tmpString, _itemExtraStrings[3], v, nameUnid);
+ else
+ sprintf(tmpString, _itemExtraStrings[4], v, nameUnid);
+ break;
+
+ case 9:
+ tstr2 = _itemExtraStrings[5];
+ tstr3 = _spells[v].name;
+ e = 1;
+ break;
+
+ case 10:
+ tstr2 = _itemExtraStrings[6];
+ tstr3 = _spells[_flags.gameID == GI_EOB1 ? (_clericSpellOffset + v) : v].name;
+ e = 1;
+ break;
+
+ case 14:
+ tstr2 = _itemExtraStrings[8];
+ tstr3 = _itemSuffixStrings[8];
+ break;
+
+ case 16:
+ tstr2 = _itemExtraStrings[7];
+ tstr3 = _itemSuffixStrings[v + 6];
+ e = 0;
+ break;
+
+ case 18:
+ if (v == 5) {
+ tstr2 = _itemExtraStrings[_flags.lang == Common::EN_ANY ? 9 : 10];
+ e = 1;
+ } else {
+ tstr2 = _itemExtraStrings[9];
+ e = 0;
+ }
+ tstr3 = _itemSuffixStrings[v + (_flags.lang == Common::EN_ANY ? 11 : 15)];
+ break;
+
+ default:
+ strcpy(tmpString, nameUnid);
+ break;
+ }
+
+
+ if (tstr3) {
+ if (!tstr2) {
+ sprintf(tmpString, _itemExtraStrings[_flags.lang == Common::EN_ANY ? 10 : 11], tstr3);
+ } else {
+ if (e == 1) {
+ if (tstr2 == _itemExtraStrings[12])
+ sprintf(tmpString, _itemExtraStrings[_flags.lang == Common::EN_ANY ? 11 : 14], tstr2, tstr3);
+ else
+ sprintf(tmpString, _itemExtraStrings[_flags.gameID == GI_EOB1 ? 10 : (_flags.lang == Common::EN_ANY ? 11 : 13)], tstr2, tstr3);
+ } else {
+ sprintf(tmpString, _itemExtraStrings[_flags.gameID == GI_EOB1 ? 10 : (_flags.lang == Common::EN_ANY ? 11 : 15)], tstr2, tstr3);
+ }
+ }
+ }
+ } else {
+ strcpy(tmpString, (itm->flags & 0x40) ? nameId : nameUnid);
+ }
+
+ _txt->printMessage(tmpString);
+}
+
+void EobCoreEngine::identifyQueuedItems(Item itemQueue) {
+ if (!itemQueue)
+ return;
+
+ Item first = itemQueue;
+ do {
+ _items[itemQueue].flags |= 0x40;
+ itemQueue = _items[itemQueue].prev;
+
+ } while (first != itemQueue);
+}
+
+void EobCoreEngine::drawItemIconShape(int pageNum, Item itemId, int x, int y) {
+ int icn = _items[itemId].icon;
+ bool applyBluePal = ((_partyEffectFlags & 2) && (_items[itemId].flags & 0x80)) ? true : false;
+
+ if (applyBluePal) {
+ _screen->setFadeTableIndex(3);
+ _screen->setShapeFadeMode(1, true);
+ }
+
+ _screen->drawShape(pageNum, _itemIconShapes[icn], x, y, 0);
+
+ if (applyBluePal) {
+ _screen->setFadeTableIndex(4);
+ _screen->setShapeFadeMode(1, false);
+ }
+}
+
+bool EobCoreEngine::isMagicWeapon(Item itemIndex) {
+ return (_items[itemIndex].type > 10 && _items[itemIndex].type < 18);
+}
+
+bool EobCoreEngine::checkInventoryForRings(int charIndex, int itemValue) {
+ for (int i = 25; i <= 26; i++) {
+ int itm = _characters[charIndex].inventory[i];
+ if (itm && _items[itm].type == 47 && _items[itm].value == itemValue)
+ return true;
+ }
+ return false;
+}
+
+void EobCoreEngine::eatItemInHand(int charIndex) {
+ EobCharacter *c = &_characters[charIndex];
+ if (!testCharacter(charIndex, 5)) {
+ _txt->printMessage(_warningStrings[1], -1, c->name);
+ } else if (_itemInHand && _items[_itemInHand].type != 31) {
+ _txt->printMessage(_warningStrings[3]);
+ } else if (_items[_itemInHand].value == -1) {
+ _txt->printMessage(_warningStrings[2]);
+ snd_playSoundEffect(79);
+ } else {
+ c->food += _items[_itemInHand].value;
+ if (c->food > 100)
+ c->food = 100;
+
+ _items[_itemInHand].block = -1;
+ setHandItem(0);
+ gui_drawFoodStatusGraph(charIndex);
+ _screen->updateScreen();
+ snd_playSoundEffect(9);
+ }
+}
+
+bool EobCoreEngine::launchObject(int charIndex, Item item, uint16 startBlock, int startPos, int dir, int type) {
+ EobFlyingObject *t = _flyingObjects;
+ int slot = 0;
+ for (; slot < 10; slot++) {
+ if (!t->enable)
+ break;
+ t++;
+ }
+
+ if (slot == 10)
+ return false;
+
+ setItemPosition((Item*)&_levelBlockProperties[startBlock].drawObjects, startBlock, item, startPos | 4);
+
+ t->enable = 1;
+ t->u2 = 1;
+ t->flags = 0;
+ t->direction = dir;
+ t->distance = 12;
+ t->curBlock = startBlock;
+ t->curPos = startPos;
+ t->item = item;
+ t->objectType = type;
+ t->attackerId = charIndex;
+ t->callBackIndex = 0;
+
+ snd_playSoundEffect(type == 7 ? 26 : 11);
+ return true;
+}
+
+void EobCoreEngine::launchMagicObject(int charIndex, int type, uint16 startBlock, int startPos, int dir) {
+ EobFlyingObject *t = _flyingObjects;
+ int slot = 0;
+ for (; slot < 10; slot++) {
+ if (!t->enable)
+ break;
+ t++;
+ }
+
+ if (slot == 10)
+ return;
+
+ t->enable = 2;
+ t->u2 = 1;
+ t->flags = _magicFlightObjectProperties[(type << 2) + 2];
+ t->direction = dir;
+ t->distance = _magicFlightObjectProperties[(type << 2) + 1];
+ t->curBlock = startBlock;
+ t->curPos = startPos;
+ t->item = type;
+ t->objectType = _magicFlightObjectProperties[(type << 2) + 3];
+ t->attackerId = charIndex;
+ t->u2 = 1;
+ t->callBackIndex = _magicFlightObjectProperties[type << 2];
+ _sceneUpdateRequired = true;
+}
+
+bool EobCoreEngine::updateObjectFlight(EobFlyingObject *fo, int block, int pos) {
+ uint8 wallFlags = _wllWallFlags[_levelBlockProperties[block].walls[fo->direction ^ 2]];
+ if (fo->enable == 1) {
+ if ((wallFlags & 1) || (fo->u2) || ((wallFlags & 2) && (_dscItemShapeMap[_items[fo->item].icon] >= 15))) {
+ getQueuedItem((Item*)&_levelBlockProperties[fo->curBlock].drawObjects, 0, fo->item);
+ setItemPosition((Item*)&_levelBlockProperties[block].drawObjects, block, fo->item, pos | 4);
+ fo->curBlock = block;
+ fo->curPos = pos;
+ fo->distance--;
+ return true;
+
+ } else {
+ _clickedSpecialFlag = 0x10;
+ specialWallAction(block, fo->direction);
+ return false;
+ }
+
+ } else {
+ if (!(wallFlags & 1) && (fo->curBlock != block))
+ return false;
+ fo->curBlock = block;
+ fo->curPos = pos;
+ if (fo->distance != 255)
+ fo->distance--;
+ }
+ return true;
+}
+
+bool EobCoreEngine::updateFlyingObjectHitTest(EobFlyingObject *fo, int block, int pos) {
+ if (fo->u2 && (fo->curBlock != _currentBlock || fo->attackerId >= 0) && (!blockHasMonsters(block) || fo->attackerId < 0))
+ return false;
+
+ if (fo->enable == 2) {
+ if (fo->callBackIndex)
+ return (this->*_spells[fo->callBackIndex].endCallback)(fo);
+ }
+
+ if (blockHasMonsters(block)) {
+ for (int i = 0; i < 30; i++) {
+ if (!isMonsterOnPos(&_monsters[i], block, pos, 1))
+ continue;
+ if (flyingObjectMonsterHit(fo, i))
+ return true;
+ }
+
+ } else if (block == _currentBlock) {
+ return flyingObjectPartyHit(fo);
+ }
+
+ return false;
+}
+
+void EobCoreEngine::updateFlyingObject_s3(EobFlyingObject *fo) {
+
+}
+
+void EobCoreEngine::endObjectFlight(EobFlyingObject *fo) {
+ if (fo->enable == 1) {
+ _items[fo->item].pos &= 3;
+ runLevelScript(fo->curBlock, 4);
+ updateEnvironmentalSfx(18);
+ }
+ memset(fo, 0, sizeof(EobFlyingObject));
+}
+
+void EobCoreEngine::checkFlyingObjects() {
+ for (int i = 0; i < 10; i++) {
+ EobFlyingObject *fo = &_flyingObjects[i];
+ if (!fo->enable)
+ continue;
+ if (updateFlyingObjectHitTest(fo, fo->curBlock, fo->curPos))
+ endObjectFlight(fo);
+ }
+}
+
+void EobCoreEngine::reloadWeaponSlot(int charIndex, int slotIndex, int itemType, int arrowOrDagger) {
+ if (arrowOrDagger && _characters[charIndex].inventory[16]) {
+ _characters[charIndex].inventory[slotIndex] = getQueuedItem(&_characters[charIndex].inventory[16], 0, -1);
+ } else {
+ for (int i = 24; i >= 22; i--) {
+ if (!_characters[charIndex].inventory[i])
+ continue;
+ if (_items[_characters[charIndex].inventory[i]].type == itemType && itemType != -1)
+ continue;
+ _characters[charIndex].inventory[slotIndex] = _characters[charIndex].inventory[i];
+ _characters[charIndex].inventory[i] = 0;
+ return;
+ }
+ }
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
+
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index 34bde7fe5c..df595b6ffa 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -171,7 +171,7 @@ KyraEngine_HoF::~KyraEngine_HoF() {
delete[] _conversationState[i];
delete[] _conversationState;
- for (Common::Array<const TIMOpcode *>::iterator i = _timOpcodes.begin(); i != _timOpcodes.end(); ++i)
+ for (Common::Array<const TIMOpcode*>::iterator i = _timOpcodes.begin(); i != _timOpcodes.end(); ++i)
delete *i;
_timOpcodes.clear();
}
diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h
index 916cac0c9d..a6add505cb 100644
--- a/engines/kyra/kyra_hof.h
+++ b/engines/kyra/kyra_hof.h
@@ -656,7 +656,7 @@ protected:
int t2_resetChat(const TIM *tim, const uint16 *param);
int t2_playSoundEffect(const TIM *tim, const uint16 *param);
- Common::Array<const TIMOpcode *> _timOpcodes;
+ Common::Array<const TIMOpcode*> _timOpcodes;
// sound
int _oldTalkFile;
diff --git a/engines/kyra/kyra_mr.cpp b/engines/kyra/kyra_mr.cpp
index 39ed0d038a..4e07c8f343 100644
--- a/engines/kyra/kyra_mr.cpp
+++ b/engines/kyra/kyra_mr.cpp
@@ -183,7 +183,7 @@ KyraEngine_MR::~KyraEngine_MR() {
delete[] _sceneStrings;
delete[] _talkObjectList;
- for (Common::Array<const Opcode *>::iterator i = _opcodesDialog.begin(); i != _opcodesDialog.end(); ++i)
+ for (Common::Array<const Opcode*>::iterator i = _opcodesDialog.begin(); i != _opcodesDialog.end(); ++i)
delete *i;
_opcodesDialog.clear();
diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h
index 473c0371dc..38ff271037 100644
--- a/engines/kyra/kyra_mr.h
+++ b/engines/kyra/kyra_mr.h
@@ -463,7 +463,7 @@ private:
void npcChatSequence(const char *str, int object, int vocHigh, int vocLow);
- Common::Array<const Opcode *> _opcodesDialog;
+ Common::Array<const Opcode*> _opcodesDialog;
int o3d_updateAnim(EMCState *script);
int o3d_delay(EMCState *script);
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index dbdcda22d5..f5ef0d09ac 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -211,7 +211,7 @@ Common::Error KyraEngine_v1::init() {
}
KyraEngine_v1::~KyraEngine_v1() {
- for (Common::Array<const Opcode *>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
+ for (Common::Array<const Opcode*>::iterator i = _opcodes.begin(); i != _opcodes.end(); ++i)
delete *i;
_opcodes.clear();
_keyMap.clear();
@@ -354,14 +354,14 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag)
}
void KyraEngine_v1::setupKeyMap() {
- struct KeyMapEntry {
+ struct KeyCodeMapEntry {
Common::KeyCode kcScummVM;
int16 kcDOS;
int16 kcPC98;
};
#define KC(x) Common::KEYCODE_##x
- static const KeyMapEntry keys[] = {
+ static const KeyCodeMapEntry keys[] = {
{ KC(SPACE), 61, 53 },
{ KC(RETURN), 43, 29 },
{ KC(UP), 96, 68 },
@@ -377,13 +377,48 @@ void KyraEngine_v1::setupKeyMap() {
{ KC(KP7), 91, 67 },
{ KC(PAGEUP), 101, 69 },
{ KC(KP9), 101, 69 },
+ { KC(END), 93, 0/*unknown*/ },
+ { KC(KP1), 93, 0/*unknown*/ },
+ { KC(PAGEDOWN), 103, 0/*unknown*/ },
+ { KC(KP3), 103, 0/*unknown*/ },
{ KC(F1), 112, 99 },
{ KC(F2), 113, 100 },
{ KC(F3), 114, 101 },
+ { KC(F4), 115, 102 },
+ { KC(F5), 116, 103 },
+ { KC(F6), 117, 104 },
+ { KC(a), 31, 31 },
+ { KC(b), 50, 50 },
+ { KC(c), 48, 48 },
+ { KC(d), 33, 33 },
+ { KC(e), 19, 19 },
+ { KC(f), 34, 34 },
+ { KC(i), 24, 24 },
+ { KC(k), 38, 38 },
+ { KC(m), 52, 52 },
+ { KC(n), 51, 51 },
{ KC(o), 25, 25 },
+ { KC(p), 26, 26 },
{ KC(r), 20, 20 },
+ { KC(s), 32, 32 },
+ { KC(w), 18, 18 },
+ { KC(y), 22, 22 },
+ { KC(z), 46, 46 },
+ { KC(1), 2, 0/*unknown*/ },
+ { KC(2), 3, 0/*unknown*/ },
+ { KC(3), 4, 0/*unknown*/ },
+ { KC(4), 5, 0/*unknown*/ },
+ { KC(5), 6, 0/*unknown*/ },
+ { KC(6), 7, 0/*unknown*/ },
+ { KC(7), 8, 0/*unknown*/ },
{ KC(SLASH), 55, 55 },
{ KC(ESCAPE), 110, 1 },
+ { KC(MINUS), 12, 0/*unknown*/ },
+ { KC(KP_MINUS), 105, 0/*unknown*/ },
+ { KC(PLUS), 13, 0/*unknown*/ },
+ { KC(KP_PLUS), 106, 0/*unknown*/ },
+ { KC(COMMA), 53, 0/*unknown*/ },
+ { KC(PERIOD), 54, 0/*unknown*/ }
};
#undef KC
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index 24a3b35418..40f9074106 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -323,7 +323,7 @@ protected:
// opcode
virtual void setupOpcodeTable() = 0;
- Common::Array<const Opcode *> _opcodes;
+ Common::Array<const Opcode*> _opcodes;
int o1_queryGameFlag(EMCState *script);
int o1_setGameFlag(EMCState *script);
diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h
index 56391d151a..7896748b96 100644
--- a/engines/kyra/kyra_v2.h
+++ b/engines/kyra/kyra_v2.h
@@ -252,7 +252,7 @@ protected:
virtual void uninitAnimationShapes(int count, uint8 *filedata) = 0;
// Shapes
- typedef Common::HashMap<int, uint8 *> ShapeMap;
+ typedef Common::HashMap<int, uint8*> ShapeMap;
ShapeMap _gameShapes;
uint8 *getShapePtr(int index) const;
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
index 120900537b..6cb3b51370 100644
--- a/engines/kyra/lol.cpp
+++ b/engines/kyra/lol.cpp
@@ -42,10 +42,9 @@ namespace Kyra {
const char *const LoLEngine::kKeymapName = "lol";
-LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(system, flags) {
+LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : LolEobBaseEngine(system, flags) {
_screen = 0;
_gui = 0;
- _txt = 0;
_tim = 0;
_lang = 0;
@@ -97,15 +96,11 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
memset(_inventory, 0, sizeof(_inventory));
memset(_charStatusFlags, 0, sizeof(_charStatusFlags));
_inventoryCurItem = 0;
- _currentControlMode = 0;
- _specialSceneFlag = 0;
_lastCharInventory = -1;
_emcLastItem = -1;
_itemIconShapes = _itemShapes = _gameShapes = _thrownShapes = _effectShapes = _fireballShapes = _healShapes = _healiShapes = 0;
_levelShpList = _levelDatList = 0;
- _monsterShapes = _monsterPalettes = 0;
- _monsterShapesEx = 0;
_gameShapeMap = 0;
memset(_monsterAnimType, 0, 3);
_healOverlay = 0;
@@ -116,10 +111,8 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_charSelection = -1;
_characters = 0;
_spellProperties = 0;
- _updateFlags = 0;
_selectedSpell = 0;
- _updateCharNum = _updatePortraitSpeechAnimDuration = _portraitSpeechAnimMode = _resetPortraitAfterSpeechAnim = _textColorFlag = _needSceneRestore = 0;
- _fadeText = false;
+ _updateCharNum = _portraitSpeechAnimMode = _textColorFlag = 0;
_palUpdateTimer = _updatePortraitNext = 0;
_lampStatusTimer = 0xffffffff;
@@ -128,66 +121,42 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_lastButtonShape = 0;
_buttonPressTimer = 0;
_selectedCharacter = 0;
- _suspendScript = _sceneUpdateRequired = false;
+ _suspendScript = false;
_scriptDirection = 0;
- _currentDirection = 0;
- _currentBlock = 0;
- _compassDirection = _compassDirectionIndex = -1;
+ _compassDirectionIndex = -1;
_compassStep = 0;
- memset(_visibleBlockIndex, 0, sizeof(_visibleBlockIndex));
_smoothScrollModeNormal = 1;
- _wllVmpMap = _specialWallTypes = _wllBuffer4 = _wllWallFlags = 0;
- _wllShapeMap = 0;
- _lvlShapeTop = _lvlShapeBottom = _lvlShapeLeftRight = 0;
- _levelBlockProperties = 0;
+ _wllAutomapData = 0;
+ _sceneXoffset = 112;
+ _sceneShpDim = 13;
_monsters = 0;
_monsterProperties = 0;
- _lvlBlockIndex = _lvlShapeIndex = 0;
+ _lvlShapeIndex = 0;
_partyAwake = true;
- _vcnBlocks = 0;
- _vcnShift = 0;
- _vcnExpTable = 0;
- _vmpPtr = 0;
- _vcfBlocks = 0;
_transparencyTable2 = 0;
_transparencyTable1 = 0;
- _levelShapeProperties = 0;
- _levelShapes = 0;
_specialGuiShape = 0;
_specialGuiShapeX = _specialGuiShapeY = _specialGuiShapeMirrorFlag = 0;
- _blockDrawingBuffer = 0;
- _sceneWindowBuffer = 0;
- memset(_doorShapes, 0, sizeof(_doorShapes));
memset(_characterFaceShapes, 0, sizeof(_characterFaceShapes));
_lampEffect = _brightness = _lampOilStatus = 0;
_lampStatusSuspended = false;
- _blockBrightness = 0;
_tempBuffer5120 = 0;
_flyingObjects = 0;
_monsters = 0;
_lastMouseRegion = 0;
- _objectLastDirection = _monsterStepCounter = _monsterStepMode = 0;
+ _objectLastDirection = 0;
_monsterCurBlock = 0;
_seqWindowX1 = _seqWindowY1 = _seqWindowX2 = _seqWindowY2 = _seqTrigger = 0;
_spsWindowX = _spsWindowY = _spsWindowW = _spsWindowH = 0;
- _dscUnk1 = 0;
- _dscShapeIndex = 0;
+ _dscWalls = 0;
_dscOvlMap = 0;
_dscShapeScaleW = 0;
- _dscShapeScaleH = 0;
- _dscShapeX = 0;
+ _dscShapeScaleH = 0;
_dscShapeY = 0;
- _dscTileIndex = 0;
- _dscUnk2 = 0;
- _dscDoorShpIndex = 0;
- _dscDim1 = 0;
- _dscDim2 = 0;
- _dscBlockMap = _dscDoor1 = _dscShapeOvlIndex = 0;
- _dscBlockIndex = 0;
- _dscDimMap = 0;
+ _dscShapeOvlIndex = 0;
_dscDoorMonsterX = _dscDoorMonsterY = 0;
_dscDoor4 = 0;
@@ -198,29 +167,24 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_curMusicTheme = -1;
_curMusicFileExt = 0;
_curMusicFileIndex = -1;
- _environmentSfx = _environmentSfxVol = _envSfxDistThreshold = 0;
_envSfxUseQueue = false;
_envSfxNumTracksInQueue = 0;
memset(_envSfxQueuedTracks, 0, sizeof(_envSfxQueuedTracks));
memset(_envSfxQueuedBlocks, 0, sizeof(_envSfxQueuedBlocks));
- _sceneDrawVarDown = _sceneDrawVarRight = _sceneDrawVarLeft = _wllProcessFlag = 0;
_partyPosX = _partyPosY = 0;
_shpDmX = _shpDmY = _dmScaleW = _dmScaleH = 0;
_floatingCursorControl = _currentFloatingCursor = 0;
memset(_activeTim, 0, sizeof(_activeTim));
- memset(_openDoorState, 0, sizeof(_openDoorState));
memset(&_activeSpell, 0, sizeof(_activeSpell));
- _activeVoiceFileTotalTime = 0;
_pageBuffer1 = _pageBuffer2 = 0;
memset(_charStatsTemp, 0, sizeof(_charStatsTemp));
_compassBroken = _drainMagic = 0;
- _dialogueField = false;
_buttonData = 0;
_activeButtons = 0;
@@ -228,8 +192,6 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
_preserveEvents = false;
_buttonList1 = _buttonList2 = _buttonList3 = _buttonList4 = _buttonList5 = _buttonList6 = _buttonList7 = _buttonList8 = 0;
- memset(_lvlTempData, 0, sizeof(_lvlTempData));
-
_mapOverlay = 0;
_automapShapes = 0;
_defaultLegendData = 0;
@@ -250,6 +212,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
LoLEngine::~LoLEngine() {
setupPrologueData(false);
+ releaseTempData();
#ifdef ENABLE_KEYMAPPER
_eventMan->getKeymapper()->cleanupGameKeymaps();
@@ -264,8 +227,6 @@ LoLEngine::~LoLEngine() {
_gui = 0;
delete _tim;
_tim = 0;
- delete _txt;
- _txt = 0;
delete[] _itemsInPlay;
delete[] _itemProperties;
@@ -322,64 +283,47 @@ LoLEngine::~LoLEngine() {
delete[] _healiShapes;
}
- for (int i = 0; i < 3; i++)
- releaseMonsterShapes(i);
+ if (_monsterDecorationShapes) {
+ for (int i = 0; i < 3; i++)
+ releaseMonsterShapes(i);
- delete[] _monsterShapes;
- delete[] _monsterPalettes;
- delete[] _monsterShapesEx;
+ delete[] _monsterShapes;
+ _monsterShapes = 0;
+ delete[] _monsterPalettes;
+ _monsterPalettes = 0;
+ delete[] _monsterDecorationShapes;
+ _monsterDecorationShapes = 0;
+ }
+
+ for (int i = 0; i < 6; i++) {
+ delete[] _doorShapes[i];
+ _doorShapes[i] = 0;
+ }
delete[] _automapShapes;
- for (Common::Array<const TIMOpcode *>::iterator i = _timIntroOpcodes.begin(); i != _timIntroOpcodes.end(); ++i)
+ for (Common::Array<const TIMOpcode*>::iterator i = _timIntroOpcodes.begin(); i != _timIntroOpcodes.end(); ++i)
delete *i;
_timIntroOpcodes.clear();
- for (Common::Array<const TIMOpcode *>::iterator i = _timOutroOpcodes.begin(); i != _timOutroOpcodes.end(); ++i)
+ for (Common::Array<const TIMOpcode*>::iterator i = _timOutroOpcodes.begin(); i != _timOutroOpcodes.end(); ++i)
delete *i;
_timOutroOpcodes.clear();
- for (Common::Array<const TIMOpcode *>::iterator i = _timIngameOpcodes.begin(); i != _timIngameOpcodes.end(); ++i)
+ for (Common::Array<const TIMOpcode*>::iterator i = _timIngameOpcodes.begin(); i != _timIngameOpcodes.end(); ++i)
delete *i;
_timIngameOpcodes.clear();
-
- delete[] _wllVmpMap;
- delete[] _wllShapeMap;
- delete[] _specialWallTypes;
- delete[] _wllBuffer4;
- delete[] _wllWallFlags;
- delete[] _lvlShapeTop;
- delete[] _lvlShapeBottom;
- delete[] _lvlShapeLeftRight;
+ delete[] _wllAutomapData;
delete[] _tempBuffer5120;
delete[] _flyingObjects;
delete[] _monsters;
- delete[] _levelBlockProperties;
delete[] _monsterProperties;
- delete[] _levelFileData;
- delete[] _vcnExpTable;
- delete[] _vcnBlocks;
- delete[] _vcnShift;
- delete[] _vmpPtr;
- delete[] _vcfBlocks;
delete[] _transparencyTable2;
delete[] _transparencyTable1;
- delete[] _levelShapeProperties;
- delete[] _blockDrawingBuffer;
- delete[] _sceneWindowBuffer;
delete[] _lightningProps;
- if (_levelShapes) {
- for (int i = 0; i < 400; i++)
- delete[] _levelShapes[i];
- delete[] _levelShapes;
- }
-
- for (int i = 0; i < 2; i++)
- delete[] _doorShapes[i];
-
delete _lvlShpFileHandle;
if (_ingameSoundList) {
@@ -388,16 +332,6 @@ LoLEngine::~LoLEngine() {
delete[] _ingameSoundList;
}
- for (int i = 0; i < 29; i++) {
- if (_lvlTempData[i]) {
- delete[] _lvlTempData[i]->wallsXorData;
- delete[] _lvlTempData[i]->flags;
- delete[] _lvlTempData[i]->monsters;
- delete[] _lvlTempData[i]->flyingObjects;
- delete _lvlTempData[i];
- }
- }
-
for (int i = 0; i < 3; i++) {
for (int ii = 0; ii < 40; ii++)
delete[] _characterFaceShapes[ii][i];
@@ -409,7 +343,7 @@ LoLEngine::~LoLEngine() {
delete[] _mapCursorOverlay;
delete[] _mapOverlay;
- for (Common::Array<const SpellProc *>::iterator i = _spellProcs.begin(); i != _spellProcs.end(); ++i)
+ for (Common::Array<const SpellProc*>::iterator i = _spellProcs.begin(); i != _spellProcs.end(); ++i)
delete *i;
_spellProcs.clear();
@@ -440,13 +374,18 @@ Common::Error LoLEngine::init() {
KyraEngine_v1::init();
initStaticResource();
- _envSfxDistThreshold = _sound->getSfxType() == Sound::kAdLib ? 15 : 3;
-
_gui = new GUI_LoL(this);
assert(_gui);
_gui->initStaticData();
_txt = new TextDisplayer_LoL(this, _screen);
+ _dialogueButtonLabelCol1 = 144;
+ _dialogueButtonLabelCol2 = 254;
+ _dialogueButtonW = 74;
+ _dialogueButtonH = 9;
+ _bkgColor_1 = -1;
+ _color1_1 = 136;
+ _color2_1 = 251;
_screen->setAnimBlockPtr(10000);
_screen->setScreenDim(0);
@@ -465,41 +404,15 @@ Common::Error LoLEngine::init() {
if (!_sound->init())
error("Couldn't init sound");
- _wllVmpMap = new uint8[80];
- memset(_wllVmpMap, 0, 80);
- _wllShapeMap = new int8[80];
- memset(_wllShapeMap, 0, 80);
- _specialWallTypes = new uint8[80];
- memset(_specialWallTypes, 0, 80);
- _wllBuffer4 = new uint8[80];
- memset(_wllBuffer4, 0, 80);
- _wllWallFlags = new uint8[80];
- memset(_wllWallFlags, 0, 80);
- _lvlShapeTop = new int16[18];
- memset(_lvlShapeTop, 0, 18 * sizeof(int16));
- _lvlShapeBottom = new int16[18];
- memset(_lvlShapeBottom, 0, 18 * sizeof(int16));
- _lvlShapeLeftRight = new int16[36];
- memset(_lvlShapeLeftRight, 0, 36 * sizeof(int16));
- _levelShapeProperties = new LevelShapeProperty[100];
- memset(_levelShapeProperties, 0, 100 * sizeof(LevelShapeProperty));
- _levelShapes = new uint8 *[400];
- memset(_levelShapes, 0, 400 * sizeof(uint8 *));
- _blockDrawingBuffer = new uint16[1320];
- memset(_blockDrawingBuffer, 0, 1320 * sizeof(uint16));
- _sceneWindowBuffer = new uint8[21120];
- memset(_sceneWindowBuffer, 0, 21120);
-
- _levelBlockProperties = new LevelBlockProperty[1025];
- memset(_levelBlockProperties, 0, 1025 * sizeof(LevelBlockProperty));
- _monsters = new MonsterInPlay[30];
- memset(_monsters, 0, 30 * sizeof(MonsterInPlay));
- _monsterProperties = new MonsterProperty[5];
- memset(_monsterProperties, 0, 5 * sizeof(MonsterProperty));
-
- _vcnExpTable = new uint8[128];
- for (int i = 0; i < 128; i++)
- _vcnExpTable[i] = i & 0x0f;
+ LolEobBaseEngine::init();
+
+ _wllAutomapData = new uint8[80];
+ memset(_wllAutomapData, 0, 80);
+
+ _monsters = new LolMonsterInPlay[30];
+ memset(_monsters, 0, 30 * sizeof(LolMonsterInPlay));
+ _monsterProperties = new LolMonsterProperty[5];
+ memset(_monsterProperties, 0, 5 * sizeof(LolMonsterProperty));
_tempBuffer5120 = new uint8[5120];
memset(_tempBuffer5120, 0, 5120);
@@ -509,25 +422,26 @@ Common::Error LoLEngine::init() {
memset(_globalScriptVars, 0, sizeof(_globalScriptVars));
- _levelFileData = 0;
_lvlShpFileHandle = 0;
_sceneDrawPage1 = 2;
_sceneDrawPage2 = 6;
- _monsterShapes = new uint8 *[48];
- memset(_monsterShapes, 0, 48 * sizeof(uint8 *));
- _monsterPalettes = new uint8 *[48];
- memset(_monsterPalettes, 0, 48 * sizeof(uint8 *));
+ _clickedShapeXOffs = 136;
+ _clickedShapeYOffs = 8;
+ _clickedSpecialFlag = 0x40;
- _monsterShapesEx = new uint8 *[576];
- memset(_monsterShapesEx, 0, 576 * sizeof(uint8 *));
+ _monsterShapes = new uint8*[48];
+ memset(_monsterShapes, 0, 48 * sizeof(uint8*));
+ _monsterPalettes = new uint8*[48];
+ memset(_monsterPalettes, 0, 48 * sizeof(uint8*));
+ _monsterDecorationShapes = new uint8*[576];
+ memset(_monsterDecorationShapes, 0, 576 * sizeof(uint8*));
memset(&_scriptData, 0, sizeof(EMCData));
- _hasTempDataFlags = 0;
_activeMagicMenu = -1;
- _automapShapes = new const uint8 *[109];
+ _automapShapes = new const uint8*[109];
_mapOverlay = new uint8[256];
memset(_availableSpells, -1, 8);
@@ -687,7 +601,7 @@ void LoLEngine::loadItemIconShapes() {
_screen->loadBitmap("ITEMICN.SHP", 3, 3, 0);
const uint8 *shp = _screen->getCPagePtr(3);
_numItemIconShapes = READ_LE_UINT16(shp);
- _itemIconShapes = new uint8 *[_numItemIconShapes];
+ _itemIconShapes = new uint8*[_numItemIconShapes];
for (int i = 0; i < _numItemIconShapes; i++)
_itemIconShapes[i] = _screen->makeShapeCopy(shp, i);
@@ -697,7 +611,7 @@ void LoLEngine::loadItemIconShapes() {
_screen->loadBitmap("GAMESHP.SHP", 3, 3, 0);
shp = _screen->getCPagePtr(3);
_numGameShapes = READ_LE_UINT16(shp);
- _gameShapes = new uint8 *[_numGameShapes];
+ _gameShapes = new uint8*[_numGameShapes];
for (int i = 0; i < _numGameShapes; i++)
_gameShapes[i] = _screen->makeShapeCopy(shp, i);
}
@@ -717,12 +631,6 @@ void LoLEngine::setMouseCursorToItemInHand() {
_screen->setMouseCursor(o, o, getItemIconShapePtr(_itemInHand));
}
-bool LoLEngine::posWithinRect(int mouseX, int mouseY, int x1, int y1, int x2, int y2) {
- if (mouseX < x1 || mouseX > x2 || mouseY < y1 || mouseY > y2)
- return false;
- return true;
-}
-
void LoLEngine::checkFloatingPointerRegions() {
if (!_floatingCursorsEnabled)
return;
@@ -877,42 +785,42 @@ void LoLEngine::startup() {
_screen->loadBitmap("ITEMSHP.SHP", 3, 3, 0);
const uint8 *shp = _screen->getCPagePtr(3);
_numItemShapes = READ_LE_UINT16(shp);
- _itemShapes = new uint8 *[_numItemShapes];
+ _itemShapes = new uint8*[_numItemShapes];
for (int i = 0; i < _numItemShapes; i++)
_itemShapes[i] = _screen->makeShapeCopy(shp, i);
_screen->loadBitmap("THROWN.SHP", 3, 3, 0);
shp = _screen->getCPagePtr(3);
_numThrownShapes = READ_LE_UINT16(shp);
- _thrownShapes = new uint8 *[_numThrownShapes];
+ _thrownShapes = new uint8*[_numThrownShapes];
for (int i = 0; i < _numThrownShapes; i++)
_thrownShapes[i] = _screen->makeShapeCopy(shp, i);
_screen->loadBitmap("ICE.SHP", 3, 3, 0);
shp = _screen->getCPagePtr(3);
_numEffectShapes = READ_LE_UINT16(shp);
- _effectShapes = new uint8 *[_numEffectShapes];
+ _effectShapes = new uint8*[_numEffectShapes];
for (int i = 0; i < _numEffectShapes; i++)
_effectShapes[i] = _screen->makeShapeCopy(shp, i);
_screen->loadBitmap("FIREBALL.SHP", 3, 3, 0);
shp = _screen->getCPagePtr(3);
_numFireballShapes = READ_LE_UINT16(shp);
- _fireballShapes = new uint8 *[_numFireballShapes];
+ _fireballShapes = new uint8*[_numFireballShapes];
for (int i = 0; i < _numFireballShapes; i++)
_fireballShapes[i] = _screen->makeShapeCopy(shp, i);
_screen->loadBitmap("HEAL.SHP", 3, 3, 0);
shp = _screen->getCPagePtr(3);
_numHealShapes = READ_LE_UINT16(shp);
- _healShapes = new uint8 *[_numHealShapes];
+ _healShapes = new uint8*[_numHealShapes];
for (int i = 0; i < _numHealShapes; i++)
_healShapes[i] = _screen->makeShapeCopy(shp, i);
_screen->loadBitmap("HEALI.SHP", 3, 3, 0);
shp = _screen->getCPagePtr(3);
_numHealiShapes = READ_LE_UINT16(shp);
- _healiShapes = new uint8 *[_numHealiShapes];
+ _healiShapes = new uint8*[_numHealiShapes];
for (int i = 0; i < _numHealiShapes; i++)
_healiShapes[i] = _screen->makeShapeCopy(shp, i);
@@ -969,10 +877,9 @@ void LoLEngine::runLoop() {
enableSysTimer(2);
- bool _runFlag = true;
_flagsTable[73] |= 0x08;
- while (!shouldQuit() && _runFlag) {
+ while (!shouldQuit()) {
if (_gameToLoad != -1) {
// FIXME: Instead of throwing away the error returned by
// loadGameState, we should use it / augment it.
@@ -1784,44 +1691,6 @@ void LoLEngine::fadeText() {
_fadeText = false;
}
-void LoLEngine::transformRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage) {
- uint16 *p1 = (uint16 *)_tempBuffer5120;
- uint16 *p2 = (uint16 *)(_tempBuffer5120 + 640);
-
- for (int i = 0; i < w; i++)
- p1[i] = i;
-
- for (int i = 0; i < h; i++)
- p2[i] = i;
-
- for (int i = 0; i < w; i++)
- SWAP(p1[_rnd.getRandomNumberRng(0, w - 1)], p1[i]);
-
- for (int i = 0; i < h; i++)
- SWAP(p2[_rnd.getRandomNumberRng(0, h - 1)], p2[i]);
-
- for (int i = 0; i < h; i++) {
- int i2 = i;
-
- for (int ii = 0; ii < w; ii++) {
- int dx1 = x1 + p1[ii];
- int dy1 = y1 + p2[i2];
- int dx2 = x2 + p1[ii];
- int dy2 = y2 + p2[i2];
-
- if (++i2 == h)
- i2 = 0;
-
- _screen->setPagePixel(dstPage, dx2, dy2, _screen->getPagePixel(srcPage, dx1, dy1));
- }
-
- if (!dstPage && (i & 5) == 5) {
- updateInput();
- _screen->updateScreen();
- }
- }
-}
-
void LoLEngine::setPaletteBrightness(const Palette &srcPal, int brightness, int modifier) {
generateBrightnessPalette(srcPal, _screen->getPalette(1), brightness, modifier);
_screen->fadePalette(_screen->getPalette(1), 5, 0);
@@ -2040,7 +1909,46 @@ int LoLEngine::playCharacterScriptChat(int charId, int mode, int restorePortrait
return 1;
}
-void LoLEngine::giveItemToMonster(MonsterInPlay *monster, Item item) {
+void LoLEngine::setupDialogueButtons(int numStr, const char *s1, const char *s2, const char *s3) {
+ screen()->setScreenDim(5);
+
+ if (numStr == 1 && speechEnabled()) {
+ _dialogueNumButtons = 0;
+ _dialogueButtonString[0] = _dialogueButtonString[1] = _dialogueButtonString[2] = 0;
+ } else {
+ _dialogueNumButtons = numStr;
+ _dialogueButtonString[0] = s1;
+ _dialogueButtonString[1] = s2;
+ _dialogueButtonString[2] = s3;
+ _dialogueHighlightedButton = 0;
+
+ const ScreenDim *d = screen()->getScreenDim(5);
+
+ static uint16 posX[3];
+ static uint8 posY[3];
+
+ memset(posY, d->sy + d->h - 9, 3);
+
+ _dialogueButtonPosX = posX;
+ _dialogueButtonPosY = posY;
+
+ if (numStr == 1) {
+ posX[0] = posX[1] = posX[2] = d->sx + d->w - (_dialogueButtonW + 3);
+ } else {
+ int xOffs = d->w / numStr;
+ posX[0] = d->sx + (xOffs >> 1) - 37;
+ posX[1] = posX[0] + xOffs;
+ posX[2] = posX[1] + xOffs;
+ }
+
+ drawDialogueButtons();
+ }
+
+ if (!shouldQuit())
+ removeInputTop();
+}
+
+void LoLEngine::giveItemToMonster(LolMonsterInPlay *monster, Item item) {
uint16 *c = &monster->assignedItems;
while (*c)
c = &_itemsInPlay[*c].nextAssignedObject;
@@ -2049,7 +1957,7 @@ void LoLEngine::giveItemToMonster(MonsterInPlay *monster, Item item) {
}
const uint16 *LoLEngine::getCharacterOrMonsterStats(int id) {
- return (id & 0x8000) ? (const uint16 *)_monsters[id & 0x7fff].properties->fightingStats : _characters[id].defaultModifiers;
+ return (id & 0x8000) ? (const uint16*)_monsters[id & 0x7fff].properties->fightingStats : _characters[id].defaultModifiers;
}
uint16 *LoLEngine::getCharacterOrMonsterItemsMight(int id) {
@@ -2073,21 +1981,6 @@ void LoLEngine::delay(uint32 millis, bool doUpdate, bool) {
}
}
-int LoLEngine::rollDice(int times, int pips) {
- if (times <= 0 || pips <= 0)
- return 0;
-
- int res = 0;
- while (times--)
- res += _rnd.getRandomNumberRng(1, pips);
-
- return res;
-}
-
-void LoLEngine::updateEnvironmentalSfx(int soundId) {
- snd_processEnvironmentalSoundEffect(soundId, _currentBlock);
-}
-
// spells
int LoLEngine::castSpell(int charNum, int spellType, int spellLevel) {
@@ -2502,7 +2395,7 @@ int LoLEngine::processMagicIce(int charNum, int spellLevel) {
int might = rollDice(iceDamageMin[spellLevel], iceDamageMax[spellLevel]) + iceDamageAdd[spellLevel];
int dmg = calcInflictableDamagePerItem(charNum, 0, might, 3, 2);
- MonsterInPlay *m = &_monsters[o & 0x7fff];
+ LolMonsterInPlay *m = &_monsters[o & 0x7fff];
if (m->hitPoints <= dmg) {
increaseExperience(charNum, 2, m->hitPoints);
o = m->nextAssignedObject;
@@ -2581,7 +2474,7 @@ int LoLEngine::processMagicFireball(int charNum, int spellLevel) {
while (o & 0x8000) {
static const uint8 fireballDamage[] = { 20, 40, 80, 100 };
int dmg = calcInflictableDamagePerItem(charNum, o, fireballDamage[spellLevel], 4, 1);
- MonsterInPlay *m = &_monsters[o & 0x7fff];
+ LolMonsterInPlay *m = &_monsters[o & 0x7fff];
o = m->nextAssignedObject;
_envSfxUseQueue = true;
inflictDamage(m->id | 0x8000, dmg, charNum, 2, 4);
@@ -2746,7 +2639,7 @@ int LoLEngine::processMagicHandOfFate(int spellLevel) {
uint16 o = _levelBlockProperties[b1].assignedObjects;
while (o & 0x8000) {
uint16 o2 = o;
- MonsterInPlay *m = &_monsters[o & 0x7fff];
+ LolMonsterInPlay *m = &_monsters[o & 0x7fff];
o = findObject(o)->nextAssignedObject;
int nX = 0;
int nY = 0;
@@ -3015,7 +2908,7 @@ int LoLEngine::processMagicVaelansCube() {
uint16 o = _levelBlockProperties[bl].assignedObjects;
while (o & 0x8000) {
- MonsterInPlay *m = &_monsters[o & 0x7fff];
+ LolMonsterInPlay *m = &_monsters[o & 0x7fff];
if (m->properties->flags & 0x1000) {
inflictDamage(o, 100, 0xffff, 0, 0x80);
v = 1;
@@ -3495,7 +3388,7 @@ int LoLEngine::calcInflictableDamage(int16 attacker, int16 target, int hitType)
}
int LoLEngine::inflictDamage(uint16 target, int damage, uint16 attacker, int skill, int flags) {
- MonsterInPlay *m = 0;
+ LolMonsterInPlay *m = 0;
LoLCharacter *c = 0;
if (target & 0x8000) {
@@ -3712,7 +3605,7 @@ void LoLEngine::checkForPartyDeath() {
}
}
-void LoLEngine::applyMonsterAttackSkill(MonsterInPlay *monster, int16 target, int16 damage) {
+void LoLEngine::applyMonsterAttackSkill(LolMonsterInPlay *monster, int16 target, int16 damage) {
if (rollDice(1, 100) > monster->properties->attackSkillChance)
return;
@@ -3782,7 +3675,7 @@ void LoLEngine::applyMonsterAttackSkill(MonsterInPlay *monster, int16 target, in
}
}
-void LoLEngine::applyMonsterDefenseSkill(MonsterInPlay *monster, int16 attacker, int flags, int skill, int damage) {
+void LoLEngine::applyMonsterDefenseSkill(LolMonsterInPlay *monster, int16 attacker, int flags, int skill, int damage) {
if (rollDice(1, 100) > monster->properties->defenseSkillChance)
return;
@@ -4041,7 +3934,7 @@ uint16 LoLEngine::getNearestMonsterFromCharacterForBlock(uint16 block, int charN
int o = _levelBlockProperties[block].assignedObjects;
while (o & 0x8000) {
- MonsterInPlay *m = &_monsters[o & 0x7fff];
+ LolMonsterInPlay *m = &_monsters[o & 0x7fff];
if (m->mode >= 13) {
o = m->nextAssignedObject;
continue;
@@ -4107,7 +4000,7 @@ void LoLEngine::displayAutomap() {
_currentMapLevel = _currentLevel;
uint8 *tmpWll = new uint8[80];
- memcpy(tmpWll, _wllBuffer4, 80);
+ memcpy(tmpWll, _wllAutomapData, 80);
_screen->loadBitmap("parch.cps", 2, 2, &_screen->getPalette(3));
_screen->loadBitmap("autobut.shp", 3, 5, 0);
@@ -4188,7 +4081,7 @@ void LoLEngine::displayAutomap() {
_screen->fadeToBlack(10);
loadLevelWallData(_currentLevel, false);
- memcpy(_wllBuffer4, tmpWll, 80);
+ memcpy(_wllAutomapData, tmpWll, 80);
delete[] tmpWll;
restoreBlockTempData(_currentLevel);
addLevelItems();
@@ -4229,7 +4122,7 @@ bool LoLEngine::updateAutoMapIntern(uint16 block, uint16 x, uint16 y, int16 xOff
uint16 b = block + blockPosTable[6 + xOffs];
if (fx != -1) {
- if (_wllBuffer4[_levelBlockProperties[b].walls[fx]] & 0xc0)
+ if (_wllAutomapData[_levelBlockProperties[b].walls[fx]] & 0xc0)
return false;
}
@@ -4237,13 +4130,13 @@ bool LoLEngine::updateAutoMapIntern(uint16 block, uint16 x, uint16 y, int16 xOff
b = block + blockPosTable[9 + yOffs];
if (fy != -1) {
- if (_wllBuffer4[_levelBlockProperties[b].walls[fy]] & 0xc0)
+ if (_wllAutomapData[_levelBlockProperties[b].walls[fy]] & 0xc0)
return false;
}
b = block + blockPosTable[6 + xOffs] + blockPosTable[9 + yOffs];
- if ((fx != -1) && (fy != -1) && (_wllBuffer4[_levelBlockProperties[b].walls[fx]] & 0xc0) && (_wllBuffer4[_levelBlockProperties[b].walls[fy]] & 0xc0))
+ if ((fx != -1) && (fy != -1) && (_wllAutomapData[_levelBlockProperties[b].walls[fx]] & 0xc0) && (_wllAutomapData[_levelBlockProperties[b].walls[fy]] & 0xc0))
return false;
_levelBlockProperties[b].flags |= 7;
@@ -4252,7 +4145,7 @@ bool LoLEngine::updateAutoMapIntern(uint16 block, uint16 x, uint16 y, int16 xOff
}
void LoLEngine::loadMapLegendData(int level) {
- uint16 *legendData = (uint16 *)_tempBuffer5120;
+ uint16 *legendData= (uint16*)_tempBuffer5120;
for (int i = 0; i < 32; i++) {
legendData[i * 6] = 0xffff;
legendData[i * 6 + 5] = 0xffff;
@@ -4306,7 +4199,7 @@ void LoLEngine::drawMapPage(int pageNum) {
for (; bl < 1024; bl++) {
uint8 *w = _levelBlockProperties[bl].walls;
- if ((_levelBlockProperties[bl].flags & 7) == 7 && (!(_wllBuffer4[w[0]] & 0xc0)) && (!(_wllBuffer4[w[2]] & 0xc0)) && (!(_wllBuffer4[w[1]] & 0xc0))&& (!(_wllBuffer4[w[3]] & 0xc0))) {
+ if ((_levelBlockProperties[bl].flags & 7) == 7 && (!(_wllAutomapData[w[0]] & 0xc0)) && (!(_wllAutomapData[w[2]] & 0xc0)) && (!(_wllAutomapData[w[1]] & 0xc0))&& (!(_wllAutomapData[w[3]] & 0xc0))) {
uint16 b0 = calcNewBlockPosition(bl, 0);
uint16 b2 = calcNewBlockPosition(bl, 2);
uint16 b1 = calcNewBlockPosition(bl, 1);
@@ -4323,25 +4216,25 @@ void LoLEngine::drawMapPage(int pageNum) {
// draw north wall
drawMapBlockWall(b3, w31, sx, sy, 3);
drawMapShape(w31, sx, sy, 3);
- if (_wllBuffer4[w31] & 0xc0)
+ if (_wllAutomapData[w31] & 0xc0)
_screen->copyBlockAndApplyOverlay(_screen->_curPage, sx, sy, _screen->_curPage, sx, sy, 1, 6, 0, _mapOverlay);
// draw west wall
drawMapBlockWall(b1, w13, sx, sy, 1);
drawMapShape(w13, sx, sy, 1);
- if (_wllBuffer4[w13] & 0xc0)
+ if (_wllAutomapData[w13] & 0xc0)
_screen->copyBlockAndApplyOverlay(_screen->_curPage, sx + 6, sy, _screen->_curPage, sx + 6, sy, 1, 6, 0, _mapOverlay);
// draw east wall
drawMapBlockWall(b0, w02, sx, sy, 0);
drawMapShape(w02, sx, sy, 0);
- if (_wllBuffer4[w02] & 0xc0)
+ if (_wllAutomapData[w02] & 0xc0)
_screen->copyBlockAndApplyOverlay(_screen->_curPage, sx, sy, _screen->_curPage, sx, sy, 7, 1, 0, _mapOverlay);
//draw south wall
drawMapBlockWall(b2, w20, sx, sy, 2);
drawMapShape(w20, sx, sy, 2);
- if (_wllBuffer4[w20] & 0xc0)
+ if (_wllAutomapData[w20] & 0xc0)
_screen->copyBlockAndApplyOverlay(_screen->_curPage, sx, sy + 5, _screen->_curPage, sx, sy + 5, 7, 1, 0, _mapOverlay);
}
@@ -4362,7 +4255,7 @@ void LoLEngine::drawMapPage(int pageNum) {
sx = mapGetStartPosX();
sy = mapGetStartPosY();
- uint16 *legendData = (uint16 *)_tempBuffer5120;
+ uint16 *legendData = (uint16*)_tempBuffer5120;
uint8 yOffset = _flags.use16ColorMode ? 4 : 0;
for (int ii = 0; ii < 32; ii++) {
@@ -4508,7 +4401,7 @@ void LoLEngine::redrawMapCursor() {
}
void LoLEngine::drawMapBlockWall(uint16 block, uint8 wall, int x, int y, int direction) {
- if (((1 << direction) & _levelBlockProperties[block].flags) || ((_wllBuffer4[wall] & 0x1f) != 13))
+ if (((1 << direction) & _levelBlockProperties[block].flags) || ((_wllAutomapData[wall] & 0x1f) != 13))
return;
int cp = _screen->_curPage;
@@ -4518,7 +4411,7 @@ void LoLEngine::drawMapBlockWall(uint16 block, uint8 wall, int x, int y, int dir
}
void LoLEngine::drawMapShape(uint8 wall, int x, int y, int direction) {
- int l = _wllBuffer4[wall] & 0x1f;
+ int l = _wllAutomapData[wall] & 0x1f;
if (l == 0x1f)
return;
@@ -4611,48 +4504,7 @@ void LoLEngine::printMapExitButtonText() {
_screen->setCurPage(cp);
}
-void LoLEngine::generateTempData() {
- int l = _currentLevel - 1;
- if (_lvlTempData[l]) {
- delete[] _lvlTempData[l]->wallsXorData;
- delete[] _lvlTempData[l]->flags;
- delete[] _lvlTempData[l]->monsters;
- delete[] _lvlTempData[l]->flyingObjects;
- delete _lvlTempData[l];
- }
-
- _lvlTempData[l] = new LevelTempData;
- _lvlTempData[l]->wallsXorData = new uint8[4096];
- _lvlTempData[l]->flags = new uint8[1024];
- _lvlTempData[l]->monsters = new MonsterInPlay[30];
- _lvlTempData[l]->flyingObjects = new FlyingObject[8];
-
- Common::String filename = Common::String::format("LEVEL%d.CMZ", _currentLevel);
-
- _screen->loadBitmap(filename.c_str(), 15, 15, 0);
- const uint8 *p = _screen->getCPagePtr(14);
- uint16 len = READ_LE_UINT16(p + 4);
- p += 6;
-
- memset(_lvlTempData[l]->wallsXorData, 0, 4096);
- memset(_lvlTempData[l]->flags, 0, 1024);
- uint8 *d = _lvlTempData[l]->wallsXorData;
- uint8 *df = _lvlTempData[l]->flags;
-
- for (int i = 0; i < 1024; i++) {
- for (int ii = 0; ii < 4; ii++)
- *d++ = p[i * len + ii] ^ _levelBlockProperties[i].walls[ii];
- *df++ = _levelBlockProperties[i].flags;
- }
-
- memcpy(_lvlTempData[l]->monsters, _monsters, sizeof(MonsterInPlay) * 30);
- memcpy(_lvlTempData[l]->flyingObjects, _flyingObjects, sizeof(FlyingObject) * 8);
-
- _lvlTempData[l]->monsterDifficulty =_monsterDifficulty;
-
- _hasTempDataFlags |= (1 << l);
-}
} // End of namespace Kyra
diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h
index eb2f6cf2d7..20519b78fb 100644
--- a/engines/kyra/lol.h
+++ b/engines/kyra/lol.h
@@ -25,7 +25,7 @@
#ifndef KYRA_LOL_H
#define KYRA_LOL_H
-#include "kyra/kyra_v1.h"
+#include "kyra/loleobbase.h"
#include "kyra/script_tim.h"
#include "kyra/script.h"
#include "kyra/gui_lol.h"
@@ -86,15 +86,7 @@ struct SpellProperty {
uint16 flags;
};
-struct LevelBlockProperty {
- uint8 walls[4];
- uint16 assignedObjects;
- uint16 drawObjects;
- uint8 direction;
- uint8 flags;
-};
-
-struct MonsterProperty {
+struct LolMonsterProperty {
uint8 shapeIndex;
uint8 maxWidth;
uint16 fightingStats[9];
@@ -116,7 +108,7 @@ struct MonsterProperty {
uint8 sounds[3];
};
-struct MonsterInPlay {
+struct LolMonsterInPlay {
uint16 nextAssignedObject;
uint16 nextDrawObject;
uint8 flyingHeight;
@@ -142,7 +134,7 @@ struct MonsterInPlay {
int16 hitPoints;
uint8 speedTick;
uint8 type;
- MonsterProperty *properties;
+ LolMonsterProperty *properties;
uint8 numDistAttacks;
uint8 curDistWeapon;
int8 distAttackTick;
@@ -179,15 +171,6 @@ struct ItemProperty {
uint8 unkD;
};
-struct LevelShapeProperty {
- uint16 shapeIndex[10];
- uint8 scaleFlag[10];
- int16 shapeX[10];
- int16 shapeY[10];
- int8 next;
- uint8 flags;
-};
-
struct CompassDef {
uint8 shapeIndex;
int8 x;
@@ -195,7 +178,7 @@ struct CompassDef {
uint8 flags;
};
-struct ButtonDef {
+struct LoLButtonDef {
uint16 buttonflags;
uint16 keyCode;
uint16 keyCode2;
@@ -207,12 +190,6 @@ struct ButtonDef {
uint16 screenDim;
};
-struct OpenDoorState {
- uint16 block;
- int8 wall;
- int8 state;
-};
-
struct ActiveSpell {
uint8 spell;
const SpellProperty *p;
@@ -245,14 +222,6 @@ struct FlyingObjectShape {
uint8 flipFlags;
};
-struct LevelTempData {
- uint8 *wallsXorData;
- uint8 *flags;
- MonsterInPlay *monsters;
- FlyingObject *flyingObjects;
- uint8 monsterDifficulty;
-};
-
struct MapLegendData {
uint8 shapeIndex;
bool enable;
@@ -296,7 +265,7 @@ struct MistOfDoomAnimData {
uint8 sound;
};
-class LoLEngine : public KyraEngine_v1 {
+class LoLEngine : public LolEobBaseEngine {
friend class GUI_LoL;
friend class TextDisplayer_LoL;
friend class TIMInterpreter_LoL;
@@ -305,7 +274,7 @@ friend class Debugger_LoL;
friend class HistoryPlayer;
public:
LoLEngine(OSystem *system, const GameFlags &flags);
- ~LoLEngine();
+ virtual ~LoLEngine();
virtual void initKeymap();
@@ -348,13 +317,11 @@ private:
// main loop
void runLoop();
void update();
- void updateEnvironmentalSfx(int soundId);
// mouse
void setMouseCursorToIcon(int icon);
void setMouseCursorToItemInHand();
uint8 *getItemIconShapePtr(int index);
- bool posWithinRect(int mouseX, int mouseY, int x1, int y1, int x2, int y2);
void checkFloatingPointerRegions();
int _floatingCursorControl;
@@ -443,11 +410,7 @@ private:
// timers
void setupTimers();
- void enableTimer(int id);
- void enableSysTimer(int sysTimer);
- void disableSysTimer(int sysTimer);
- void timerProcessDoors(int timerNum);
void timerProcessMonsters(int timerNum);
void timerSpecialCharacterUpdate(int timerNum);
void timerProcessFlyingObjects(int timerNum);
@@ -457,6 +420,9 @@ private:
void timerUpdateLampState(int timerNum);
void timerFadeMessageText(int timerNum);
+ uint8 getClock2Timer(int index) { return index < _numClock2Timers ? _clock2Timers[index] : 0; }
+ uint8 getNumClock2Timers() { return _numClock2Timers; }
+
static const uint8 _clock2Timers[];
static const uint8 _numClock2Timers;
@@ -470,7 +436,7 @@ private:
int snd_updateCharacterSpeech();
void snd_stopSpeech(bool setFlag);
void snd_playSoundEffect(int track, int volume);
- void snd_processEnvironmentalSoundEffect(int soundId, int block);
+ bool snd_processEnvironmentalSoundEffect(int soundId, int block);
void snd_queueEnvironmentalSoundEffect(int soundId, int block);
void snd_playQueuedEffects();
void snd_loadSoundFile(int track);
@@ -479,21 +445,17 @@ private:
int _lastSpeechId;
int _lastSpeaker;
- uint32 _activeVoiceFileTotalTime;
int _lastSfxTrack;
int _lastMusicTrack;
int _curMusicFileIndex;
char _curMusicFileExt;
- int _environmentSfx;
- int _environmentSfxVol;
- int _envSfxDistThreshold;
bool _envSfxUseQueue;
int _envSfxNumTracksInQueue;
uint16 _envSfxQueuedTracks[10];
uint16 _envSfxQueuedBlocks[10];
int _nextSpeechId;
int _nextSpeaker;
- typedef Common::List<Audio::SeekableAudioStream *> SpeechList;
+ typedef Common::List<Audio::SeekableAudioStream*> SpeechList;
SpeechList _speechList;
int _curTlkFile;
@@ -502,9 +464,7 @@ private:
int _ingameSoundListSize;
const uint8 *_musicTrackMap;
- int _musicTrackMapSize;
const uint16 *_ingameSoundIndex;
- int _ingameSoundIndexSize;
const uint8 *_ingameGMSoundIndex;
int _ingameGMSoundIndexSize;
const uint8 *_ingameMT32SoundIndex;
@@ -519,7 +479,6 @@ private:
void gui_drawScene(int pageNum);
void gui_drawAllCharPortraitsWithStats();
void gui_drawCharPortraitWithStats(int charNum);
- void gui_drawBox(int x, int y, int w, int h, int frameColor1, int frameColor2, int fillColor);
void gui_drawCharFaceShape(int charNum, int x, int y, int pageNum);
void gui_highlightPortraitFrame(int charNum);
void gui_drawLiveMagicBar(int x, int y, int curPoints, int unk, int maxPoints, int w, int h, int col1, int col2, int flag);
@@ -534,7 +493,6 @@ private:
void gui_printCharacterStats(int index, int redraw, int value);
void gui_changeCharacterStats(int charNum);
void gui_drawCharInventoryItem(int itemIndex);
- void gui_drawBarGraph(int x, int y, int w, int h, int32 curVal, int32 maxVal, int col1, int col2);
int gui_enableControls();
int gui_disableControls(int controlMode);
@@ -548,37 +506,27 @@ private:
int _lastButtonShape;
uint32 _buttonPressTimer;
int _selectedCharacter;
- int _compassDirection;
int _compassStep;
int _compassDirectionIndex;
uint32 _compassTimer;
int _charInventoryUnk;
const CompassDef *_compassDefs;
- int _compassDefsSize;
void gui_updateInput();
void gui_triggerEvent(int eventType);
- void removeInputTop();
void gui_enableDefaultPlayfieldButtons();
void gui_enableSequenceButtons(int x, int y, int w, int h, int enableFlags);
void gui_specialSceneRestoreButtons();
void gui_enableCharInventoryButtons(int charNum);
- void gui_resetButtonList();
- void gui_initButtonsFromList(const int16 *list);
void gui_setFaceFramesControlButtons(int index, int xOffs);
void gui_initCharInventorySpecialButtons(int charNum);
void gui_initMagicScrollButtons();
void gui_initMagicSubmenu(int charNum);
void gui_initButton(int index, int x = -1, int y = -1, int val = -1);
- void gui_notifyButtonListChanged();
- Common::Array<Button::Callback> _buttonCallbacks;
- Button *_activeButtons;
- Button _activeButtonData[70];
- ButtonDef _sceneWindowButton;
- bool _preserveEvents;
+ LoLButtonDef _sceneWindowButton;
int clickedUpArrow(Button *button);
int clickedDownArrow(Button *button);
@@ -613,45 +561,34 @@ private:
int clickedLamp(Button *button);
int clickedStatusIcon(Button *button);
- const ButtonDef *_buttonData;
- int _buttonDataSize;
+ Common::Array<Button::Callback> _buttonCallbacks;
+ const LoLButtonDef *_buttonData;
const int16 *_buttonList1;
- int _buttonList1Size;
const int16 *_buttonList2;
- int _buttonList2Size;
const int16 *_buttonList3;
- int _buttonList3Size;
const int16 *_buttonList4;
- int _buttonList4Size;
const int16 *_buttonList5;
- int _buttonList5Size;
const int16 *_buttonList6;
- int _buttonList6Size;
const int16 *_buttonList7;
- int _buttonList7Size;
const int16 *_buttonList8;
- int _buttonList8Size;
// text
int characterSays(int track, int charId, bool redraw);
int playCharacterScriptChat(int charId, int mode, int restorePortrait, char *str, EMCState *script, const uint16 *paramList, int16 paramIndex);
+ void setupDialogueButtons(int numStr, const char *s1, const char *s2, const char *s3);
TextDisplayer_LoL *_txt;
+ TextDisplayer_Eob *txt() { return _txt; }
// emc scripts
void runInitScript(const char *filename, int optionalFunc);
void runInfScript(const char *filename);
void runLevelScript(int block, int flags);
void runLevelScriptCustom(int block, int flags, int charNum, int item, int reg3, int reg4);
- bool checkSceneUpdateNeed(int func);
EMCData _scriptData;
bool _suspendScript;
uint16 _scriptDirection;
- uint16 _currentDirection;
- uint16 _currentBlock;
- bool _sceneUpdateRequired;
- int16 _visibleBlockIndex[18];
int16 _globalScriptVars[24];
// emc opcode
@@ -702,7 +639,7 @@ private:
int olol_checkEquippedItemScriptFlags(EMCState *script);
int olol_setDoorState(EMCState *script);
int olol_updateBlockAnimations(EMCState *script);
- int olol_mapShapeToBlock(EMCState *script);
+ int olol_assignLevelDecorationShape(EMCState *script);
int olol_resetBlockShapeAssignment(EMCState *script);
int olol_copyRegion(EMCState *script);
int olol_initMonster(EMCState *script);
@@ -716,7 +653,7 @@ private:
int olol_battleHitSkillTest(EMCState *script);
int olol_inflictDamage(EMCState *script);
int olol_moveMonster(EMCState *script);
- int olol_dialogueBox(EMCState *script);
+ int olol_setupDialogueButtons(EMCState *script);
int olol_giveTakeMoney(EMCState *script);
int olol_checkMoney(EMCState *script);
int olol_setScriptTimer(EMCState *script);
@@ -792,7 +729,7 @@ private:
int olol_assignCustomSfx(EMCState *script);
int olol_findAssignedMonster(EMCState *script);
int olol_checkBlockForMonster(EMCState *script);
- int olol_transformRegion(EMCState *script);
+ int olol_crossFadeRegion(EMCState *script);
int olol_calcCoordinatesAddDirectionOffset(EMCState *script);
int olol_resetPortraitsAndDisableSysTimer(EMCState *script);
int olol_enableSysTimer(EMCState *script);
@@ -820,7 +757,7 @@ private:
int olol_shakeScene(EMCState *script);
int olol_gasExplosion(EMCState *script);
int olol_calcNewBlockPosition(EMCState *script);
- int olol_fadeScene(EMCState *script);
+ int olol_crossFadeScene(EMCState *script);
int olol_updateDrawPage2(EMCState *script);
int olol_setMouseCursor(EMCState *script);
int olol_characterSays(EMCState *script);
@@ -834,14 +771,14 @@ private:
// tim opcode
void setupOpcodeTable();
- Common::Array<const TIMOpcode *> _timIntroOpcodes;
+ Common::Array<const TIMOpcode*> _timIntroOpcodes;
int tlol_setupPaletteFade(const TIM *tim, const uint16 *param);
int tlol_loadPalette(const TIM *tim, const uint16 *param);
int tlol_setupPaletteFadeEx(const TIM *tim, const uint16 *param);
int tlol_processWsaFrame(const TIM *tim, const uint16 *param);
int tlol_displayText(const TIM *tim, const uint16 *param);
- Common::Array<const TIMOpcode *> _timOutroOpcodes;
+ Common::Array<const TIMOpcode*> _timOutroOpcodes;
int tlol_fadeInScene(const TIM *tim, const uint16 *param);
int tlol_unusedResourceFunc(const TIM *tim, const uint16 *param);
int tlol_fadeInPalette(const TIM *tim, const uint16 *param);
@@ -850,7 +787,7 @@ private:
int tlol_delayForChat(const TIM *tim, const uint16 *param);
int tlol_fadeOutSound(const TIM *tim, const uint16 *param);
- Common::Array<const TIMOpcode *> _timIngameOpcodes;
+ Common::Array<const TIMOpcode*> _timIngameOpcodes;
int tlol_initSceneWindowDialogue(const TIM *tim, const uint16 *param);
int tlol_restoreAfterSceneWindowDialogue(const TIM *tim, const uint16 *param);
int tlol_giveItem(const TIM *tim, const uint16 *param);
@@ -900,7 +837,6 @@ private:
void createTransparencyTables();
void updateSequenceBackgroundAnimations();
- bool _dialogueField;
uint8 **_itemIconShapes;
int _numItemIconShapes;
uint8 **_itemShapes;
@@ -913,7 +849,6 @@ private:
int _numEffectShapes;
const int8 *_gameShapeMap;
- int _gameShapeMapSize;
uint8 *_characterFaceShapes[40][3];
@@ -942,19 +877,13 @@ private:
LoLCharacter *_characters;
uint16 _activeCharsXpos[3];
- int _updateFlags;
- int _updateCharNum;
- int _updatePortraitSpeechAnimDuration;
+
int _portraitSpeechAnimMode;
- int _resetPortraitAfterSpeechAnim;
int _textColorFlag;
- bool _fadeText;
- int _needSceneRestore;
uint32 _palUpdateTimer;
uint32 _updatePortraitNext;
int _loadLevelFlag;
- int _hasTempDataFlags;
int _activeMagicMenu;
uint16 _scriptCharacterCycle;
int _charStatsTemp[5];
@@ -963,15 +892,10 @@ private:
int _charDefaultsSize;
const uint16 *_charDefsMan;
- int _charDefsManSize;
const uint16 *_charDefsWoman;
- int _charDefsWomanSize;
const uint16 *_charDefsKieran;
- int _charDefsKieranSize;
const uint16 *_charDefsAkshel;
- int _charDefsAkshelSize;
const int32 *_expRequirements;
- int _expRequirementsSize;
// lamp
void resetLampStatus();
@@ -983,16 +907,14 @@ private:
int _lampOilStatus;
uint32 _lampStatusTimer;
bool _lampStatusSuspended;
- uint8 _blockBrightness;
// level
void loadLevel(int index);
void addLevelItems();
- void loadLevelWallData(int index, bool mapShapes);
+ void loadLevelWallData(int fileIndex, bool mapShapes);
void assignBlockObject(LevelBlockProperty *l, uint16 item);
- int assignLevelShapes(int index);
- uint8 *getLevelShapes(int index);
- void restoreBlockTempData(int index);
+ int assignLevelDecorationShapes(int index);
+ uint8 *getLevelDecorationShapes(int index);
void restoreTempDataAdjustMonsterStrength(int index);
void loadBlockProperties(const char *cmzFile);
void loadLevelShpDat(const char *shpFile, const char *datFile, bool flag);
@@ -1006,17 +928,7 @@ private:
void drawScene(int pageNum);
- void generateBlockDrawingBuffer();
- void generateVmpTileData(int16 startBlockX, uint8 startBlockY, uint8 wllVmpIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY);
- void generateVmpTileDataFlipped(int16 startBlockX, uint8 startBlockY, uint8 wllVmpIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY);
- bool hasWall(int index);
- void assignVisibleBlocks(int block, int direction);
-
- void drawVcnBlocks();
void drawSceneShapes();
- void setLevelShapesDim(int index, int16 &x1, int16 &x2, int dim);
- void scaleLevelShapesDim(int index, int16 &y1, int16 &y2, int dim);
- void drawLevelModifyScreenDim(int dim, int16 x1, int16 y1, int16 x2, int16 y2);
void drawDecorations(int index);
void drawBlockEffects(int index, int type);
void drawSpecialGuiShape(int pageNum);
@@ -1033,27 +945,17 @@ private:
void updateCompass();
void moveParty(uint16 direction, int unk1, int unk2, int buttonShape);
- bool checkBlockPassability(uint16 block, uint16 direction);
void notifyBlockNotPassable(int scrollFlag);
+ virtual bool checkBlockPassability(uint16 block, uint16 direction);
- uint16 calcNewBlockPosition(uint16 curBlock, uint16 direction);
uint16 calcBlockIndex(uint16 x, uint16 y);
void calcCoordinates(uint16 &x, uint16 &y, int block, uint16 xOffs, uint16 yOffs);
void calcCoordinatesForSingleCharacter(int charNum, uint16 &x, uint16 &y);
void calcCoordinatesAddDirectionOffset(uint16 &x, uint16 &y, int direction);
- int clickedWallShape(uint16 block, uint16 direction);
- int clickedLeverOn(uint16 block, uint16 direction);
- int clickedLeverOff(uint16 block, uint16 direction);
- int clickedWallOnlyScript(uint16 block);
int clickedDoorSwitch(uint16 block, uint16 direction);
int clickedNiche(uint16 block, uint16 direction);
- bool clickedShape(int shapeIndex);
- void processDoorSwitch(uint16 block, int unk);
- void openCloseDoor(uint16 block, int openClose);
- void completeDoorOperations();
-
void movePartySmoothScrollBlocked(int speed);
void movePartySmoothScrollUp(int speed);
void movePartySmoothScrollDown(int speed);
@@ -1069,79 +971,40 @@ private:
int smoothScrollDrawSpecialGuiShape(int pageNum);
- OpenDoorState _openDoorState[3];
int _blockDoor;
int _smoothScrollModeNormal;
const uint8 *_scrollXTop;
- int _scrollXTopSize;
const uint8 *_scrollYTop;
- int _scrollYTopSize;
const uint8 *_scrollXBottom;
- int _scrollXBottomSize;
const uint8 *_scrollYBottom;
- int _scrollYBottomSize;
int _nextScriptFunc;
- uint8 _currentLevel;
- int _sceneDefaultUpdate;
- int _lvlBlockIndex;
int _lvlShapeIndex;
bool _partyAwake;
- uint8 *_vcnBlocks;
- uint8 *_vcnShift;
- uint8 *_vcnExpTable;
- uint16 *_vmpPtr;
- uint8 *_vcfBlocks;
- uint16 *_blockDrawingBuffer;
- uint8 *_sceneWindowBuffer;
- LevelShapeProperty *_levelShapeProperties;
- uint8 **_levelShapes;
uint8 *_specialGuiShape;
uint16 _specialGuiShapeX;
uint16 _specialGuiShapeY;
uint16 _specialGuiShapeMirrorFlag;
- char _lastBlockDataFile[12];
char _lastOverridePalFile[12];
char *_lastOverridePalFilePtr;
int _lastSpecialColor;
int _lastSpecialColorWeight;
- int _sceneDrawVarDown;
- int _sceneDrawVarRight;
- int _sceneDrawVarLeft;
- int _wllProcessFlag;
-
uint8 *_transparencyTable2;
uint8 *_transparencyTable1;
int _loadSuppFilesFlag;
-
- uint8 *_wllVmpMap;
- int8 *_wllShapeMap;
- uint8 *_specialWallTypes;
- uint8 *_wllBuffer4;
- uint8 *_wllWallFlags;
-
- int16 *_lvlShapeTop;
- int16 *_lvlShapeBottom;
- int16 *_lvlShapeLeftRight;
-
- LevelBlockProperty *_levelBlockProperties;
- LevelBlockProperty *_visibleBlocks[18];
+ uint8 *_wllAutomapData;
uint16 _partyPosX;
uint16 _partyPosY;
Common::SeekableReadStream *_lvlShpFileHandle;
- uint16 _lvlShpNum;
- uint16 _levelFileDataSize;
- LevelShapeProperty *_levelFileData;
- uint8 *_doorShapes[2];
int _shpDmX;
int _shpDmY;
uint16 _dmScaleW;
@@ -1154,55 +1017,20 @@ private:
uint8 *_tempBuffer5120;
const char * const *_levelDatList;
- int _levelDatListSize;
const char * const *_levelShpList;
- int _levelShpListSize;
- const int8 *_dscUnk1;
- int _dscUnk1Size;
- const int8 *_dscShapeIndex;
- int _dscShapeIndexSize;
+ const int8 *_dscWalls;
+
const uint8 *_dscOvlMap;
- int _dscOvlMapSize;
+ const uint8 *_dscShapeOvlIndex;
const uint16 *_dscShapeScaleW;
- int _dscShapeScaleWSize;
const uint16 *_dscShapeScaleH;
- int _dscShapeScaleHSize;
- const int16 *_dscShapeX;
- int _dscShapeXSize;
const int8 *_dscShapeY;
- int _dscShapeYSize;
- const uint8 *_dscTileIndex;
- int _dscTileIndexSize;
- const uint8 *_dscUnk2;
- int _dscUnk2Size;
- const uint8 *_dscDoorShpIndex;
- int _dscDoorShpIndexSize;
- const int8 *_dscDim1;
- int _dscDim1Size;
- const int8 *_dscDim2;
- int _dscDim2Size;
- const uint8 *_dscBlockMap;
- int _dscBlockMapSize;
- const uint8 *_dscDimMap;
- int _dscDimMapSize;
+
const uint16 *_dscDoorMonsterScaleTable;
- int _dscDoorMonsterScaleTableSize;
const uint16 *_dscDoor4;
- int _dscDoor4Size;
- const uint8 *_dscShapeOvlIndex;
- int _dscShapeOvlIndexSize;
- const int8 *_dscBlockIndex;
- int _dscBlockIndexSize;
- const uint8 *_dscDoor1;
- int _dscDoor1Size;
const int16 *_dscDoorMonsterX;
- int _dscDoorMonsterXSize;
const int16 *_dscDoorMonsterY;
- int _dscDoorMonsterYSize;
-
- int _sceneDrawPage1;
- int _sceneDrawPage2;
// items
void giveCredits(int credits, int redraw);
@@ -1239,8 +1067,7 @@ private:
Item _itemInHand;
Item _inventory[48];
Item _inventoryCurItem;
- int _currentControlMode;
- int _specialSceneFlag;
+
int _lastCharInventory;
uint16 _charStatusFlags[3];
int _emcLastItem;
@@ -1250,34 +1077,27 @@ private:
EMCData _itemScript;
const uint8 *_charInvIndex;
- int _charInvIndexSize;
const uint8 *_charInvDefs;
- int _charInvDefsSize;
const uint16 *_inventorySlotDesc;
- int _inventorySlotDescSize;
const uint16 *_itemCost;
- int _itemCostSize;
const uint8 *_stashSetupData;
- int _stashSetupDataSize;
const int8 *_sceneItemOffs;
- int _sceneItemOffsSize;
const FlyingObjectShape *_flyingItemShapes;
- int _flyingItemShapesSize;
// monsters
void loadMonsterShapes(const char *file, int monsterIndex, int b);
void releaseMonsterShapes(int monsterIndex);
int deleteMonstersFromBlock(int block);
- void setMonsterMode(MonsterInPlay *monster, int mode);
- bool updateMonsterAdjustBlocks(MonsterInPlay *monster);
- void placeMonster(MonsterInPlay *monster, uint16 x, uint16 y);
+ void setMonsterMode(LolMonsterInPlay *monster, int mode);
+ bool updateMonsterAdjustBlocks(LolMonsterInPlay *monster);
+ void placeMonster(LolMonsterInPlay *monster, uint16 x, uint16 y);
int calcMonsterDirection(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
- void setMonsterDirection(MonsterInPlay *monster, int dir);
- void monsterDropItems(MonsterInPlay *monster);
+ void setMonsterDirection(LolMonsterInPlay *monster, int dir);
+ void monsterDropItems(LolMonsterInPlay *monster);
void removeAssignedObjectFromBlock(LevelBlockProperty *l, uint16 id);
void removeDrawObjectFromBlock(LevelBlockProperty *l, uint16 id);
void assignMonsterToBlock(uint16 *assignedBlockObjects, uint16 id);
- void giveItemToMonster(MonsterInPlay *monster, Item item);
+ void giveItemToMonster(LolMonsterInPlay *monster, Item item);
int checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 objectWidth, uint16 testFlag, uint16 wallFlag);
int checkBlockForWallsAndSufficientSpace(int block, int x, int y, int objectWidth, int testFlag, int wallFlag);
int calcMonsterSkillLevel(int id, int a);
@@ -1288,7 +1108,7 @@ private:
void drawBlockObjects(int blockArrayIndex);
void drawMonster(uint16 id);
- int getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags);
+ int getMonsterCurFrame(LolMonsterInPlay *m, uint16 dirFlags);
void reassignDrawObjects(uint16 direction, uint16 itemIndex, LevelBlockProperty *l, bool flag);
void redrawSceneItem();
int calcItemMonsterPosition(ItemInPlay *i, uint16 direction);
@@ -1298,47 +1118,35 @@ private:
uint8 *drawItemOrMonster(uint8 *shape, uint8 *monsterPalette, int x, int y, int fineX, int fineY, int flags, int tblValue, bool vflip);
int calcDrawingLayerParameters(int srcX, int srcY, int &x2, int &y2, uint16 &w, uint16 &h, uint8 *shape, int vflip);
- void updateMonster(MonsterInPlay *monster);
- void moveMonster(MonsterInPlay *monster);
- void walkMonster(MonsterInPlay *monster);
- bool chasePartyWithDistanceAttacks(MonsterInPlay *monster);
- void chasePartyWithCloseAttacks(MonsterInPlay *monster);
- int walkMonsterCalcNextStep(MonsterInPlay *monster);
- int getMonsterDistance(uint16 block1, uint16 block2);
+ void updateMonster(LolMonsterInPlay *monster);
+ void moveMonster(LolMonsterInPlay *monster);
+ void walkMonster(LolMonsterInPlay *monster);
+ bool chasePartyWithDistanceAttacks(LolMonsterInPlay *monster);
+ void chasePartyWithCloseAttacks(LolMonsterInPlay *monster);
+ int walkMonsterCalcNextStep(LolMonsterInPlay *monster);
int checkForPossibleDistanceAttack(uint16 monsterBlock, int direction, int distance, uint16 curBlock);
- int walkMonsterCheckDest(int x, int y, MonsterInPlay *monster, int unk);
+ int walkMonsterCheckDest(int x, int y, LolMonsterInPlay *monster, int unk);
void getNextStepCoords(int16 monsterX, int16 monsterY, int &newX, int &newY, uint16 direction);
- void rearrangeAttackingMonster(MonsterInPlay *monster);
- void moveStrayingMonster(MonsterInPlay *monster);
- void killMonster(MonsterInPlay *monster);
-
- MonsterInPlay *_monsters;
- MonsterProperty *_monsterProperties;
- uint8 **_monsterShapes;
- uint8 **_monsterPalettes;
- uint8 **_monsterShapesEx;
+ void rearrangeAttackingMonster(LolMonsterInPlay *monster);
+ void moveStrayingMonster(LolMonsterInPlay *monster);
+ void killMonster(LolMonsterInPlay *monster);
+
+ LolMonsterInPlay *_monsters;
+ LolMonsterProperty *_monsterProperties;
+ uint8 **_monsterDecorationShapes;
uint8 _monsterAnimType[3];
uint16 _monsterCurBlock;
int _objectLastDirection;
- int _monsterStepCounter;
- int _monsterStepMode;
const uint16 *_monsterModifiers;
- int _monsterModifiersSize;
const int8 *_monsterShiftOffs;
- int _monsterShiftOffsSize;
const uint8 *_monsterDirFlags;
- int _monsterDirFlagsSize;
const uint8 *_monsterScaleX;
- int _monsterScaleXSize;
const uint8 *_monsterScaleY;
- int _monsterScaleYSize;
const uint16 *_monsterScaleWH;
- int _monsterScaleWHSize;
// misc
void delay(uint32 millis, bool doUpdate = false, bool isMainLoop = false);
- int rollDice(int times, int pips);
uint8 _compassBroken;
uint8 _drainMagic;
@@ -1349,7 +1157,7 @@ private:
// spells
typedef Common::Functor1Mem<ActiveSpell *, int, LoLEngine> SpellProc;
- Common::Array<const SpellProc *> _spellProcs;
+ Common::Array<const SpellProc*> _spellProcs;
typedef void (LoLEngine::*SpellProcCallback)(WSAMovie_v2 *, int, int);
int castSpell(int charNum, int spellType, int spellLevel);
@@ -1398,7 +1206,7 @@ private:
int8 _availableSpells[8];
int _selectedSpell;
const SpellProperty *_spellProperties;
- int _spellPropertiesSize;
+ //int _spellPropertiesSize;
int _subMenuIndex;
LightningProperty *_lightningProps;
@@ -1420,13 +1228,9 @@ private:
static const MistOfDoomAnimData _mistAnimData[];
const uint8 *_updateSpellBookCoords;
- int _updateSpellBookCoordsSize;
const uint8 *_updateSpellBookAnimData;
- int _updateSpellBookAnimDataSize;
const uint8 *_healShapeFrames;
- int _healShapeFramesSize;
const int16 *_fireBallCoords;
- int _fireBallCoordsSize;
// fight
int battleHitSkillTest(int16 attacker, int16 target, int skill);
@@ -1437,8 +1241,8 @@ private:
int calcInflictableDamagePerItem(int16 attacker, int16 target, uint16 itemMight, int index, int hitType);
void checkForPartyDeath();
- void applyMonsterAttackSkill(MonsterInPlay *monster, int16 target, int16 damage);
- void applyMonsterDefenseSkill(MonsterInPlay *monster, int16 attacker, int flags, int skill, int damage);
+ void applyMonsterAttackSkill(LolMonsterInPlay *monster, int16 target, int16 damage);
+ void applyMonsterDefenseSkill(LolMonsterInPlay *monster, int16 attacker, int flags, int skill, int damage);
int removeCharacterItem(int charNum, int itemFlags);
int paralyzePoisonCharacter(int charNum, int typeFlag, int immunityFlags, int hitChance, int redraw);
void paralyzePoisonAllCharacters(int typeFlag, int immunityFlags, int hitChance);
@@ -1478,7 +1282,6 @@ private:
uint8 *_mapOverlay;
const uint8 **_automapShapes;
const uint16 *_autoMapStrings;
- int _autoMapStringsSize;
MapLegendData *_defaultLegendData;
uint8 *_mapCursorOverlay;
uint8 _automapTopLeftX;
@@ -1495,10 +1298,15 @@ private:
Common::Error loadGameState(int slot);
Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail);
- Graphics::Surface *generateSaveThumbnail() const;
+ void *generateMonsterTempData(LevelTempData *tmp);
+ void *generateFlyingObjectTempData(LevelTempData *tmp);
+ void restoreBlockTempData(int levelIndex);
+ void restoreMonsterTempData(LevelTempData *tmp);
+ void restoreFlyingObjectTempData(LevelTempData *tmp);
+ void releaseMonsterTempData(LevelTempData *tmp);
+ void releaseFlyingObjectTempData(LevelTempData *tmp);
- void generateTempData();
- LevelTempData *_lvlTempData[29];
+ Graphics::Surface *generateSaveThumbnail() const;
};
class HistoryPlayer {
diff --git a/engines/kyra/loleobbase.cpp b/engines/kyra/loleobbase.cpp
new file mode 100644
index 0000000000..05b683b830
--- /dev/null
+++ b/engines/kyra/loleobbase.cpp
@@ -0,0 +1,354 @@
+/* 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.
+ *
+ */
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#include "kyra/loleobbase.h"
+#include "kyra/sound.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+LolEobBaseEngine::LolEobBaseEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(system, flags) {
+ _txt = 0;
+ _mouseClick = 0;
+ _preserveEvents = _buttonListChanged = false;
+
+ _sceneXoffset = 0;
+ _sceneShpDim = 5;
+ _activeButtons = 0;
+
+ _currentLevel = 0;
+
+ _vmpPtr = 0;
+ _vcnBlocks = 0;
+ _vcfBlocks = 0;
+ _vcnShift = 0;
+ _vcnExpTable = 0;
+ _vmpPtr = 0;
+ _blockBrightness = _wllVcnOffset = 0;
+ _blockDrawingBuffer = 0;
+ _sceneWindowBuffer = 0;
+ _monsterShapes = _monsterPalettes = 0;
+
+ _doorShapes = 0;
+
+ _levelDecorationProperties = 0;
+ _levelDecorationData = 0;
+ _levelDecorationShapes = 0;
+ _decorationCount = 0;
+ _mappedDecorationsCount = 0;
+ memset(_visibleBlockIndex, 0, sizeof(_visibleBlockIndex));
+
+ _lvlShapeTop = _lvlShapeBottom = _lvlShapeLeftRight = 0;
+ _levelBlockProperties = 0;
+ _hasTempDataFlags = 0;
+
+ _wllVmpMap = _specialWallTypes = _wllWallFlags = 0;
+ _wllShapeMap = 0;
+
+ _sceneDrawVarDown = _sceneDrawVarRight = _sceneDrawVarLeft = _wllProcessFlag = 0;
+
+ _currentBlock = 0;
+ _currentDirection = 0;
+ _compassDirection = -1;
+ _updateFlags = _clickedSpecialFlag = 0;
+ _sceneDefaultUpdate = 0;
+ _sceneUpdateRequired = false;
+
+ _clickedShapeXOffs = _clickedShapeYOffs = 0;
+
+ _dscShapeX = 0;
+ _dscTileIndex = 0;
+ _dscUnk2 = 0;
+ _dscDim1 = 0;
+ _dscDim2 = 0;
+ _dscBlockMap = 0;
+ _dscBlockIndex = 0;
+ _dscShapeIndex = 0;
+ _dscDimMap = 0;
+ _dscDoorShpIndex = 0;
+ _dscDoorY2 = 0;
+
+ _shpDmX1 = _shpDmX2 = 0;
+
+ memset(_openDoorState, 0, sizeof(_openDoorState));
+ memset(_dialogueButtonString, 0, 3 * sizeof(const char *));
+ _dialogueButtonPosX = 0;
+ _dialogueButtonPosY = 0;
+ _dialogueNumButtons = _dialogueButtonYoffs = _dialogueHighlightedButton = 0;
+ _currentControlMode = 0;
+ _specialSceneFlag = 0;
+ _dialogueButtonLabelCol1 = 9;
+ _dialogueButtonLabelCol2 = 15;
+ _dialogueButtonW = 95;
+ _dialogueButtonH = 9;
+
+ _updateCharNum = -1;
+ _activeVoiceFileTotalTime = 0;
+ _updatePortraitSpeechAnimDuration = _resetPortraitAfterSpeechAnim = _needSceneRestore = 0;
+ _fadeText = false;
+
+ memset(_lvlTempData, 0, sizeof(_lvlTempData));
+
+ _dialogueField = false;
+
+ _environmentSfx = _environmentSfxVol = _envSfxDistThreshold = 0;
+ _monsterStepCounter = _monsterStepMode = 0;
+}
+
+LolEobBaseEngine::~LolEobBaseEngine() {
+ delete[] _wllVmpMap;
+ delete[] _wllShapeMap;
+ delete[] _specialWallTypes;
+ delete[] _wllWallFlags;
+
+ delete[] _vmpPtr;
+ delete[] _vcnExpTable;
+ delete[] _vcnBlocks;
+ delete[] _vcfBlocks;
+ delete[] _vcnShift;
+ delete[] _blockDrawingBuffer;
+ delete[] _sceneWindowBuffer;
+
+ delete[] _lvlShapeTop;
+ delete[] _lvlShapeBottom;
+ delete[] _lvlShapeLeftRight;
+
+ delete[] _doorShapes;
+
+ delete[] _levelDecorationShapes;
+ delete[] _levelDecorationData;
+ delete[] _levelDecorationProperties;
+ delete[] _levelBlockProperties;
+
+ delete _txt;
+ _txt = 0;
+}
+
+Common::Error LolEobBaseEngine::init() {
+ _levelDecorationProperties = new LevelDecorationProperty[100];
+ memset(_levelDecorationProperties, 0, 100 * sizeof(LevelDecorationProperty));
+ _levelDecorationShapes = new uint8*[400];
+ memset(_levelDecorationShapes, 0, 400 * sizeof(uint8*));
+ _levelBlockProperties = new LevelBlockProperty[1025];
+ memset(_levelBlockProperties, 0, 1025 * sizeof(LevelBlockProperty));
+
+ _wllVmpMap = new uint8[255];
+ memset(_wllVmpMap, 0, 255);
+ _wllShapeMap = new int8[255];
+ memset(_wllShapeMap, 0, 255);
+ _specialWallTypes = new uint8[255];
+ memset(_specialWallTypes, 0, 255);
+ _wllWallFlags = new uint8[255];
+ memset(_wllWallFlags, 0, 255);
+
+ _blockDrawingBuffer = new uint16[1320];
+ memset(_blockDrawingBuffer, 0, 1320 * sizeof(uint16));
+ _sceneWindowBuffer = new uint8[21120];
+ memset(_sceneWindowBuffer, 0, 21120);
+
+ _lvlShapeTop = new int16[18];
+ memset(_lvlShapeTop, 0, 18 * sizeof(int16));
+ _lvlShapeBottom = new int16[18];
+ memset(_lvlShapeBottom, 0, 18 * sizeof(int16));
+ _lvlShapeLeftRight = new int16[36];
+ memset(_lvlShapeLeftRight, 0, 36 * sizeof(int16));
+
+ _vcnExpTable = new uint8[128];
+ for (int i = 0; i < 128; i++)
+ _vcnExpTable[i] = i & 0x0f;
+
+ _doorShapes = new uint8*[6];
+ memset(_doorShapes, 0, 6 * sizeof(uint8*));
+
+ initStaticResource();
+
+ _envSfxDistThreshold = (_sound->getSfxType() == Sound::kAdLib || _sound->getSfxType() == Sound::kPCSpkr) ? 15 : 3;
+
+ return Common::kNoError;
+}
+
+bool LolEobBaseEngine::posWithinRect(int mouseX, int mouseY, int x1, int y1, int x2, int y2) {
+ if (mouseX < x1 || mouseX > x2 || mouseY < y1 || mouseY > y2)
+ return false;
+ return true;
+}
+
+void LolEobBaseEngine::drawDialogueButtons() {
+ int cp = screen()->setCurPage(0);
+ Screen::FontId of = screen()->setFont(gameFlags().use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_6_FNT);
+
+ for (int i = 0; i < _dialogueNumButtons; i++) {
+ int x = _dialogueButtonPosX[i];
+ if (gameFlags().use16ColorMode) {
+ gui_drawBox(x, ((_dialogueButtonYoffs + _dialogueButtonPosY[i]) & ~7) - 1, 74, 10, 0xee, 0xcc, -1);
+ screen()->printText(_dialogueButtonString[i], (x + 37 - (screen()->getTextWidth(_dialogueButtonString[i])) / 2) & ~3,
+ ((_dialogueButtonYoffs + _dialogueButtonPosY[i]) + 2) & ~7, _dialogueHighlightedButton == i ? 0xc1 : 0xe1, 0);
+ } else {
+ gui_drawBox(x, (_dialogueButtonYoffs + _dialogueButtonPosY[i]), _dialogueButtonW, _dialogueButtonH, _color1_1, _color2_1, _bkgColor_1);
+ screen()->printText(_dialogueButtonString[i], x + (_dialogueButtonW >> 1) - (screen()->getTextWidth(_dialogueButtonString[i])) / 2,
+ (_dialogueButtonYoffs + _dialogueButtonPosY[i]) + 2, _dialogueHighlightedButton == i ? _dialogueButtonLabelCol1 : _dialogueButtonLabelCol2, 0);
+ }
+ }
+ screen()->setFont(of);
+ screen()->setCurPage(cp);
+}
+
+uint16 LolEobBaseEngine::processDialogue() {
+ int df = _dialogueHighlightedButton;
+ int res = 0;
+
+ for (int i = 0; i < _dialogueNumButtons; i++) {
+ int x = _dialogueButtonPosX[i];
+ int y = (gameFlags().use16ColorMode ? ((_dialogueButtonYoffs + _dialogueButtonPosY[i]) & ~7) - 1 : (_dialogueButtonYoffs + _dialogueButtonPosY[i]));
+ Common::Point p = getMousePos();
+ if (posWithinRect(p.x, p.y, x, y, x + _dialogueButtonW, y + _dialogueButtonH)) {
+ _dialogueHighlightedButton = i;
+ break;
+ }
+ }
+
+ if (_dialogueNumButtons == 0) {
+ int e = checkInput(0, false) & 0xFF;
+ removeInputTop();
+
+ if (e) {
+ gui_notifyButtonListChanged();
+
+ if (e == _keyMap[Common::KEYCODE_SPACE] || e == _keyMap[Common::KEYCODE_RETURN]) {
+ snd_stopSpeech(true);
+ }
+ }
+
+ if (snd_updateCharacterSpeech() != 2) {
+ res = 1;
+ if (!shouldQuit()) {
+ removeInputTop();
+ gui_notifyButtonListChanged();
+ }
+ }
+ } else {
+ int e = checkInput(0, false) & 0xFF;
+ removeInputTop();
+ if (e)
+ gui_notifyButtonListChanged();
+
+ if (_flags.gameID == GI_LOL && (e == 200 || e == 202) || _flags.gameID != GI_LOL && (e == 199 || e == 201)) {
+ for (int i = 0; i < _dialogueNumButtons; i++) {
+ int x = _dialogueButtonPosX[i];
+ int y = (gameFlags().use16ColorMode ? ((_dialogueButtonYoffs + _dialogueButtonPosY[i]) & ~7) - 1 : (_dialogueButtonYoffs + _dialogueButtonPosY[i]));
+ Common::Point p = getMousePos();
+ if (posWithinRect(p.x, p.y, x, y, x + _dialogueButtonW, y + _dialogueButtonH)) {
+ _dialogueHighlightedButton = i;
+ res = _dialogueHighlightedButton + 1;
+ break;
+ }
+ }
+ } else if (e == _keyMap[Common::KEYCODE_SPACE] || e == _keyMap[Common::KEYCODE_RETURN]) {
+ snd_stopSpeech(true);
+ res = _dialogueHighlightedButton + 1;
+ } else if (e == _keyMap[Common::KEYCODE_LEFT] || e == _keyMap[Common::KEYCODE_DOWN]) {
+ if (_dialogueNumButtons > 1 && _dialogueHighlightedButton > 0)
+ _dialogueHighlightedButton--;
+ } else if (e == _keyMap[Common::KEYCODE_RIGHT] || e == _keyMap[Common::KEYCODE_UP]) {
+ if (_dialogueNumButtons > 1 && _dialogueHighlightedButton < (_dialogueNumButtons - 1))
+ _dialogueHighlightedButton++;
+ }
+ }
+
+ if (df != _dialogueHighlightedButton)
+ drawDialogueButtons();
+
+ screen()->updateScreen();
+
+ if (res == 0)
+ return 0;
+
+ stopPortraitSpeechAnim();
+
+ if (game() == GI_LOL) {
+ if (!textEnabled() && _currentControlMode) {
+ screen()->setScreenDim(5);
+ const ScreenDim *d = screen()->getScreenDim(5);
+ screen()->fillRect(d->sx, d->sy + d->h - 9, d->sx + d->w - 1, d->sy + d->h - 1, d->unkA);
+ } else {
+ const ScreenDim *d = screen()->_curDim;
+ if (gameFlags().use16ColorMode)
+ screen()->fillRect(d->sx, d->sy, d->sx + d->w - 3, d->sy + d->h - 2, d->unkA);
+ else
+ screen()->fillRect(d->sx, d->sy, d->sx + d->w - 2, d->sy + d->h - 1, d->unkA);
+ txt()->clearDim(4);
+ txt()->resetDimTextPositions(4);
+ }
+ }
+
+ return res;
+}
+
+void LolEobBaseEngine::delayUntil(uint32 time, bool doUpdate, bool isMainLoop) {
+ uint32 curTime = _system->getMillis();
+ if (time > curTime)
+ delay(time - curTime, doUpdate, isMainLoop);
+}
+
+int LolEobBaseEngine::rollDice(int times, int pips, int inc) {
+ if (times <= 0 || pips <= 0)
+ return inc;
+
+ int res = 0;
+ while (times--)
+ res += _rnd.getRandomNumberRng(1, pips);
+
+ return res + inc;
+}
+
+bool LolEobBaseEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) {
+ if (!_sound->sfxEnabled() || shouldQuit())
+ return false;
+
+ if (_environmentSfx)
+ snd_playSoundEffect(_environmentSfx, _environmentSfxVol);
+
+ int dist = 0;
+ if (block) {
+ dist = getBlockDistance(_currentBlock, block);
+ if (dist > _envSfxDistThreshold) {
+ _environmentSfx = 0;
+ return false;
+ }
+ }
+
+ _environmentSfx = soundId;
+ _environmentSfxVol = (15 - ((block || (_flags.gameID == GI_LOL && dist < 2)) ? dist : 0)) << 4;
+
+ return true;
+}
+
+void LolEobBaseEngine::updateEnvironmentalSfx(int soundId) {
+ snd_processEnvironmentalSoundEffect(soundId, _currentBlock);
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB || ENABLE_LOL
diff --git a/engines/kyra/loleobbase.h b/engines/kyra/loleobbase.h
new file mode 100644
index 0000000000..042f9c0e78
--- /dev/null
+++ b/engines/kyra/loleobbase.h
@@ -0,0 +1,324 @@
+/* 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.
+ *
+ */
+
+#ifndef KYRA_LOLEOBBASE_H
+#define KYRA_LOLEOBBASE_H
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#include "kyra/kyra_v1.h"
+#include "kyra/screen_eob.h"
+#include "kyra/gui_eob.h"
+#include "kyra/text_lol.h"
+
+namespace Kyra {
+
+struct LevelDecorationProperty {
+ uint16 shapeIndex[10];
+ uint8 scaleFlag[10];
+ int16 shapeX[10];
+ int16 shapeY[10];
+ int8 next;
+ uint8 flags;
+};
+
+struct LevelBlockProperty {
+ uint8 walls[4];
+ uint16 assignedObjects;
+ uint16 drawObjects;
+ uint8 direction;
+ uint16 flags;
+};
+
+struct OpenDoorState {
+ uint16 block;
+ int8 wall;
+ int8 state;
+};
+
+struct LevelTempData {
+ uint8 *wallsXorData;
+ uint16 *flags;
+ void *monsters;
+ void *flyingObjects;
+ uint8 monsterDifficulty;
+};
+
+class LolEobBaseEngine : public KyraEngine_v1 {
+friend class TextDisplayer_Eob;
+public:
+ LolEobBaseEngine(OSystem *system, const GameFlags &flags);
+ virtual ~LolEobBaseEngine();
+
+ virtual Screen *screen() = 0;
+ virtual GUI *gui() const = 0;
+
+protected:
+ // Startup
+ virtual Common::Error init();
+ virtual Common::Error go() = 0;
+
+ // Init
+ void initStaticResource();
+
+ const uint8 **_itemIconShapes;
+
+ // Main loop
+ virtual void update() = 0;
+ void updateEnvironmentalSfx(int soundId);
+
+ // timers
+ virtual void setupTimers() = 0;
+ void enableSysTimer(int sysTimer);
+ void disableSysTimer(int sysTimer);
+ void enableTimer(int id);
+ virtual uint8 getClock2Timer(int index) = 0;
+ virtual uint8 getNumClock2Timers() = 0;
+
+ void timerProcessDoors(int timerNum);
+
+ // mouse
+ bool posWithinRect(int mouseX, int mouseY, int x1, int y1, int x2, int y2);
+ virtual void setHandItem(Item itemIndex) = 0;
+
+ // Characters
+ int _updateCharNum;
+ int _updatePortraitSpeechAnimDuration;
+ bool _fadeText;
+ int _resetPortraitAfterSpeechAnim;
+ int _needSceneRestore;
+
+ // Items
+ int _itemInHand;
+
+ // Monsters
+ int getBlockDistance(uint16 block1, uint16 block2);
+
+ uint8 **_monsterPalettes;
+ uint8 **_monsterShapes;
+
+ int16 _shpDmX1;
+ int16 _shpDmX2;
+
+ int _monsterStepCounter;
+ int _monsterStepMode;
+
+ // Level
+ virtual void addLevelItems() = 0;
+ virtual void loadBlockProperties(const char *file) = 0;
+
+ virtual void drawScene(int pageNum) = 0;
+ virtual void drawSceneShapes() = 0;
+ virtual void drawDecorations(int index) = 0;
+
+ void setLevelShapesDim(int index, int16 &x1, int16 &x2, int dim);
+ void scaleLevelShapesDim(int index, int16 &y1, int16 &y2, int dim);
+ void drawLevelModifyScreenDim(int dim, int16 x1, int16 y1, int16 x2, int16 y2);
+ void generateBlockDrawingBuffer();
+ void generateVmpTileData(int16 startBlockX, uint8 startBlockY, uint8 wllVmpIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY);
+ void generateVmpTileDataFlipped(int16 startBlockX, uint8 startBlockY, uint8 wllVmpIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY);
+ bool hasWall(int index);
+ void assignVisibleBlocks(int block, int direction);
+ bool checkSceneUpdateNeed(int block);
+ void drawVcnBlocks();
+ uint16 calcNewBlockPosition(uint16 curBlock, uint16 direction);
+
+ virtual int clickedDoorSwitch(uint16 block, uint16 direction) = 0;
+ int clickedWallShape(uint16 block, uint16 direction);
+ int clickedLeverOn(uint16 block, uint16 direction);
+ int clickedLeverOff(uint16 block, uint16 direction);
+ int clickedWallOnlyScript(uint16 block);
+ virtual int clickedNiche(uint16 block, uint16 direction) = 0;
+
+ void processDoorSwitch(uint16 block, int openClose);
+ void openCloseDoor(int block, int openClose);
+ void completeDoorOperations();
+
+ uint8 *_wllVmpMap;
+ int8 *_wllShapeMap;
+ uint8 *_specialWallTypes;
+ uint8 *_wllWallFlags;
+
+ int _sceneXoffset;
+ int _sceneShpDim;
+
+ LevelBlockProperty *_levelBlockProperties;
+ LevelBlockProperty *_visibleBlocks[18];
+ LevelDecorationProperty *_levelDecorationData;
+ uint16 _levelDecorationDataSize;
+ LevelDecorationProperty *_levelDecorationProperties;
+ uint8 **_levelDecorationShapes;
+ uint16 _decorationCount;
+ int16 _mappedDecorationsCount;
+ uint16 *_vmpPtr;
+ uint8 *_vcnBlocks;
+ uint8 *_vcfBlocks;
+ uint8 *_vcnShift;
+ uint8 *_vcnExpTable;
+ uint16 *_blockDrawingBuffer;
+ uint8 *_sceneWindowBuffer;
+ uint8 _blockBrightness;
+ uint8 _wllVcnOffset;
+
+ uint8 **_doorShapes;
+
+ uint8 _currentLevel;
+ uint16 _currentBlock;
+ uint16 _currentDirection;
+ int _sceneDefaultUpdate;
+ bool _sceneUpdateRequired;
+
+ int16 _visibleBlockIndex[18];
+ int16 *_lvlShapeLeftRight;
+ int16 *_lvlShapeTop;
+ int16 *_lvlShapeBottom;
+
+ char _lastBlockDataFile[13];
+ uint32 _hasTempDataFlags;
+
+ int16 _sceneDrawVarDown;
+ int16 _sceneDrawVarRight;
+ int16 _sceneDrawVarLeft;
+ int _wllProcessFlag;
+
+ OpenDoorState _openDoorState[3];
+
+ int _sceneDrawPage1;
+ int _sceneDrawPage2;
+
+ const int8 *_dscShapeIndex;
+ const uint8 *_dscDimMap;
+ const int8 *_dscDim1;
+ const int8 *_dscDim2;
+ const int16 *_dscShapeX;
+ const uint8 *_dscUnk2;
+ const uint8 *_dscBlockMap;
+ const int8 *_dscBlockIndex;
+ const uint8 *_dscTileIndex;
+
+ const uint8 *_dscDoorShpIndex;
+ const uint8 *_dscDoorY2;
+
+ // Script
+ virtual void runLevelScript(int block, int flags) = 0;
+
+ // Gui
+ void removeInputTop();
+ void gui_drawBox(int x, int y, int w, int h, int frameColor1, int frameColor2, int fillColor);
+ virtual void gui_drawHorizontalBarGraph(int x, int y, int w, int h, int32 curVal, int32 maxVal, int col1, int col2);
+ void gui_initButtonsFromList(const int16 *list);
+ virtual void gui_initButton(int index, int x = -1, int y = -1, int val = -1) = 0;
+ void gui_resetButtonList();
+ void gui_notifyButtonListChanged();
+
+ bool clickedShape(int shapeIndex);
+
+ int _clickedShapeXOffs;
+ int _clickedShapeYOffs;
+
+ Button *_activeButtons;
+ Button _activeButtonData[70];
+
+ uint8 _mouseClick;
+ bool _preserveEvents;
+ bool _buttonListChanged;
+
+ int _updateFlags;
+ int _clickedSpecialFlag;
+
+ int _compassDirection;
+
+ static const uint8 _dropItemDirIndex[];
+
+ // text
+ void drawDialogueButtons();
+ uint16 processDialogue();
+
+ TextDisplayer_Eob *_txt;
+ virtual TextDisplayer_Eob *txt() { return _txt; }
+
+ bool _dialogueField;
+
+ const char *_dialogueButtonString[9];
+ const uint16 *_dialogueButtonPosX;
+ const uint8 *_dialogueButtonPosY;
+ int16 _dialogueButtonYoffs;
+ uint16 _dialogueButtonW;
+ uint16 _dialogueButtonH;
+ int _dialogueNumButtons;
+ int _dialogueHighlightedButton;
+ int _currentControlMode;
+ int _specialSceneFlag;
+ uint8 _dialogueButtonLabelCol1;
+ uint8 _dialogueButtonLabelCol2;
+
+ int _bkgColor_1;
+ uint8 _color1_1;
+ uint8 _color2_1;
+
+ const char *const *_moreStrings;
+
+ // misc
+ virtual void delay(uint32 millis, bool doUpdate = false, bool isMainLoop = false) = 0;
+ void delayUntil(uint32 time, bool doUpdate = false, bool isMainLoop = false);
+ int rollDice(int times, int pips, int inc = 0);
+
+ virtual Common::Error loadGameState(int slot) = 0;
+ virtual Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) = 0;
+
+ void generateTempData();
+ void restoreBlockTempData(int levelIndex);
+ void releaseTempData();
+ virtual void *generateMonsterTempData(LevelTempData *tmp) = 0;
+ virtual void *generateFlyingObjectTempData(LevelTempData *tmp) = 0;
+ virtual void restoreMonsterTempData(LevelTempData *tmp) = 0;
+ virtual void restoreFlyingObjectTempData(LevelTempData *tmp) = 0;
+ virtual void releaseMonsterTempData(LevelTempData *tmp) = 0;
+ virtual void releaseFlyingObjectTempData(LevelTempData *tmp) = 0;
+
+ LevelTempData *_lvlTempData[29];
+
+ // sound
+ virtual bool snd_processEnvironmentalSoundEffect(int soundId, int block);
+ virtual void snd_stopSpeech(bool) {}
+ virtual int snd_updateCharacterSpeech() { return 0; }
+ virtual void stopPortraitSpeechAnim() {}
+ virtual void setupOpcodeTable() {}
+ virtual void snd_playVoiceFile(int) {}
+
+ int _environmentSfx;
+ int _environmentSfxVol;
+ int _envSfxDistThreshold;
+
+ uint32 _activeVoiceFileTotalTime;
+
+ // unused
+ void setWalkspeed(uint8) {}
+ void removeHandItem() {}
+ bool lineIsPassable(int, int) { return false; }
+};
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB || ENABLE_LOL
+
+#endif \ No newline at end of file
diff --git a/engines/kyra/magic_eob.cpp b/engines/kyra/magic_eob.cpp
new file mode 100644
index 0000000000..aefe20c06a
--- /dev/null
+++ b/engines/kyra/magic_eob.cpp
@@ -0,0 +1,780 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/eobcommon.h"
+#include "kyra/resource.h"
+
+namespace Kyra {
+
+void EobCoreEngine::useMagicBookOrSymbol(int charIndex, int type) {
+ EobCharacter *c = &_characters[charIndex];
+ _openBookSpellLevel = c->slotStatus[3];
+ _openBookSpellSelectedItem = c->slotStatus[2];
+ _openBookSpellListOffset = c->slotStatus[4];
+ _openBookChar = charIndex;
+ _openBookType = type;
+ _openBookSpellList = (type == 1) ? _clericSpellList : _mageSpellList;
+ _openBookAvailableSpells = (type == 1) ? c->clericSpells : c->mageSpells;
+ int8 *tmp = _openBookAvailableSpells + _openBookSpellLevel * 10 + _openBookSpellListOffset + _openBookSpellSelectedItem;
+
+ if (*tmp <= 0) {
+ for (bool loop = true; loop && _openBookSpellSelectedItem < 10; ) {
+ tmp = _openBookAvailableSpells + _openBookSpellLevel * 10 + _openBookSpellListOffset + _openBookSpellSelectedItem;
+ if (*tmp > 0) {
+ if (_openBookSpellSelectedItem > 5) {
+ _openBookSpellListOffset = 6;
+ _openBookSpellSelectedItem -= 6;
+ }
+ loop = false;
+ } else {
+ _openBookSpellSelectedItem++;
+ }
+ }
+
+ if (_openBookSpellSelectedItem == 10) {
+ _openBookSpellListOffset = 0;
+ _openBookSpellSelectedItem = 6;
+ }
+ }
+
+ if (!_updateFlags)
+ _screen->copyRegion(64, 121, 0, 0, 112, 56, 0, 10, Screen::CR_NO_P_CHECK);
+ _updateFlags = 1;
+ gui_setPlayFieldButtons();
+ gui_drawSpellbook();
+}
+
+void EobCoreEngine::useMagicScroll(int charIndex, int type, int weaponSlot) {
+ _openBookCharBackup = _openBookChar;
+ _openBookTypeBackup = _openBookType;
+ _castScrollSlot = weaponSlot + 1;
+ _openBookChar = charIndex;
+ _openBookType = type <= _clericSpellOffset ? 0 : 1;
+ castSpell(type, weaponSlot);
+}
+
+void EobCoreEngine::usePotion(int charIndex, int weaponSlot) {
+ EobCharacter *c = &_characters[_openBookChar];
+ int offset = (_flags.gameID == GI_EOB1) ? 13 : (_flags.lang == Common::DE_DEU ? 19 : 15);
+
+ int val = deleteInventoryItem(charIndex, weaponSlot);
+ snd_playSoundEffect(10);
+
+ switch (val) {
+ case 0:
+ sparkEffectDefensive(charIndex);
+ c->strengthCur = 22;
+ c->strengthExtCur = 0;
+ setCharEventTimer(charIndex, 546 * rollDice(1, 4, 4), 7, 1);
+ break;
+
+ case 1:
+ sparkEffectDefensive(charIndex);
+ modifyCharacterHitpoints(charIndex, rollDice(2, 4, 2));
+ break;
+
+ case 2:
+ sparkEffectDefensive(charIndex);
+ modifyCharacterHitpoints(charIndex, rollDice(3, 8, 3));
+ break;
+
+ case 3:
+ statusAttack(charIndex, 2, _itemExtraStrings[offset], 0, 1, 8, 1);
+ c->effectFlags &= ~0x2000;
+ if (c->flags & 2)
+ return;
+ break;
+
+ case 4:
+ sparkEffectDefensive(charIndex);
+ c->food = 100;
+ if (_currentControlMode)
+ gui_drawCharPortraitWithStats(charIndex);
+ break;
+
+ case 5:
+ sparkEffectDefensive(charIndex);
+ c->effectFlags |= 0x10000;
+ setCharEventTimer(charIndex, 546 * rollDice(1, 4, 4), 12, 1);
+ snd_playSoundEffect(100);
+ gui_drawCharPortraitWithStats(charIndex);
+ break;
+
+ case 6:
+ sparkEffectDefensive(charIndex);
+ c->effectFlags |= 0x40;
+ gui_drawCharPortraitWithStats(charIndex);
+ break;
+
+ case 7:
+ sparkEffectDefensive(charIndex);
+ neutralizePoison(charIndex);
+ break;
+
+ default:
+ break;
+ }
+
+ _txt->printMessage(_itemExtraStrings[offset + 1], -1, c->name, _potionEffectStrings[val]);
+}
+
+void EobCoreEngine::castSpell(int spell, int weaponSlot) {
+ EobSpell *s = &_spells[spell];
+ EobCharacter *c = &_characters[_openBookChar];
+ _activeSpell = spell;
+
+ if ((s->flags & 0x100) && (c->effectFlags & 0x40))
+ // remove invisibility effect
+ removeCharacterEffect(10, _openBookChar, 1);
+
+ int ci = _openBookChar;
+ if (ci > 3)
+ ci -= 2;
+
+ _activeSpellCasterPos = _dropItemDirIndex[(_currentDirection << 2) + ci];
+
+ if (s->flags & 0x400) {
+ if (c->inventory[0] && c->inventory[1]) {
+ _txt->printMessage(_magicStrings1[2]);
+ snd_playSoundEffect(79);
+ return;
+ }
+
+ if (isMagicWeapon(c->inventory[0]) || isMagicWeapon(c->inventory[1])) {
+ _txt->printMessage(_magicStrings1[3]);
+ snd_playSoundEffect(79);
+ return;
+ }
+ }
+
+ if (!(_flags.gameID == GI_EOB2 && _activeSpell == 62)) {
+ if (!_castScrollSlot) {
+ int8 tmp = _openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellListOffset + _openBookSpellSelectedItem];
+ if (_openBookSpellListOffset + _openBookSpellSelectedItem < 8)
+ memmove(&_openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellListOffset + _openBookSpellSelectedItem], &_openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellListOffset + _openBookSpellSelectedItem + 1], 8 - (_openBookSpellListOffset + _openBookSpellSelectedItem));
+ _openBookAvailableSpells[_openBookSpellLevel * 10 + 8] = -tmp;
+ if (_openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellListOffset + _openBookSpellSelectedItem] < 0) {
+ if (--_openBookSpellSelectedItem == -1)
+ if (_openBookSpellListOffset) {
+ _openBookSpellListOffset = 0;
+ _openBookSpellSelectedItem = 5;
+ } else {
+ _openBookSpellSelectedItem = 6;
+ }
+ }
+ } else if (weaponSlot != -1) {
+ updateUsedCharacterHandItem(_openBookChar, weaponSlot);
+ }
+ }
+
+ _txt->printMessage(_magicStrings1[4], -1, c->name, s->name);
+
+ if (s->flags & 0x20) {
+ castOnWhomDialogue();
+ return;
+ }
+
+ _activeSpellCaster = _openBookChar;
+ startSpell(spell);
+}
+
+void EobCoreEngine::removeCharacterEffect(int spell, int charIndex, int showWarning) {
+ EobCharacter *c = &_characters[charIndex];
+ EobSpell *s = &_spells[spell];
+
+ if (showWarning) {
+ _txt->printMessage(_magicStrings3[2], -1, c->name, s->name);
+ snd_playSoundEffect(79);
+ }
+
+ if (s->endCallback)
+ (this->*s->endCallback)(0);
+
+ if (s->flags & 1)
+ c->effectFlags &= ~s->effectFlags;
+
+ if (s->flags & 4)
+ _partyEffectFlags &= ~s->effectFlags;
+
+ if (s->flags & 0x200) {
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ if (!testCharacter(i, 2) && !(s->flags & 0x800))
+ continue;
+ _characters[i].effectFlags &= ~s->effectFlags;
+ }
+ }
+
+ if (s->flags & 0x2)
+ recalcArmorClass(_activeSpellCaster);
+
+ if (showWarning) {
+ if (s->flags & 0x20A0)
+ gui_drawCharPortraitWithStats(charIndex);
+ else if (s->flags & 0x20A0)
+ gui_drawAllCharPortraitsWithStats();
+ }
+}
+
+void EobCoreEngine::removeAllCharacterEffects(int charIndex) {
+ EobCharacter *c = &_characters[charIndex];
+ memset(c->effectsRemainder, 0, 4);
+
+ for (int i = 0; i < 10; i++) {
+ if (c->events[i] < 0)
+ removeCharacterEffect(-c->events[i], charIndex, 0);
+ c->timers[i] = 0;
+ c->events[i] = 0;
+ }
+
+ setupCharacterTimers();
+ recalcArmorClass(charIndex);
+ c->disabledSlots = 0;
+ c->slotStatus[0] = c->slotStatus[1] = 0;
+ c->damageTaken = 0;
+ c->strengthCur = c->strengthMax;
+ c->strengthExtCur = c->strengthExtMax;
+ gui_drawAllCharPortraitsWithStats();
+}
+
+void EobCoreEngine::castOnWhomDialogue() {
+ _txt->printMessage(_magicStrings3[0]);
+ snd_playSoundEffect(79);
+ gui_setCastOnWhomButtons();
+}
+
+void EobCoreEngine::startSpell(int spell) {
+ EobSpell *s = &_spells[spell];
+ EobCharacter *c = &_characters[_activeSpellCaster];
+ snd_playSoundEffect(s->sound);
+
+ if (s->flags & 0xa0)
+ sparkEffectDefensive(_activeSpellCaster);
+ else if (s->flags & 0x40)
+ sparkEffectDefensive(-1);
+ else if (s->flags & 0x1000)
+ sparkEffectOffensive();
+
+ if (s->flags & 0x20) {
+ _txt->printMessage(c->name);
+ _txt->printMessage(_magicStrings1[5]);
+ }
+
+ if ((s->flags & 0x30) && (s->effectFlags & c->effectFlags)) {
+ _txt->printMessage(_magicStrings7[0], -1, c->name, s->name);
+ snd_playSoundEffect(79);
+ } else if ((s->flags & 0x50) && (s->effectFlags & _partyEffectFlags)) {
+ _txt->printMessage(_magicStrings7[1], -1, s->name);
+ snd_playSoundEffect(79);
+ } else {
+ if (s->flags & 8)
+ setSpellEventTimer(spell, s->timingPara[0], s->timingPara[1], s->timingPara[2], s->timingPara[3]);
+
+ _returnAfterSpellCallback = false;
+ if (s->startCallback)
+ (this->*s->startCallback)();
+ if (_returnAfterSpellCallback)
+ return;
+
+ if (s->flags & 1)
+ c->effectFlags |= s->effectFlags;
+ if (s->flags & 4)
+ _partyEffectFlags |= s->effectFlags;
+
+ if (s->flags & 0x200) {
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ if (!testCharacter(i, 2) && !(s->flags & 0x800))
+ continue;
+ _characters[i].effectFlags |= s->effectFlags;
+ }
+ }
+
+ if (s->flags & 2)
+ recalcArmorClass(_activeSpellCaster);
+
+ if (s->flags & 0x20A0)
+ gui_drawCharPortraitWithStats(_activeSpellCaster);
+ if (s->flags & 0x40)
+ gui_drawAllCharPortraitsWithStats();
+ }
+
+ if (_castScrollSlot) {
+ gui_updateSlotAfterScrollUse();
+ } else {
+ c->disabledSlots |= 4;
+ setCharEventTimer(_openBookChar, 72, 11, 1);
+ gui_toggleButtons();
+ gui_drawSpellbook();
+ }
+
+ if (_flags.gameID == GI_EOB2) {
+ //_castSpellWd1 = spell;
+ runLevelScript(_currentBlock, 0x800);
+ //_castSpellWd1 = 0;
+ }
+}
+
+void EobCoreEngine::sparkEffectDefensive(int charIndex) {
+ int first = charIndex;
+ int last = charIndex;
+ if (charIndex == -1) {
+ first = 0;
+ last = 5;
+ }
+
+ for (int i = 0; i < 8; i++) {
+ for (int ii = first; ii <= last; ii++) {
+ if (!testCharacter(ii, 1) || (_currentControlMode && ii != _updateCharNum))
+ continue;
+
+ gui_drawCharPortraitWithStats(ii);
+
+ for (int iii = 0; iii < 4; iii++) {
+ int shpIndex = ((_sparkEffectDefSteps[i] & _sparkEffectDefSubSteps[iii]) >> _sparkEffectDefShift[iii]);
+ if (!shpIndex)
+ continue;
+ int x = _sparkEffectDefAdd[iii * 2] - 8;
+ int y = _sparkEffectDefAdd[iii * 2 + 1];
+ if (_currentControlMode) {
+ x += 181;
+ y += 3;
+ } else {
+ x += (_sparkEffectDefX[ii] << 3);
+ y += _sparkEffectDefY[ii];
+ }
+ _screen->drawShape(0, _sparkShapes[shpIndex - 1], x, y, 0);
+ _screen->updateScreen();
+ }
+ }
+ resetSkipFlag();
+ delay(2 * _tickLength);
+ }
+
+ for (int i = first; i < last; i++)
+ gui_drawCharPortraitWithStats(i);
+}
+
+void EobCoreEngine::sparkEffectOffensive() {
+ disableSysTimer(2);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 0, 2, Screen::CR_NO_P_CHECK);
+
+ for (int i = 0; i < 16; i++)
+ _screen->copyRegionToBuffer(0, _sparkEffectOfX[i], _sparkEffectOfY[i], 16, 16, &_spellAnimBuffer[i << 8]);
+ _screen->updateScreen();
+
+ for (int i = 0; i < 11; i++) {
+ for (int ii = 0; ii < 16; ii++)
+ _screen->copyBlockToPage(2, _sparkEffectOfX[ii], _sparkEffectOfY[ii], 16, 16, &_spellAnimBuffer[ii << 8]);
+
+ for (int ii = 0; ii < 16; ii++) {
+ int shpIndex = (_sparkEffectOfFlags1[i] & _sparkEffectOfFlags2[ii]) >> _sparkEffectOfShift[ii];
+ if (shpIndex)
+ _screen->drawShape(2, _sparkShapes[shpIndex - 1], _sparkEffectOfX[ii], _sparkEffectOfY[ii], 0);
+ }
+ resetSkipFlag();
+ delay(2 * _tickLength);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ }
+
+ for (int i = 0; i < 16; i++)
+ _screen->copyBlockToPage(0, _sparkEffectOfX[i], _sparkEffectOfY[i], 16, 16, &_spellAnimBuffer[i << 8]);
+
+ _screen->updateScreen();
+ enableSysTimer(2);
+}
+
+void EobCoreEngine::setSpellEventTimer(int spell, int timerBaseFactor, int timerLength, int timerLevelFactor, int updateExistingTimer) {
+ int l = _openBookType == 1 ? getCharacterClericPaladinLevel(_openBookChar) : getCharacterMageLevel(_openBookChar);
+ uint32 countdown = timerLength * timerBaseFactor + timerLength * l * timerLevelFactor;
+ setCharEventTimer(_activeSpellCaster, countdown, -spell, updateExistingTimer);
+}
+
+bool EobCoreEngine::magicObjectHit(EobFlyingObject *fo, int dcTimes, int dcPips, int dcOffs, int level) {
+ int ignoreAttackerId = fo->flags & 0x10;
+ int singleTargetCheckAdjacent = fo->flags & 1;
+ int blockDamage = fo->flags & 2;
+ int hitTest = fo->flags & 4;
+
+ int s = 5;
+ int dmgType = 3;
+ if (fo->flags & 8) {
+ s = 4;
+ dmgType = 0;
+ }
+
+ int dmgFlag = _spells[fo->callBackIndex].damageFlags;
+ if (fo->attackerId >= 0)
+ dmgFlag |= 0x800;
+
+ bool res = false;
+ if (!level)
+ level = 1;
+
+ if ((_levelBlockProperties[fo->curBlock].flags & 7) && (fo->attackerId >= 0 || ignoreAttackerId)) {
+ _inflictMonsterDamageUnk = 1;
+
+ for (const int16 *m = findBlockMonsters(fo->curBlock, fo->curPos, fo->direction, blockDamage, singleTargetCheckAdjacent); *m != -1; m++) {
+ int dmg = rollDice(dcTimes, dcPips, dcOffs) * level;
+
+ if (hitTest) {
+ if (!characterAttackHitTest(fo->attackerId, *m, 0, 0))
+ continue;
+ }
+
+ calcAndInflictMonsterDamage(&_monsters[*m], 0, 0, dmg, dmgFlag, s, dmgType);
+ res = true;
+ }
+ updateAllMonsterShapes();
+
+ } else if (fo->curBlock == _currentBlock && (fo->attackerId < 0 || ignoreAttackerId)) {
+ if (blockDamage) {
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ if (hitTest && !monsterAttackHitTest(&_monsters[0], i))
+ continue;
+
+ int dmg = rollDice(dcTimes, dcPips, dcOffs) * level;
+ res = true;
+
+ calcAndInflictCharacterDamage(i, 0, 0, dmg, dmgFlag, s, dmgType);
+ }
+ } else {
+ int c = _dscItemPosIndex[(_currentDirection << 2) + (fo->curPos & 3)];
+ if ((c > 2) && (testCharacter(5, 1) || testCharacter(6, 1)) && rollDice(1, 2, -1))
+ c += 2;
+
+ if (!fo->item && (_characters[c].effectFlags & 8)) {
+ res = true;
+ } else {
+ if ((_characters[c].flags & 1) && hitTest && !monsterAttackHitTest(&_monsters[0], c)) {
+ int dmg = rollDice(dcTimes, dcPips, dcOffs) * level;
+ res = true;
+ calcAndInflictCharacterDamage(c, 0, 0, dmg, dmgFlag, s, dmgType);
+ }
+ }
+ }
+ }
+
+ if (res && (fo->flags & 0x40))
+ updateFlyingObject_s3(fo);
+ else if ((_flags.gameID == GI_EOB1 && fo->item == 5) || (_flags.gameID == GI_EOB2 && fo->item == 4))
+ res = false;
+
+ return res;
+}
+
+void EobCoreEngine::spellCallback_start_armor() {
+
+}
+
+void EobCoreEngine::spellCallback_start_burningHands() {
+
+}
+
+void EobCoreEngine::spellCallback_start_detectMagic() {
+
+}
+
+bool EobCoreEngine::spellCallback_end_detectMagic(EobFlyingObject*) {
+ return true;
+}
+
+void EobCoreEngine::spellCallback_start_magicMissile() {
+ launchMagicObject(_openBookChar, 0, _currentBlock, _activeSpellCasterPos, _currentDirection);
+}
+
+bool EobCoreEngine::spellCallback_end_magicMissile(EobFlyingObject *fo) {
+ return magicObjectHit(fo, 1, 4, 1, (getCharacterMageLevel(fo->attackerId) - 1) >> 1);
+}
+
+void EobCoreEngine::spellCallback_start_shockingGrasp() {
+
+}
+
+bool EobCoreEngine::spellCallback_end_shockingGraspFlameBlade(EobFlyingObject*) {
+ return true;
+}
+
+void EobCoreEngine::spellCallback_start_improvedIdentify() {
+
+}
+
+void EobCoreEngine::spellCallback_start_melfsAcidArrow() {
+ launchMagicObject(_openBookChar, 1, _currentBlock, _activeSpellCasterPos, _currentDirection);
+}
+
+bool EobCoreEngine::spellCallback_end_melfsAcidArrow(EobFlyingObject *fo) {
+ return magicObjectHit(fo, 2, 4, 0, getCharacterMageLevel(fo->attackerId) / 3);
+}
+
+void EobCoreEngine::spellCallback_start_dispelMagic() {
+
+}
+
+void EobCoreEngine::spellCallback_start_fireball() {
+ launchMagicObject(_openBookChar, 2, _currentBlock, _activeSpellCasterPos, _currentDirection);
+}
+
+bool EobCoreEngine::spellCallback_end_fireball(EobFlyingObject *fo) {
+ return magicObjectHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId));
+}
+
+void EobCoreEngine::spellCallback_start_flameArrow() {
+ launchMagicObject(_openBookChar, 3, _currentBlock, _activeSpellCasterPos, _currentDirection);
+}
+
+bool EobCoreEngine::spellCallback_end_flameArrow(EobFlyingObject *fo) {
+ return magicObjectHit(fo, 5, 6, 0, getCharacterMageLevel(fo->attackerId));
+}
+
+void EobCoreEngine::spellCallback_start_holdPerson() {
+ launchMagicObject(_openBookChar, _flags.gameID == GI_EOB1 ? 4 : 3, _currentBlock, _activeSpellCasterPos, _currentDirection);
+}
+
+bool EobCoreEngine::spellCallback_end_holdPerson(EobFlyingObject *fo) {
+ return true;
+}
+
+void EobCoreEngine::spellCallback_start_lightningBolt() {
+ launchMagicObject(_openBookChar, _flags.gameID == GI_EOB1 ? 5 : 4, _currentBlock, _activeSpellCasterPos, _currentDirection);
+}
+
+bool EobCoreEngine::spellCallback_end_lightningBolt(EobFlyingObject *fo) {
+ return magicObjectHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId));
+}
+
+void EobCoreEngine::spellCallback_start_vampiricTouch() {
+
+}
+
+bool EobCoreEngine::spellCallback_end_vampiricTouch(EobFlyingObject*) {
+ return true;
+}
+
+void EobCoreEngine::spellCallback_start_fear() {
+
+}
+
+void EobCoreEngine::spellCallback_start_iceStorm() {
+ launchMagicObject(_openBookChar, _flags.gameID == GI_EOB1 ? 6 : 5, _currentBlock, _activeSpellCasterPos, _currentDirection);
+}
+
+bool EobCoreEngine::spellCallback_end_iceStorm(EobFlyingObject *fo) {
+ static int8 blockAdv[] = { -32, 32, 1, -1 };
+ bool res = magicObjectHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId));
+ if (res) {
+ for (int i = 0; i < 4; i++) {
+ uint16 bl = fo->curBlock;
+ fo->curBlock = (fo->curBlock + blockAdv[i]) & 0x3ff;
+ magicObjectHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId));
+ fo->curBlock = bl;
+ }
+ }
+ return res;
+}
+
+void EobCoreEngine::spellCallback_start_removeCurse() {
+
+}
+
+void EobCoreEngine::spellCallback_start_coneOfCold() {
+
+}
+
+void EobCoreEngine::spellCallback_start_holdMonster() {
+
+}
+
+bool EobCoreEngine::spellCallback_end_holdMonster(EobFlyingObject *fo) {
+ return true;
+}
+
+void EobCoreEngine::spellCallback_start_wallOfForce() {
+
+}
+
+void EobCoreEngine::spellCallback_start_disintegrate() {
+
+}
+
+void EobCoreEngine::spellCallback_start_fleshToStone() {
+
+}
+
+void EobCoreEngine::spellCallback_start_stoneToFlesh() {
+
+}
+
+void EobCoreEngine::spellCallback_start_trueSeeing() {
+
+}
+
+bool EobCoreEngine::spellCallback_end_trueSeeing(EobFlyingObject*) {
+ return true;
+}
+
+void EobCoreEngine::spellCallback_start_slayLiving() {
+
+}
+
+void EobCoreEngine::spellCallback_start_powerWordStun() {
+
+}
+
+void EobCoreEngine::spellCallback_start_causeLightWounds() {
+
+}
+
+void EobCoreEngine::spellCallback_start_cureLightWounds() {
+ modifyCharacterHitpoints(_activeSpellCaster, rollDice(1, 8));
+}
+
+void EobCoreEngine::spellCallback_start_aid() {
+
+}
+
+bool EobCoreEngine::spellCallback_end_aid(EobFlyingObject*) {
+ return true;
+}
+
+void EobCoreEngine::spellCallback_start_flameBlade() {
+
+}
+
+void EobCoreEngine::spellCallback_start_slowPoison() {
+
+}
+
+bool EobCoreEngine::spellCallback_end_slowPoison(EobFlyingObject*) {
+ return true;
+}
+
+void EobCoreEngine::spellCallback_start_createFood() {
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 3))
+ continue;
+ _characters[_activeSpellCaster].food = 100;
+ }
+}
+
+void EobCoreEngine::spellCallback_start_removeParalysis() {
+
+}
+
+void EobCoreEngine::spellCallback_start_causeSeriousWounds() {
+ modifyCharacterHitpoints(_activeSpellCaster, rollDice(2, 8, 1));
+}
+
+void EobCoreEngine::spellCallback_start_cureSeriousWounds() {
+
+}
+
+void EobCoreEngine::spellCallback_start_neutralizePoison() {
+
+}
+
+void EobCoreEngine::spellCallback_start_causeCriticalWounds() {
+
+}
+
+void EobCoreEngine::spellCallback_start_cureCriticalWounds() {
+ modifyCharacterHitpoints(_activeSpellCaster, rollDice(3, 8, 3));
+}
+
+void EobCoreEngine::spellCallback_start_flameStrike() {
+ launchMagicObject(_openBookChar, _flags.gameID == GI_EOB1 ? 8 : 7, _currentBlock, _activeSpellCasterPos, _currentDirection);
+}
+
+bool EobCoreEngine::spellCallback_end_flameStrike(EobFlyingObject *fo) {
+ return magicObjectHit(fo, 6, 8, 0, 0);
+}
+
+void EobCoreEngine::spellCallback_start_raiseDead() {
+
+}
+
+void EobCoreEngine::spellCallback_start_harm() {
+
+}
+
+void EobCoreEngine::spellCallback_start_heal() {
+ EobCharacter *c = &_characters[_activeSpellCaster];
+ if (c->hitPointsMax <= c->hitPointsCur) {
+ _txt->printMessage(_magicStrings4[0]);
+ snd_playSoundEffect(79);
+ } else {
+ modifyCharacterHitpoints(_activeSpellCaster, c->hitPointsMax - c->hitPointsCur);
+ }
+}
+
+void EobCoreEngine::spellCallback_start_layOnHands() {
+
+}
+
+void EobCoreEngine::spellCallback_start_turnUndead() {
+
+}
+
+bool EobCoreEngine::spellCallback_end_unk1Passive(EobFlyingObject *fo) {
+ bool res = false;
+ if (_partyEffectFlags & 0x20000) {
+ res = magicObjectHit(fo, 4, 10, 6, 0);
+ if (res) {
+ gui_drawAllCharPortraitsWithStats();
+ _partyEffectFlags &= ~0x20000;
+ }
+ } else {
+ res = magicObjectHit(fo, 12, 10, 6, 0);
+ }
+ return res;
+}
+
+bool EobCoreEngine::spellCallback_end_unk2Passive(EobFlyingObject *fo) {
+ return magicObjectHit(fo, 0, 0, 18, 0);
+}
+
+bool EobCoreEngine::spellCallback_end_deathSpellPassive(EobFlyingObject *fo) {
+ return true;
+}
+
+bool EobCoreEngine::spellCallback_end_disintegratePassive(EobFlyingObject *fo) {
+ return true;
+}
+
+bool EobCoreEngine::spellCallback_end_causeCriticalWoundsPassive(EobFlyingObject *fo) {
+ return true;
+}
+
+bool EobCoreEngine::spellCallback_end_fleshToStonePassive(EobFlyingObject *fo) {
+ return true;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk
index abd535ee29..50bcbdd6e9 100644
--- a/engines/kyra/module.mk
+++ b/engines/kyra/module.mk
@@ -72,8 +72,19 @@ MODULE_OBJS := \
vqa.o \
wsamovie.o
+KYRARPG_COMMON_OBJ = \
+ gui_eob.o \
+ loleobbase.o \
+ saveload_eob.o \
+ scene_eob.o \
+ sprites_eob.o \
+ staticres_eob.o \
+ text_eob.o \
+ timer_eob.o
+
ifdef ENABLE_LOL
MODULE_OBJS += \
+ $(KYRARPG_COMMON_OBJ) \
gui_lol.o \
items_lol.o \
lol.o \
@@ -89,6 +100,24 @@ MODULE_OBJS += \
timer_lol.o
endif
+ifdef ENABLE_EOB
+ifndef ENABLE_LOL
+MODULE_OBJS += \
+ $(KYRARPG_COMMON_OBJ)
+endif
+MODULE_OBJS += \
+ chargen.o \
+ eobcommon.o \
+ eob1.o \
+ eob2.o \
+ items_eob.o \
+ magic_eob.o \
+ screen_eob.o \
+ script_eob.o \
+ sequences_eob1.o \
+ sequences_eob2.o
+endif
+
# This module can be built as a plugin
ifeq ($(ENABLE_KYRA), DYNAMIC_PLUGIN)
PLUGIN := 1
diff --git a/engines/kyra/resource.cpp b/engines/kyra/resource.cpp
index a35ec3d81b..3aaab07c0d 100644
--- a/engines/kyra/resource.cpp
+++ b/engines/kyra/resource.cpp
@@ -59,7 +59,7 @@ bool Resource::reset() {
if (!dir.exists() || !dir.isDirectory())
error("invalid game path '%s'", dir.getPath().c_str());
- if (_vm->game() == GI_KYRA1) {
+ if (_vm->game() == GI_KYRA1 || _vm->game() == GI_EOB1) {
// We only need kyra.dat for the demo.
if (_vm->gameFlags().isDemo && !_vm->gameFlags().isTalkie)
return true;
@@ -128,7 +128,7 @@ bool Resource::reset() {
loadProtectedFiles(list);
}
- } else {
+ } else if (_vm->game() != GI_EOB2) {
error("Unknown game id: %d", _vm->game());
return false; // for compilers that don't support NORETURN
}
diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h
index c2a697f18d..2c484b4d01 100644
--- a/engines/kyra/resource.h
+++ b/engines/kyra/resource.h
@@ -35,6 +35,7 @@
#include "common/archive.h"
#include "kyra/kyra_v1.h"
+#include "kyra/eob2.h"
#include "kyra/lol.h"
#include "kyra/kyra_hof.h"
@@ -250,7 +251,264 @@ enum KyraResources {
k3ItemMagicTable,
k3ItemStringMap,
-#ifdef ENABLE_LOL
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ kLolEobCommonMoreStrings,
+ kLolEobCommonDscShapeIndex,
+ kLolEobCommonDscX,
+ kLolEobCommonDscTileIndex,
+ kLolEobCommonDscUnk2,
+ kLolEobCommonDscDoorShapeIndex,
+ kLolEobCommonDscDimData1,
+ kLolEobCommonDscDimData2,
+ kLolEobCommonDscBlockMap,
+ kLolEobCommonDscDimMap,
+ kLolEobCommonDscDoorY2,
+ kLolEobCommonDscBlockIndex,
+
+ kEobBaseChargenStrings1,
+ kEobBaseChargenStrings2,
+ kEobBaseChargenStartLevels,
+ kEobBaseChargenStatStrings,
+ kEobBaseChargenRaceSexStrings,
+ kEobBaseChargenClassStrings,
+ kEobBaseChargenAlignmentStrings,
+ kEobBaseChargenEnterGameStrings,
+ kEobBaseChargenClassMinStats,
+ kEobBaseChargenRaceMinStats,
+ kEobBaseChargenRaceMaxStats,
+
+ kEobBaseConstModTable1,
+ kEobBaseConstModTable2,
+ kEobBaseConstModTable3,
+ kEobBaseConstModTable4,
+ kEobBaseConstModLvlIndex,
+ kEobBaseConstModDiv,
+ kEobBaseConstModExt,
+
+ kEobBasePryDoorStrings,
+ kEobBaseWarningStrings,
+ kEobBaseItemSuffixStrings,
+ kEobBaseItemExtraStrings,
+ kEobBaseTakenStrings,
+ kEobBasePotionEffectStrings,
+
+ kEobBaseYesNoStrings,
+ kEobBaseNpcMaxStrings,
+ kEobBaseOkStrings,
+ kEobBaseNpcJoinStrings,
+ kEobBaseCancelStrings,
+ kEobBaseAbortStrings,
+
+ kEobBaseCharGuiStringsHp,
+ kEobBaseCharGuiStringsWp1,
+ kEobBaseCharGuiStringsWp2,
+ kEobBaseCharGuiStringsWr,
+ kEobBaseCharGuiStringsSt1,
+ kEobBaseCharGuiStringsSt2,
+ kEobBaseCharGuiStringsIn,
+
+ kEobBaseCharStatusStrings7,
+ kEobBaseCharStatusStrings81,
+ kEobBaseCharStatusStrings82,
+ kEobBaseCharStatusStrings9,
+ kEobBaseCharStatusStrings12,
+ kEobBaseCharStatusStrings131,
+ kEobBaseCharStatusStrings132,
+
+ kEobBaseLevelGainStrings,
+ kEobBaseExperienceTable0,
+ kEobBaseExperienceTable1,
+ kEobBaseExperienceTable2,
+ kEobBaseExperienceTable3,
+ kEobBaseExperienceTable4,
+
+ kEobBaseClassModifierFlags,
+
+ kEobBaseMonsterStepTable01,
+ kEobBaseMonsterStepTable02,
+ kEobBaseMonsterStepTable1,
+ kEobBaseMonsterStepTable2,
+ kEobBaseMonsterStepTable3,
+ kEobBaseMonsterCloseAttPosTable1,
+ kEobBaseMonsterCloseAttPosTable21,
+ kEobBaseMonsterCloseAttPosTable22,
+ kEobBaseMonsterCloseAttUnkTable,
+ kEobBaseMonsterCloseAttChkTable1,
+ kEobBaseMonsterCloseAttChkTable2,
+ kEobBaseMonsterCloseAttDstTable1,
+ kEobBaseMonsterCloseAttDstTable2,
+
+ kEobBaseMonsterProximityTable,
+ kEobBaseFindBlockMonstersTable,
+ kEobBaseMonsterDirChangeTable,
+ kEobBaseMonsterDistAttStrings,
+
+ kEobBaseEncodeMonsterDefs,
+ kEobBaseNpcPresets,
+
+ kEobBaseWllFlagPreset,
+ kEobBaseDscShapeCoords,
+
+ kEobBaseDscDoorScaleOffs,
+ kEobBaseDscDoorScaleMult1,
+ kEobBaseDscDoorScaleMult2,
+ kEobBaseDscDoorScaleMult3,
+ kEobBaseDscDoorScaleMult4,
+ kEobBaseDscDoorScaleMult5,
+ kEobBaseDscDoorScaleMult6,
+ kEobBaseDscDoorType5Offs,
+ kEobBaseDscDoorY1,
+ kEobBaseDscDoorY3,
+ kEobBaseDscDoorY4,
+ kEobBaseDscDoorY5,
+ kEobBaseDscDoorY6,
+ kEobBaseDscDoorCoordsExt,
+
+ kEobBaseDscItemPosIndex,
+ kEobBaseDscItemShpX,
+ kEobBaseDscItemScaleIndex,
+ kEobBaseDscItemTileIndex,
+ kEobBaseDscItemShapeMap,
+
+ kEobBaseDscMonsterFrmOffsTbl1,
+ kEobBaseDscMonsterFrmOffsTbl2,
+
+ kEobBaseInvSlotX,
+ kEobBaseInvSlotY,
+ kEobBaseSlotValidationFlags,
+ kEobBaseDrawObjPosIndex,
+ kEobBaseFlightObjFlipIndex,
+ kEobBaseFlightObjShpMap,
+ kEobBaseFlightObjSclIndex,
+
+ kEobBaseDscTelptrShpCoords,
+
+ kEobBaseBookNumbers,
+ kEobBaseMageSpellsList,
+ kEobBaseClericSpellsList,
+ kEobBaseSpellNames,
+ kEobBaseMagicStrings1,
+ kEobBaseMagicStrings2,
+ kEobBaseMagicStrings3,
+ kEobBaseMagicStrings4,
+ kEobBaseMagicStrings5,
+ kEobBaseMagicStrings6,
+ kEobBaseMagicStrings7,
+ kEobBaseMagicStrings8,
+
+ kEobBaseSparkDefSteps,
+ kEobBaseSparkDefSubSteps,
+ kEobBaseSparkDefShift,
+ kEobBaseSparkDefAdd,
+ kEobBaseSparkDefX,
+ kEobBaseSparkDefY,
+ kEobBaseSparkOfFlags1,
+ kEobBaseSparkOfFlags2,
+ kEobBaseSparkOfShift,
+ kEobBaseSparkOfX,
+ kEobBaseSparkOfY,
+
+ kEobBaseSpellProperties,
+ kEobBaseMagicFlightProps,
+
+ kEob1MainMenuStrings,
+ kEob1DoorShapeDefs,
+ kEob1DoorSwitchShapeDefs,
+ kEob1DoorSwitchCoords,
+ kEob1MonsterProperties,
+
+ kEob1MonsterDistAttType10,
+ kEob1MonsterDistAttSfx10,
+ kEob1MonsterDistAttType17,
+ kEob1MonsterDistAttSfx17,
+
+ kEob2MainMenuStrings,
+ kEob2IntroStrings,
+ kEob2IntroCPSFiles,
+ kEob2IntroSeqData00,
+ kEob2IntroSeqData01,
+ kEob2IntroSeqData02,
+ kEob2IntroSeqData03,
+ kEob2IntroSeqData04,
+ kEob2IntroSeqData05,
+ kEob2IntroSeqData06,
+ kEob2IntroSeqData07,
+ kEob2IntroSeqData08,
+ kEob2IntroSeqData09,
+ kEob2IntroSeqData10,
+ kEob2IntroSeqData11,
+ kEob2IntroSeqData12,
+ kEob2IntroSeqData13,
+ kEob2IntroSeqData14,
+ kEob2IntroSeqData15,
+ kEob2IntroSeqData16,
+ kEob2IntroSeqData17,
+ kEob2IntroSeqData18,
+ kEob2IntroSeqData19,
+ kEob2IntroSeqData20,
+ kEob2IntroSeqData21,
+ kEob2IntroSeqData22,
+ kEob2IntroSeqData23,
+ kEob2IntroSeqData24,
+ kEob2IntroSeqData25,
+ kEob2IntroSeqData26,
+ kEob2IntroSeqData27,
+ kEob2IntroSeqData28,
+ kEob2IntroSeqData29,
+ kEob2IntroSeqData30,
+ kEob2IntroSeqData31,
+ kEob2IntroSeqData32,
+ kEob2IntroSeqData33,
+ kEob2IntroSeqData34,
+ kEob2IntroSeqData35,
+ kEob2IntroSeqData36,
+ kEob2IntroSeqData37,
+ kEob2IntroSeqData38,
+ kEob2IntroSeqData39,
+ kEob2IntroSeqData40,
+ kEob2IntroSeqData41,
+ kEob2IntroSeqData42,
+ kEob2IntroSeqData43,
+ kEob2IntroShapes00,
+ kEob2IntroShapes01,
+ kEob2IntroShapes04,
+ kEob2IntroShapes07,
+
+ kEob2FinaleStrings,
+ kEob2CreditsData,
+ kEob2FinaleCPSFiles,
+ kEob2FinaleSeqData00,
+ kEob2FinaleSeqData01,
+ kEob2FinaleSeqData02,
+ kEob2FinaleSeqData03,
+ kEob2FinaleSeqData04,
+ kEob2FinaleSeqData05,
+ kEob2FinaleSeqData06,
+ kEob2FinaleSeqData07,
+ kEob2FinaleSeqData08,
+ kEob2FinaleSeqData09,
+ kEob2FinaleSeqData10,
+ kEob2FinaleSeqData11,
+ kEob2FinaleSeqData12,
+ kEob2FinaleSeqData13,
+ kEob2FinaleSeqData14,
+ kEob2FinaleSeqData15,
+ kEob2FinaleSeqData16,
+ kEob2FinaleSeqData17,
+ kEob2FinaleSeqData18,
+ kEob2FinaleSeqData19,
+ kEob2FinaleSeqData20,
+ kEob2FinaleShapes00,
+ kEob2FinaleShapes03,
+ kEob2FinaleShapes07,
+ kEob2FinaleShapes09,
+ kEob2FinaleShapes10,
+
+ kEob2NpcShapeData,
+ kEob2Npc1Strings,
+ kEob2Npc2Strings,
+ kEob2MonsterDustStrings,
+
kLolIngamePakFiles,
kLolCharacterDefs,
kLolIngameSfxFiles,
@@ -284,27 +542,17 @@ enum KyraResources {
kLolItemPrices,
kLolStashSetup,
- kLolDscUnk1,
- kLolDscShapeIndex,
+ kLolDscWalls,
kLolDscOvlMap,
kLolDscScaleWidthData,
kLolDscScaleHeightData,
- kLolDscX,
- kLolDscY,
- kLolDscTileIndex,
- kLolDscUnk2,
- kLolDscDoorShapeIndex,
- kLolDscDimData1,
- kLolDscDimData2,
- kLolDscBlockMap,
- kLolDscDimMap,
- kLolDscDoor1,
+ kLolBaseDscY,
+
kLolDscDoorScale,
kLolDscDoor4,
kLolDscDoorX,
kLolDscDoorY,
kLolDscOvlIndex,
- kLolDscBlockIndex,
kLolScrollXTop,
kLolScrollYTop,
@@ -334,7 +582,7 @@ enum KyraResources {
kLolCredits,
kLolHistory,
-#endif
+#endif // ENABLE_EOB || ENABLE_LOL
kMaxResIDs
};
@@ -363,15 +611,22 @@ public:
const HofSeqData *loadHofSequenceData(int id, int &entries);
const ItemAnimData_v1 *loadShapeAnimData_v1(int id, int &entries);
const ItemAnimData_v2 *loadShapeAnimData_v2(int id, int &entries);
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ const uint16 *loadRawDataBe16(int id, int &entries);
+ const uint32 *loadRawDataBe32(int id, int &entries);
+#endif // (ENABLE_EOB || ENABLE_LOL)
#ifdef ENABLE_LOL
const LoLCharacter *loadCharData(int id, int &entries);
const SpellProperty *loadSpellData(int id, int &entries);
const CompassDef *loadCompassData(int id, int &entries);
const FlyingObjectShape *loadFlyingObjectData(int id, int &entries);
- const uint16 *loadRawDataBe16(int id, int &entries);
- const uint32 *loadRawDataBe32(int id, int &entries);
- const ButtonDef *loadButtonDefs(int id, int &entries);
+ const LoLButtonDef *loadButtonDefs(int id, int &entries);
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+ const EobSequenceStep *loadEob2SeqData(int id, int &entries);
+ const EobShapeDef *loadEob2ShapeData(int id, int &entries);
+ const EobCharacter *loadEobNpcData(int id, int &entries);
+#endif // ENABLE_EOB
// use '-1' to prefetch/unload all ids
// prefetchId retruns false if only on of the resources
@@ -398,15 +653,22 @@ private:
bool loadHofSequenceData(Common::SeekableReadStream &stream, void *&ptr, int &size);
bool loadShapeAnimData_v1(Common::SeekableReadStream &stream, void *&ptr, int &size);
bool loadShapeAnimData_v2(Common::SeekableReadStream &stream, void *&ptr, int &size);
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ bool loadRawDataBe16(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadRawDataBe32(Common::SeekableReadStream &stream, void *&ptr, int &size);
+#endif // (ENABLE_LOL || ENABLE_EOB)
#ifdef ENABLE_LOL
bool loadCharData(Common::SeekableReadStream &stream, void *&ptr, int &size);
bool loadSpellData(Common::SeekableReadStream &stream, void *&ptr, int &size);
bool loadCompassData(Common::SeekableReadStream &stream, void *&ptr, int &size);
bool loadFlyingObjectData(Common::SeekableReadStream &stream, void *&ptr, int &size);
- bool loadRawDataBe16(Common::SeekableReadStream &stream, void *&ptr, int &size);
- bool loadRawDataBe32(Common::SeekableReadStream &stream, void *&ptr, int &size);
bool loadButtonDefs(Common::SeekableReadStream &stream, void *&ptr, int &size);
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+ bool loadEob2SeqData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadEob2ShapeData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+ bool loadEobNpcData(Common::SeekableReadStream &stream, void *&ptr, int &size);
+#endif // ENABLE_EOB
void freeRawData(void *&ptr, int &size);
void freeStringTable(void *&ptr, int &size);
@@ -416,15 +678,22 @@ private:
void freeHofSequenceData(void *&ptr, int &size);
void freeHofShapeAnimDataV1(void *&ptr, int &size);
void freeHofShapeAnimDataV2(void *&ptr, int &size);
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ void freeRawDataBe16(void *&ptr, int &size);
+ void freeRawDataBe32(void *&ptr, int &size);
+#endif // (ENABLE_EOB || ENABLE_LOL)
#ifdef ENABLE_LOL
void freeCharData(void *&ptr, int &size);
void freeSpellData(void *&ptr, int &size);
void freeCompassData(void *&ptr, int &size);
void freeFlyingObjectData(void *&ptr, int &size);
- void freeRawDataBe16(void *&ptr, int &size);
- void freeRawDataBe32(void *&ptr, int &size);
void freeButtonDefs(void *&ptr, int &size);
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+ void freeEob2SeqData(void *&ptr, int &size);
+ void freeEob2ShapeData(void *&ptr, int &size);
+ void freeEobNpcData(void *&ptr, int &size);
+#endif // ENABLE_EOB
enum ResTypes {
kStringList = 0,
@@ -443,7 +712,11 @@ private:
kLolFlightShpData = 11,
kLolButtonData = 12,
kLolRawDataBe16 = 13,
- kLolRawDataBe32 = 14
+ kLolRawDataBe32 = 14,
+
+ kEob2SequenceData = 15,
+ kEob2ShapeData = 16,
+ kEobNpcData = 17
};
struct FileType {
diff --git a/engines/kyra/resource_intern.cpp b/engines/kyra/resource_intern.cpp
index f9aae2c550..af050b12e7 100644
--- a/engines/kyra/resource_intern.cpp
+++ b/engines/kyra/resource_intern.cpp
@@ -254,6 +254,8 @@ bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableRe
offset = SWAP_BYTES_32(offset);
}
+ int32 firstOffset = offset;
+
Common::String file;
while (!stream.eos()) {
// The start offset of a file should never be in the filelist
@@ -276,7 +278,7 @@ bool ResLoaderPak::isLoadable(const Common::String &filename, Common::SeekableRe
firstFile = false;
offset = switchEndian ? stream.readUint32BE() : stream.readUint32LE();
- if (!offset || offset == filesize)
+ if (!offset || offset == filesize || firstOffset == stream.pos())
break;
}
@@ -297,6 +299,7 @@ Common::Archive *ResLoaderPak::load(Common::ArchiveMemberPtr memberFile, Common:
bool firstFile = true;
startoffset = stream.readUint32LE();
+ int32 firstOffset = startoffset;
if (startoffset > filesize || startoffset < 0) {
switchEndian = true;
startoffset = SWAP_BYTES_32(startoffset);
@@ -330,12 +333,12 @@ Common::Archive *ResLoaderPak::load(Common::ArchiveMemberPtr memberFile, Common:
firstFile = false;
endoffset = switchEndian ? stream.readUint32BE() : stream.readUint32LE();
- if (endoffset < 0) {
+ if (endoffset < 0 && stream.pos() != firstOffset) {
warning("PAK file '%s' is corrupted", memberFile->getDisplayName().c_str());
return 0;
}
- if (!endoffset)
+ if (!endoffset || stream.pos() == firstOffset)
endoffset = filesize;
if (startoffset != endoffset)
@@ -493,7 +496,7 @@ public:
void advSrcBitsBy1();
void advSrcBitsByIndex(uint8 newIndex);
- uint8 getKeyLower() { return _key & 0xff; }
+ uint8 getKeyLower() const { return _key & 0xff; }
void setIndex(uint8 index) { _index = index; }
uint16 getKeyMasked(uint8 newIndex);
uint16 keyMaskedAlign(uint16 val);
diff --git a/engines/kyra/saveload_eob.cpp b/engines/kyra/saveload_eob.cpp
new file mode 100644
index 0000000000..3b3964bdc5
--- /dev/null
+++ b/engines/kyra/saveload_eob.cpp
@@ -0,0 +1,549 @@
+/* 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.
+ *
+ */
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#include "kyra/eobcommon.h"
+#include "kyra/resource.h"
+#include "kyra/script_eob.h"
+
+#include "common/system.h"
+#include "common/savefile.h"
+#include "common/substream.h"
+
+namespace Kyra {
+
+void LolEobBaseEngine::generateTempData() {
+ int l = _currentLevel - 1;
+ if (_lvlTempData[l]) {
+ delete[] _lvlTempData[l]->wallsXorData;
+ delete[] _lvlTempData[l]->flags;
+ releaseMonsterTempData(_lvlTempData[l]);
+ releaseFlyingObjectTempData(_lvlTempData[l]);
+ delete _lvlTempData[l];
+ }
+
+ _lvlTempData[l] = new LevelTempData;
+
+ _lvlTempData[l]->wallsXorData = new uint8[4096];
+ _lvlTempData[l]->flags = new uint16[1024];
+
+ char filename[13];
+ const uint8 *p = 0;
+ const uint8 *p2 = 0;
+ if (_flags.gameID == GI_LOL) {
+ snprintf(filename, sizeof(filename), "LEVEL%d.CMZ", _currentLevel);
+ screen()->loadBitmap(filename, 15, 15, 0);
+ p = screen()->getCPagePtr(14);
+ } else {
+ snprintf(filename, sizeof(filename), "LEVEL%d.MAZ", _currentLevel);
+ p2 = p = _res->fileData(filename, 0);
+ }
+
+ uint16 len = READ_LE_UINT16(p + 4);
+ p += 6;
+
+ memset(_lvlTempData[l]->wallsXorData, 0, 4096);
+ memset(_lvlTempData[l]->flags, 0, 1024 * sizeof(uint16));
+ uint8 *d = _lvlTempData[l]->wallsXorData;
+ uint16 *df = _lvlTempData[l]->flags;
+
+ for (int i = 0; i < 1024; i++) {
+ for (int ii = 0; ii < 4; ii++)
+ *d++ = p[i * len + ii] ^ _levelBlockProperties[i].walls[ii];
+ *df++ = _levelBlockProperties[i].flags;
+ }
+
+ _lvlTempData[l]->monsters = generateMonsterTempData(_lvlTempData[l]);
+ _lvlTempData[l]->flyingObjects = generateFlyingObjectTempData(_lvlTempData[l]);
+
+ _hasTempDataFlags |= (1 << l);
+ delete[] p2;
+}
+
+void LolEobBaseEngine::restoreBlockTempData(int levelIndex) {
+ int l = levelIndex - 1;
+ char filename[13];
+ const uint8 *p = 0;
+ const uint8 *p2 = 0;
+ if (_flags.gameID == GI_LOL) {
+ snprintf(filename, sizeof(filename), "LEVEL%d.CMZ", levelIndex);
+ screen()->loadBitmap(filename, 3, 3, 0);
+ p = screen()->getCPagePtr(2);
+ } else {
+ snprintf(filename, sizeof(filename), "LEVEL%d.MAZ", levelIndex);
+ p2 = p = _res->fileData(filename, 0);
+ }
+
+ uint16 len = READ_LE_UINT16(p + 4);
+ p += 6;
+
+ memset(_levelBlockProperties, 0, 1024 * sizeof(LevelBlockProperty));
+
+ uint8 *t = _lvlTempData[l]->wallsXorData;
+ uint16 *t2 = _lvlTempData[l]->flags;
+
+ for (int i = 0; i < 1024; i++) {
+ for (int ii = 0; ii < 4; ii++)
+ _levelBlockProperties[i].walls[ii] = p[i * len + ii] ^ *t++;
+ _levelBlockProperties[i].flags = *t2++;
+ }
+
+ restoreMonsterTempData(_lvlTempData[l]);
+ restoreFlyingObjectTempData(_lvlTempData[l]);
+
+ delete[] p2;
+}
+
+void LolEobBaseEngine::releaseTempData() {
+ for (int i = 0; i < 29; i++) {
+ if (_lvlTempData[i]) {
+ delete[] _lvlTempData[i]->wallsXorData;
+ delete[] _lvlTempData[i]->flags;
+ releaseMonsterTempData(_lvlTempData[i]);
+ releaseFlyingObjectTempData(_lvlTempData[i]);
+ delete _lvlTempData[i];
+ _lvlTempData[i] = 0;
+ }
+ }
+}
+
+#ifdef ENABLE_EOB
+
+Common::Error EobCoreEngine::loadGameState(int slot) {
+ const char *fileName = getSavegameFilename(slot);
+
+ SaveHeader header;
+ Common::InSaveFile *saveFile = openSaveForReading(fileName, header);
+ if (!saveFile) {
+ //_txt->printMessage(2, "%s", getLangString(0x425d));
+ return Common::kNoError;
+ }
+
+ Common::SeekableSubReadStreamEndian in(saveFile, saveFile->pos(), saveFile->size(), !header.originalSave, DisposeAfterUse::YES);
+
+ for (int i = 0; i < 6; i++) {
+ EobCharacter *c = &_characters[i];
+ c->id = in.readByte();
+ c->flags = in.readByte();
+ in.read(c->name, 11);
+ c->strengthCur = in.readSByte();
+ c->strengthMax = in.readSByte();
+ c->strengthExtCur = in.readSByte();
+ c->strengthExtMax = in.readSByte();
+ c->intelligenceCur = in.readSByte();
+ c->intelligenceMax = in.readSByte();
+ c->wisdomCur = in.readSByte();
+ c->wisdomMax = in.readSByte();
+ c->dexterityCur = in.readSByte();
+ c->dexterityMax = in.readSByte();
+ c->constitutionCur = in.readSByte();
+ c->constitutionMax = in.readSByte();
+ c->charismaCur = in.readSByte();
+ c->charismaMax = in.readSByte();
+ c->hitPointsCur = in.readSint16BE();
+ c->hitPointsMax = in.readSint16BE();
+ c->armorClass = in.readSByte();
+ c->disabledSlots = in.readByte();
+ c->raceSex = in.readByte();
+ c->cClass = in.readByte();
+ c->alignment = in.readByte();
+ c->portrait = in.readSByte();
+ c->food = in.readByte();
+ in.read(c->level, 3);
+ for (int ii = 0; ii < 3; ii++)
+ c->experience[ii] = in.readUint32BE();
+ delete[] c->faceShape;
+ c->faceShape = 0;
+ in.read(c->mageSpells, 80);
+ in.read(c->clericSpells, 80);
+ c->mageSpellsAvailabilityFlags = in.readUint32BE();
+ for (int ii = 0; ii < 27; ii++)
+ c->inventory[ii] = in.readSint16BE();
+ uint32 ct = _system->getMillis();
+ for (int ii = 0; ii < 10; ii++) {
+ c->timers[ii] = in.readUint32BE();
+ if (c->timers[ii])
+ c->timers[ii] += ct;
+ }
+ in.read(c->events, 10);
+ in.read(c->effectsRemainder, 4);
+ c->effectFlags = in.readUint32BE();
+ c->damageTaken = in.readByte();
+ in.read(c->slotStatus, 5);
+ }
+
+ setupCharacterTimers();
+
+ _screen->loadEobBitmap("CHARGENA", 3, 3);
+ for (int i = 0; i < 6; i++) {
+ EobCharacter *c = &_characters[i];
+ if (!c->flags || c->portrait < 0)
+ continue;
+ c->faceShape = _screen->encodeShape((c->portrait % 10) << 2, (c->portrait / 10) << 5, 4, 32, true);
+ }
+
+ _screen->loadEobBitmap(_flags.gameID == GI_EOB2 ? "OUTPORTS" : "OUTTAKE", 3, 3);
+ for (int i = 0; i < 6; i++) {
+ EobCharacter *c = &_characters[i];
+ if (!c->flags || c->portrait >= 0)
+ continue;
+ c->faceShape = _screen->encodeShape(-(c->portrait + 1), _flags.gameID == GI_EOB2 ? 0 : 160, 4, 32, true);
+ }
+ _screen->_curPage = 0;
+
+ _currentLevel = in.readByte();
+ _currentSub = in.readSByte();
+ _currentBlock = in.readUint16BE();
+ _currentDirection = in.readUint16BE();
+ _itemInHand = in.readSint16BE();
+ _hasTempDataFlags = in.readUint32BE();
+ _partyEffectFlags = in.readUint32BE();
+ _inf->loadState(in);
+
+ for (int i = 0; i < 600; i++) {
+ EobItem *t = &_items[i];
+ t->nameUnid = in.readByte();
+ t->nameId = in.readByte();
+ t->flags = in.readByte();
+ t->icon = in.readSByte();
+ t->type = in.readSByte();
+ t->pos = in.readSByte();
+ t->block = in.readSint16BE();
+ t->next = in.readSint16BE();
+ t->prev = in.readSint16BE();
+ t->level = in.readByte();
+ t->value = in.readSByte();
+ }
+
+ for (int i = 51; i < 65; i++) {
+ EobItemType *t = &_itemTypes[i];
+ t->invFlags = in.readUint16BE();
+ t->handFlags = in.readUint16BE();
+ t->armorClass = in.readSByte();
+ t->allowedClasses = in.readSByte();
+ t->requiredHands = in.readSByte();
+ t->dmgNumDiceS = in.readSByte();
+ t->dmgNumPipsS = in.readSByte();
+ t->dmgIncS = in.readSByte();
+ t->dmgNumDiceL = in.readSByte();
+ t->dmgNumPipsL = in.readSByte();
+ t->dmgIncL = in.readSByte();
+ t->unk1 = in.readByte();
+ t->extraProperties = in.readUint16BE();
+ }
+
+ for (int i = 0; i < 18; i++) {
+ if (!(_hasTempDataFlags & (1 << i)))
+ continue;
+
+ if (_lvlTempData[i]) {
+ delete[] _lvlTempData[i]->wallsXorData;
+ delete[] _lvlTempData[i]->flags;
+ releaseMonsterTempData(_lvlTempData[i]);
+ releaseFlyingObjectTempData(_lvlTempData[i]);
+ delete _lvlTempData[i];
+ }
+
+ _lvlTempData[i] = new LevelTempData;
+ _lvlTempData[i]->wallsXorData = new uint8[4096];
+ _lvlTempData[i]->flags = new uint16[1024];
+ EobMonsterInPlay *lm = new EobMonsterInPlay[30];
+ _lvlTempData[i]->monsters = lm;
+ EobFlyingObject *lf = new EobFlyingObject[10];
+ _lvlTempData[i]->flyingObjects = lf;
+ LevelTempData *l = _lvlTempData[i];
+
+ in.read(l->wallsXorData, 4096);
+ for (int ii = 0; ii < 1024; ii++)
+ l->flags[ii] = in.readByte();
+
+ for (int ii = 0; ii < 30; ii++) {
+ EobMonsterInPlay *m = &lm[ii];
+ m->type = in.readByte();
+ m->unit = in.readByte();
+ m->block = in.readUint16BE();
+ m->pos = in.readByte();
+ m->dir = in.readSByte();
+ m->animStep = in.readByte();
+ m->shpIndex = in.readByte();
+ m->mode = in.readSByte();
+ m->f_9 = in.readSByte();
+ m->curAttackFrame = in.readSByte();
+ m->f_b = in.readByte();
+ m->hitPointsMax = in.readSint16BE();
+ m->hitPointsCur = in.readSint16BE();
+ m->dest = in.readUint16BE();
+ m->randItem = in.readUint16BE();
+ m->fixedItem = in.readUint16BE();
+ m->flags = in.readByte();
+ m->idleAnimState = in.readByte();
+ m->curRemoteWeapon = in.readByte();
+ m->numRemoteAttacks = in.readByte();
+ m->palette = in.readSByte();
+ m->directionChanged = in.readByte();
+ m->stepsTillRemoteAttack = in.readByte();
+ m->sub = in.readByte();
+ }
+
+ for (int ii = 0; ii < 10; ii++) {
+ EobFlyingObject *m = &lf[ii];
+ m->enable = in.readByte();
+ m->objectType = in.readByte();
+ m->attackerId = in.readSint16BE();
+ m->item = in.readSint16BE();
+ m->curBlock = in.readUint16BE();
+ m->u2 = in.readUint16BE();
+ m->u1 = in.readByte();
+ m->direction = in.readByte();
+ m->distance = in.readByte();
+ m->callBackIndex = in.readSByte();
+ m->curPos = in.readByte();
+ m->flags = in.readByte();
+ m->unused = in.readByte();
+ }
+ }
+
+ if (_saveLoadMode != -1) {
+ loadLevel(_currentLevel, _currentSub);
+ gui_drawPlayField(0);
+ _sceneUpdateRequired = true;
+ _screen->setCurPage(0);
+ _screen->setFont(Screen::FID_6_FNT);
+ gui_drawAllCharPortraitsWithStats();
+ updateHandItemCursor();
+ _saveLoadMode = 1;
+ }
+
+ while (!_screen->isMouseVisible())
+ _screen->showMouse();
+
+ return Common::kNoError;
+}
+
+Common::Error EobCoreEngine::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) {
+ const Common::String finSuffix(".FIN");
+ const char *fileName = (slot != -1) ? getSavegameFilename(slot) : (_targetName + finSuffix).c_str();
+
+ Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumbnail);
+ if (!out)
+ return _saveFileMan->getError();
+
+ completeDoorOperations();
+ generateTempData();
+
+ for (int i = 0; i < 6; i++) {
+ timerSpecialCharacterUpdate(0x30 + i);
+ uint32 ct = _system->getMillis();
+ EobCharacter *c = &_characters[i];
+
+ out->writeByte(c->id);
+ out->writeByte(c->flags);
+ out->write(c->name, 11);
+ out->writeSByte(c->strengthCur);
+ out->writeSByte(c->strengthMax);
+ out->writeSByte(c->strengthExtCur);
+ out->writeSByte(c->strengthExtMax);
+ out->writeSByte(c->intelligenceCur);
+ out->writeSByte(c->intelligenceMax);
+ out->writeSByte(c->wisdomCur);
+ out->writeSByte(c->wisdomMax);
+ out->writeSByte(c->dexterityCur);
+ out->writeSByte(c->dexterityMax);
+ out->writeSByte(c->constitutionCur);
+ out->writeSByte(c->constitutionMax);
+ out->writeSByte(c->charismaCur);
+ out->writeSByte(c->charismaMax);
+ out->writeSint16BE(c->hitPointsCur);
+ out->writeSint16BE(c->hitPointsMax);
+ out->writeSByte(c->armorClass);
+ out->writeByte(c->disabledSlots);
+ out->writeByte(c->raceSex);
+ out->writeByte(c->cClass);
+ out->writeByte(c->alignment);
+ out->writeByte(c->portrait);
+ out->writeByte(c->food);
+ out->write(c->level, 3);
+ for (int ii = 0; ii < 3; ii++)
+ out->writeUint32BE(c->experience[ii]);
+ out->write(c->mageSpells, 80);
+ out->write(c->clericSpells, 80);
+ out->writeUint32BE(c->mageSpellsAvailabilityFlags);
+ for (int ii = 0; ii < 27; ii++)
+ out->writeSint16BE(c->inventory[ii]);
+ for (int ii = 0; ii < 10; ii++)
+ out->writeUint32BE(c->timers[ii] ? c->timers[ii] - ct : 0);
+
+ out->write(c->events, 10);
+ out->write(c->effectsRemainder, 4);
+ out->writeUint32BE(c->effectFlags);
+ out->writeByte(c->damageTaken);
+ out->write(c->slotStatus, 5);
+ }
+
+ out->writeByte(_currentLevel);
+ out->writeSByte(_currentSub);
+ out->writeUint16BE(_currentBlock);
+ out->writeUint16BE(_currentDirection);
+ out->writeSint16BE(_itemInHand);
+ out->writeUint32BE(_hasTempDataFlags);
+ out->writeUint32BE(_partyEffectFlags);
+ _inf->saveState(out);
+
+ for (int i = 0; i < 600; i++) {
+ EobItem *t = &_items[i];
+ out->writeByte(t->nameUnid);
+ out->writeByte(t->nameId);
+ out->writeByte(t->flags);
+ out->writeSByte(t->icon);
+ out->writeSByte(t->type);
+ out->writeSByte(t->pos);
+ out->writeSint16BE(t->block);
+ out->writeSint16BE(t->next);
+ out->writeSint16BE(t->prev);
+ out->writeByte(t->level);
+ out->writeSByte(t->value);
+ }
+
+ for (int i = 51; i < 65; i++) {
+ EobItemType *t = &_itemTypes[i];
+ out->writeUint16BE(t->invFlags);
+ out->writeUint16BE(t->handFlags);
+ out->writeSByte(t->armorClass);
+ out->writeSByte(t->allowedClasses);
+ out->writeSByte(t->requiredHands);
+ out->writeSByte(t->dmgNumDiceS);
+ out->writeSByte(t->dmgNumPipsS);
+ out->writeSByte(t->dmgIncS);
+ out->writeSByte(t->dmgNumDiceL);
+ out->writeSByte(t->dmgNumPipsL);
+ out->writeSByte(t->dmgIncL);
+ out->writeByte(t->unk1);
+ out->writeUint16BE(t->extraProperties);
+ }
+
+ for (int i = 0; i < 18; i++) {
+ LevelTempData *l = _lvlTempData[i];
+ if (!l || !(_hasTempDataFlags & (1 << i)))
+ continue;
+
+ out->write(l->wallsXorData, 4096);
+ for (int ii = 0; ii < 1024; ii++)
+ out->writeByte(l->flags[ii] & 0xff);
+
+ EobMonsterInPlay *lm = (EobMonsterInPlay*)_lvlTempData[i]->monsters;
+ EobFlyingObject *lf = (EobFlyingObject*)_lvlTempData[i]->flyingObjects;
+
+ for (int ii = 0; ii < 30; ii++) {
+ EobMonsterInPlay *m = &lm[ii];
+ out->writeByte(m->type);
+ out->writeByte(m->unit);
+ out->writeUint16BE(m->block);
+ out->writeByte(m->pos);
+ out->writeSByte(m->dir);
+ out->writeByte(m->animStep);
+ out->writeByte(m->shpIndex);
+ out->writeSByte(m->mode);
+ out->writeSByte(m->f_9);
+ out->writeSByte(m->curAttackFrame);
+ out->writeByte(m->f_b);
+ out->writeSint16BE(m->hitPointsMax);
+ out->writeSint16BE(m->hitPointsCur);
+ out->writeUint16BE(m->dest);
+ out->writeUint16BE(m->randItem);
+ out->writeUint16BE(m->fixedItem);
+ out->writeByte(m->flags);
+ out->writeByte(m->idleAnimState);
+ out->writeByte(m->curRemoteWeapon);
+ out->writeByte(m->numRemoteAttacks);
+ out->writeSByte(m->palette);
+ out->writeByte(m->directionChanged);
+ out->writeByte(m->stepsTillRemoteAttack);
+ out->writeByte(m->sub);
+ }
+
+ for (int ii = 0; ii < 10; ii++) {
+ EobFlyingObject *m = &lf[ii];
+ out->writeByte(m->enable);
+ out->writeByte(m->objectType);
+ out->writeSint16BE(m->attackerId);
+ out->writeSint16BE(m->item);
+ out->writeUint16BE(m->curBlock);
+ out->writeUint16BE(m->u2);
+ out->writeByte(m->u1);
+ out->writeByte(m->direction);
+ out->writeByte(m->distance);
+ out->writeSByte(m->callBackIndex);
+ out->writeByte(m->curPos);
+ out->writeByte(m->flags);
+ out->writeByte(m->unused);
+ }
+ }
+
+ out->finalize();
+
+ // check for errors
+ if (out->err()) {
+ warning("Can't write file '%s'. (Disk full?)", fileName);
+ return Common::kUnknownError;
+ } else {
+ debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName);
+ }
+
+ delete out;
+ return Common::kNoError;
+}
+
+void *EobCoreEngine::generateMonsterTempData(LevelTempData *tmp) {
+ EobMonsterInPlay *m = new EobMonsterInPlay[30];
+ memcpy(m, _monsters, sizeof(EobMonsterInPlay) * 30);
+ return m;
+}
+
+void *EobCoreEngine::generateFlyingObjectTempData(LevelTempData *tmp) {
+ EobFlyingObject *f = new EobFlyingObject[10];
+ memcpy(f, _flyingObjects, sizeof(EobFlyingObject) * 10);
+ return f;
+}
+
+void EobCoreEngine::restoreMonsterTempData(LevelTempData *tmp) {
+ memcpy(_monsters, tmp->monsters, sizeof(EobMonsterInPlay) * 30);
+}
+
+void EobCoreEngine::restoreFlyingObjectTempData(LevelTempData *tmp) {
+ memcpy(_flyingObjects, tmp->flyingObjects, sizeof(EobFlyingObject) * 10);
+}
+
+void EobCoreEngine::releaseMonsterTempData(LevelTempData *tmp) {
+ EobMonsterInPlay *p = (EobMonsterInPlay*)tmp->monsters;
+ delete[] p;
+}
+
+void EobCoreEngine::releaseFlyingObjectTempData(LevelTempData *tmp) {
+
+}
+
+#endif // ENABLE_EOB
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB || ENABLE_LOL
diff --git a/engines/kyra/saveload_lol.cpp b/engines/kyra/saveload_lol.cpp
index 1bf26477e6..7d8e6c32d9 100644
--- a/engines/kyra/saveload_lol.cpp
+++ b/engines/kyra/saveload_lol.cpp
@@ -96,7 +96,7 @@ Common::Error LoLEngine::loadGameState(int slot) {
}
}
- in.read(_wllBuffer4, 80);
+ in.read(_wllAutomapData, 80);
_currentBlock = in.readUint16BE();
_partyPosX = in.readUint16BE();
@@ -185,23 +185,26 @@ Common::Error LoLEngine::loadGameState(int slot) {
if (_lvlTempData[i]) {
delete[] _lvlTempData[i]->wallsXorData;
delete[] _lvlTempData[i]->flags;
- delete[] _lvlTempData[i]->monsters;
- delete[] _lvlTempData[i]->flyingObjects;
+ releaseMonsterTempData(_lvlTempData[i]);
+ releaseFlyingObjectTempData(_lvlTempData[i]);
delete _lvlTempData[i];
}
_lvlTempData[i] = new LevelTempData;
_lvlTempData[i]->wallsXorData = new uint8[4096];
- _lvlTempData[i]->flags = new uint8[1024];
- _lvlTempData[i]->monsters = new MonsterInPlay[30];
- _lvlTempData[i]->flyingObjects = new FlyingObject[8];
+ _lvlTempData[i]->flags = new uint16[1024];
+ LolMonsterInPlay *lm = new LolMonsterInPlay[30];
+ _lvlTempData[i]->monsters = lm;
+ FlyingObject *lf = new FlyingObject[8];
+ _lvlTempData[i]->flyingObjects = lf;
LevelTempData *l = _lvlTempData[i];
in.read(l->wallsXorData, 4096);
- in.read(l->flags, 1024);
+ for (int ii = 0; ii < 1024; ii++)
+ l->flags[ii] = in.readByte();
for (int ii = 0; ii < 30; ii++) {
- MonsterInPlay *m = &l->monsters[ii];
+ LolMonsterInPlay *m = &lm[ii];
m->nextAssignedObject = in.readUint16BE();
m->nextDrawObject = in.readUint16BE();
m->flyingHeight = in.readByte();
@@ -234,7 +237,7 @@ Common::Error LoLEngine::loadGameState(int slot) {
}
for (int ii = 0; ii < 8; ii++) {
- FlyingObject *m = &l->flyingObjects[ii];
+ FlyingObject *m = &lf[ii];
m->enable = in.readByte();
m->objectType = in.readByte();
m->attackerId = in.readUint16BE();
@@ -319,7 +322,7 @@ Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, con
out->writeByte(c->characterUpdateDelay[ii]);
}
- out->write(_wllBuffer4, 80);
+ out->write(_wllAutomapData, 80);
out->writeUint16BE(_currentBlock);
out->writeUint16BE(_partyPosX);
@@ -379,10 +382,14 @@ Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, con
continue;
out->write(l->wallsXorData, 4096);
- out->write(l->flags, 1024);
+ for (int ii = 0; ii < 1024; ii++)
+ out->writeByte(l->flags[ii] & 0xff);
+
+ LolMonsterInPlay *lm = (LolMonsterInPlay*)_lvlTempData[i]->monsters;
+ FlyingObject *lf = (FlyingObject*)_lvlTempData[i]->flyingObjects;
for (int ii = 0; ii < 30; ii++) {
- MonsterInPlay *m = &l->monsters[ii];
+ LolMonsterInPlay *m = &lm[ii];
out->writeUint16BE(m->nextAssignedObject);
out->writeUint16BE(m->nextDrawObject);
out->writeByte(m->flyingHeight);
@@ -414,7 +421,7 @@ Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, con
}
for (int ii = 0; ii < 8; ii++) {
- FlyingObject *m = &l->flyingObjects[ii];
+ FlyingObject *m = &lf[ii];
out->writeByte(m->enable);
out->writeByte(m->objectType);
out->writeUint16BE(m->attackerId);
@@ -469,6 +476,69 @@ Graphics::Surface *LoLEngine::generateSaveThumbnail() const {
return dst;
}
+void LoLEngine::restoreBlockTempData(int levelIndex) {
+ memset(_tempBuffer5120, 0, 5120);
+ LolEobBaseEngine::restoreBlockTempData(levelIndex);
+ restoreTempDataAdjustMonsterStrength(levelIndex - 1);
+}
+
+void *LoLEngine::generateMonsterTempData(LevelTempData *tmp) {
+ LolMonsterInPlay *m = new LolMonsterInPlay[30];
+ memcpy(m, _monsters, sizeof(LolMonsterInPlay) * 30);
+ tmp->monsterDifficulty = _monsterDifficulty;
+ return m;
+}
+
+void *LoLEngine::generateFlyingObjectTempData(LevelTempData *tmp) {
+ FlyingObject *f = new FlyingObject[8];
+ memcpy(f, _flyingObjects, sizeof(FlyingObject) * 8);
+ return f;
+}
+
+void LoLEngine::restoreTempDataAdjustMonsterStrength(int index) {
+ if (_lvlTempData[index]->monsterDifficulty == _monsterDifficulty)
+ return;
+
+ uint16 d = (_monsterModifiers[_lvlTempData[index]->monsterDifficulty] << 8) / _monsterModifiers[_monsterDifficulty];
+
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].mode >= 14 || _monsters[i].block == 0 || _monsters[i].hitPoints <= 0)
+ continue;
+
+ _monsters[i].hitPoints = (d * _monsters[i].hitPoints) >> 8;
+ if (_monsterDifficulty < _lvlTempData[index]->monsterDifficulty)
+ _monsters[i].hitPoints++;
+ if (_monsters[i].hitPoints == 0)
+ _monsters[i].hitPoints = 1;
+ }
+}
+
+void LoLEngine::restoreMonsterTempData(LevelTempData *tmp) {
+ memcpy(_monsters, tmp->monsters, sizeof(LolMonsterInPlay) * 30);
+
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].block) {
+ _monsters[i].block = 0;
+ _monsters[i].properties = &_monsterProperties[_monsters[i].type];
+ placeMonster(&_monsters[i], _monsters[i].x, _monsters[i].y);
+ }
+ }
+}
+
+void LoLEngine::restoreFlyingObjectTempData(LevelTempData *tmp) {
+ memcpy(_flyingObjects, tmp->flyingObjects, sizeof(FlyingObject) * 8);
+}
+
+void LoLEngine::releaseMonsterTempData(LevelTempData *tmp) {
+ LolMonsterInPlay *p = (LolMonsterInPlay*)tmp->monsters;
+ delete[] p;
+}
+
+void LoLEngine::releaseFlyingObjectTempData(LevelTempData *tmp) {
+ FlyingObject *p = (FlyingObject*)tmp->flyingObjects;
+ delete[] p;
+}
+
} // End of namespace Kyra
#endif // ENABLE_LOL
diff --git a/engines/kyra/scene_eob.cpp b/engines/kyra/scene_eob.cpp
new file mode 100644
index 0000000000..90aa9ff533
--- /dev/null
+++ b/engines/kyra/scene_eob.cpp
@@ -0,0 +1,1350 @@
+/* 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.
+ *
+ */
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#include "kyra/eobcommon.h"
+#include "kyra/resource.h"
+#include "kyra/script_eob.h"
+#include "kyra/timer.h"
+#include "kyra/sound.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void LolEobBaseEngine::setLevelShapesDim(int index, int16 &x1, int16 &x2, int dim) {
+ if (_lvlShapeLeftRight[index << 1] == -1) {
+ x1 = 0;
+ x2 = 22;
+
+ int16 y1 = 0;
+ int16 y2 = 120;
+
+ int m = index * 18;
+
+ for (int i = 0; i < 18; i++) {
+ uint8 d = _visibleBlocks[i]->walls[_sceneDrawVarDown];
+ uint8 a = _wllWallFlags[d];
+
+ if (a & 8) {
+ int t = _dscDim2[(m + i) << 1];
+
+ if (t > x1) {
+ x1 = t;
+ if (!(a & 0x10))
+ scaleLevelShapesDim(index, y1, y2, -1);
+ }
+
+ t = _dscDim2[((m + i) << 1) + 1];
+
+ if (t < x2) {
+ x2 = t;
+ if (!(a & 0x10))
+ scaleLevelShapesDim(index, y1, y2, -1);
+ }
+ } else {
+ int t = _dscDim1[m + i];
+
+ if (!_wllVmpMap[d] || t == -40)
+ continue;
+
+ if (t == -41) {
+ x1 = 22;
+ x2 = 0;
+ break;
+ }
+
+ if (t > 0 && x2 > t)
+ x2 = t;
+
+ if (t < 0 && x1 < -t)
+ x1 = -t;
+ }
+
+ if (x2 < x1)
+ break;
+ }
+
+ x1 += (_sceneXoffset >> 3);
+ x2 += (_sceneXoffset >> 3);
+
+
+ _lvlShapeTop[index] = y1;
+ _lvlShapeBottom[index] = y2;
+ _lvlShapeLeftRight[index << 1] = x1;
+ _lvlShapeLeftRight[(index << 1) + 1] = x2;
+ } else {
+ x1 = _lvlShapeLeftRight[index << 1];
+ x2 = _lvlShapeLeftRight[(index << 1) + 1];
+ }
+
+ drawLevelModifyScreenDim(dim, x1, 0, x2, 15);
+}
+
+void LolEobBaseEngine::scaleLevelShapesDim(int index, int16 &y1, int16 &y2, int dim) {
+ static const int8 dscY1[] = { 0x1E, 0x18, 0x10, 0x00 };
+ static const int8 dscY2[] = { 0x3B, 0x47, 0x56, 0x78 };
+
+ uint8 a = _dscDimMap[index];
+
+ if (dim == -1 && a != 3)
+ a++;
+
+ y1 = dscY1[a];
+ y2 = dscY2[a];
+
+ if (dim == -1)
+ return;
+
+ const ScreenDim *cDim = screen()->getScreenDim(dim);
+
+ screen()->modifyScreenDim(dim, cDim->sx, y1, cDim->w, y2 - y1);
+}
+
+void LolEobBaseEngine::drawLevelModifyScreenDim(int dim, int16 x1, int16 y1, int16 x2, int16 y2) {
+ screen()->modifyScreenDim(dim, x1, y1 << 3, x2 - x1, (y2 - y1) << 3);
+}
+
+void LolEobBaseEngine::generateBlockDrawingBuffer() {
+ _sceneDrawVarDown = _dscBlockMap[_currentDirection];
+ _sceneDrawVarRight = _dscBlockMap[_currentDirection + 4];
+ _sceneDrawVarLeft = _dscBlockMap[_currentDirection + 8];
+
+ /*******************************************
+ * _visibleBlocks map *
+ * *
+ * | | | | | | *
+ * 00 | 01 | 02 | 03 | 04 | 05 | 06 *
+ * ____|_____|_____|_____|_____|_____|_____ *
+ * | | | | | | *
+ * | 07 | 08 | 09 | 10 | 11 | *
+ * |_____|_____|_____|_____|_____| *
+ * | | | | *
+ * | 12 | 13 | 14 | *
+ * |_____|_____|_____| *
+ * | | *
+ * 15 | 16 | 17 *
+ * | (P) | *
+ ********************************************/
+
+ memset(_blockDrawingBuffer, 0, 660 * sizeof(uint16));
+
+ _wllProcessFlag = ((_currentBlock >> 5) + (_currentBlock & 0x1f) + _currentDirection) & 1;
+
+ if (_wllProcessFlag) // floor and ceiling
+ generateVmpTileDataFlipped(0, 15, 1, -330, 22, 15);
+ else
+ generateVmpTileData(0, 15, 1, -330, 22, 15);
+
+ assignVisibleBlocks(_currentBlock, _currentDirection);
+
+ uint8 t = _visibleBlocks[0]->walls[_sceneDrawVarRight];
+ if (t)
+ generateVmpTileData(-2, 3, t, 102, 3, 5);
+
+ t = _visibleBlocks[6]->walls[_sceneDrawVarLeft];
+ if (t)
+ generateVmpTileDataFlipped(21, 3, t, 102, 3, 5);
+
+ t = _visibleBlocks[1]->walls[_sceneDrawVarRight];
+ uint8 t2 = _visibleBlocks[2]->walls[_sceneDrawVarDown];
+
+ if (hasWall(t) && !(_wllWallFlags[t2] & 8))
+ generateVmpTileData(2, 3, t, 102, 3, 5);
+ else if (t && (_wllWallFlags[t2] & 8))
+ generateVmpTileData(2, 3, t2, 102, 3, 5);
+
+ t = _visibleBlocks[5]->walls[_sceneDrawVarLeft];
+ t2 = _visibleBlocks[4]->walls[_sceneDrawVarDown];
+
+ if (hasWall(t) && !(_wllWallFlags[t2] & 8))
+ generateVmpTileDataFlipped(17, 3, t, 102, 3, 5);
+ else if (t && (_wllWallFlags[t2] & 8))
+ generateVmpTileDataFlipped(17, 3, t2, 102, 3, 5);
+
+ t = _visibleBlocks[2]->walls[_sceneDrawVarRight];
+ if (t)
+ generateVmpTileData(8, 3, t, 97, 1, 5);
+
+ t = _visibleBlocks[4]->walls[_sceneDrawVarLeft];
+ if (t)
+ generateVmpTileDataFlipped(13, 3, t, 97, 1, 5);
+
+ t = _visibleBlocks[1]->walls[_sceneDrawVarDown];
+ if (hasWall(t))
+ generateVmpTileData(-4, 3, t, 129, 6, 5);
+
+ t = _visibleBlocks[5]->walls[_sceneDrawVarDown];
+ if (hasWall(t))
+ generateVmpTileData(20, 3, t, 129, 6, 5);
+
+ t = _visibleBlocks[2]->walls[_sceneDrawVarDown];
+ if (hasWall(t))
+ generateVmpTileData(2, 3, t, 129, 6, 5);
+
+ t = _visibleBlocks[4]->walls[_sceneDrawVarDown];
+ if (hasWall(t))
+ generateVmpTileData(14, 3, t, 129, 6, 5);
+
+ t = _visibleBlocks[3]->walls[_sceneDrawVarDown];
+ if (t)
+ generateVmpTileData(8, 3, t, 129, 6, 5);
+
+ t = _visibleBlocks[7]->walls[_sceneDrawVarRight];
+ if (t)
+ generateVmpTileData(0, 3, t, 117, 2, 6);
+
+ t = _visibleBlocks[11]->walls[_sceneDrawVarLeft];
+ if (t)
+ generateVmpTileDataFlipped(20, 3, t, 117, 2, 6);
+
+ t = _visibleBlocks[8]->walls[_sceneDrawVarRight];
+ if (t)
+ generateVmpTileData(6, 2, t, 81, 2, 8);
+
+ t = _visibleBlocks[10]->walls[_sceneDrawVarLeft];
+ if (t)
+ generateVmpTileDataFlipped(14, 2, t, 81, 2, 8);
+
+ t = _visibleBlocks[8]->walls[_sceneDrawVarDown];
+ if (hasWall(t))
+ generateVmpTileData(-4, 2, t, 159, 10, 8);
+
+ t = _visibleBlocks[10]->walls[_sceneDrawVarDown];
+ if (hasWall(t))
+ generateVmpTileData(16, 2, t, 159, 10, 8);
+
+ t = _visibleBlocks[9]->walls[_sceneDrawVarDown];
+ if (t)
+ generateVmpTileData(6, 2, t, 159, 10, 8);
+
+ t = _visibleBlocks[12]->walls[_sceneDrawVarRight];
+ if (t)
+ generateVmpTileData(3, 1, t, 45, 3, 12);
+
+ t = _visibleBlocks[14]->walls[_sceneDrawVarLeft];
+ if (t)
+ generateVmpTileDataFlipped(16, 1, t, 45, 3, 12);
+
+ t = _visibleBlocks[12]->walls[_sceneDrawVarDown];
+ if (!(_wllWallFlags[t] & 8))
+ generateVmpTileData(-13, 1, t, 239, 16, 12);
+
+ t = _visibleBlocks[14]->walls[_sceneDrawVarDown];
+ if (!(_wllWallFlags[t] & 8))
+ generateVmpTileData(19, 1, t, 239, 16, 12);
+
+ t = _visibleBlocks[13]->walls[_sceneDrawVarDown];
+ if (t)
+ generateVmpTileData(3, 1, t, 239, 16, 12);
+
+ t = _visibleBlocks[15]->walls[_sceneDrawVarRight];
+ t2 = _visibleBlocks[17]->walls[_sceneDrawVarLeft];
+ if (t)
+ generateVmpTileData(0, 0, t, 0, 3, 15);
+ if (t2)
+ generateVmpTileDataFlipped(19, 0, t2, 0, 3, 15);
+}
+
+void LolEobBaseEngine::generateVmpTileData(int16 startBlockX, uint8 startBlockY, uint8 vmpMapIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY) {
+ if (!_wllVmpMap[vmpMapIndex])
+ return;
+
+ uint16 *vmp = &_vmpPtr[(_wllVmpMap[vmpMapIndex] - 1) * 431 + vmpOffset + 330];
+
+ for (int i = 0; i < numBlocksY; i++) {
+ uint16 *bl = &_blockDrawingBuffer[(startBlockY + i) * 22 + startBlockX];
+ for (int ii = 0; ii < numBlocksX; ii++) {
+ if ((startBlockX + ii >= 0) && (startBlockX + ii < 22) && *vmp)
+ *bl = *vmp;
+ bl++;
+ vmp++;
+ }
+ }
+}
+
+void LolEobBaseEngine::generateVmpTileDataFlipped(int16 startBlockX, uint8 startBlockY, uint8 vmpMapIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY) {
+ if (!_wllVmpMap[vmpMapIndex])
+ return;
+
+ uint16 *vmp = &_vmpPtr[(_wllVmpMap[vmpMapIndex] - 1) * 431 + vmpOffset + 330];
+
+ for (int i = 0; i < numBlocksY; i++) {
+ for (int ii = 0; ii < numBlocksX; ii++) {
+ if ((startBlockX + ii) < 0 || (startBlockX + ii) > 21)
+ continue;
+
+ uint16 v = vmp[i * numBlocksX + (numBlocksX - 1 - ii)];
+ if (!v)
+ continue;
+
+ if (v & 0x4000)
+ v -= 0x4000;
+ else
+ v |= 0x4000;
+
+ _blockDrawingBuffer[(startBlockY + i) * 22 + startBlockX + ii] = v;
+ }
+ }
+}
+
+bool LolEobBaseEngine::hasWall(int index) {
+ if (!index || (_wllWallFlags[index] & 8))
+ return false;
+ return true;
+}
+
+void LolEobBaseEngine::assignVisibleBlocks(int block, int direction) {
+ for (int i = 0; i < 18; i++) {
+ uint16 t = (block + _dscBlockIndex[direction * 18 + i]) & 0x3ff;
+ _visibleBlockIndex[i] = t;
+
+ _visibleBlocks[i] = &_levelBlockProperties[t];
+ _lvlShapeLeftRight[i] = _lvlShapeLeftRight[18 + i] = -1;
+ }
+}
+
+bool LolEobBaseEngine::checkSceneUpdateNeed(int block) {
+ if (_sceneUpdateRequired)
+ return true;
+
+ for (int i = 0; i < 15; i++) {
+ if (_visibleBlockIndex[i] == block) {
+ _sceneUpdateRequired = true;
+ return true;
+ }
+ }
+
+ if (_currentBlock == block){
+ _sceneUpdateRequired = true;
+ return true;
+ }
+
+ return false;
+}
+
+void LolEobBaseEngine::drawVcnBlocks() {
+ uint8 *d = _sceneWindowBuffer;
+ uint16 *bdb = _blockDrawingBuffer;
+
+ for (int y = 0; y < 15; y++) {
+ for (int x = 0; x < 22; x++) {
+ bool horizontalFlip = false;
+ int remainder = 0;
+
+ uint16 vcnOffset = *bdb++;
+ int wllVcnOffset = 0;
+ int wllVcnRmdOffset = 0;
+
+ if (vcnOffset & 0x8000) {
+ // this renders a wall block over the transparent pixels of a floor/ceiling block
+ remainder = vcnOffset - 0x8000;
+ vcnOffset = 0;
+ wllVcnRmdOffset = _wllVcnOffset;
+ }
+
+ if (vcnOffset & 0x4000) {
+ horizontalFlip = true;
+ vcnOffset &= 0x3fff;
+ }
+
+ uint8 *src = 0;
+ if (vcnOffset) {
+ src = &_vcnBlocks[vcnOffset << 5];
+ wllVcnOffset = _wllVcnOffset;
+ } else {
+ // floor/ceiling blocks
+ vcnOffset = bdb[329];
+ if (vcnOffset & 0x4000) {
+ horizontalFlip = true;
+ vcnOffset &= 0x3fff;
+ }
+
+ src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset << 5);
+ }
+
+ uint8 shift = _vcnShift ? _vcnShift[vcnOffset] : _blockBrightness;
+
+ if (horizontalFlip) {
+ for (int blockY = 0; blockY < 8; blockY++) {
+ src += 3;
+ for (int blockX = 0; blockX < 4; blockX++) {
+ uint8 t = *src--;
+ *d++ = _vcnExpTable[((t & 0x0f) + wllVcnOffset) | shift];
+ *d++ = _vcnExpTable[((t >> 4) + wllVcnOffset) | shift];
+ }
+ src += 5;
+ d += 168;
+ }
+ } else {
+ for (int blockY = 0; blockY < 8; blockY++) {
+ for (int blockX = 0; blockX < 4; blockX++) {
+ uint8 t = *src++;
+ *d++ = _vcnExpTable[((t >> 4) + wllVcnOffset) | shift];
+ *d++ = _vcnExpTable[((t & 0x0f) + wllVcnOffset) | shift];
+ }
+ d += 168;
+ }
+ }
+ d -= 1400;
+
+ if (remainder) {
+ d -= 8;
+ horizontalFlip = false;
+
+ if (remainder & 0x4000) {
+ remainder &= 0x3fff;
+ horizontalFlip = true;
+ }
+
+ shift = _vcnShift ? _vcnShift[remainder] : _blockBrightness;
+ src = &_vcnBlocks[remainder << 5];
+
+ if (horizontalFlip) {
+ for (int blockY = 0; blockY < 8; blockY++) {
+ src += 3;
+ for (int blockX = 0; blockX < 4; blockX++) {
+ uint8 t = *src--;
+ uint8 h = _vcnExpTable[((t & 0x0f) + wllVcnRmdOffset) | shift];
+ uint8 l = _vcnExpTable[((t >> 4) + wllVcnRmdOffset) | shift];
+ if (h)
+ *d = h;
+ d++;
+ if (l)
+ *d = l;
+ d++;
+ }
+ src += 5;
+ d += 168;
+ }
+ } else {
+ for (int blockY = 0; blockY < 8; blockY++) {
+ for (int blockX = 0; blockX < 4; blockX++) {
+ uint8 t = *src++;
+ uint8 h = _vcnExpTable[((t >> 4) + wllVcnRmdOffset) | shift];
+ uint8 l = _vcnExpTable[((t & 0x0f) + wllVcnRmdOffset) | shift];
+ if (h)
+ *d = h;
+ d++;
+ if (l)
+ *d = l;
+ d++;
+ }
+ d += 168;
+ }
+ }
+ d -= 1400;
+ }
+ }
+ d += 1232;
+ }
+
+ screen()->copyBlockToPage(_sceneDrawPage1, _sceneXoffset, 0, 176, 120, _sceneWindowBuffer);
+}
+
+uint16 LolEobBaseEngine::calcNewBlockPosition(uint16 curBlock, uint16 direction) {
+ static const int16 blockPosTable[] = { -32, 1, 32, -1 };
+ return (curBlock + blockPosTable[direction]) & 0x3ff;
+}
+
+int LolEobBaseEngine::clickedWallShape(uint16 block, uint16 direction) {
+ uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
+ if (!clickedShape(v))
+ return 0;
+
+ snd_stopSpeech(true);
+ runLevelScript(block, 0x40);
+
+ return 1;
+}
+
+int LolEobBaseEngine::clickedLeverOn(uint16 block, uint16 direction) {
+ uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
+ if (!clickedShape(v))
+ return 0;
+
+ _levelBlockProperties[block].walls[direction]++;
+ _sceneUpdateRequired = true;
+
+ if (_flags.gameID == GI_LOL)
+ snd_playSoundEffect(30, -1);
+
+ runLevelScript(block, _clickedSpecialFlag);
+
+ return 1;
+}
+
+int LolEobBaseEngine::clickedLeverOff(uint16 block, uint16 direction) {
+ uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
+ if (!clickedShape(v))
+ return 0;
+
+ _levelBlockProperties[block].walls[direction]--;
+ _sceneUpdateRequired = true;
+
+ if (_flags.gameID == GI_LOL)
+ snd_playSoundEffect(29, -1);
+
+ runLevelScript(block, _clickedSpecialFlag);
+ return 1;
+}
+
+int LolEobBaseEngine::clickedWallOnlyScript(uint16 block) {
+ runLevelScript(block, _clickedSpecialFlag);
+ return 1;
+}
+
+void LolEobBaseEngine::processDoorSwitch(uint16 block, int openClose) {
+ if (block == _currentBlock)
+ return;
+
+ if ((_flags.gameID == GI_LOL && (_levelBlockProperties[block].assignedObjects & 0x8000)) || (_flags.gameID != GI_LOL && (_levelBlockProperties[block].flags & 7)))
+ return;
+
+ if (openClose == 0) {
+ for (int i = 0; i < 3; i++) {
+ if (_openDoorState[i].block != block)
+ continue;
+ openClose = -_openDoorState[i].state;
+ break;
+ }
+ }
+
+ if (openClose == 0) {
+ openClose = (_wllWallFlags[_levelBlockProperties[block].walls[_wllWallFlags[_levelBlockProperties[block].walls[0]] & 8 ? 0 : 1]] & 1) ? 1 : -1;
+ if (_flags.gameID != GI_LOL)
+ openClose *= -1;
+ }
+
+ openCloseDoor(block, openClose);
+}
+
+void LolEobBaseEngine::openCloseDoor(int block, int openClose) {
+ int s1 = -1;
+ int s2 = -1;
+
+ int c = (_wllWallFlags[_levelBlockProperties[block].walls[0]] & 8) ? 0 : 1;
+ int v = _levelBlockProperties[block].walls[c];
+ int flg = (openClose == 1) ? 0x10 : (openClose == -1 ? 0x20 : 0);
+
+ if (_wllWallFlags[v] & flg)
+ return;
+
+ for (int i = 0; i < 3; i++) {
+ if (_openDoorState[i].block == block) {
+ s1 = i;
+ break;
+ } else if (_openDoorState[i].block == 0 && s2 == -1) {
+ s2 = i;
+ }
+ }
+
+ if (s1 != -1 || s2 != -1) {
+ if (s1 == -1)
+ s1 = s2;
+
+ _openDoorState[s1].block = block;
+ _openDoorState[s1].state = openClose;
+ _openDoorState[s1].wall = c;
+
+ flg = (-openClose == 1) ? 0x10 : (-openClose == -1 ? 0x20 : 0);
+
+ if (_wllWallFlags[v] & flg) {
+ _levelBlockProperties[block].walls[c] += openClose;
+ _levelBlockProperties[block].walls[c ^ 2] += openClose;
+
+ int snd = (openClose == -1) ? 4 : 3;
+ if (_flags.gameID == GI_LOL) {
+ snd_processEnvironmentalSoundEffect(snd + 28, _currentBlock);
+ if (!checkSceneUpdateNeed(block))
+ updateEnvironmentalSfx(0);
+ } else {
+ updateEnvironmentalSfx(snd);
+ }
+ }
+
+ enableTimer(_flags.gameID == GI_LOL ? 0 : 12);
+
+ } else {
+ while (!(flg & _wllWallFlags[v]))
+ v += openClose;
+
+ _levelBlockProperties[block].walls[c] = _levelBlockProperties[block].walls[c ^ 2] = v;
+ checkSceneUpdateNeed(block);
+ }
+}
+
+void LolEobBaseEngine::completeDoorOperations() {
+ for (int i = 0; i < 3; i++) {
+ if (!_openDoorState[i].block)
+ continue;
+
+ uint16 b = _openDoorState[i].block;
+
+ do {
+ _levelBlockProperties[b].walls[_openDoorState[i].wall] += _openDoorState[i].state;
+ _levelBlockProperties[b].walls[_openDoorState[i].wall ^ 2] += _openDoorState[i].state;
+ } while (!(_wllWallFlags[_levelBlockProperties[b].walls[_openDoorState[i].wall]] & 0x30));
+
+ _openDoorState[i].block = 0;
+ }
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB || ENABLE_LOL
+#ifdef ENABLE_EOB
+
+namespace Kyra {
+
+void EobCoreEngine::loadLevel(int level, int sub) {
+ _currentLevel = level;
+ _currentSub = sub;
+
+ char file[13];
+ snprintf(file, 13, "LEVEL%d.INF", level);
+
+ Common::SeekableReadStream *s = _res->createReadStream(file);
+ if (!s) {
+ snprintf(file, 13, "LEVEL%d.DRO", level);
+ s = _res->createReadStream(file);
+ }
+
+ if (!s) {
+ snprintf(file, 13, "LEVEL%d.ELO", level);
+ s = _res->createReadStream(file);
+ }
+
+ if (!s)
+ error("Failed loading level file LEVEL%d.INF/DRO/ELO", level);
+
+ if (s->readUint16LE() + 2 == s->size()) {
+ if (s->readUint16LE() == 4) {
+ delete s;
+ s = 0;
+ _screen->loadBitmap(file, 5, 5, 0);
+ }
+ }
+
+ if (s) {
+ s->seek(0);
+ _screen->loadFileDataToPage(s, 5, 15000);
+ delete s;
+ }
+
+ const char *gfxFile = initLevelData(sub);
+
+ const uint8 *data = _screen->getCPagePtr(5);
+ const uint8 *pos = data + READ_LE_UINT16(data);
+ uint16 len = READ_LE_UINT16(pos);
+ uint16 len2 = len;
+ pos += 2;
+
+ if (_flags.gameID == GI_EOB2) {
+ if (*pos++ == 0xEC)
+ pos = loadActiveMonsterData(pos, level);
+ else if (!(_hasTempDataFlags & (1 << (level - 1))))
+ memset(_monsters, 0, 30 * sizeof(EobMonsterInPlay));
+
+ len2 = len - (pos - data);
+ _inf->loadData(pos, len2);
+ } else {
+ _inf->loadData(data, READ_LE_UINT16(data));
+ }
+
+ _screen->setCurPage(2);
+ addLevelItems();
+
+ if (_flags.gameID == GI_EOB2) {
+ pos = data + len;
+ len2 = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ for (uint16 i = 0; i < len2; i++) {
+ LevelBlockProperty *p = &_levelBlockProperties[READ_LE_UINT16(pos)];
+ pos += 2;
+ if (_flags.gameID == GI_EOB2) {
+ p->flags |= READ_LE_UINT16(pos);
+ pos += 2;
+ } else {
+ p->flags |= *pos++;
+ }
+ p->assignedObjects = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ loadVcnData(gfxFile, 0);
+ _screen->loadEobCpsFileToPage("INVENT", 0, 5, 3, 2);
+
+ enableSysTimer(2);
+ _sceneDrawPage1 = 2;
+ _sceneDrawPage2 = 1;
+ _screen->setCurPage(0);
+}
+
+const char *EobCoreEngine::initLevelData(int sub){
+ const uint8 *data = _screen->getCPagePtr(5) + 2;
+ const uint8 *pos = data;
+
+ int slen = (_flags.gameID == GI_EOB1) ? 12 : 13;
+
+ char tmpStr[13];
+ _sound->playTrack(0);
+
+ for (int i = 0; i < sub; i++)
+ pos = data + READ_LE_UINT16(pos);
+
+ pos += 2;
+ if (*pos++ == 0xEC || _flags.gameID == GI_EOB1) {
+ if (_flags.gameID == GI_EOB1)
+ pos -= 3;
+
+ loadBlockProperties((const char*)pos);
+ pos += slen;
+
+ snprintf(tmpStr, slen, "%s.VMP", (const char*) pos);
+ Common::SeekableReadStream *s = _res->createReadStream(tmpStr);
+ uint16 size = s->readUint16LE();
+ delete[] _vmpPtr;
+ _vmpPtr = new uint16[size];
+ for (int i = 0; i < size; i++)
+ _vmpPtr[i] = s->readUint16LE();
+ delete s;
+
+ snprintf(tmpStr, 13, "%s.PAL", (const char*) pos);
+ strcpy(_curGfxFile, (const char*) pos);
+ pos += slen;
+
+ if (*pos++ != 0xff && _flags.gameID == GI_EOB2) {
+ snprintf(tmpStr, 13, "%s.PAL", (const char*) pos);
+ pos += 13;
+ }
+
+ //////// _screen->loadPalette(tmpStr, _screen->getPalette(0));
+
+ if (_flags.gameID == GI_EOB1) {
+ pos += 11;
+ _screen->setShapeFadeMode(0, false);
+ _screen->setShapeFadeMode(1, false);
+ } ////////////////////
+ else
+ _screen->loadPalette(tmpStr, _screen->getPalette(0));
+ ////////////////////7
+
+ Palette backupPal(256);
+ backupPal.copy(_screen->getPalette(0), 224, 32, 224);
+ _screen->getPalette(0).fill(224, 32, 0x3f);
+ uint8 *src = _screen->getPalette(0).getData();
+
+ _screen->createFadeTable(src, _screen->getFadeTable(0), 4, 75); // green
+ _screen->createFadeTable(src, _screen->getFadeTable(1), 12, 200); // black
+ _screen->createFadeTable(src, _screen->getFadeTable(2), 10, 85); // blue
+ _screen->createFadeTable(src, _screen->getFadeTable(3), 11, 125); // light blue
+
+ _screen->getPalette(0).copy(backupPal, 224, 32, 224);
+ _screen->createFadeTable(src, _screen->getFadeTable(4), 12, 85); // grey (shadow)
+ _screen->setFadeTableIndex(4);
+ }
+
+ if (_flags.gameID == GI_EOB2) {
+ delay(_tickLength);
+ _sound->loadSoundFile((const char*) pos);
+ pos += 13;
+ }
+
+ releaseDoorShapes();
+ releaseMonsterShapes(0, 36);
+ releaseDecorations();
+
+ if (_flags.gameID == GI_EOB1) {
+ loadDoorShapes(pos[0], pos[1], pos[2], pos[3]);
+ pos += 4;
+ _scriptTimersMode = *pos++;
+ _scriptTimers[0].ticks = READ_LE_UINT16(pos);
+ _scriptTimers[0].func = 0;
+ _scriptTimers[0].next = _system->getMillis() + _scriptTimers[0].ticks * _tickLength;
+ pos+= 2;
+ } else {
+ for (int i = 0; i < 2; i++) {
+ int a = (*pos == 0xEC) ? 0 : ((*pos == 0xEA) ? 1 : -1);
+ pos++;
+ if (a == -1)
+ continue;
+ toggleWallState(pos[13], a);
+ _doorType[pos[13]] = pos[14];
+ _noDoorSwitch[pos[13]] = pos[15];
+ pos = loadDoorShapes((const char*)pos, pos[13], pos + 16);
+ }
+ }
+
+ _stepsUntilScriptCall = READ_LE_UINT16(pos);
+ pos+= 2;
+ _stepCounter = 0;
+
+ for (int i = 0; i < 2; i++) {
+ if (_flags.gameID == GI_EOB1) {
+ if (*pos == 0xFF)
+ continue;
+ loadMonsterShapes((const char *)(pos + 1), i * 18, false, *pos * 18);
+ pos += 13;
+ } else {
+ if (*pos++ != 0xEC)
+ continue;
+ loadMonsterShapes((const char *)(pos + 2), pos[1] * 18, pos[15] ? true : false, *pos * 18);
+ pos += 16;
+ }
+ }
+
+ if (_flags.gameID == GI_EOB1)
+ pos = loadActiveMonsterData(pos, _currentLevel) - 1;
+ else
+ pos = loadMonsterProperties(pos);
+
+ if (*pos++ == 0xEC || _flags.gameID == GI_EOB1) {
+ int num = READ_LE_UINT16(pos);
+ pos += 2;
+
+ for (int i = 0; i < num; i++) {
+ if (*pos++ == 0xEC) {
+ loadDecorations((const char*)pos, (const char*)(pos + slen));
+ pos += (slen << 1);
+ } else {
+ assignWallsAndDecorations(pos[0], pos[1], (int8)pos[2], pos[3], pos[4]);
+ pos += 5;
+ }
+ }
+ }
+
+ if (_flags.gameID == GI_EOB2)
+ pos = initScriptTimers(pos);
+
+ return _curGfxFile;
+}
+
+void EobCoreEngine::addLevelItems() {
+ for (int i = 0; i < 1024; i++)
+ _levelBlockProperties[i].drawObjects = 0;
+
+ for (int i = 0; i < 600; i++) {
+ if (_items[i].level != _currentLevel || _items[i].block <= 0)
+ continue;
+ setItemPosition((Item*)&_levelBlockProperties[_items[i].block & 0x3ff].drawObjects, _items[i].block, i, _items[i].pos);
+ }
+}
+
+void EobCoreEngine::loadVcnData(const char *file, const char*/*nextFile*/) {
+ if (file)
+ strcpy(_lastBlockDataFile, file);
+
+ char fname[13];
+ snprintf(fname, sizeof(fname), "%s.VCN", _lastBlockDataFile);
+ _screen->loadBitmap(fname, 3, 3, 0);
+ const uint8 *v = _screen->getCPagePtr(2);
+ uint32 tlen = READ_LE_UINT16(v) << 5;
+ v += 2;
+ memcpy(_vcnExpTable, v, 32);
+ v += 32;
+ delete[] _vcnBlocks;
+ _vcnBlocks = new uint8[tlen];
+ memcpy(_vcnBlocks, v, tlen);
+}
+
+void EobCoreEngine::loadBlockProperties(const char *mazFile) {
+ memset(_levelBlockProperties, 0, 1024 * sizeof(LevelBlockProperty));
+ Common::SeekableReadStream *s = _res->createReadStream(mazFile);
+ _screen->loadFileDataToPage(s, 2, 4096);
+ delete s;
+
+ if (_hasTempDataFlags & (1 << (_currentLevel - 1))) {
+ restoreBlockTempData(_currentLevel);
+ return;
+ }
+
+ const uint8 *p = _screen->getCPagePtr(2) + 6;
+
+ for (int i = 0; i < 1024; i++) {
+ for (int ii = 0; ii < 4; ii++)
+ _levelBlockProperties[i].walls[ii] = *p++;
+ }
+}
+
+void EobCoreEngine::loadDecorations(const char *cpsFile, const char *decFile) {
+ _screen->loadEobBitmap(cpsFile, 3, 3);
+ Common::SeekableReadStream *s = _res->createReadStream(decFile);
+
+ _levelDecorationDataSize = s->readUint16LE();
+ delete[] _levelDecorationData;
+ _levelDecorationData = new LevelDecorationProperty[_levelDecorationDataSize];
+
+ for (int i = 0; i < _levelDecorationDataSize; i++) {
+ LevelDecorationProperty *l = &_levelDecorationData[i];
+ for (int ii = 0; ii < 10; ii++) {
+ l->shapeIndex[ii] = s->readByte();
+ if (l->shapeIndex[ii] == 0xff)
+ l->shapeIndex[ii] = 0xffff;
+ }
+ l->next = s->readByte();
+ l->flags = s->readByte();
+ for (int ii = 0; ii < 10; ii++)
+ l->shapeX[ii] = s->readSint16LE();
+ for (int ii = 0; ii < 10; ii++)
+ l->shapeY[ii] = s->readSint16LE();
+ }
+
+ int len = s->readUint16LE();
+ delete[] _levelDecorationRects;
+ _levelDecorationRects = new EobRect8[len];
+ for (int i = 0; i < len; i++) {
+ EobRect8 *l = &_levelDecorationRects[i];
+ l->x = s->readUint16LE();
+ l->y = s->readUint16LE();
+ l->w = s->readUint16LE();
+ l->h = s->readUint16LE();
+ }
+
+ delete s;
+}
+
+void EobCoreEngine::assignWallsAndDecorations(int wallIndex, int vmpIndex, int decIndex, int specialType, int flags) {
+ _wllVmpMap[wallIndex] = vmpIndex;
+ _wllShapeMap[wallIndex] = _mappedDecorationsCount + 1;
+ _specialWallTypes[wallIndex] = specialType;
+ _wllWallFlags[wallIndex] = flags ^ 4;
+
+ if (decIndex == -1) {
+ _wllShapeMap[wallIndex] = 0;
+ return;
+ }
+
+ do {
+ memcpy(&_levelDecorationProperties[_mappedDecorationsCount], &_levelDecorationData[decIndex], sizeof(LevelDecorationProperty));
+
+ for (int i = 0; i < 10; i++) {
+ uint16 t = _levelDecorationProperties[_mappedDecorationsCount].shapeIndex[i];
+ if (t == 0xffff)
+ continue;
+
+ if (_levelDecorationShapes[t])
+ continue;
+
+ EobRect8 *r = &_levelDecorationRects[t];
+ if (r->w == 0 || r->h == 0)
+ error("Error trying to make decoration %d x: %d y:%d w:%d h:%d", decIndex, r->x, r->y, r->w, r->h);
+
+ _levelDecorationShapes[t] = _screen->encodeShape(r->x, r->y, r->w, r->h);
+ }
+
+ decIndex = _levelDecorationProperties[_mappedDecorationsCount++].next;
+
+ if (decIndex)
+ _levelDecorationProperties[_mappedDecorationsCount - 1].next = _mappedDecorationsCount + 1;
+ else
+ decIndex = -1;
+
+ } while (decIndex != -1);
+}
+
+void EobCoreEngine::releaseDecorations() {
+ if (_levelDecorationShapes) {
+ for (int i = 0; i < 400; i++) {
+ delete[] _levelDecorationShapes[i];
+ _levelDecorationShapes[i] = 0;
+ }
+ }
+ _mappedDecorationsCount = 0;
+}
+
+void EobCoreEngine::releaseDoorShapes() {
+ for (int i = 0; i < 6; i++) {
+ delete[] _doorShapes[i];
+ _doorShapes[i] = 0;
+ delete[] _doorSwitches[i].shp;
+ _doorSwitches[i].shp = 0;
+ }
+}
+
+void EobCoreEngine::toggleWallState(int wall, int toggle) {
+ wall = wall * 10 + 3;
+
+ for (int i = 0; i < 9 ; i++) {
+ if (i == 4)
+ continue;
+
+ if (toggle)
+ _wllWallFlags[wall + i] |= 2;
+ else
+ _wllWallFlags[wall + i] &= 0xfd;
+ }
+}
+
+void EobCoreEngine::drawScene(int update) {
+ generateBlockDrawingBuffer();
+ drawVcnBlocks();
+ drawSceneShapes();
+
+ if (_sceneDrawPage2) {
+ if (update)
+ _screen->fillRect(0, 0, 176, 120, 12);
+
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _sceneDrawPage2 = 0;
+ }
+
+ uint32 ct = _system->getMillis();
+ if (_flashShapeTimer > ct) {
+ int diff = _flashShapeTimer - ct;
+ while ((diff > 0) && !shouldQuit()) {
+ updateInput();
+ uint32 step = MIN<uint32>(diff, _tickLength / 5);
+ _system->delayMillis(step);
+ diff -= step;
+ }
+ }
+
+ if (_sceneDefaultUpdate) {
+ resetSkipFlag();
+ delayUntil(_drawSceneTimer);
+ }
+
+ if (update && !_partyResting)
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 2, 0, Screen::CR_NO_P_CHECK);
+
+ updateEnvironmentalSfx(0);
+
+ if (!_dialogueField && update && !_updateFlags)
+ gui_drawCompass(false);
+
+ if (update && !_partyResting)
+ _screen->updateScreen();
+
+ if (_sceneDefaultUpdate) {
+ _sceneDefaultUpdate = false;
+ _drawSceneTimer = _system->getMillis() /*+ 4 * _tickLength*/;
+ }
+
+ _sceneUpdateRequired = false;
+}
+
+void EobCoreEngine::drawSceneShapes() {
+ for (int i = 0; i < 18; i++) {
+ uint8 t = _dscTileIndex[i];
+ uint8 s = _visibleBlocks[t]->walls[_sceneDrawVarDown];
+
+ _shpDmX1 = 0;
+ _shpDmX2 = 0;
+
+ setLevelShapesDim(t, _shpDmX1, _shpDmX2, _sceneShpDim);
+
+ if (_shpDmX2 <= _shpDmX1)
+ continue;
+
+ drawDecorations(t);
+
+ if (_visibleBlocks[t]->drawObjects)
+ drawBlockItems(t);
+
+ if (t < 15) {
+ uint16 w = _wllWallFlags[s];
+
+ if (w & 8)
+ drawDoor(t);
+
+ if (_visibleBlocks[t]->flags & 7) {
+ const ScreenDim *dm = _screen->getScreenDim(5);
+ _screen->modifyScreenDim(5, dm->sx, _lvlShapeTop[t], dm->w, _lvlShapeBottom[t] - _lvlShapeTop[t]);
+ drawMonsters(t);
+ drawLevelModifyScreenDim(5, _lvlShapeLeftRight[(t << 1)], 0, _lvlShapeLeftRight[(t << 1) + 1], 15);
+ }
+
+ if (_flags.gameID == GI_EOB2 && s == 74)
+ drawWallOfForce(t);
+ }
+
+ drawFlyingObjects(t);
+
+ if (s == _teleporterWallId)
+ drawTeleporter(t);
+ }
+}
+
+void EobCoreEngine::drawDecorations(int index) {
+ static const int16 *dscWalls[] = { 0, 0, &_sceneDrawVarDown, &_sceneDrawVarRight, &_sceneDrawVarDown,
+ &_sceneDrawVarRight, &_sceneDrawVarDown, 0, &_sceneDrawVarDown, &_sceneDrawVarLeft, &_sceneDrawVarDown,
+ &_sceneDrawVarLeft, 0, 0, &_sceneDrawVarDown, &_sceneDrawVarRight, &_sceneDrawVarDown, &_sceneDrawVarRight,
+ &_sceneDrawVarDown, 0, &_sceneDrawVarDown, &_sceneDrawVarLeft, &_sceneDrawVarDown, &_sceneDrawVarLeft,
+ &_sceneDrawVarDown, &_sceneDrawVarRight, &_sceneDrawVarDown, 0, &_sceneDrawVarDown, &_sceneDrawVarLeft,
+ 0, &_sceneDrawVarRight, &_sceneDrawVarDown, 0, 0, &_sceneDrawVarLeft
+ };
+
+ for (int i = 1; i >= 0; i--) {
+ int s = index * 2 + i;
+ if (dscWalls[s]) {
+ int d = *dscWalls[s];
+ int8 l = _wllShapeMap[_visibleBlocks[index]->walls[d]];
+
+ uint8 *shapeData = 0;
+
+ int x = 0;
+
+ while (l > 0) {
+ l--;
+ int8 ix = _dscShapeIndex[s];
+ uint8 shpIx = ABS(ix) - 1;
+ uint8 flg = _levelDecorationProperties[l].flags;
+
+ if ((i == 0) && (flg & 1 || ((flg & 2) && _wllProcessFlag)))
+ ix = -ix;
+
+ if (_levelDecorationProperties[l].shapeIndex[shpIx] == 0xffff) {
+ l = _levelDecorationProperties[l].next;
+ continue;
+ }
+
+ shapeData = _levelDecorationShapes[_levelDecorationProperties[l].shapeIndex[shpIx]];
+ if (shapeData) {
+ x = 0;
+ if (i == 0) {
+ if (flg & 4)
+ x += _dscShapeCoords[(index * 5 + 4) << 1];
+ else
+ x += _dscShapeX[index];
+ }
+
+ if (ix < 0) {
+ x += (176 - _levelDecorationProperties[l].shapeX[shpIx] - (shapeData[2] << 3));
+ drawBlockObject(1, 2, shapeData, x, _levelDecorationProperties[l].shapeY[shpIx], _sceneShpDim);
+ } else {
+ x += _levelDecorationProperties[l].shapeX[shpIx];
+ drawBlockObject(0, 2, shapeData, x, _levelDecorationProperties[l].shapeY[shpIx], _sceneShpDim);
+
+ }
+ }
+ l = _levelDecorationProperties[l].next;
+ continue;
+ }
+ }
+ }
+}
+
+int EobCoreEngine::calcNewBlockPositionAndTestPassability(uint16 curBlock, uint16 direction) {
+ uint16 b = calcNewBlockPosition(curBlock, direction);
+ int w = _levelBlockProperties[b].walls[direction ^ 2];
+ int f = _wllWallFlags[w];
+
+ if (w == 74 && _currentBlock == curBlock) {
+ for (int i = 0; i < 5; i++) {
+
+ }
+ }
+
+ if (!(f & 1) || _levelBlockProperties[b].flags & 7)
+ return -1;
+
+ return b;
+}
+
+void EobCoreEngine::notifyBlockNotPassable() {
+ _txt->printMessage(_warningStrings[0]);
+ snd_playSoundEffect(29);
+ removeInputTop();
+}
+
+void EobCoreEngine::moveParty(uint16 block) {
+ //processMonstersUnk1();
+ uint16 old = _currentBlock;
+ _currentBlock = block;
+
+ runLevelScript(old, 2);
+
+ if (++_moveCounter > 3) {
+ _txt->printMessage("\r");
+ _moveCounter = 0;
+ }
+
+ runLevelScript(block, 1);
+
+ if (_levelBlockProperties[block].walls[0] == 26)
+ memset(_levelBlockProperties[block].walls, 0, 4);
+
+ //processMonstersUnk1();
+ _stepCounter++;
+ //_keybControlUnk = -1;
+ _sceneUpdateRequired = true;
+
+ checkFlyingObjects();
+}
+
+int EobCoreEngine::clickedDoorSwitch(uint16 block, uint16 direction) {
+ uint8 v = _visibleBlocks[13]->walls[_sceneDrawVarDown];
+ SpriteDecoration *d = &_doorSwitches[((v > 12 && v < 23) || v == 31) ? 3 : 0];
+ int x1 = d->x + _dscShapeCoords[138] - 4;
+ int y1 = d->y - 4;
+ if (!posWithinRect(_mouseX, _mouseY, x1, y1, x1 + (d->shp[2] << 3) + 8, y1 + d->shp[1] + 8) && (_clickedSpecialFlag == 0x40))
+ return clickedDoorNoPry(block, direction);
+
+ processDoorSwitch(block, 0);
+ snd_playSoundEffect(6);
+
+ return 1;
+}
+
+int EobCoreEngine::clickedNiche(uint16 block, uint16 direction) {
+ uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
+ if (!clickedShape(v))
+ return 0;
+
+ if (_itemInHand) {
+ if (_dscItemShapeMap[_items[_itemInHand].icon] <= 14) {
+ _txt->printMessage(_pryDoorStrings[5]);
+ } else {
+ setItemPosition((Item*)&_levelBlockProperties[block & 0x3ff].drawObjects, block, _itemInHand, 8);
+ runLevelScript(block, 4);
+ setHandItem(0);
+ _sceneUpdateRequired = true;
+ }
+ } else {
+ int d = getQueuedItem((Item*)&_levelBlockProperties[block].drawObjects, 8, -1);
+ if (!d)
+ return 1;
+ runLevelScript(block, 8);
+ setHandItem(d);
+ _sceneUpdateRequired = true;
+ }
+
+ return 1;
+}
+
+int EobCoreEngine::clickedDoorPry(uint16 block, uint16 direction) {
+ if (!posWithinRect(_mouseX, _mouseY, 40, 16, 136, 88) && (_clickedSpecialFlag == 0x40))
+ return 0;
+
+ int d = -1;
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 0x0d))
+ continue;
+ if (d >= 0) {
+ int s1 = _characters[i].strengthCur + _characters[i].strengthExtCur;
+ int s2 = _characters[d].strengthCur + _characters[d].strengthExtCur;
+ if (s1 >= s2)
+ d = i;
+ } else {
+ d = i;
+ }
+ }
+
+ if (d == -1) {
+ _txt->printMessage(_pryDoorStrings[_flags.gameID == GI_EOB2 ? 1 : 0]);
+ return 1;
+ }
+
+ static const uint8 forceDoorChanceTable[] = { 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 12, 13 };
+ int s = _characters[d].strengthCur > 18 ? 18 : _characters[d].strengthCur;
+
+ if (rollDice(1, 20) < forceDoorChanceTable[s]) {
+ _txt->printMessage(_pryDoorStrings[_flags.gameID == GI_EOB2 ? 2 : 1]);
+ _levelBlockProperties[block].walls[direction] = _levelBlockProperties[block].walls[direction ^ 2] =
+ (_levelBlockProperties[block].walls[direction] == (_flags.gameID == GI_EOB2 ? 51 : 30)) ? 8 : 18;
+ openDoor(block);
+ } else {
+ _txt->printMessage(_pryDoorStrings[3]);
+ }
+
+ return 1;
+}
+
+int EobCoreEngine::clickedDoorNoPry(uint16 block, uint16 direction) {
+ if (!posWithinRect(_mouseX, _mouseY, 40, 16, 136, 88) && (_clickedSpecialFlag == 0x40))
+ return 0;
+
+ if (!(_wllWallFlags[_levelBlockProperties[block].walls[direction]] & 0x20))
+ return 0;
+ _txt->printMessage(_pryDoorStrings[6]);
+ return 1;
+}
+
+int EobCoreEngine::specialWallAction(int block, int direction) {
+ direction ^= 2;
+ uint8 type = _specialWallTypes[_levelBlockProperties[block].walls[direction]];
+ if (!type || !(_clickedSpecialFlag & (((_levelBlockProperties[block].flags & 0xf8) >> 3) | 0xe0)))
+ return 0;
+
+ int res = 0;
+ switch (type) {
+ case 1:
+ res = clickedDoorSwitch(block, direction);
+ break;
+
+ case 2:
+ case 8:
+ res = clickedWallShape(block, direction);
+ break;
+
+ case 3:
+ res = clickedLeverOn(block, direction);
+ break;
+
+ case 4:
+ res = clickedLeverOff(block, direction);
+ break;
+
+ case 5:
+ res = clickedDoorPry(block, direction);
+ break;
+
+ case 6:
+ res = clickedDoorNoPry(block, direction);
+ break;
+
+ case 7:
+ case 9:
+ res = clickedWallOnlyScript(block);
+ break;
+
+ case 10:
+ res = clickedNiche(block, direction);
+ break;
+
+ default:
+ break;
+ }
+
+ _clickedSpecialFlag = 0;
+ _sceneUpdateRequired = true;
+
+ return res;
+}
+
+void EobCoreEngine::openDoor(int block) {
+ openCloseDoor(block, 1);
+}
+
+void EobCoreEngine::closeDoor(int block) {
+ if (block == _currentBlock || _levelBlockProperties[block].flags & 7)
+ return;
+ openCloseDoor(block, -1);
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp
index a5a2562448..c2b16cab88 100644
--- a/engines/kyra/scene_lol.cpp
+++ b/engines/kyra/scene_lol.cpp
@@ -42,8 +42,8 @@ void LoLEngine::loadLevel(int index) {
stopPortraitSpeechAnim();
for (int i = 0; i < 400; i++) {
- delete[] _levelShapes[i];
- _levelShapes[i] = 0;
+ delete[] _levelDecorationShapes[i];
+ _levelDecorationShapes[i] = 0;
}
_emc->unload(&_scriptData);
@@ -160,7 +160,7 @@ void LoLEngine::loadLevelWallData(int index, bool mapShapes) {
if (mapShapes) {
int16 sh = (int16) READ_LE_UINT16(d);
if (sh > 0)
- _wllShapeMap[c] = assignLevelShapes(sh);
+ _wllShapeMap[c] = assignLevelDecorationShapes(sh);
else
_wllShapeMap[c] = *d;
}
@@ -169,7 +169,7 @@ void LoLEngine::loadLevelWallData(int index, bool mapShapes) {
d += 2;
_wllWallFlags[c] = *d;
d += 2;
- _wllBuffer4[c] = *d;
+ _wllAutomapData[c] = *d;
d += 2;
}
@@ -179,7 +179,7 @@ void LoLEngine::loadLevelWallData(int index, bool mapShapes) {
_lvlShpFileHandle = 0;
}
-int LoLEngine::assignLevelShapes(int index) {
+int LoLEngine::assignLevelDecorationShapes(int index) {
uint16 *p1 = (uint16 *)_tempBuffer5120;
uint16 *p2 = (uint16 *)(_tempBuffer5120 + 4000);
@@ -187,34 +187,34 @@ int LoLEngine::assignLevelShapes(int index) {
if (r)
return r;
- uint16 o = _lvlBlockIndex++;
+ uint16 o = _mappedDecorationsCount++;
- memcpy(&_levelShapeProperties[o], &_levelFileData[index], sizeof(LevelShapeProperty));
+ memcpy(&_levelDecorationProperties[o], &_levelDecorationData[index], sizeof(LevelDecorationProperty));
for (int i = 0; i < 10; i++) {
- uint16 t = _levelShapeProperties[o].shapeIndex[i];
+ uint16 t = _levelDecorationProperties[o].shapeIndex[i];
if (t == 0xffff)
continue;
uint16 pv = p1[t];
if (pv) {
- _levelShapeProperties[o].shapeIndex[i] = pv;
+ _levelDecorationProperties[o].shapeIndex[i] = pv;
} else {
- _levelShapes[_lvlShapeIndex] = getLevelShapes(t);
+ _levelDecorationShapes[_lvlShapeIndex] = getLevelDecorationShapes(t);
p1[t] = _lvlShapeIndex;
- _levelShapeProperties[o].shapeIndex[i] = _lvlShapeIndex++;
+ _levelDecorationProperties[o].shapeIndex[i] = _lvlShapeIndex++;
}
}
p2[index] = o;
- if (_levelShapeProperties[o].next)
- _levelShapeProperties[o].next = assignLevelShapes(_levelShapeProperties[o].next);
+ if (_levelDecorationProperties[o].next)
+ _levelDecorationProperties[o].next = assignLevelDecorationShapes(_levelDecorationProperties[o].next);
return o;
}
-uint8 *LoLEngine::getLevelShapes(int shapeIndex) {
- if (_lvlShpNum <= shapeIndex)
+uint8 *LoLEngine::getLevelDecorationShapes(int shapeIndex) {
+ if (_decorationCount <= shapeIndex)
return 0;
_lvlShpFileHandle->seek(shapeIndex * 4 + 2, SEEK_SET);
@@ -232,60 +232,6 @@ uint8 *LoLEngine::getLevelShapes(int shapeIndex) {
return res;
}
-void LoLEngine::restoreBlockTempData(int index) {
- memset(_tempBuffer5120, 0, 5120);
- int l = index - 1;
-
- memcpy(_monsters, _lvlTempData[l]->monsters, sizeof(MonsterInPlay) * 30);
- memcpy(_flyingObjects, _lvlTempData[l]->flyingObjects, sizeof(FlyingObject) * 8);
-
- Common::String filename = Common::String::format("LEVEL%d.CMZ", index);
-
- _screen->loadBitmap(filename.c_str(), 3, 3, 0);
- const uint8 *p = _screen->getCPagePtr(2);
- uint16 len = READ_LE_UINT16(p + 4);
- p += 6;
-
- memset(_levelBlockProperties, 0, 1024 * sizeof(LevelBlockProperty));
-
- uint8 *t = _lvlTempData[l]->wallsXorData;
- uint8 *t2 = _lvlTempData[l]->flags;
-
- for (int i = 0; i < 1024; i++) {
- for (int ii = 0; ii < 4; ii++)
- _levelBlockProperties[i].walls[ii] = p[i * len + ii] ^ *t++;
- _levelBlockProperties[i].flags = *t2++;
- }
-
- for (int i = 0; i < 30; i++) {
- if (_monsters[i].block) {
- _monsters[i].block = 0;
- _monsters[i].properties = &_monsterProperties[_monsters[i].type];
- placeMonster(&_monsters[i], _monsters[i].x, _monsters[i].y);
- }
- }
-
- restoreTempDataAdjustMonsterStrength(l);
-}
-
-void LoLEngine::restoreTempDataAdjustMonsterStrength(int index) {
- if (_lvlTempData[index]->monsterDifficulty == _monsterDifficulty)
- return;
-
- uint16 d = (_monsterModifiers[_lvlTempData[index]->monsterDifficulty] << 8) / _monsterModifiers[_monsterDifficulty];
-
- for (int i = 0; i < 30; i++) {
- if (_monsters[i].mode >= 14 || _monsters[i].block == 0 || _monsters[i].hitPoints <= 0)
- continue;
-
- _monsters[i].hitPoints = (d * _monsters[i].hitPoints) >> 8;
- if (_monsterDifficulty < _lvlTempData[index]->monsterDifficulty)
- _monsters[i].hitPoints++;
- if (_monsters[i].hitPoints == 0)
- _monsters[i].hitPoints = 1;
- }
-}
-
void LoLEngine::loadBlockProperties(const char *cmzFile) {
memset(_levelBlockProperties, 0, 1024 * sizeof(LevelBlockProperty));
_screen->loadBitmap(cmzFile, 2, 2, 0);
@@ -299,7 +245,7 @@ void LoLEngine::loadBlockProperties(const char *cmzFile) {
_levelBlockProperties[i].direction = 5;
- if (_wllBuffer4[_levelBlockProperties[i].walls[0]] == 17) {
+ if (_wllAutomapData[_levelBlockProperties[i].walls[0]] == 17) {
_levelBlockProperties[i].flags &= 0xef;
_levelBlockProperties[i].flags |= 0x20;
}
@@ -310,15 +256,15 @@ void LoLEngine::loadLevelShpDat(const char *shpFile, const char *datFile, bool f
memset(_tempBuffer5120, 0, 5120);
_lvlShpFileHandle = _res->createReadStream(shpFile);
- _lvlShpNum = _lvlShpFileHandle->readUint16LE();
+ _decorationCount = _lvlShpFileHandle->readUint16LE();
Common::SeekableReadStream *s = _res->createReadStream(datFile);
- _levelFileDataSize = s->readUint16LE();
- delete[] _levelFileData;
- _levelFileData = new LevelShapeProperty[_levelFileDataSize];
- for (int i = 0; i < _levelFileDataSize; i++) {
- LevelShapeProperty * l = &_levelFileData[i];
+ _levelDecorationDataSize = s->readUint16LE();
+ delete[] _levelDecorationData;
+ _levelDecorationData = new LevelDecorationProperty[_levelDecorationDataSize];
+ for (int i = 0; i < _levelDecorationDataSize; i++) {
+ LevelDecorationProperty * l = &_levelDecorationData[i];
for (int ii = 0; ii < 10; ii++)
l->shapeIndex[ii] = s->readUint16LE();
for (int ii = 0; ii < 10; ii++)
@@ -334,7 +280,7 @@ void LoLEngine::loadLevelShpDat(const char *shpFile, const char *datFile, bool f
delete s;
if (!flag) {
- _lvlBlockIndex = 1;
+ _mappedDecorationsCount = 1;
_lvlShapeIndex = 1;
}
}
@@ -515,10 +461,10 @@ void LoLEngine::resetItems(int flag) {
for (int i = 0; i < 1024; i++) {
_levelBlockProperties[i].direction = 5;
uint16 id = _levelBlockProperties[i].assignedObjects;
- MonsterInPlay *r = 0;
+ LolMonsterInPlay *r = 0;
while (id & 0x8000) {
- r = (MonsterInPlay *)findObject(id);
+ r = (LolMonsterInPlay *)findObject(id);
id = r->nextAssignedObject;
}
@@ -537,7 +483,7 @@ void LoLEngine::resetItems(int flag) {
}
void LoLEngine::disableMonsters() {
- memset(_monsters, 0, 30 * sizeof(MonsterInPlay));
+ memset(_monsters, 0, 30 * sizeof(LolMonsterInPlay));
for (int i = 0; i < 30; i++)
_monsters[i].mode = 0x10;
}
@@ -751,11 +697,6 @@ void LoLEngine::moveParty(uint16 direction, int unk1, int unk2, int buttonShape)
updateAutoMap(_currentBlock);
}
-uint16 LoLEngine::calcNewBlockPosition(uint16 curBlock, uint16 direction) {
- static const int16 blockPosTable[] = { -32, 1, 32, -1 };
- return (curBlock + blockPosTable[direction]) & 0x3ff;
-}
-
uint16 LoLEngine::calcBlockIndex(uint16 x, uint16 y) {
return (((y & 0xff00) >> 3) | (x >> 8)) & 0x3ff;
}
@@ -827,51 +768,6 @@ void LoLEngine::notifyBlockNotPassable(int scrollFlag) {
snd_playSoundEffect(19, -1);
}
-int LoLEngine::clickedWallShape(uint16 block, uint16 direction) {
- uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
- if (!clickedShape(v))
- return 0;
-
- snd_stopSpeech(true);
- runLevelScript(block, 0x40);
-
- return 1;
-}
-
-int LoLEngine::clickedLeverOn(uint16 block, uint16 direction) {
- uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
- if (!clickedShape(v))
- return 0;
-
- _levelBlockProperties[block].walls[direction]++;
- _sceneUpdateRequired = true;
-
- snd_playSoundEffect(30, -1);
-
- runLevelScript(block, 0x40);
-
- return 1;
-}
-
-int LoLEngine::clickedLeverOff(uint16 block, uint16 direction) {
- uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
- if (!clickedShape(v))
- return 0;
-
- _levelBlockProperties[block].walls[direction]--;
- _sceneUpdateRequired = true;
-
- snd_playSoundEffect(29, -1);
-
- runLevelScript(block, 0x40);
- return 1;
-}
-
-int LoLEngine::clickedWallOnlyScript(uint16 block) {
- runLevelScript(block, 0x40);
- return 1;
-}
-
int LoLEngine::clickedDoorSwitch(uint16 block, uint16 direction) {
uint8 v = _wllShapeMap[_levelBlockProperties[block].walls[direction]];
if (!clickedShape(v))
@@ -903,119 +799,6 @@ int LoLEngine::clickedNiche(uint16 block, uint16 direction) {
return 1;
}
-bool LoLEngine::clickedShape(int shapeIndex) {
- while (shapeIndex) {
- uint16 s = _levelShapeProperties[shapeIndex].shapeIndex[1];
-
- if (s == 0xffff) {
- shapeIndex = _levelShapeProperties[shapeIndex].next;
- continue;
- }
-
- int w = _levelShapes[s][3];
- int h = _levelShapes[s][2];
- int x = _levelShapeProperties[shapeIndex].shapeX[1] + 136;
- int y = _levelShapeProperties[shapeIndex].shapeY[1] + 8;
-
- if (_levelShapeProperties[shapeIndex].flags & 1)
- w <<= 1;
-
- if (posWithinRect(_mouseX, _mouseY, x - 4, y - 4, x + w + 8, y + h + 8))
- return true;
-
- shapeIndex = _levelShapeProperties[shapeIndex].next;
- }
-
- return false;
-}
-
-void LoLEngine::processDoorSwitch(uint16 block, int openClose) {
- if ((block == _currentBlock) || (_levelBlockProperties[block].assignedObjects & 0x8000))
- return;
-
- if (openClose == 0) {
- for (int i = 0; i < 3; i++) {
- if (_openDoorState[i].block != block)
- continue;
- openClose = -_openDoorState[i].state;
- break;
- }
- }
-
- if (openClose == 0)
- openClose = (_wllWallFlags[_levelBlockProperties[block].walls[_wllWallFlags[_levelBlockProperties[block].walls[0]] & 8 ? 0 : 1]] & 1) ? 1 : -1;
-
- openCloseDoor(block, openClose);
-}
-
-void LoLEngine::openCloseDoor(uint16 block, int openClose) {
- int s1 = -1;
- int s2 = -1;
-
- int c = (_wllWallFlags[_levelBlockProperties[block].walls[0]] & 8) ? 0 : 1;
- int v = _levelBlockProperties[block].walls[c];
- int flg = (openClose == 1) ? 0x10 : (openClose == -1 ? 0x20 : 0);
-
- if (_wllWallFlags[v] & flg)
- return;
-
- for (int i = 0; i < 3; i++) {
- if (_openDoorState[i].block == block) {
- s1 = i;
- break;
- } else if (_openDoorState[i].block == 0 && s2 == -1) {
- s2 = i;
- }
- }
-
- if (s1 != -1 || s2 != -1) {
- if (s1 == -1)
- s1 = s2;
-
- _openDoorState[s1].block = block;
- _openDoorState[s1].state = openClose;
- _openDoorState[s1].wall = c;
-
- flg = (-openClose == 1) ? 0x10 : (-openClose == -1 ? 0x20 : 0);
-
- if (_wllWallFlags[v] & flg) {
- _levelBlockProperties[block].walls[c] += openClose;
- _levelBlockProperties[block].walls[c ^ 2] += openClose;
-
- int snd = (openClose == -1) ? 32 : 31;
-
- snd_processEnvironmentalSoundEffect(snd, block);
- if (!checkSceneUpdateNeed(block))
- updateEnvironmentalSfx(0);
- }
-
- enableTimer(0);
-
- } else {
- while (!(flg & _wllWallFlags[v]))
- v += openClose;
-
- _levelBlockProperties[block].walls[c] = _levelBlockProperties[block].walls[c ^ 2] = v;
- checkSceneUpdateNeed(block);
- }
-}
-
-void LoLEngine::completeDoorOperations() {
- for (int i = 0; i < 3; i++) {
- if (!_openDoorState[i].block)
- continue;
-
- uint16 b = _openDoorState[i].block;
-
- do {
- _levelBlockProperties[b].walls[_openDoorState[i].wall] += _openDoorState[i].state;
- _levelBlockProperties[b].walls[_openDoorState[i].wall ^ 2] += _openDoorState[i].state;
- } while (!(_wllWallFlags[_levelBlockProperties[b].walls[_openDoorState[i].wall]] & 0x30));
-
- _openDoorState[i].block = 0;
- }
-}
-
void LoLEngine::movePartySmoothScrollBlocked(int speed) {
if (!_smoothScrollingEnabled || (_smoothScrollingEnabled && _needSceneRestore))
return;
@@ -1447,7 +1230,7 @@ void LoLEngine::setWallType(int block, int wall, int val) {
if (wall == -1) {
for (int i = 0; i < 4; i++)
_levelBlockProperties[block].walls[i] = val;
- if (_wllBuffer4[val] == 17) {
+ if (_wllAutomapData[val] == 17) {
_levelBlockProperties[block].flags &= 0xef;
_levelBlockProperties[block].flags |= 0x20;
} else {
@@ -1603,334 +1386,20 @@ void LoLEngine::setDefaultButtonState() {
_lampStatusSuspended = false;
}
-void LoLEngine::generateBlockDrawingBuffer() {
- _sceneDrawVarDown = _dscBlockMap[_currentDirection];
- _sceneDrawVarRight = _dscBlockMap[_currentDirection + 4];
- _sceneDrawVarLeft = _dscBlockMap[_currentDirection + 8];
-
- /*******************************************
- * _visibleBlocks map *
- * *
- * | | | | | | *
- * 00 | 01 | 02 | 03 | 04 | 05 | 06 *
- * ____|_____|_____|_____|_____|_____|_____ *
- * | | | | | | *
- * | 07 | 08 | 09 | 10 | 11 | *
- * |_____|_____|_____|_____|_____| *
- * | | | | *
- * | 12 | 13 | 14 | *
- * |_____|_____|_____| *
- * | | *
- * 15 | 16 | 17 *
- * | (P) | *
- ********************************************/
-
- memset(_blockDrawingBuffer, 0, 660 * sizeof(uint16));
-
- _wllProcessFlag = ((_currentBlock >> 5) + (_currentBlock & 0x1f) + _currentDirection) & 1;
-
- if (_wllProcessFlag) // floor and ceiling
- generateVmpTileDataFlipped(0, 15, 1, -330, 22, 15);
- else
- generateVmpTileData(0, 15, 1, -330, 22, 15);
-
- assignVisibleBlocks(_currentBlock, _currentDirection);
-
- uint8 t = _visibleBlocks[0]->walls[_sceneDrawVarRight];
- if (t)
- generateVmpTileData(-2, 3, t, 102, 3, 5);
-
- t = _visibleBlocks[6]->walls[_sceneDrawVarLeft];
- if (t)
- generateVmpTileDataFlipped(21, 3, t, 102, 3, 5);
-
- t = _visibleBlocks[1]->walls[_sceneDrawVarRight];
- uint8 t2 = _visibleBlocks[2]->walls[_sceneDrawVarDown];
-
- if (hasWall(t) && !(_wllWallFlags[t2] & 8))
- generateVmpTileData(2, 3, t, 102, 3, 5);
- else if (t && (_wllWallFlags[t2] & 8))
- generateVmpTileData(2, 3, t2, 102, 3, 5);
-
- t = _visibleBlocks[5]->walls[_sceneDrawVarLeft];
- t2 = _visibleBlocks[4]->walls[_sceneDrawVarDown];
-
- if (hasWall(t) && !(_wllWallFlags[t2] & 8))
- generateVmpTileDataFlipped(17, 3, t, 102, 3, 5);
- else if (t && (_wllWallFlags[t2] & 8))
- generateVmpTileDataFlipped(17, 3, t2, 102, 3, 5);
-
- t = _visibleBlocks[2]->walls[_sceneDrawVarRight];
- if (t)
- generateVmpTileData(8, 3, t, 97, 1, 5);
-
- t = _visibleBlocks[4]->walls[_sceneDrawVarLeft];
- if (t)
- generateVmpTileDataFlipped(13, 3, t, 97, 1, 5);
-
- t = _visibleBlocks[1]->walls[_sceneDrawVarDown];
- if (hasWall(t))
- generateVmpTileData(-4, 3, t, 129, 6, 5);
-
- t = _visibleBlocks[5]->walls[_sceneDrawVarDown];
- if (hasWall(t))
- generateVmpTileData(20, 3, t, 129, 6, 5);
-
- t = _visibleBlocks[2]->walls[_sceneDrawVarDown];
- if (hasWall(t))
- generateVmpTileData(2, 3, t, 129, 6, 5);
-
- t = _visibleBlocks[4]->walls[_sceneDrawVarDown];
- if (hasWall(t))
- generateVmpTileData(14, 3, t, 129, 6, 5);
-
- t = _visibleBlocks[3]->walls[_sceneDrawVarDown];
- if (t)
- generateVmpTileData(8, 3, t, 129, 6, 5);
-
- t = _visibleBlocks[7]->walls[_sceneDrawVarRight];
- if (t)
- generateVmpTileData(0, 3, t, 117, 2, 6);
-
- t = _visibleBlocks[11]->walls[_sceneDrawVarLeft];
- if (t)
- generateVmpTileDataFlipped(20, 3, t, 117, 2, 6);
-
- t = _visibleBlocks[8]->walls[_sceneDrawVarRight];
- if (t)
- generateVmpTileData(6, 2, t, 81, 2, 8);
-
- t = _visibleBlocks[10]->walls[_sceneDrawVarLeft];
- if (t)
- generateVmpTileDataFlipped(14, 2, t, 81, 2, 8);
-
- t = _visibleBlocks[8]->walls[_sceneDrawVarDown];
- if (hasWall(t))
- generateVmpTileData(-4, 2, t, 159, 10, 8);
-
- t = _visibleBlocks[10]->walls[_sceneDrawVarDown];
- if (hasWall(t))
- generateVmpTileData(16, 2, t, 159, 10, 8);
-
- t = _visibleBlocks[9]->walls[_sceneDrawVarDown];
- if (t)
- generateVmpTileData(6, 2, t, 159, 10, 8);
-
- t = _visibleBlocks[12]->walls[_sceneDrawVarRight];
- if (t)
- generateVmpTileData(3, 1, t, 45, 3, 12);
-
- t = _visibleBlocks[14]->walls[_sceneDrawVarLeft];
- if (t)
- generateVmpTileDataFlipped(16, 1, t, 45, 3, 12);
-
- t = _visibleBlocks[12]->walls[_sceneDrawVarDown];
- if (!(_wllWallFlags[t] & 8))
- generateVmpTileData(-13, 1, t, 239, 16, 12);
-
- t = _visibleBlocks[14]->walls[_sceneDrawVarDown];
- if (!(_wllWallFlags[t] & 8))
- generateVmpTileData(19, 1, t, 239, 16, 12);
-
- t = _visibleBlocks[13]->walls[_sceneDrawVarDown];
- if (t)
- generateVmpTileData(3, 1, t, 239, 16, 12);
-
- t = _visibleBlocks[15]->walls[_sceneDrawVarRight];
- t2 = _visibleBlocks[17]->walls[_sceneDrawVarLeft];
- if (t)
- generateVmpTileData(0, 0, t, 0, 3, 15);
- if (t2)
- generateVmpTileDataFlipped(19, 0, t2, 0, 3, 15);
-}
-
-void LoLEngine::generateVmpTileData(int16 startBlockX, uint8 startBlockY, uint8 vmpMapIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY) {
- if (!_wllVmpMap[vmpMapIndex])
- return;
-
- uint16 *vmp = &_vmpPtr[(_wllVmpMap[vmpMapIndex] - 1) * 431 + vmpOffset + 330];
-
- for (int i = 0; i < numBlocksY; i++) {
- uint16 *bl = &_blockDrawingBuffer[(startBlockY + i) * 22 + startBlockX];
- for (int ii = 0; ii < numBlocksX; ii++) {
- if ((startBlockX + ii >= 0) && (startBlockX + ii < 22) && *vmp)
- *bl = *vmp;
- bl++;
- vmp++;
- }
- }
-}
-
-void LoLEngine::generateVmpTileDataFlipped(int16 startBlockX, uint8 startBlockY, uint8 vmpMapIndex, int16 vmpOffset, uint8 numBlocksX, uint8 numBlocksY) {
- if (!_wllVmpMap[vmpMapIndex])
- return;
-
- uint16 *vmp = &_vmpPtr[(_wllVmpMap[vmpMapIndex] - 1) * 431 + vmpOffset + 330];
-
- for (int i = 0; i < numBlocksY; i++) {
- for (int ii = 0; ii < numBlocksX; ii++) {
- if ((startBlockX + ii) < 0 || (startBlockX + ii) > 21)
- continue;
-
- uint16 v = vmp[i * numBlocksX + (numBlocksX - 1 - ii)];
- if (!v)
- continue;
-
- if (v & 0x4000)
- v -= 0x4000;
- else
- v |= 0x4000;
-
- _blockDrawingBuffer[(startBlockY + i) * 22 + startBlockX + ii] = v;
- }
- }
-}
-
-bool LoLEngine::hasWall(int index) {
- if (!index || (_wllWallFlags[index] & 8))
- return false;
- return true;
-}
-
-void LoLEngine::assignVisibleBlocks(int block, int direction) {
- for (int i = 0; i < 18; i++) {
- uint16 t = (block + _dscBlockIndex[direction * 18 + i]) & 0x3ff;
- _visibleBlockIndex[i] = t;
-
- _visibleBlocks[i] = &_levelBlockProperties[t];
- _lvlShapeLeftRight[i] = _lvlShapeLeftRight[18 + i] = -1;
- }
-}
-
-void LoLEngine::drawVcnBlocks() {
- uint8 *d = _sceneWindowBuffer;
- uint16 *bdb = _blockDrawingBuffer;
-
- for (int y = 0; y < 15; y++) {
- for (int x = 0; x < 22; x++) {
- bool horizontalFlip = false;
- int remainder = 0;
-
- uint16 vcnOffset = *bdb++;
-
- if (vcnOffset & 0x8000) {
- // this renders a wall block over the transparent pixels of a floor/ceiling block
- remainder = vcnOffset - 0x8000;
- vcnOffset = 0;
- }
-
- if (vcnOffset & 0x4000) {
- horizontalFlip = true;
- vcnOffset &= 0x3fff;
- }
-
- uint8 *src = 0;
- if (vcnOffset) {
- src = &_vcnBlocks[vcnOffset << 5];
- } else {
- // floor/ceiling blocks
- vcnOffset = bdb[329];
- if (vcnOffset & 0x4000) {
- horizontalFlip = true;
- vcnOffset &= 0x3fff;
- }
-
- src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset << 5);
- }
-
- uint8 shift = _vcnShift ? _vcnShift[vcnOffset] : _blockBrightness;
-
- if (horizontalFlip) {
- for (int blockY = 0; blockY < 8; blockY++) {
- src += 3;
- for (int blockX = 0; blockX < 4; blockX++) {
- uint8 t = *src--;
- *d++ = _vcnExpTable[(t & 0x0f) | shift];
- *d++ = _vcnExpTable[(t >> 4) | shift];
- }
- src += 5;
- d += 168;
- }
- } else {
- for (int blockY = 0; blockY < 8; blockY++) {
- for (int blockX = 0; blockX < 4; blockX++) {
- uint8 t = *src++;
- *d++ = _vcnExpTable[(t >> 4) | shift];
- *d++ = _vcnExpTable[(t & 0x0f) | shift];
- }
- d += 168;
- }
- }
- d -= 1400;
-
- if (remainder) {
- d -= 8;
- horizontalFlip = false;
-
- if (remainder & 0x4000) {
- remainder &= 0x3fff;
- horizontalFlip = true;
- }
-
- shift = _vcnShift ? _vcnShift[remainder] : _blockBrightness;
- src = &_vcnBlocks[remainder << 5];
-
- if (horizontalFlip) {
- for (int blockY = 0; blockY < 8; blockY++) {
- src += 3;
- for (int blockX = 0; blockX < 4; blockX++) {
- uint8 t = *src--;
- uint8 h = _vcnExpTable[(t & 0x0f) | shift];
- uint8 l = _vcnExpTable[(t >> 4) | shift];
- if (h)
- *d = h;
- d++;
- if (l)
- *d = l;
- d++;
- }
- src += 5;
- d += 168;
- }
- } else {
- for (int blockY = 0; blockY < 8; blockY++) {
- for (int blockX = 0; blockX < 4; blockX++) {
- uint8 t = *src++;
- uint8 h = _vcnExpTable[(t >> 4) | shift];
- uint8 l = _vcnExpTable[(t & 0x0f) | shift];
- if (h)
- *d = h;
- d++;
- if (l)
- *d = l;
- d++;
- }
- d += 168;
- }
- }
- d -= 1400;
- }
- }
- d += 1232;
- }
-
- _screen->copyBlockToPage(_sceneDrawPage1, 112, 0, 176, 120, _sceneWindowBuffer);
-}
-
void LoLEngine::drawSceneShapes() {
for (int i = 0; i < 18; i++) {
uint8 t = _dscTileIndex[i];
uint8 s = _visibleBlocks[t]->walls[_sceneDrawVarDown];
- int16 x1 = 0;
- int16 x2 = 0;
+ _shpDmX1 = 0;
+ _shpDmX2 = 0;
int16 dimY1 = 0;
int16 dimY2 = 0;
- setLevelShapesDim(t, x1, x2, 13);
+ setLevelShapesDim(t, _shpDmX1, _shpDmX2, _sceneShpDim);
- if (x2 <= x1)
+ if (_shpDmX2 <= _shpDmX1)
continue;
drawDecorations(t);
@@ -1954,104 +1423,12 @@ void LoLEngine::drawSceneShapes() {
if (v > 80)
v = 80;
- scaleLevelShapesDim(t, dimY1, dimY2, 13);
+ scaleLevelShapesDim(t, dimY1, dimY2, _sceneShpDim);
drawDoor(_doorShapes[(s < 23 ? _dscDoorShpIndex[s] : 0)], 0, t, 10, 0, -v, 2);
- setLevelShapesDim(t, dimY1, dimY2, 13);
+ setLevelShapesDim(t, dimY1, dimY2, _sceneShpDim);
}
}
-void LoLEngine::setLevelShapesDim(int index, int16 &x1, int16 &x2, int dim) {
- if (_lvlShapeLeftRight[index << 1] == -1) {
- x1 = 0;
- x2 = 22;
-
- int16 y1 = 0;
- int16 y2 = 120;
-
- int m = index * 18;
-
- for (int i = 0; i < 18; i++) {
- uint8 d = _visibleBlocks[i]->walls[_sceneDrawVarDown];
- uint8 a = _wllWallFlags[d];
-
- if (a & 8) {
- int t = _dscDim2[(m + i) << 1];
-
- if (t > x1) {
- x1 = t;
- if (!(a & 0x10))
- scaleLevelShapesDim(index, y1, y2, -1);
- }
-
- t = _dscDim2[((m + i) << 1) + 1];
-
- if (t < x2) {
- x2 = t;
- if (!(a & 0x10))
- scaleLevelShapesDim(index, y1, y2, -1);
- }
- } else {
- int t = _dscDim1[m + i];
-
- if (!_wllVmpMap[d] || t == -40)
- continue;
-
- if (t == -41) {
- x1 = 22;
- x2 = 0;
- break;
- }
-
- if (t > 0 && x2 > t)
- x2 = t;
-
- if (t < 0 && x1 < -t)
- x1 = -t;
- }
-
- if (x2 < x1)
- break;
- }
-
- x1 += 14;
- x2 += 14;
-
- _lvlShapeTop[index] = y1;
- _lvlShapeBottom[index] = y2;
- _lvlShapeLeftRight[index << 1] = x1;
- _lvlShapeLeftRight[(index << 1) + 1] = x2;
- } else {
- x1 = _lvlShapeLeftRight[index << 1];
- x2 = _lvlShapeLeftRight[(index << 1) + 1];
- }
-
- drawLevelModifyScreenDim(dim, x1, 0, x2, 15);
-}
-
-void LoLEngine::scaleLevelShapesDim(int index, int16 &y1, int16 &y2, int dim) {
- static const int8 dscY1[] = { 0x1E, 0x18, 0x10, 0x00 };
- static const int8 dscY2[] = { 0x3B, 0x47, 0x56, 0x78 };
-
- uint8 a = _dscDimMap[index];
-
- if (dim == -1 && a != 3)
- a++;
-
- y1 = dscY1[a];
- y2 = dscY2[a];
-
- if (dim == -1)
- return;
-
- const ScreenDim *cDim = _screen->getScreenDim(dim);
-
- _screen->modifyScreenDim(dim, cDim->sx, y1, cDim->w, y2 - y1);
-}
-
-void LoLEngine::drawLevelModifyScreenDim(int dim, int16 x1, int16 y1, int16 x2, int16 y2) {
- _screen->modifyScreenDim(dim, x1, y1 << 3, x2 - x1, (y2 - y1) << 3);
-}
-
void LoLEngine::drawDecorations(int index) {
for (int i = 1; i >= 0; i--) {
int s = index * 2 + i;
@@ -2066,7 +1443,7 @@ void LoLEngine::drawDecorations(int index) {
if (!scaleW || !scaleH)
continue;
- uint8 d = (_currentDirection + _dscUnk1[s]) & 3;
+ uint8 d = (_currentDirection + _dscWalls[s]) & 3;
int8 l = _wllShapeMap[_visibleBlocks[index]->walls[d]];
uint8 *shapeData = 0;
@@ -2076,21 +1453,21 @@ void LoLEngine::drawDecorations(int index) {
int flags = 0;
while (l > 0) {
- if ((_levelShapeProperties[l].flags & 8) && index != 3 && index != 9 && index != 13) {
- l = _levelShapeProperties[l].next;
+ if ((_levelDecorationProperties[l].flags & 8) && index != 3 && index != 9 && index != 13) {
+ l = _levelDecorationProperties[l].next;
continue;
}
- if (_dscOvlMap[shpIx] == 1 && ((_levelShapeProperties[l].flags & 2) || ((_levelShapeProperties[l].flags & 4) && _wllProcessFlag)))
+ if (_dscOvlMap[shpIx] == 1 && ((_levelDecorationProperties[l].flags & 2) || ((_levelDecorationProperties[l].flags & 4) && _wllProcessFlag)))
ix = -ix;
int xOffs = 0;
int yOffs = 0;
uint8 *ovl = 0;
- if (_levelShapeProperties[l].scaleFlag[shpIx] & 1) {
- xOffs = _levelShapeProperties[l].shapeX[shpIx];
- yOffs = _levelShapeProperties[l].shapeY[shpIx];
+ if (_levelDecorationProperties[l].scaleFlag[shpIx] & 1) {
+ xOffs = _levelDecorationProperties[l].shapeX[shpIx];
+ yOffs = _levelDecorationProperties[l].shapeY[shpIx];
shpIx = _dscOvlMap[shpIx];
int ov = ovlIndex;
if (_flags.use16ColorMode) {
@@ -2100,8 +1477,8 @@ void LoLEngine::drawDecorations(int index) {
else
ov = 0;
}
- ovl = _screen->getLevelOverlay(ov);
- } else if (_levelShapeProperties[l].shapeIndex[shpIx] != 0xffff) {
+ ovl = screen()->getLevelOverlay(ov);
+ } else if (_levelDecorationProperties[l].shapeIndex[shpIx] != 0xffff) {
scaleW = scaleH = 0x100;
int ov = 7;
if (_flags.use16ColorMode) {
@@ -2111,37 +1488,37 @@ void LoLEngine::drawDecorations(int index) {
else
ov = 0;
}
- ovl = _screen->getLevelOverlay(ov);
+ ovl = screen()->getLevelOverlay(ov);
}
- if (_levelShapeProperties[l].shapeIndex[shpIx] != 0xffff) {
- shapeData = _levelShapes[_levelShapeProperties[l].shapeIndex[shpIx]];
+ if (_levelDecorationProperties[l].shapeIndex[shpIx] != 0xffff) {
+ shapeData = _levelDecorationShapes[_levelDecorationProperties[l].shapeIndex[shpIx]];
if (shapeData) {
if (ix < 0) {
- x = _dscShapeX[s] + xOffs + ((_levelShapeProperties[l].shapeX[shpIx] * scaleW) >> 8);
+ x = _dscShapeX[s] + xOffs + ((_levelDecorationProperties[l].shapeX[shpIx] * scaleW) >> 8);
if (ix == _dscShapeIndex[s]) {
- x = _dscShapeX[s] - ((_levelShapeProperties[l].shapeX[shpIx] * scaleW) >> 8) -
- _screen->getShapeScaledWidth(shapeData, scaleW) - xOffs;
+ x = _dscShapeX[s] - ((_levelDecorationProperties[l].shapeX[shpIx] * scaleW) >> 8) -
+ screen()->getShapeScaledWidth(shapeData, scaleW) - xOffs;
}
flags = 0x105;
} else {
- x = _dscShapeX[s] + xOffs + ((_levelShapeProperties[l].shapeX[shpIx] * scaleW) >> 8);
+ x = _dscShapeX[s] + xOffs + ((_levelDecorationProperties[l].shapeX[shpIx] * scaleW) >> 8);
flags = 0x104;
}
- y = _dscShapeY[s] + yOffs + ((_levelShapeProperties[l].shapeY[shpIx] * scaleH) >> 8);
- _screen->drawShape(_sceneDrawPage1, shapeData, x + 112, y, 13, flags, ovl, 1, scaleW, scaleH);
+ y = _dscShapeY[s] + yOffs + ((_levelDecorationProperties[l].shapeY[shpIx] * scaleH) >> 8);
+ screen()->drawShape(_sceneDrawPage1, shapeData, x + 112, y, _sceneShpDim, flags, ovl, 1, scaleW, scaleH);
- if ((_levelShapeProperties[l].flags & 1) && shpIx < 4) {
+ if ((_levelDecorationProperties[l].flags & 1) && shpIx < 4) {
//draw shadow
- x += (_screen->getShapeScaledWidth(shapeData, scaleW));
+ x += (screen()->getShapeScaledWidth(shapeData, scaleW));
flags ^= 1;
- _screen->drawShape(_sceneDrawPage1, shapeData, x + 112, y, 13, flags, ovl, 1, scaleW, scaleH);
+ screen()->drawShape(_sceneDrawPage1, shapeData, x + 112, y, _sceneShpDim, flags, ovl, 1, scaleW, scaleH);
}
}
}
- l = _levelShapeProperties[l].next;
+ l = _levelDecorationProperties[l].next;
shpIx = (_dscShapeIndex[s] < 0) ? -_dscShapeIndex[s] : _dscShapeIndex[s];
}
}
diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp
index 4eae89e0d4..5e424b4817 100644
--- a/engines/kyra/screen.cpp
+++ b/engines/kyra/screen.cpp
@@ -976,6 +976,58 @@ void Screen::fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum,
}
}
+void Screen::crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage) {
+ if (srcPage > 13 || dstPage > 13)
+ error("Screen::crossFadeRegion: attempting to use temp page as source or dest page.");
+
+ hideMouse();
+
+ uint16 *wB = (uint16*)_pagePtrs[14];
+ uint8 *hB = _pagePtrs[14] + 640;
+
+ for (int i = 0; i < w; i++)
+ wB[i] = i;
+
+ for (int i = 0; i < h; i++)
+ hB[i] = i;
+
+ for (int i = 0; i < w; i++)
+ SWAP(wB[_vm->_rnd.getRandomNumberRng(0, w - 1)], wB[i]);
+
+ for (int i = 0; i < h; i++)
+ SWAP(hB[_vm->_rnd.getRandomNumberRng(0, h - 1)], hB[i]);
+
+ uint8 *s = _pagePtrs[srcPage];
+ uint8 *d = _pagePtrs[dstPage];
+
+ for (int i = 0; i < h; i++) {
+ int iH = i;
+ uint32 end = _system->getMillis() + 1;
+ for (int ii = 0; ii < w; ii++) {
+ int sX = x1 + wB[ii];
+ int sY = y1 + hB[iH];
+ int dX = x2 + wB[ii];
+ int dY = y2 + hB[iH];
+
+ if (++iH >= h)
+ iH = 0;
+
+ d[dY * 320 + dX] = s[sY * 320 + sX];
+ addDirtyRect(dX, dY, 1, 1);
+ }
+
+ // This tries to speed things up, to get similiar speeds as in DOSBox etc.
+ if ((i & 5) == 5)
+ updateScreen();
+
+ uint32 cur = _system->getMillis();
+ if (end > cur)
+ _system->delayMillis(end - cur);
+ }
+
+ showMouse();
+}
+
void Screen::drawBox(int x1, int y1, int x2, int y2, int color) {
drawClippedLine(x1, y1, x2, y1, color);
drawClippedLine(x1, y1, x1, y2, color);
@@ -1088,6 +1140,10 @@ bool Screen::loadFont(FontId fontId, const char *filename) {
if (!fnt) {
if (_isAmiga)
fnt = new AMIGAFont();
+#ifdef ENABLE_EOB
+ else if (_vm->game() == GI_EOB1 || _vm->game() == GI_EOB2)
+ fnt = new OldDOSFont();
+#endif // ENABLE_EOB
else
fnt = new DOSFont();
@@ -2859,7 +2915,7 @@ void Screen::loadBitmap(const char *filename, int tempPage, int dstPage, Palette
const char *ext = filename + strlen(filename) - 3;
uint8 compType = srcData[2];
- uint32 imgSize = scumm_stricmp(ext, "CMP") ? READ_LE_UINT32(srcData + 4) : READ_LE_UINT16(srcData);
+ uint32 imgSize = (_vm->game() == GI_KYRA2 && !scumm_stricmp(ext, "CMP")) ? READ_LE_UINT16(srcData) : READ_LE_UINT32(srcData + 4);
uint16 palSize = READ_LE_UINT16(srcData + 8);
if (pal && palSize)
diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h
index 51a9a7f744..cb7d73d1c1 100644
--- a/engines/kyra/screen.h
+++ b/engines/kyra/screen.h
@@ -137,6 +137,37 @@ private:
uint16 *_bitmapOffsets;
};
+#ifdef ENABLE_EOB
+/**
+ * Implementation of the Font interface for old DOS fonts used
+ * in EOB and EOB II.
+ *
+ */
+class OldDOSFont : public Font {
+public:
+ OldDOSFont();
+ ~OldDOSFont() { unload(); }
+
+ bool load(Common::SeekableReadStream &file);
+ int getHeight() const { return _height; }
+ int getWidth() const { return _width; }
+ int getCharWidth(uint16 c) const;
+ void setColorMap(const uint8 *src) { _colorMap = src; }
+ void drawChar(uint16 c, byte *dst, int pitch) const;
+
+private:
+ void unload();
+
+ uint8 *_data;
+ uint16 *_bitmapOffsets;
+
+ int _width, _height;
+ const uint8 *_colorMap;
+
+ int _numGlyphs;
+};
+#endif // ENABLE_EOB
+
/**
* Implementation of the Font interface for AMIGA fonts.
*/
@@ -369,6 +400,8 @@ public:
void shuffleScreen(int sx, int sy, int w, int h, int srcPage, int dstPage, int ticks, bool transparent);
void fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum = -1, bool xored = false);
+ void crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage);
+
void clearPage(int pageNum);
uint8 getPagePixel(int pageNum, int x, int y);
@@ -420,6 +453,8 @@ public:
virtual void setScreenDim(int dim) = 0;
virtual const ScreenDim *getScreenDim(int dim) = 0;
+ virtual int curDimIndex() const { return 0; }
+ virtual void modifyScreenDim(int dim, int x, int y, int w, int h) {}
virtual int screenDimTableCount() const = 0;
const ScreenDim *_curDim;
@@ -430,13 +465,15 @@ public:
int setNewShapeHeight(uint8 *shape, int height);
int resetShapeHeight(uint8 *shape);
- void drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...);
+ virtual int getShapeScaledWidth( const uint8*, int) { return 0; }
+
+ virtual void drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...);
// mouse handling
void hideMouse();
void showMouse();
bool isMouseVisible() const;
- void setMouseCursor(int x, int y, const byte *shape);
+ virtual void setMouseCursor(int x, int y, const byte *shape);
// rect handling
virtual int getRectSize(int w, int h) = 0;
@@ -463,6 +500,8 @@ public:
void blockInRegion(int x, int y, int width, int height);
void blockOutRegion(int x, int y, int width, int height);
+ virtual uint8 *getLevelOverlay(int) { return 0; }
+
int _charWidth;
int _charOffset;
int _curPage;
@@ -514,7 +553,7 @@ protected:
uint8 _sjisInvisibleColor;
Palette *_screenPalette;
- Common::Array<Palette *> _palettes;
+ Common::Array<Palette*> _palettes;
Palette *_internFadePalette;
Font *_fonts[FID_NUM];
diff --git a/engines/kyra/screen_eob.cpp b/engines/kyra/screen_eob.cpp
new file mode 100644
index 0000000000..eb5a52477b
--- /dev/null
+++ b/engines/kyra/screen_eob.cpp
@@ -0,0 +1,965 @@
+/* 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.
+ *
+ */
+
+
+#if !defined(ENABLE_EOB)
+#include "kyra/screen.h"
+#endif
+
+#ifdef ENABLE_EOB
+
+#include "kyra/eobcommon.h"
+#include "kyra/resource.h"
+
+#include "common/system.h"
+
+#include "graphics/cursorman.h"
+
+namespace Kyra {
+
+Screen_Eob::Screen_Eob(EobCoreEngine *vm, OSystem *system) : Screen(vm, system) {
+ _shapeFadeMode[0] = _shapeFadeMode[1] = 0;
+ _shapeFadeInternal = 0;
+ _fadeData = 0;
+ _fadeDataIndex = 0;
+ _dsX1 = _dsX2 = _dsY1 = _dsY2 = 0;
+ _customDimTable = 0;
+ _dsTempPage = 0;
+}
+
+Screen_Eob::~Screen_Eob() {
+ delete[] _fadeData;
+ delete[] _customDimTable;
+ delete[] _dsTempPage;
+}
+
+bool Screen_Eob::init() {
+ if (Screen::init()) {
+ _customDimTable = new ScreenDim*[_screenDimTableCount];
+ memset(_customDimTable, 0, sizeof(ScreenDim *)* _screenDimTableCount);
+
+ _fadeData = _vm->resource()->fileData("FADING.DAT", 0);
+
+ if (!_fadeData) {
+ _fadeData = new uint8[0x700];
+ memset(_fadeData, 0, 0x700);
+ uint8 *pal = _vm->resource()->fileData("palette1.pal", 0); // EGA: palette0.pal
+ for (int i = 0; i < 7; i++)
+ createFadeTable(pal, &_fadeData[i << 8], 18, (i + 1) * 36);
+ delete[] pal;
+ }
+
+ _dsTempPage = new uint8[6000];
+
+ return true;
+ }
+ return false;
+}
+
+void Screen_Eob::setScreenDim(int dim) {
+ assert(dim < _screenDimTableCount);
+ _curDim = _customDimTable[dim] ? (const ScreenDim *)_customDimTable[dim] : &_screenDimTable[dim];
+ _curDimIndex = dim;
+}
+
+const ScreenDim *Screen_Eob::getScreenDim(int dim) {
+ assert(dim < _screenDimTableCount);
+ return _customDimTable[dim] ? (const ScreenDim *)_customDimTable[dim] : &_screenDimTable[dim];
+}
+
+void Screen_Eob::modifyScreenDim(int dim, int x, int y, int w, int h) {
+ delete _customDimTable[dim];
+ _customDimTable[dim] = new ScreenDim;
+ memcpy(_customDimTable[dim], &_screenDimTable[dim], sizeof(ScreenDim));
+ _customDimTable[dim]->sx = x;
+ _customDimTable[dim]->sy = y;
+ _customDimTable[dim]->w = w;
+ _customDimTable[dim]->h = h;
+ if (dim == _curDimIndex)
+ setScreenDim(dim);
+}
+
+void Screen_Eob::setClearScreenDim(int dim) {
+ setScreenDim(dim);
+ clearCurDim();
+}
+
+void Screen_Eob::clearCurDim() {
+ fillRect(_curDim->sx << 3, _curDim->sy, ((_curDim->sx + _curDim->w) << 3) - 1, (_curDim->sy + _curDim->h) - 1, _curDim->unkA);
+}
+
+void Screen_Eob::setMouseCursor(int x, int y, const byte *shape) {
+ if (!shape)
+ return;
+ int mouseW = shape[2] << 3;
+ int mouseH = shape[3];
+ uint8 *cursor = new uint8[mouseW * mouseH];
+ fillRect(0, 0, mouseW, mouseH, _cursorColorKey, 8);
+ drawShape(8, shape, 0, 0, 0);
+ CursorMan.showMouse(false);
+ copyRegionToBuffer(8, 0, 0, mouseW, mouseH, cursor);
+ CursorMan.replaceCursor(cursor, mouseW, mouseH, x, y, _cursorColorKey);
+ if (isMouseVisible())
+ CursorMan.showMouse(true);
+ delete[] cursor;
+
+ // makes sure that the cursor is drawn
+ // we do not use Screen::updateScreen here
+ // so we can be sure that changes to page 0
+ // are NOT updated on the real screen here
+ _system->updateScreen();
+}
+
+void Screen_Eob::loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size) {
+ s->read(_pagePtrs[pageNum], size);
+}
+
+void Screen_Eob::printShadedText(const char *string, int x, int y, int col1, int col2) {
+ printText(string, x - 1, y, 12, col2);
+ printText(string, x, y + 1, 12, 0);
+ printText(string, x - 1, y + 1, 12, 0);
+ printText(string, x, y, col1, 0);
+}
+
+void Screen_Eob::loadEobBitmap(const char *file, int tempPage, int destPage) {
+ loadEobCpsFileToPage(file, 0, tempPage, destPage, -1);
+ _curPage = 2;
+}
+
+void Screen_Eob::loadEobCpsFileToPage(const char *file, const uint8 *ditheringData, int tempPage, int destPage, int copyToPage) {
+ char tmp[13];
+ sprintf(tmp, "%s.CPS", file);
+
+ Common::SeekableReadStream *s = _vm->resource()->createReadStream(tmp);
+ bool loadAlternative = false;
+ if (s) {
+ // This additional check is necessary since some localized versions of EOB II seem to contain invalid (size zero) cps files
+ if (s->size())
+ loadBitmap(tmp, tempPage, destPage, 0);
+ else
+ loadAlternative = true;
+
+ delete s;
+ } else {
+ loadAlternative = true;
+ }
+
+ if (loadAlternative) {
+ tmp[0] = 'X';
+ s = _vm->resource()->createReadStream(tmp);
+ if (!s)
+ error("Screen_Eob::loadEobCpsFileToPage(): CPS file loading failed.");
+ s->seek(768);
+ loadFileDataToPage(s, destPage, 64000);
+ delete s;
+ }
+
+ if (copyToPage == -1) {
+ return;
+ } else if (copyToPage == 0) {
+ copyPage(destPage, 2);
+ copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ copyPage(destPage, copyToPage);
+ }
+}
+
+uint8 *Screen_Eob::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool flag) {
+ uint8 *shp = 0;
+ uint16 shapesize = 0;
+
+ uint8 *srcPage = getPagePtr(_curPage) + y * 320 + (x << 3);
+ uint8 *src = srcPage;
+
+ if (flag) {
+ uint16 h1 = h;
+ while (h1--) {
+ uint8 *lineEnd = src + (w << 3);
+ do {
+ if (!*src++) {
+ shapesize++;
+ uint8 *startZeroPos = src;
+ while (src != lineEnd && *src == 0)
+ src++;
+
+ uint16 numZero = src - startZeroPos + 1;
+ if (numZero >> 8)
+ shapesize += 2;
+ }
+ shapesize++;
+ } while (src != lineEnd);
+
+ srcPage += 320;
+ src = srcPage;
+ }
+
+ shapesize += 4;
+
+ shp = new uint8[shapesize];
+ memset (shp, 0, shapesize);
+ uint8 *dst = shp;
+
+ *dst++ = 0;
+ *dst++ = (h & 0xff);
+ *dst++ = (w & 0xff);
+ *dst++ = (h & 0xff);
+
+ srcPage = getPagePtr(_curPage) + y * 320 + (x << 3);
+ src = srcPage;
+
+ h1 = h;
+ while (h1--) {
+ uint8 *lineEnd = src + (w << 3);
+ do {
+ uint8 val = *src++;
+ if (!val) {
+ *dst++ = val;
+ uint8 *startZeroPos = src;
+ while (src != lineEnd && *src == 0)
+ src++;
+
+ uint16 numZero = src - startZeroPos + 1;
+ if (numZero >> 8) {
+ numZero -= 0xff;
+ *dst++ = 0xff;
+ *dst++ = 0;
+ }
+ val = (numZero & 0xff);
+ }
+ *dst++ = val;
+ } while (src != lineEnd);
+
+ srcPage += 320;
+ src = srcPage;
+ }
+
+ } else {
+ uint8 nib = 0, col = 0;
+ uint8 *colorMap = new uint8[0x100];
+ memset (colorMap, 0xff, 0x100);
+
+ shapesize = h * (w << 2) + 0x14;
+ shp = new uint8[shapesize];
+ memset (shp, 0, shapesize);
+ uint8 *dst = shp;
+
+ *dst++ = 1;
+ *dst++ = (h & 0xff);
+ *dst++ = (w & 0xff);
+ *dst++ = (h & 0xff);
+ memset (dst, 0xff, 0x10);
+
+ uint8 *pal = dst;
+ dst += 0x10;
+
+ srcPage = getPagePtr(_curPage) + y * 320 + (x << 3);
+ src = srcPage;
+ nib = col = 0;
+
+ uint16 h1 = h;
+ while (h1--) {
+ uint16 w1 = w << 3;
+ while (w1--) {
+ uint8 s = *src++;
+ uint8 c = colorMap[s];
+ if (c == 0xff) {
+ if (col < 0x10) {
+ *pal++ = s;
+ c = colorMap[s] = col++;
+ if (!col)
+ c = 0;
+ } else {
+ c = 0;
+ }
+ }
+
+ if(++nib & 1) {
+ *dst = c << 4;
+ } else {
+ *dst++ |= c;
+ }
+ }
+ srcPage += 320;
+ src = srcPage;
+ }
+ delete [] colorMap;
+ }
+
+ return shp;
+}
+
+void Screen_Eob::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...) {
+ uint8 *dst = getPagePtr(pageNum);
+ const uint8 *src = shapeData;
+
+ if (!src)
+ return;
+
+ va_list args;
+ va_start(args, flags);
+ uint8 *ovl = (flags & 2) ? va_arg(args, uint8*) : 0;
+ va_end(args);
+
+ if (sd != -1) {
+ const ScreenDim *dm = getScreenDim(sd);
+ setShapeFrame(dm->sx, dm->sy, dm->sx + dm->w, dm->sy + dm->h);
+ x += (_dsX1 << 3);
+ y += _dsY1;
+ }
+
+ dst += (_dsX1 << 3);
+ int16 dX = x - (_dsX1 << 3);
+ int16 dY = y;
+ int16 dW = _dsX2 - _dsX1;
+ uint8 flag = *src++;
+
+ uint16 dH = *src++;
+ uint16 width = (*src++) << 3;
+ src++;
+
+ int rX = x;
+ int rY = y;
+ int rW = width + 8;
+ int rH = dH;
+
+ uint16 w2 = width;
+ int d = dY - _dsY1;
+
+ int pixelStep = (flags & 1) ? -1 : 1;
+
+ if (flag) {
+ const uint8 *pal = ovl ? ovl : src;
+ src += 16;
+
+ if (d < 0) {
+ d = -d;
+ if (d >= dH)
+ return;
+ src += (d * (width >> 1));
+ d = dY + dH - _dsY1;
+ if (d >=0) {
+ dH = d;
+ dY = _dsY1;
+ d = _dsY2 - dY;
+ }
+ } else {
+ d = _dsY2 - dY;
+ }
+
+ if (d < 1)
+ return;
+
+ if (d < dH)
+ dH = d;
+
+ int16 cnt1 = 0;
+ int16 cnt2 = 0;
+ int16 dXbit1 = dX & 1;
+
+ if (dX < 0) {
+ width += dX;
+ d = -dX;
+ if ((flags & 1))
+ src -= (d >> 1);
+ else
+ src += (d >> 1);
+
+ if (d >= w2)
+ return;
+
+ dX = 0;
+ cnt1++;
+ }
+
+ d = (dW << 3) - dX;
+
+ if (d < 1)
+ return;
+
+ if (d < width) {
+ width = d;
+ cnt2++;
+ }
+
+ dst += (dY * 320 + dX);
+
+ if (pageNum == 0 || pageNum == 1)
+ addDirtyRect(rX, rY, rW, rH);
+
+ int w3 = w2;
+ dY = 320 - width;
+ width >>= 1;
+ w2 >>= 1;
+ if ((flags & 1))
+ src += (w2 - 1);
+
+ int16 w1shr = width;
+
+ if (cnt1 && (dXbit1 & 1)) {
+ w1shr++;
+ w2++;
+ if (!cnt2)
+ dY += 2;
+ }
+
+ if (cnt2 && (dXbit1 & 1))
+ w1shr++;
+
+ int lineSrcStep = (w2 - w1shr);
+ if ((flags & 1))
+ lineSrcStep = w3 - lineSrcStep;
+
+ while (dH--) {
+ int16 hpos = width;
+ uint8 col = 0;
+ uint8 b = 0;
+ uint8 nextloop = 0;
+
+ if (cnt1 && dXbit1) {
+ if (!hpos)
+ return;
+ b = *src;
+ src += pixelStep;
+ nextloop = 2;
+ } else {
+ nextloop = hpos ? 1 : 3;
+ }
+
+ while (nextloop) {
+ switch (nextloop) {
+ case 1:
+ b = *src;
+ src += pixelStep;
+ col = pal[(flags & 1) ? (b & 0x0f) : (b >> 4)];
+ if (col)
+ drawShapeSetPixel(dst, col);
+ dst++;
+
+ case 2:
+ col = pal[(flags & 1) ? (b >> 4) : (b & 0x0f)];
+
+ if (!col) {
+ nextloop = 4;
+ break;
+ }
+
+ drawShapeSetPixel(dst++, col);
+ nextloop = --hpos ? 1 : 3;
+ break;
+
+ case 3:
+ if (cnt2 && dXbit1) {
+ col = pal[(flags & 1) ? (*src & 0x0f) : (*src >> 4)];
+ src += pixelStep;
+ if (col)
+ drawShapeSetPixel(dst, col);
+ dst++;
+ }
+
+ src += lineSrcStep;
+ dst += dY;
+ nextloop = 0;
+ break;
+
+ case 4:
+ dst++;
+ nextloop = --hpos ? 1 : 3;
+ break;
+ }
+ }
+ }
+ } else {
+ uint16 marginLeft = 0;
+ uint16 marginRight = 0;
+
+ if (d < 0) {
+ dH += d;
+ if (dH <= 0)
+ return;
+ d = -d;
+
+ for (int ii = 0; ii < d; ii++) {
+ marginLeft = width;
+ int i = 0;
+ do {
+ for (i = 0; i < marginLeft; i++)
+ if (!*src++)
+ break;
+
+ if (!*(src-1) || i < marginLeft)
+ marginLeft = ++marginLeft - *src++;
+ else
+ marginLeft = 0;
+
+ } while (marginLeft);
+ }
+ dY = _dsY1;
+ }
+
+ d = _dsY2 - dY;
+
+ if (d < 1)
+ return;
+
+ if (d < dH)
+ dH = d;
+
+ marginLeft = 0;
+
+ if (dX < 0) {
+ width += dX;
+ marginLeft = -dX;
+
+ if (marginLeft >= w2)
+ return;
+
+ dX = 0;
+ }
+
+ marginRight = 0;
+ d = (dW << 3) - dX;
+
+ if (d < 1)
+ return;
+
+ if (d < width) {
+ width = d;
+ marginRight = w2 - marginLeft - width;
+ }
+
+ dst += (y * 320 + dX);
+ uint8 * dstL = dst;
+
+ if (pageNum == 0 || pageNum == 1)
+ addDirtyRect(rX, rY, rW, rH);
+
+ while (dH--) {
+ int16 xpos = (int16) marginLeft;
+
+ if (xpos) {
+ do {
+ while (*src && xpos) {
+ src++;
+ xpos--;
+ }
+
+ if (!*src) {
+ uint8 bt = *++src;
+ src++;
+ xpos = xpos - bt;
+ }
+ } while (xpos > 0);
+ }
+
+ dst -= xpos;
+ xpos += width;
+
+ while (xpos > 0) {
+ uint8 c = *src++;
+
+ if (c) {
+ drawShapeSetPixel(dst++, c);
+ xpos--;
+ } else {
+ dst += *src;
+ xpos -= *src++;
+ }
+ }
+ xpos += marginRight;
+
+ if (xpos) {
+ do {
+ while (*src && xpos) {
+ src++;
+ xpos--;
+ }
+
+ if (!*src) {
+ uint8 bt = *++src;
+ src++;
+ xpos = xpos - bt;
+ }
+ } while (xpos > 0);
+ }
+
+ dstL += 320;
+ dst = dstL;
+ }
+ }
+}
+
+void Screen_Eob::drawShapeSetPixel(uint8 * dst, uint8 c) {
+ if (_shapeFadeMode[0]) {
+ if (_shapeFadeMode[1]) {
+ c = *dst;
+ } else {
+ _shapeFadeInternal &= 7;
+ c = *(dst + _shapeFadeInternal++);
+ }
+ }
+
+ if (_shapeFadeMode[1]) {
+ uint8 cnt = _shapeFadeMode[1];
+ while (cnt--)
+ c = _fadeData[_fadeDataIndex + c];
+ }
+
+ *dst = c;
+}
+
+const uint8 *Screen_Eob::scaleShape(const uint8 *shapeData, int steps) {
+ setShapeFadeMode(1, steps ? true : false);
+
+ while (shapeData && steps--)
+ shapeData = scaleShapeStep(shapeData);
+
+ return shapeData;
+}
+
+const uint8 *Screen_Eob::scaleShapeStep(const uint8 *shp) {
+ uint8 *d = _dsTempPage;
+ *d++ = *shp++;
+
+ uint16 h = (*shp++) + 1;
+ d[0] = d[2] = (h << 1) / 3;
+ d++;
+
+ uint16 w = *shp++;
+ uint16 w2 = w << 2;
+ uint16 t = ((w << 1) % 3) ? 1 : 0;
+ *d++ = ((w << 1) / 3) + t;
+
+ shp++;
+ d++;
+
+ int i = 0;
+ while (i < 16) {
+ if (!shp[i]) {
+ i = -i;
+ break;
+ }
+ i++;
+ }
+
+ if (i >= 0)
+ i = 0;
+ else
+ i = -i;
+
+ _dsScaleTmp = (i << 4) | (i & 0x0f);
+ memcpy(d, shp, 16);
+ d += 16;
+ shp += 16;
+
+ _dsDiv = w2 / 3;
+ _dsRem = w2 % 3;
+
+ do {
+ scaleShapeProcessLine(d, shp);
+ if (!--h)
+ break;
+ scaleShapeProcessLine(d, shp);
+ if (!--h)
+ break;
+ shp += w2;
+ } while (--h);
+
+ return (const uint8 *) _dsTempPage;
+}
+
+void Screen_Eob::replaceShapePalette(uint8 *shp, const uint8 *pal) {
+ if (*shp != 1)
+ return;
+ shp += 4;
+ memcpy(shp, pal, 16);
+}
+
+void Screen_Eob::applyShapeOverlay(uint8 *shp, int ovlIndex) {
+ if (*shp != 1)
+ return;
+ shp += 4;
+ uint8 *ovl = getFadeTable(ovlIndex);
+ for (int i = 0; i < 16; i++)
+ shp[i] = ovl[shp[i]];
+}
+
+void Screen_Eob::scaleShapeProcessLine(uint8 *&dst, const uint8 *&src) {
+ for (int i = 0; i < _dsDiv; i++) {
+ *dst++ = *src++;
+ *dst++ = READ_BE_UINT16(src) >> 4;
+ src += 2;
+ }
+
+ if (_dsRem == 1) {
+ *dst++ = *src++;
+ *dst++ = _dsScaleTmp;
+
+ } if (_dsRem == 2) {
+ *dst++ = (src[0] & 0xf0) | (src[1] >> 4);
+ src += 2;
+ *dst++ = _dsScaleTmp;
+ *dst++ = _dsScaleTmp;
+ *dst++ = _dsScaleTmp;
+ }
+}
+
+void Screen_Eob::fadeTextColor(Palette *pal, int color1, int rate) {
+ uint8 *col = pal->getData();
+
+ for (bool loop = true; loop; ) {
+ loop = true;
+ uint32 end = _system->getMillis() + 16;
+
+ loop = false;
+ for (int ii = 0; ii < 3; ii++) {
+ uint8 c = col[color1 * 3 + ii];
+ if (c > rate) {
+ col[color1 * 3 + ii] -= rate;
+ loop = true;
+ } else if (c) {
+ col[color1 * 3 + ii] = 0;
+ loop = true;
+ }
+ }
+
+ if (loop) {
+ setScreenPalette(*pal);
+ updateScreen();
+ uint32 cur = _system->getMillis();
+ if (end > cur)
+ _system->delayMillis(end - cur);
+ }
+ }
+}
+
+bool Screen_Eob::delayedFadePalStep(Palette *fadePal, Palette *destPal, int rate) {
+ bool res = false;
+
+ uint8 *s = fadePal->getData();
+ uint8 *d = destPal->getData();
+
+ for (int i = 0; i < 765; i++) {
+ int fadeVal = *s++;
+ int dstCur = *d;
+ int diff = ABS(fadeVal - dstCur);
+
+ if (diff == 0) {
+ d++;
+ continue;
+ }
+
+ res = true;
+ diff = MIN(diff, rate);
+
+ if (dstCur < fadeVal)
+ *d += diff;
+ else
+ *d -= diff;
+ d++;
+ }
+
+ return res;
+}
+
+void Screen_Eob::createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight) {
+ if (!palData)
+ return;
+
+ uint8 *src = palData + 3 * rootColor;
+ uint8 r = *src++;
+ uint8 g = *src++;
+ uint8 b = *src;
+ uint8 tr, tg, tb;
+ src = palData + 3;
+
+ *dst++ = 0;
+ weight >>= 1;
+
+ for (uint8 i = 1; i; i++) {
+ uint16 tmp = (uint16)((*src - r) * weight) << 1;
+ tr = *src++ - ((tmp >> 8) & 0xff);
+ tmp = (uint16)((*src - g) * weight) << 1;
+ tg = *src++ - ((tmp >> 8) & 0xff);
+ tmp = (uint16)((*src - b) * weight) << 1;
+ tb = *src++ - ((tmp >> 8) & 0xff);
+
+ uint8 * d = palData + 3;
+ uint16 v = 0xffff;
+ uint8 col = rootColor;
+
+ for (uint8 ii = 1; ii; ii++) {
+ int a = *d++ - tr;
+ int t = a * a;
+ a = *d++ - tg;
+ t += (a * a);
+ a = *d++ - tb;
+ t += (a * a);
+
+ if (t <= v && (ii == rootColor || ii != i)) {
+ v = t;
+ col = ii ;
+ }
+ }
+ *dst++ = col;
+ }
+}
+
+OldDOSFont::OldDOSFont() {
+ _data = 0;
+ _width = _height = _numGlyphs = 0;
+ _bitmapOffsets = 0;
+}
+
+bool OldDOSFont::load(Common::SeekableReadStream &file) {
+ unload();
+
+ _data = new uint8[file.size()];
+ assert(_data);
+
+ file.read(_data, file.size());
+ if (file.err())
+ return false;
+
+ if (file.size() - 2 != READ_LE_UINT16(_data))
+ return false;
+
+ _width = _data[0x103];
+ _height = _data[0x102];
+ _numGlyphs = 255;
+
+ _bitmapOffsets = (uint16 *)(_data + 2);
+
+ for (int i = 0; i < _numGlyphs; ++i)
+ _bitmapOffsets[i] = READ_LE_UINT16(&_bitmapOffsets[i]);
+
+ return true;
+}
+
+int OldDOSFont::getCharWidth(uint16 c) const {
+ if (c >= _numGlyphs)
+ return 0;
+ return _width;
+}
+
+void OldDOSFont::drawChar(uint16 c, byte *dst, int pitch) const {
+ static const uint8 renderMaskTable6[] = { 0xFC, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x80, 0x0F, 0xC0, 0x07, 0xE0, 0x03, 0xF0, 0x01, 0xF8 };
+ static const uint8 renderMaskTable8[] = { 0xFF, 0x00, 0x7F, 0x80, 0x3F, 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE };
+
+ if (_width != 8 && _width != 6)
+ error("EOB font rendering not implemented for other font widths than 6 and 8.");
+
+ if (_width == 6) {
+ switch (c) {
+ case 0x81:
+ case 0x9a:
+ c = 0x5d;
+ break;
+ case 0x84:
+ case 0x8e:
+ c = 0x5b;
+ break;
+ case 0x94:
+ case 0x99:
+ c = 0x40;
+ case 0xe1:
+ // TODO: recheck this: no conversion for 'ß' ?
+ break;
+ }
+ } else if (_width == 8){
+ switch (c) {
+ case 0x81:
+ case 0x9a:
+ case 0x5d:
+ c = 0x1d;
+ break;
+ case 0x84:
+ case 0x5b:
+ c = 0x1e;
+ break;
+ case 0x94:
+ case 0x40:
+ c = 0x1f;
+ break;
+ case 0x8e:
+ c = 0x1b;
+ break;
+ case 0x99:
+ c = 0x1c;
+ break;
+ case 0xe1:
+ c = 0x19;
+ break;
+ }
+ }
+
+ const uint8 *src = &_data[_bitmapOffsets[c]];
+
+ int w = (_width - 1) >> 3;
+ pitch -= _width;
+
+ uint8 color1 = _colorMap[1];
+ uint8 color2 = _colorMap[0];
+
+ int cH = _height;
+ while (cH--) {
+ int cW = w;
+ const uint8 *mtbl = _width == 8 ? renderMaskTable8 : renderMaskTable6;
+
+ for (bool runWidthLoop = true; runWidthLoop; ) {
+ uint8 s = *src++;
+ uint8 m = *mtbl++;
+
+ for (uint8 i = 0x80; i; i >>= 1) {
+ if (!(m & i)) {
+ runWidthLoop = false;
+ break;
+ }
+
+ if (s & i) {
+ if (color1)
+ *dst = color1;
+ } else if (color2) {
+ *dst = color2;
+ }
+ dst++;
+ }
+
+ if (cW)
+ cW--;
+ else
+ runWidthLoop = false;
+ }
+
+ dst += pitch;
+ }
+}
+
+void OldDOSFont::unload() {
+ delete[] _data;
+ _data = 0;
+ _width = _height = _numGlyphs = 0;
+ _bitmapOffsets = 0;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/screen_eob.h b/engines/kyra/screen_eob.h
new file mode 100644
index 0000000000..038ba85791
--- /dev/null
+++ b/engines/kyra/screen_eob.h
@@ -0,0 +1,105 @@
+/* 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.
+ *
+ */
+
+#ifndef KYRA_SCREEN_EOB_H
+#define KYRA_SCREEN_EOB_H
+
+#ifdef ENABLE_EOB
+
+#include "kyra/screen.h"
+
+namespace Kyra {
+
+class EobCoreEngine;
+class Screen_Eob : public Screen{
+public:
+ Screen_Eob(EobCoreEngine *vm, OSystem *system);
+ virtual ~Screen_Eob();
+
+ bool init();
+
+ void setScreenDim(int dim);
+ const ScreenDim *getScreenDim(int dim);
+ int curDimIndex() const { return _curDimIndex; }
+ void modifyScreenDim(int dim, int x, int y, int w, int h);
+ int screenDimTableCount() const { return _screenDimTableCount; }
+
+ void setClearScreenDim(int dim);
+ void clearCurDim();
+
+ void setMouseCursor(int x, int y, const byte *shape);
+
+ void loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size);
+
+ void printShadedText(const char *string, int x, int y, int col1, int col2);
+ void loadEobCpsFileToPage(const char *file, const uint8 *ditheringData, int tempPage, int destPage, int copyToPage);
+ void loadEobBitmap(const char *file, int tempPage, int destPage);
+
+ uint8 *encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool flag = false);
+ void drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd = -1, int flags = 0, ...);
+ const uint8 *scaleShape(const uint8 *shapeData, int blockDistance);
+ const uint8 *scaleShapeStep(const uint8 *shp);
+ void replaceShapePalette(uint8 *shp, const uint8 *pal);
+ void applyShapeOverlay(uint8 *shp, int ovlIndex);
+
+ void setShapeFrame(int x1, int y1, int x2, int y2) { _dsX1 = x1; _dsY1 = y1; _dsX2 = x2; _dsY2 = y2; }
+ void setShapeFadeMode (uint8 i, bool b) { if (!i || i == 1) _shapeFadeMode[i] = b; }
+
+ void fadeTextColor(Palette *pal, int color1, int fadeTextColor);
+ bool delayedFadePalStep(Palette *fadePal, Palette *destPal, int rate);
+
+ void setTextColorMap(const uint8 *cmap) {}
+ int getRectSize(int w, int h) { return w * h; }
+
+ void setFadeTableIndex(int index) { _fadeDataIndex = (CLIP(index, 0, 7) << 8); }
+ void createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight);
+ uint8 *getFadeTable(int index) { return (index >= 0 && index < 5) ? &_fadeData[index << 8] : 0; }
+
+protected:
+ int16 _dsX1, _dsX2, _dsY1, _dsY2;
+ bool _shapeFadeMode[2];
+ uint16 _shapeFadeInternal;
+ uint8 *_fadeData;
+ int _fadeDataIndex;
+
+ uint8 *_dsTempPage;
+
+ static const ScreenDim _screenDimTable[];
+ static const int _screenDimTableCount;
+
+ ScreenDim **_customDimTable;
+ int _curDimIndex;
+
+private:
+ void drawShapeSetPixel(uint8 *dst, uint8 c);
+ void scaleShapeProcessLine(uint8 *&dst, const uint8 *&src);
+
+ int _dsDiv, _dsRem, _dsScaleTmp;
+};
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
+
+#endif
+
+
diff --git a/engines/kyra/script.cpp b/engines/kyra/script.cpp
index 303cbb45aa..1981341063 100644
--- a/engines/kyra/script.cpp
+++ b/engines/kyra/script.cpp
@@ -95,7 +95,7 @@ bool EMCInterpreter::callback(Common::IFFChunk &chunk) {
return false;
}
-bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Common::Array<const Opcode *> *opcodes) {
+bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Common::Array<const Opcode*> *opcodes) {
Common::SeekableReadStream *stream = _vm->resource()->createReadStream(filename);
if (!stream) {
error("Couldn't open script file '%s'", filename);
diff --git a/engines/kyra/script.h b/engines/kyra/script.h
index 5bd75f7b80..858b2b11b8 100644
--- a/engines/kyra/script.h
+++ b/engines/kyra/script.h
@@ -41,7 +41,7 @@ struct EMCData {
uint16 *ordr;
uint16 dataSize;
- const Common::Array<const Opcode *> *sysFuncs;
+ const Common::Array<const Opcode*> *sysFuncs;
};
struct EMCState {
@@ -92,7 +92,7 @@ class EMCInterpreter {
public:
EMCInterpreter(KyraEngine_v1 *vm);
- bool load(const char *filename, EMCData *data, const Common::Array<const Opcode *> *opcodes);
+ bool load(const char *filename, EMCData *data, const Common::Array<const Opcode*> *opcodes);
void unload(EMCData *data);
void init(EMCState *scriptState, const EMCData *data);
diff --git a/engines/kyra/script_eob.cpp b/engines/kyra/script_eob.cpp
new file mode 100644
index 0000000000..40656c575a
--- /dev/null
+++ b/engines/kyra/script_eob.cpp
@@ -0,0 +1,1528 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/eobcommon.h"
+#include "kyra/screen_eob.h"
+#include "kyra/script_eob.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void EobCoreEngine::runLevelScript(int block, int flags) {
+ _inf->run(block, flags);
+}
+
+void EobCoreEngine::setScriptFlag(int flag) {
+ _inf->setFlag(flag);
+}
+
+bool EobCoreEngine::checkScriptFlag(int flag) {
+ return _inf->checkFlag(0x8000);
+}
+
+const uint8 *EobCoreEngine::initScriptTimers(const uint8 *pos) {
+ _scriptTimersCount = 0;
+
+ while (((int16)READ_LE_UINT16(pos)) != -1) {
+ _scriptTimers[_scriptTimersCount].func = READ_LE_UINT16(pos);
+ pos += 2;
+ uint16 ticks = (int16)READ_LE_UINT16(pos) * 18;
+ _scriptTimers[_scriptTimersCount].ticks = ticks;
+ pos += 2;
+ _scriptTimers[_scriptTimersCount++].next = _system->getMillis() + ticks * _tickLength;
+ }
+
+ return pos;
+}
+
+void EobCoreEngine::updateScriptTimers() {
+ if ((_scriptTimersMode & 1) && _stepsUntilScriptCall && _stepCounter > _stepsUntilScriptCall) {
+ _inf->run(0, 0x20);
+ _stepCounter = 0;
+ }
+
+ if (_scriptTimersMode & 2) {
+ for (int i = 0; i < _scriptTimersCount; i++) {
+ if (_scriptTimers[i].next < _system->getMillis()) {
+ _inf->run(_scriptTimers[i].func, _flags.gameID == GI_EOB1 ? 0x20 : 0x80);
+ _scriptTimers[i].next = _system->getMillis() + _scriptTimers[i].ticks * _tickLength;
+ _sceneUpdateRequired = true;
+ }
+ }
+ }
+}
+
+EobInfProcessor::EobInfProcessor(EobCoreEngine *engine, Screen_Eob *screen) : _vm(engine), _screen(screen),
+ _commandMin(engine->game() == GI_EOB1 ? -27 : -31) {
+
+#define Opcode(x) _opcodes.push_back(new InfProc(this, &EobInfProcessor::x))
+#define OpcodeAlt(x, y) if (_vm->game() == GI_EOB1) Opcode(x); else Opcode(y);
+ Opcode(oeob_setWallType);
+ Opcode(oeob_toggleWallState);
+ Opcode(oeob_openDoor);
+ Opcode(oeob_closeDoor);
+ Opcode(oeob_replaceMonster);
+ Opcode(oeob_movePartyOrObject);
+ Opcode(oeob_moveInventoryItemToBlock);
+ OpcodeAlt(oeob_printMessage_v1, oeob_printMessage_v2);
+ Opcode(oeob_setFlags);
+ Opcode(oeob_playSoundEffect);
+ Opcode(oeob_removeFlags);
+ Opcode(oeob_modifyCharacterHitPoints);
+ Opcode(oeob_calcAndInflictCharacterDamage);
+ Opcode(oeob_jump);
+ Opcode(oeob_end);
+ Opcode(oeob_popPosAndReturn);
+ Opcode(oeob_pushPosAndJump);
+ OpcodeAlt(oeob_eval_v1, oeob_eval_v2);
+ Opcode(oeob_deleteItem);
+ Opcode(oeob_loadNewLevelOrMonsters);
+ Opcode(oeob_increasePartyExperience);
+ OpcodeAlt(oeob_createItem_v1, oeob_createItem_v2);
+ Opcode(oeob_launchObject);
+ Opcode(oeob_changeDirection);
+ Opcode(oeob_identifyItems);
+ Opcode(oeob_sequence);
+ Opcode(oeob_delay);
+ Opcode(oeob_drawScene);
+ Opcode(oeob_dialogue);
+ Opcode(oeob_specialEvent);
+#undef Opcode
+#undef OpcodeAlt
+
+ _scriptData = 0;
+
+ _abortScript = 0;
+ _abortAfterSubroutine = 0;
+ _dlgResult = 0;
+ _script2 = 0;
+
+ _lastScriptFunc = 0;
+ _lastScriptSub = 0;
+
+ _scriptPosStack = new int8*[10];
+ memset(_scriptPosStack, 0, 10 * sizeof(int8*));
+ _scriptPosStackIndex = 0;
+
+ _flagTable = new uint32[18];
+ memset(_flagTable, 0, 18 * sizeof(uint32));
+
+ _stack = new int16[30];
+ memset(_stack, 0, 30 * sizeof(int16));
+ _stackIndex = 0;
+
+ memset(_scriptPosStack, 0, sizeof(_scriptPosStack));
+ _scriptPosStackIndex = 0;
+
+ _activeCharacter = -1;
+}
+
+EobInfProcessor::~EobInfProcessor() {
+ delete[] _scriptPosStack;
+ delete[] _flagTable;
+ delete[] _stack;
+ delete[] _scriptData;
+ for (Common::Array<const InfProc*>::const_iterator a = _opcodes.begin(); a != _opcodes.end(); ++a)
+ delete *a;
+ _opcodes.clear();
+}
+
+void EobInfProcessor::loadData(const uint8 *data, uint32 dataSize) {
+ delete[] _scriptData;
+ _scriptData = new int8[dataSize];
+ memcpy(_scriptData, data, dataSize);
+}
+
+void EobInfProcessor::run(int func, int sub) {
+ int o = _vm->_levelBlockProperties[func].assignedObjects;
+ if (!o)
+ return;
+
+ uint16 f = _vm->_levelBlockProperties[func].flags;
+
+ uint16 subFlags = ((f & 0xfff8) >> 3) | 0xe0;
+ if (!(sub & subFlags))
+ return;
+
+ _abortScript = 0;
+ _abortAfterSubroutine = 0;
+ _dlgResult = 0;
+ _activeCharacter = -1;
+
+ _lastScriptFunc = func;
+ _lastScriptSub = sub;
+
+ _vm->resetSkipFlag(true);
+
+ int8 *pos = (int8*)(_scriptData + o);
+
+ do {
+ int8 cmd = *pos++;
+ if (cmd <= _commandMin || cmd >= 0)
+ continue;
+ pos += (*_opcodes[-(cmd + 1)])(pos);
+ } while (!_abortScript && !_abortAfterSubroutine);
+}
+
+void EobInfProcessor::loadState(Common::SeekableSubReadStreamEndian &in) {
+ _script2 = in.readByte();
+ for (int i = 0; i < 18; i++)
+ _flagTable[i] = in.readUint16BE();
+}
+
+void EobInfProcessor::saveState(Common::OutSaveFile *out) {
+ out->writeByte(_script2);
+ for (int i = 0; i < 18; i++)
+ out->writeUint16BE(_flagTable[i]);
+}
+
+const char *EobInfProcessor::getString(uint16 index) {
+ if (index == 0xffff)
+ return 0;
+
+ int8 *res = _scriptData + READ_LE_UINT16(_scriptData);
+
+ while (index) {
+ if(*res++)
+ continue;
+ index--;
+ }
+
+ return (const char*)res;
+}
+
+int EobInfProcessor::oeob_setWallType(int8 *data) {
+ int8 *pos = data;
+
+ uint16 block = 0;
+ int8 dir = 0;
+
+ switch (*pos++) {
+ case -23:
+ block = READ_LE_UINT16(pos);
+ pos += 2;
+ dir = *pos++;
+ _vm->_levelBlockProperties[block].walls[dir] = *pos++;
+ _vm->checkSceneUpdateNeed(block);
+ break;
+
+ case -19:
+ _vm->_currentDirection = *pos++;
+ break;
+
+ case -9:
+ block = READ_LE_UINT16(pos);
+ pos += 2;
+ dir = *pos++;
+ memset(_vm->_levelBlockProperties[block].walls, dir, 4 * sizeof(uint8));
+ _vm->checkSceneUpdateNeed(block);
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_toggleWallState(int8 *data) {
+ int8 *pos = data;
+
+ uint16 block = 0;
+ int8 dir = 0;
+ uint8 a = 0;
+ uint8 b = 0;
+
+ switch (*pos++) {
+ case -23:
+ block = READ_LE_UINT16(pos);
+ pos += 2;
+ dir = *pos++;
+ a = (uint8)*pos++;
+ b = (uint8)*pos++;
+ a = (_vm->_levelBlockProperties[block].walls[dir] == a) ? b : a;
+ _vm->_levelBlockProperties[block].walls[dir] = a;
+ _vm->checkSceneUpdateNeed(block);
+ break;
+
+ case -22:
+ _vm->processDoorSwitch(READ_LE_UINT16(pos), 0);
+ pos += 2;
+ break;
+
+ case -9:
+ block = READ_LE_UINT16(pos);
+ pos += 2;
+ a = (uint8)*pos++;
+ b = (uint8)*pos++;
+ a = (_vm->_levelBlockProperties[block].walls[dir] == a) ? b : a;
+ memset(_vm->_levelBlockProperties[block].walls, a, 4 * sizeof(uint8));
+ _vm->checkSceneUpdateNeed(block);
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_openDoor(int8 *data) {
+ int8 *pos = data;
+ _vm->openDoor(READ_LE_UINT16(pos));
+ pos += 2;
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_closeDoor(int8 *data) {
+ int8 *pos = data;
+ _vm->closeDoor(READ_LE_UINT16(pos));
+ pos += 2;
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_replaceMonster(int8 *data) {
+ int8 *pos = data;
+ _vm->replaceMonster(pos[1], READ_LE_UINT16(pos + 2), pos[4], pos[5], pos[6], pos[7], pos[8], pos[9], READ_LE_UINT16(pos + 10), READ_LE_UINT16(pos + 12));
+ pos += 14;
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_movePartyOrObject(int8 *data) {
+ int8 *pos = data;
+
+ int8 a = *pos++;
+ uint16 b = 0xffff;
+ uint16 c = 0;
+ uint16 d = 0;
+
+ if (_vm->game() == GI_EOB2 && a == -31) {
+ b = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ if (_vm->game() == GI_EOB1) {
+ if (a != -15) {
+ c = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+ d = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ if (_vm->game() == GI_EOB2 && a != -31 && a != -11) {
+ c = READ_LE_UINT16(pos);
+ pos += 2;
+ d = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ if (a == -13) {
+ // move monster from block c to block d
+ for (int i = 0; i < 30; i++) {
+ if (_vm->_monsters[i].block != c)
+ continue;
+ _vm->placeMonster(&_vm->_monsters[i], d, _vm->_monsters[i].pos);
+ }
+
+ } else if (a == -24) {
+ // move party to block d
+ int ba = _dlgResult;
+ int bb = _lastScriptFunc;
+ int bc = _lastScriptSub;
+ int bd = _abortScript;
+ int be = _activeCharacter;
+ int bf = _scriptPosStackIndex;
+
+ _vm->moveParty(d);
+
+ _dlgResult = ba;
+ _lastScriptFunc = bb;
+ _lastScriptSub = bc;
+ _abortScript = bd;
+ _activeCharacter = be;
+ if (!_abortAfterSubroutine)
+ _scriptPosStackIndex = bf;
+ _vm->_sceneDefaultUpdate = 0;
+
+ } else if ((a == -31 && _vm->game() == GI_EOB2) || a == -11) {
+ // move item
+ int8 e = _vm->_currentLevel;
+ int8 f = _vm->_currentLevel;
+
+ if (_vm->game() == GI_EOB2) {
+ e = (*pos++ == -21) ? _vm->_currentLevel : *pos++;
+ c = READ_LE_UINT16(pos);
+ pos += 2;
+ f = (*pos++ == -21) ? _vm->_currentLevel : *pos++;
+ d = READ_LE_UINT16(pos);
+ pos += 2;
+ }
+
+ if (e == _vm->_currentLevel) {
+ int i = _vm->countQueuedItems(_vm->_levelBlockProperties[c].drawObjects, -1, (int16)b, 0, 1);
+ while (i) {
+ int p = _vm->_items[i].pos;
+ _vm->getQueuedItem((Item*)&_vm->_levelBlockProperties[c].drawObjects, 0, i);
+ if (_vm->_currentLevel == f) {
+ _vm->setItemPosition((Item*)&_vm->_levelBlockProperties[d].drawObjects, d, i, p);
+ } else {
+ _vm->_items[i].level = f;
+ _vm->_items[i].block = d;
+ if (p < 8)
+ _vm->_items[i].pos = p & 3;
+ }
+ i = _vm->countQueuedItems(_vm->_levelBlockProperties[c].drawObjects, -1, (int16)b, 0, 1);
+ }
+
+ for (i = 0; i < 10; i++) {
+ if (_vm->_flyingObjects[i].enable != 1 || _vm->_flyingObjects[i].curBlock != c)
+ continue;
+ if (f == _vm->_currentLevel || _vm->game() == GI_EOB1)
+ _vm->_flyingObjects[i].curBlock = d;
+ else
+ _vm->_flyingObjects[i].enable = 0;
+ }
+
+ } else {
+ for (int i = 0; i < 600; i++) {
+ if (_vm->_items[i].level != e || _vm->_items[i].block != c)
+ continue;
+ _vm->_items[i].level = f;
+ _vm->_items[i].block = d;
+ }
+ }
+ }
+
+ _vm->_sceneUpdateRequired = true;
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_moveInventoryItemToBlock(int8 *data) {
+ int8 *pos = data;
+ int8 c = *pos++;
+ uint16 block = READ_LE_UINT16(pos);
+ pos += 2;
+ int8 p = *pos++;
+
+ if (c == -1)
+ c = _vm->rollDice(1, 6, -1);
+
+ while (!(_vm->_characters[c].flags & 1)) {
+ if (++c == 5)
+ c = 0;
+ }
+
+ if (_vm->_currentControlMode && (_vm->_updateCharNum == c))
+ return pos - data;
+
+ int slot = _vm->rollDice(1, 27, 0);
+ int itm = 0;
+ int i = 0;
+
+ for (; i < 27; i++) {
+ if ((!_vm->_currentControlMode && slot > 1) || slot == 16)
+ continue;
+
+ itm = _vm->_characters[c].inventory[slot];
+
+ if (!itm)
+ continue;
+
+ if (_vm->_dscItemShapeMap[_vm->_items[itm].icon] >= 15)
+ break;
+
+ if (++slot == 27)
+ slot = 0;
+ }
+
+ if (i < 27 && itm) {
+ _vm->_characters[c].inventory[slot] = 0;
+ _vm->setItemPosition((Item*)&_vm->_levelBlockProperties[block].drawObjects, block, itm, p);
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_printMessage_v1(int8 *data) {
+ static const char ColorConfig[] = { 6, 33, 2, 33, 0 };
+ char col[5];
+ int8 *pos = data;
+
+ strcpy(col, ColorConfig);
+ const char *str = (const char*) pos;
+ pos += (strlen(str) + 1);
+
+ col[1] = *pos++;
+ col[3] = *pos++;
+ _vm->txt()->printMessage(col);
+ _vm->txt()->printMessage(str);
+
+ col[1] = _screen->_curDim->unk8;
+ col[3] = _screen->_curDim->unkA;
+ _vm->txt()->printMessage(col);
+ _vm->txt()->printMessage("\r");
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_printMessage_v2(int8 *data) {
+ int8 *pos = data;
+ uint16 str = READ_LE_UINT16(pos);
+ pos += 2;
+ uint8 col = (uint8)*pos;
+ pos += 2;
+
+ int c = 0;
+ if (_activeCharacter == -1) {
+ c = _vm->rollDice(1, 6, -1);
+ while (!_vm->testCharacter(c, 3))
+ c = (c + 1) % 6;
+ } else {
+ c = _activeCharacter;
+ }
+
+ _vm->txt()->printMessage(getString(str), col, _vm->_characters[c].name);
+ _vm->txt()->printMessage("\r");
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_setFlags(int8 *data) {
+ int8 *pos = data;
+ int8 b = 0;
+
+ switch (*pos++) {
+ case -47:
+ _script2 = 0;
+ break;
+
+ case -28:
+ _dlgResult = 1;
+ break;
+
+ case -17:
+ _flagTable[_vm->_currentLevel] |= (1 << (*pos++));
+ break;
+
+ case -16:
+ _flagTable[17] |= (1 << (*pos++));
+ break;
+
+ case -13:
+ b = *pos++;
+ _vm->_monsters[b].flags |= (1 << (*pos++));
+ _vm->_monsters[b].mode = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_playSoundEffect(int8 *data) {
+ int8 *pos = data;
+ uint16 block = READ_LE_UINT16(pos + 1);
+
+ if (block) {
+ _vm->snd_processEnvironmentalSoundEffect(pos[0], block);
+ } else {
+ _vm->snd_playSoundEffect(pos[0]);
+ }
+
+ pos += 3;
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_removeFlags(int8 *data) {
+ int8 *pos = data;
+ int8 a = *pos++;
+ int8 b = *pos++;
+
+ switch (a) {
+ case -47:
+ _script2 = 1;
+ break;
+
+ case -28:
+ _dlgResult = 0;
+ break;
+
+ case -17:
+ _flagTable[_vm->_currentLevel] &= ~(1 << b);
+ break;
+
+ case -16:
+ _flagTable[17] &= ~(1 << b);
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_modifyCharacterHitPoints(int8 *data) {
+ int8 *pos = data;
+ int8 c = *pos++;
+ int8 p = *pos++;
+
+ if (c == -1) {
+ for (c = 0; c < 6; c++)
+ _vm->modifyCharacterHitpoints(c, p);
+ } else {
+ _vm->modifyCharacterHitpoints(c, p);
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_calcAndInflictCharacterDamage(int8 *data) {
+ int8 *pos = data;
+ int charIndex = *pos++;
+ int times = *pos++;
+ int itemOrPips = *pos++;
+ int useStrModifierOrBase = *pos++;
+
+ int flg = (charIndex == -1) ? 4 : 0;
+ int a = 5;
+ int damageType = 1;
+
+ if (_vm->game() == GI_EOB2) {
+ flg = *pos++;
+ a = *pos++;
+ damageType = *pos++;
+ } else if (!itemOrPips) {
+ useStrModifierOrBase = times;
+ times = 0;
+ }
+
+ if (charIndex == -1) {
+ for (int i = 0; i < 6; i++)
+ _vm->calcAndInflictCharacterDamage(i, times, itemOrPips, useStrModifierOrBase, flg, a, damageType);
+ } else {
+ _vm->calcAndInflictCharacterDamage(charIndex, times, itemOrPips, useStrModifierOrBase, flg, a, damageType);
+ }
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_jump(int8 *data) {
+ int8 *pos = data;
+ pos = _scriptData + READ_LE_UINT16(pos);
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_end(int8 *data) {
+ _abortScript = 1;
+ _scriptPosStackIndex = 0;
+ return 0;
+}
+
+int EobInfProcessor::oeob_popPosAndReturn(int8 *data) {
+ int8 *pos = data;
+
+ if (_scriptPosStackIndex)
+ pos = _scriptPosStack[--_scriptPosStackIndex];
+ else
+ _abortScript = 1;
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_pushPosAndJump(int8 *data) {
+ int8 *pos = data;
+ uint16 offs = READ_LE_UINT16(pos);
+ pos += 2;
+
+ if (_scriptPosStackIndex < 10) {
+ _scriptPosStack[_scriptPosStackIndex++] = pos;
+ pos = _scriptData + offs;
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_eval_v1(int8 *data) {
+ int8 *pos = data;
+ int8 cmd = *pos++;
+
+ int a = 0;
+ int b = 0;
+ int i = 0;
+ EobItem *itm = &_vm->_items[_vm->_itemInHand];
+ Common::String tempString1;
+ Common::String tempString2;
+
+ while (cmd != -18) {
+ switch (cmd + 38) {
+ case 0:
+ a = 0;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if (_vm->_characters[i].effectFlags & 4)
+ continue;
+ a = 1;
+ break;
+ }
+ _stack[_stackIndex++] = a;
+ break;
+
+ case 1:
+ _stack[_stackIndex++] = _vm->rollDice(pos[0], pos[1], pos[2]);
+ pos += 3;
+ break;
+
+ case 2:
+ cmd = *pos++;
+ b = 0;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if (_vm->_classModifierFlags[_vm->_characters[i].cClass] & cmd) {
+ b = 1;
+ break;
+ }
+ }
+ _stack[_stackIndex++] = b;
+ break;
+
+ case 3:
+ cmd = *pos++;
+ b = 0;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if ((_vm->_characters[a].raceSex >> 1) == cmd) {
+ b = 1;
+ break;
+ }
+ }
+ _stack[_stackIndex++] = b;
+ break;
+
+ case 6:
+ _stack[_stackIndex++] = _lastScriptSub;
+ break;
+
+ case 13:
+ itm = &_vm->_items[_vm->_itemInHand];
+ switch (*pos++) {
+ case -31:
+ _stack[_stackIndex++] = itm->type;
+ break;
+
+ case -11:
+ _stack[_stackIndex++] = _vm->_itemInHand;
+ break;
+
+ default:
+ _stack[_stackIndex++] = itm->value;
+ break;
+ }
+ break;
+
+ case 15:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos + 1)].walls[pos[0]];
+ pos += 3;
+ break;
+
+ case 19:
+ _stack[_stackIndex++] = _vm->_currentDirection;
+ break;
+
+ case 21:
+ _stack[_stackIndex++] = (_flagTable[_vm->_currentLevel] & (1 << (*pos++))) ? 1 : 0;
+ break;
+
+ case 22:
+ _stack[_stackIndex++] = (_flagTable[17] & (1 << (*pos++))) ? 1 : 0;
+ break;
+
+ case 23:
+ _stack[_stackIndex++] = (_vm->_currentBlock == READ_LE_UINT16(pos)) ? 1 : 0;
+ pos += 2;
+ break;
+
+ case 24:
+ a = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ b = READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[b].drawObjects, a, -1, 0, 1);
+ break;
+
+ case 25:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].flags ? 1 : 0;
+ pos += 2;
+ break;
+
+ case 27:
+ b = *pos++;
+ i = READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[i].drawObjects, -1, b, 1, 1);
+ break;
+
+ case 29:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].walls[0];
+ pos += 2;
+ break;
+
+ case 30:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a || b) ? 1 : 0;
+ break;
+
+ case 31:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a && b) ? 1 : 0;
+ break;
+
+ case 32:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a <= b) ? 1 : 0;
+ break;
+
+ case 33:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a < b) ? 1 : 0;
+ break;
+
+ case 34:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a >= b) ? 1 : 0;
+ break;
+
+ case 35:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a > b) ? 1 : 0;
+ break;
+
+ case 36:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a != b) ? 1 : 0;
+ break;
+
+ case 37:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a == b) ? 1 : 0;
+ break;
+
+ default:
+ a = cmd;
+ if (a >= 0 && a < 128)
+ _stack[_stackIndex++] = a;
+ break;
+ }
+ cmd = *pos++;
+ }
+
+ cmd = _stack[--_stackIndex];
+ if (cmd)
+ pos += 2;
+ else
+ pos = _scriptData + READ_LE_UINT16(pos);
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_eval_v2(int8 *data) {
+ int8 *pos = data;
+ int8 cmd = *pos++;
+
+ int a = 0;
+ int b = 0;
+ int i = 0;
+ EobItem *itm = (_vm->_itemInHand != -1) ? &_vm->_items[_vm->_itemInHand] : 0;
+ Common::String tempString1;
+ Common::String tempString2;
+
+ while (cmd != -18) {
+ switch (cmd + 50) {
+ case 0:
+ a = 0;
+ b = *pos++;
+
+ for (i = 0; i < 6; i++) {
+ if (!_vm->testCharacter(i, 5))
+ continue;
+
+ if (_vm->_characters[i].portrait != b) {
+ a = 1;
+ _activeCharacter = i;
+ break;
+ }
+ }
+
+ _stack[_stackIndex++] = a;
+ break;
+
+ case 4:
+ _stack[_stackIndex++] = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ break;
+
+ case 9:
+ switch (*pos++) {
+ case -36:
+ _stack[_stackIndex++] = _vm->_itemTypes[_vm->_items[_vm->_lastUsedItem].type].extraProperties & 0x7f;
+ break;
+ case -31:
+ _stack[_stackIndex++] = _vm->_items[_vm->_lastUsedItem].type;
+ break;
+ case -11:
+ _stack[_stackIndex++] = _vm->_lastUsedItem;
+ break;
+ case -10:
+ _stack[_stackIndex++] = _vm->_items[_vm->_lastUsedItem].value;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case 12:
+ a = 0;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if (_vm->_characters[i].effectFlags & 0x40)
+ continue;
+ a = 1;
+ break;
+ }
+ _stack[_stackIndex++] = a;
+ break;
+
+ case 13:
+ _stack[_stackIndex++] = _vm->rollDice(pos[0], pos[1], pos[2]);
+ pos += 3;
+ break;
+
+ case 14:
+ cmd = *pos++;
+ a = _vm->rollDice(1, 6);
+ b = 0;
+ for (i = 0; i < 6 && b == 0; i++) {
+ if (++a > 5)
+ a = 0;
+ if (_vm->testCharacter(a, 5)) {
+ if (_vm->_classModifierFlags[_vm->_characters[a].cClass] & cmd) {
+ _activeCharacter = a;
+ b = 1;
+ }
+ }
+ }
+ _stack[_stackIndex++] = b;
+ break;
+
+ case 15:
+ cmd = *pos++;
+ a = _vm->rollDice(1, 6);
+ b = 0;
+ for (i = 0; i < 6; i++) {
+ if (++a > 5)
+ a = 0;
+ if (_vm->testCharacter(a, 5)) {
+ if ((_vm->_characters[a].raceSex >> 1) == cmd) {
+ _activeCharacter = a;
+ b = 1;
+ }
+ }
+ }
+ _stack[_stackIndex++] = b;
+ break;
+
+ case 17:
+ _stack[_stackIndex++] = _vm->_activeSpell;
+ break;
+
+ case 18:
+ _stack[_stackIndex++] = _lastScriptSub;
+ break;
+
+ case 22:
+ _stack[_stackIndex++] = _dlgResult;
+ break;
+
+ case 25:
+ itm = &_vm->_items[_vm->_itemInHand];
+
+ switch (*pos++) {
+ case -49:
+ a = *pos++;
+ tempString1 = _vm->_itemNames[itm->nameId];
+ tempString1.toUppercase();
+ tempString2 = (const char*)pos;
+ tempString2.toUppercase();
+ pos += a;
+ _stack[_stackIndex++] = tempString1.contains(tempString2) ? 1 : 0;
+ break;
+
+ case -48:
+ a = *pos++;
+ tempString1 = _vm->_itemNames[itm->nameUnid];
+ tempString1.toUppercase();
+ tempString2 = (const char*)pos;
+ tempString2.toUppercase();
+ pos += a;
+ _stack[_stackIndex++] = tempString1.contains(tempString2) ? 1 : 0;
+ break;
+
+ case -31:
+ _stack[_stackIndex++] = itm->type;
+ break;
+
+ case -11:
+ _stack[_stackIndex++] = _vm->_itemInHand;
+ break;
+
+ case -10:
+ _stack[_stackIndex++] = itm->value;
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case 26:
+ a = 0;
+ for (i = 0; i < 6; i++) {
+ if (_vm->testCharacter(i, 0x0f))
+ a++;
+ }
+ _stack[_stackIndex++] = a;
+ break;
+
+ case 27:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos + 1)].walls[pos[0]];
+ pos += 3;
+ break;
+
+ case 31:
+ _stack[_stackIndex++] = _vm->_currentDirection;
+ break;
+
+ case 33:
+ _stack[_stackIndex++] = (_flagTable[_vm->_currentLevel] & (1 << (*pos++))) ? 1 : 0;
+ break;
+
+ case 34:
+ _stack[_stackIndex++] = (_flagTable[17] & (1 << (*pos++))) ? 1 : 0;
+ break;
+
+ case 35:
+ if (*pos++ == -11) {
+ a = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ b = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countCharactersWithSpecificItems(a, b);
+ } else {
+ _stack[_stackIndex++] = (_vm->_currentBlock == READ_LE_UINT16(pos)) ? 1 : 0;
+ pos += 2;
+ }
+ break;
+
+ case 36:
+ a = (int16)READ_LE_UINT16(pos);
+ pos += 2;
+ b = READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[b].drawObjects, a, -1, 0, 0);
+ break;
+
+ case 37:
+ if (*pos++ == -1) {
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].flags & 7;
+ pos += 2;
+ } else {
+ do {
+ a += _vm->countSpecificMonsters(*pos++);
+ } while (*pos != -1);
+ pos++;
+ _stack[_stackIndex++] = a;
+ }
+ break;
+
+ case 39:
+ a = *pos++;
+ b = *pos++;
+ i = READ_LE_UINT16(pos);
+ pos += 2;
+ _stack[_stackIndex++] = _vm->countQueuedItems(_vm->_levelBlockProperties[i].drawObjects, -1, b, 1, a);
+ break;
+
+ case 41:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].walls[0];
+ pos += 2;
+ break;
+
+ case 42:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a || b) ? 1 : 0;
+ break;
+
+ case 43:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a && b) ? 1 : 0;
+ break;
+
+ case 44:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a <= b) ? 1 : 0;
+ break;
+
+ case 45:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a < b) ? 1 : 0;
+ break;
+
+ case 46:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a >= b) ? 1 : 0;
+ break;
+
+ case 47:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a > b) ? 1 : 0;
+ break;
+
+ case 48:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a != b) ? 1 : 0;
+ break;
+
+ case 49:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a == b) ? 1 : 0;
+ break;
+
+ default:
+ break;
+ }
+ cmd = *pos++;
+ }
+
+ cmd = _stack[--_stackIndex];
+ if (cmd)
+ pos += 2;
+ else
+ pos = _scriptData + READ_LE_UINT16(pos);
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_deleteItem(int8 *data) {
+ int8 *pos = data;
+ int8 c = *pos++;
+ if (c == -1) {
+ _vm->deleteInventoryItem(0, -1);
+ } else {
+ _vm->deleteBlockItem(READ_LE_UINT16(pos), (c == -2) ? -1 : c);
+ pos += 2;
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_loadNewLevelOrMonsters(int8 *data) {
+ int8 *pos = data;
+ _vm->gui_updateControls();
+
+ int8 cmd = *pos++;
+ int8 index = *pos++;
+ int res = 0;
+
+ if (cmd == -27 || _vm->game() == GI_EOB1) {
+ cmd = _vm->game() == GI_EOB2 ? *pos++ : 0;
+ _vm->_currentBlock = READ_LE_UINT16(pos);
+ pos += 2;
+ uint8 dir = (uint8)*pos++;
+
+ if (dir != 0xff)
+ _vm->_currentDirection = dir;
+
+ for (int i = 0; i < 30; i++)
+ _vm->_monsters[i].curAttackFrame = 0;
+
+ for (int i = 0; i < 10; i++) {
+ EobFlyingObject *fo = &_vm->_flyingObjects[i];
+ if (fo->enable == 1) {
+ _vm->_items[fo->item].pos &= 3;
+ run(_vm->_items[fo->item].block, 4);
+ }
+ fo->enable = 0;
+ }
+
+ _vm->completeDoorOperations();
+
+ _vm->generateTempData();
+ _vm->txt()->removePageBreakFlag();
+ _screen->setScreenDim(7);
+
+ _vm->loadLevel(index, cmd);
+
+ if (_vm->_dialogueField)
+ _vm->restoreAfterDialogueSequence();
+
+ _vm->moveParty(_vm->_currentBlock);
+
+ _abortScript = 1;
+ _abortAfterSubroutine = 1;
+ _vm->_sceneUpdateRequired = true;
+
+ _vm->gui_drawAllCharPortraitsWithStats();
+ _scriptPosStackIndex = 0;
+
+ } else {
+ cmd = *pos++;
+ _vm->releaseMonsterShapes(cmd * 18, 18);
+ _vm->loadMonsterShapes((const char*)pos, cmd * 18, true, index * 18);
+ pos += 13;
+ _vm->gui_restorePlayField();
+ res = pos - data;
+ }
+
+ return res;
+}
+
+int EobInfProcessor::oeob_increasePartyExperience(int8 *data) {
+ int8 *pos = data;
+ if (*pos++ == -30) {
+ _vm->increasePartyExperience((int16)READ_LE_UINT16(pos));
+ pos += 2;
+ }
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_createItem_v1(int8 *data) {
+ int8 *pos = data;
+ uint16 itm = _vm->duplicateItem(READ_LE_UINT16(pos));
+ pos += 2;
+ uint16 block = READ_LE_UINT16(pos);
+ pos += 2;
+ uint8 itmPos = *pos++;
+
+ if (itm) {
+ if (block == 0xffff && !_vm->_itemInHand)
+ _vm->setHandItem(itm);
+ else if (block != 0xffff )
+ _vm->setItemPosition((Item*)&_vm->_levelBlockProperties[block & 0x3ff].drawObjects, block, itm, itmPos);
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_createItem_v2(int8 *data) {
+ static const uint8 _itemPos[] = { 0, 1, 2, 3, 1, 3, 0, 2, 3, 2, 1, 0, 2, 0, 3, 1 };
+ int8 *pos = data;
+
+ uint16 itm = _vm->duplicateItem(READ_LE_UINT16(pos));
+ pos += 2;
+ uint16 block = READ_LE_UINT16(pos);
+ pos += 2;
+ uint8 itmPos = *pos++;
+ uint8 flg = *pos++;
+
+ if (flg & 1)
+ _vm->_items[itm].value = *pos++;
+
+ if (flg & 2)
+ _vm->_items[itm].flags = *pos++;
+
+ if (flg & 4)
+ _vm->_items[itm].icon = *pos++;
+
+ if (!itm)
+ return pos - data;
+
+ if (block == 0xffff) {
+ if (!_vm->_itemInHand)
+ _vm->setHandItem(itm);
+ else
+ _vm->setItemPosition((Item*)&_vm->_levelBlockProperties[_vm->_currentBlock & 0x3ff].drawObjects, _vm->_currentBlock, itm, _itemPos[_vm->rollDice(1, 2, -1)]);
+ } else if (block == 0xfffe) {
+ _vm->setItemPosition((Item*)&_vm->_levelBlockProperties[_vm->_currentBlock & 0x3ff].drawObjects, _vm->_currentBlock, itm, _itemPos[(_vm->_currentDirection << 2) + _vm->rollDice(1, 2, -1)]);
+ } else {
+ _vm->setItemPosition((Item*)&_vm->_levelBlockProperties[block & 0x3ff].drawObjects, block, itm, itmPos);
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_launchObject(int8 *data) {
+ static const uint8 startPos[] = { 2, 3, 0, 2, 1, 0, 3, 1 };
+
+ int8 *pos = data;
+ bool m = (*pos++ == -33);
+ int i = READ_LE_UINT16(pos);
+ pos += 2;
+ uint16 block = READ_LE_UINT16(pos);
+ pos += 2;
+ int dir = *pos++;
+ int dirOffs = *pos++;
+
+ if (m) {
+ uint8 openBookType = _vm->_openBookType;
+ _vm->_openBookType = 0;
+ _vm->launchMagicObject(-1, i, block, startPos[dir * 2 + dirOffs], dir);
+ _vm->_openBookType = openBookType;
+ } else {
+ Item itm = _vm->duplicateItem(i);
+ if (itm) {
+ if (!_vm->launchObject(-1, itm, block, startPos[dir * 2 + dirOffs], dir, _vm->_items[itm].type))
+ _vm->_items[itm].block = -1;
+ }
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_changeDirection(int8 *data) {
+ int8 *pos = data;
+
+ int8 cmd = *pos++;
+ int8 dir = *pos++;
+
+ if (cmd == -15) {
+ _vm->_currentDirection = (_vm->_currentDirection + dir) & 3;
+ //_vm->_keybControlUnk = -1;
+ _vm->_sceneUpdateRequired = true;
+
+ } else if (cmd == -11) {
+ for (int i = 0; i < 10; i++) {
+ if (_vm->_flyingObjects[i].enable)
+ _vm->_flyingObjects[i].direction = (_vm->_flyingObjects[i].direction + dir) & 3;
+ }
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_identifyItems(int8 *data) {
+ int8 *pos = data;
+ uint16 block = READ_LE_UINT16(pos);
+
+ if (block == _vm->_currentBlock) {
+ for (int i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+
+ for (int ii = 0; ii < 27; ii++) {
+ int inv = _vm->_characters[i].inventory[ii];
+ if (inv)
+ _vm->_items[inv].flags |= 0x40;
+ }
+
+ _vm->identifyQueuedItems(_vm->_characters[i].inventory[16]);
+ }
+ }
+
+ _vm->identifyQueuedItems(_vm->_levelBlockProperties[block].drawObjects);
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_sequence(int8 *data) {
+ int8 *pos = data;
+ _vm->_dlgUnk1 = -1;
+ _vm->txt()->setWaitButtonMode(0);
+ _vm->gui_updateControls();
+ _vm->drawScene(1);
+
+ int cmd = *pos++;
+
+ if (_vm->game() == GI_EOB1) {
+ if (cmd == 10)
+ cmd = -1;
+ else if (cmd == 9)
+ cmd = -3;
+ else if (cmd == 8)
+ cmd = -2;
+ }
+
+ switch (cmd) {
+ case -3:
+ // eob1 outro
+ _vm->_runFlag = false;
+ _vm->_playFinale = true;
+ _abortScript = 1;
+ return 0;
+
+ case -2:
+ // portal sequence
+ pos=pos;
+ break;
+
+ case -1:
+ // copy protection
+ pos=pos;
+ break;
+
+ default:
+ _vm->npcSequence(cmd);
+ break;
+ }
+ _vm->screen()->setScreenDim(7);
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_delay(int8 *data) {
+ int8 *pos = data;
+ _vm->delay(READ_LE_UINT16(pos) * _vm->tickLength());
+ pos += 2;
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_drawScene(int8 *data) {
+ _vm->drawScene(1);
+ return 0;
+}
+
+int EobInfProcessor::oeob_dialogue(int8 *data) {
+ int8 *pos = data;
+
+ switch (*pos++) {
+ case -45:
+ _vm->drawSequenceBitmap((const char*)pos, pos[13], READ_LE_UINT16(pos + 14), READ_LE_UINT16(pos + 16), READ_LE_UINT16(pos + 18));
+ pos += 20;
+ break;
+
+ case -44:
+ _vm->restoreAfterDialogueSequence();
+ break;
+
+ case -43:
+ _vm->initDialogueSequence();
+ break;
+
+ case -42:
+ _vm->gui_drawDialogueBox();
+ break;
+
+ case -40:
+ _dlgResult = _vm->runDialogue(READ_LE_UINT16(pos), READ_LE_UINT16(pos + 6) == 0xffff ? 0 : 1, getString(READ_LE_UINT16(pos + 2)), getString(READ_LE_UINT16(pos + 4)), getString(READ_LE_UINT16(pos + 6)), 0);
+ pos += 8;
+ break;
+
+ case -8:
+ _vm->txt()->printDialogueText(READ_LE_UINT16(pos), getString(READ_LE_UINT16(pos + 2)));
+ pos += 4;
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+int EobInfProcessor::oeob_specialEvent(int8 *data) {
+ int8 *pos = data;
+ uint16 cmd = READ_LE_UINT16(pos);
+ pos += 2;
+
+ uint32 endTime = 0;
+ int i = 0;
+
+ switch (cmd) {
+ case 0:
+ _vm->drawScene(1);
+ _screen->_curPage = 2;
+ _screen->copyRegion(72, 0, 0, 0, 32, 120, 2, 12, Screen::CR_NO_P_CHECK);
+
+ for (; i < 4; i++) {
+ endTime = _vm->_system->getMillis() + _vm->_tickLength;
+ _vm->drawLightningColumn();
+ _screen->copyRegion(72, 0, 72, 0, 32, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _screen->copyRegion(0, 0, 72, 0, 32, 120, 12, 2, Screen::CR_NO_P_CHECK);
+ _vm->delayUntil(endTime);
+ }
+
+ _screen->_curPage = 0;
+ _vm->_sceneUpdateRequired = true;
+ break;
+
+ case 1:
+ _dlgResult = _vm->charSelectDialogue();
+ break;
+
+ case 2:
+ _vm->characterLevelGain(_dlgResult);
+ break;
+
+ case 3:
+ _dlgResult = _vm->resurrectionSelectDialogue();
+ break;
+
+ case 4:
+ if (_vm->prepareForNewPartyMember(33, 5))
+ _vm->initNpc(4);
+ break;
+
+ case 5:
+ _vm->deletePartyItem(46, 5);
+ _vm->deletePartyItem(46, 6);
+ break;
+
+ case 6:
+ _vm->loadVcnData(0, 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return pos - data;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/script_eob.h b/engines/kyra/script_eob.h
new file mode 100644
index 0000000000..2b02807531
--- /dev/null
+++ b/engines/kyra/script_eob.h
@@ -0,0 +1,121 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#ifndef KYRA_SCRIPT_EOB_H
+#define KYRA_SCRIPT_EOB_H
+
+#include "common/func.h"
+#include "common/substream.h"
+#include "common/savefile.h"
+
+namespace Kyra {
+
+class LolEobBaseEngine;
+
+class EobInfProcessor {
+public:
+ EobInfProcessor(EobCoreEngine *engine, Screen_Eob *_screen);
+ ~EobInfProcessor();
+
+ void loadData(const uint8 *data, uint32 dataSize);
+ void run(int func, int sub);
+
+ void setFlag(int flag) { _flagTable[17] |= flag; }
+ bool checkFlag(int flag) { return (_flagTable[17] & flag) ? true : false; }
+
+ void loadState(Common::SeekableSubReadStreamEndian &in);
+ void saveState(Common::OutSaveFile *out);
+
+private:
+ const char *getString(uint16 index);
+
+ int oeob_setWallType(int8 *data);
+ int oeob_toggleWallState(int8 *data);
+ int oeob_openDoor(int8 *data);
+ int oeob_closeDoor(int8 *data);
+ int oeob_replaceMonster(int8 *data);
+ int oeob_movePartyOrObject(int8 *data);
+ int oeob_moveInventoryItemToBlock(int8 *data);
+ int oeob_printMessage_v1(int8 *data);
+ int oeob_printMessage_v2(int8 *data);
+ int oeob_setFlags(int8 *data);
+ int oeob_playSoundEffect(int8 *data);
+ int oeob_removeFlags(int8 *data);
+ int oeob_modifyCharacterHitPoints(int8 *data);
+ int oeob_calcAndInflictCharacterDamage(int8 *data);
+ int oeob_jump(int8 *data);
+ int oeob_end(int8 *data);
+ int oeob_popPosAndReturn(int8 *data);
+ int oeob_pushPosAndJump(int8 *data);
+ int oeob_eval_v1(int8 *data);
+ int oeob_eval_v2(int8 *data);
+ int oeob_deleteItem(int8 *data);
+ int oeob_loadNewLevelOrMonsters(int8 *data);
+ int oeob_increasePartyExperience(int8 *data);
+ int oeob_createItem_v1(int8 *data);
+ int oeob_createItem_v2(int8 *data);
+ int oeob_launchObject(int8 *data);
+ int oeob_changeDirection(int8 *data);
+ int oeob_identifyItems(int8 *data);
+ int oeob_sequence(int8 *data);
+ int oeob_delay(int8 *data);
+ int oeob_drawScene(int8 *data);
+ int oeob_dialogue(int8 *data);
+ int oeob_specialEvent(int8 *data);
+
+ EobCoreEngine *_vm;
+ Screen_Eob *_screen;
+
+ typedef Common::Functor1Mem<int8*, int, EobInfProcessor> InfProc;
+ Common::Array<const InfProc*> _opcodes;
+
+ int8 *_scriptData;
+
+ uint8 _abortScript;
+ uint16 _abortAfterSubroutine;
+ int _dlgResult;
+ uint8 _script2;
+
+ uint16 _lastScriptFunc;
+ uint16 _lastScriptSub;
+
+ int8 **_scriptPosStack;
+ int _scriptPosStackIndex;
+
+ uint32 *_flagTable;
+
+ int16 *_stack;
+ int _stackIndex;
+
+ int8 _activeCharacter;
+
+ const int _commandMin;
+};
+
+} // End of namespace Kyra
+
+#endif
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp
index b80b8105a1..73b6915c89 100644
--- a/engines/kyra/script_hof.cpp
+++ b/engines/kyra/script_hof.cpp
@@ -1480,7 +1480,7 @@ typedef Common::Functor2Mem<const TIM *, const uint16 *, int, KyraEngine_HoF> TI
#define OpcodeTimUnImpl() _timOpcodes.push_back(new TIMOpcodeV2(this, 0))
void KyraEngine_HoF::setupOpcodeTable() {
- Common::Array<const Opcode *> *table = 0;
+ Common::Array<const Opcode*> *table = 0;
_opcodes.reserve(176);
SetOpcodeTable(_opcodes);
diff --git a/engines/kyra/script_lok.cpp b/engines/kyra/script_lok.cpp
index 4d40971124..ae6fb4b5e5 100644
--- a/engines/kyra/script_lok.cpp
+++ b/engines/kyra/script_lok.cpp
@@ -1754,7 +1754,7 @@ typedef Common::Functor1Mem<EMCState *, int, KyraEngine_LoK> OpcodeV1;
#define SetOpcodeTable(x) table = &x;
#define Opcode(x) table->push_back(new OpcodeV1(this, &KyraEngine_LoK::x))
void KyraEngine_LoK::setupOpcodeTable() {
- Common::Array<const Opcode *> *table = 0;
+ Common::Array<const Opcode*> *table = 0;
_opcodes.reserve(157);
SetOpcodeTable(_opcodes);
diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp
index d8ba32ce09..ead7e17f4c 100644
--- a/engines/kyra/script_lol.cpp
+++ b/engines/kyra/script_lol.cpp
@@ -93,25 +93,6 @@ void LoLEngine::runLevelScriptCustom(int block, int flags, int charNum, int item
checkSceneUpdateNeed(block);
}
-bool LoLEngine::checkSceneUpdateNeed(int func) {
- if (_sceneUpdateRequired)
- return true;
-
- for (int i = 0; i < 15; i++) {
- if (_visibleBlockIndex[i] == func) {
- _sceneUpdateRequired = true;
- return true;
- }
- }
-
- if (_currentBlock == func){
- _sceneUpdateRequired = true;
- return true;
- }
-
- return false;
-}
-
int LoLEngine::olol_setWallType(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setWallType(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2));
if (stackPos(2) != -1) {
@@ -796,9 +777,9 @@ int LoLEngine::olol_updateBlockAnimations(EMCState *script) {
return 0;
}
-int LoLEngine::olol_mapShapeToBlock(EMCState *script) {
- debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_mapShapeToBlock(%p) (%d)", (const void *)script, stackPos(0));
- return assignLevelShapes(stackPos(0));
+int LoLEngine::olol_assignLevelDecorationShape(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_assignLevelDecorationShape(%p) (%d)", (const void *)script, stackPos(0));
+ return assignLevelDecorationShapes(stackPos(0));
}
int LoLEngine::olol_resetBlockShapeAssignment(EMCState *script) {
@@ -830,11 +811,11 @@ int LoLEngine::olol_initMonster(EMCState *script) {
return -1;
for (uint8 i = 0; i < 30; i++) {
- MonsterInPlay *l = &_monsters[i];
+ LolMonsterInPlay *l = &_monsters[i];
if (l->hitPoints || l->mode == 13)
continue;
- memset(l, 0, sizeof(MonsterInPlay));
+ memset(l, 0, sizeof(LolMonsterInPlay));
l->id = i;
l->x = x;
l->y = y;
@@ -945,7 +926,7 @@ int LoLEngine::olol_loadMonsterProperties(EMCState *script) {
stackPos(28), stackPos(29), stackPos(30), stackPos(31), stackPos(32), stackPos(33), stackPos(34),
stackPos(35), stackPos(36), stackPos(37), stackPos(38), stackPos(39), stackPos(40), stackPos(41));
- MonsterProperty *l = &_monsterProperties[stackPos(0)];
+ LolMonsterProperty *l = &_monsterProperties[stackPos(0)];
l->shapeIndex = stackPos(1) & 0xff;
int shpWidthMax = 0;
@@ -1017,7 +998,7 @@ int LoLEngine::olol_inflictDamage(EMCState *script) {
int LoLEngine::olol_moveMonster(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_moveMonster(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
- MonsterInPlay *m = &_monsters[stackPos(0)];
+ LolMonsterInPlay *m = &_monsters[stackPos(0)];
if (m->mode == 1 || m->mode == 2) {
calcCoordinates(m->destX, m->destY, stackPos(1), stackPos(2), stackPos(3));
@@ -1029,10 +1010,9 @@ int LoLEngine::olol_moveMonster(EMCState *script) {
return 1;
}
-int LoLEngine::olol_dialogueBox(EMCState *script) {
- debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_dialogueBox(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
-
- _tim->drawDialogueBox(stackPos(0), getLangString(stackPos(1)), getLangString(stackPos(2)), getLangString(stackPos(3)));
+int LoLEngine::olol_setupDialogueButtons(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setupDialogueButtons(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ setupDialogueButtons(stackPos(0), getLangString(stackPos(1)), getLangString(stackPos(2)), getLangString(stackPos(3)));
return 1;
}
@@ -1194,7 +1174,7 @@ int LoLEngine::olol_playSoundEffect(EMCState *script) {
int LoLEngine::olol_processDialogue(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_processDialogue(%p)", (const void *)script);
- return _tim->processDialogue();
+ return processDialogue();
}
int LoLEngine::olol_stopTimScript(EMCState *script) {
@@ -1213,7 +1193,7 @@ int LoLEngine::olol_changeMonsterStat(EMCState *script) {
if (stackPos(0) == -1)
return 1;
- MonsterInPlay *m = &_monsters[stackPos(0) & 0x7fff];
+ LolMonsterInPlay *m = &_monsters[stackPos(0) & 0x7fff];
int16 d = stackPos(2);
uint16 x = 0;
@@ -1254,7 +1234,7 @@ int LoLEngine::olol_getMonsterStat(EMCState *script) {
if (stackPos(0) == -1)
return 0;
- MonsterInPlay *m = &_monsters[stackPos(0) & 0x7fff];
+ LolMonsterInPlay *m = &_monsters[stackPos(0) & 0x7fff];
int d = stackPos(1);
switch (d) {
@@ -1567,7 +1547,7 @@ int LoLEngine::olol_moveBlockObjects(EMCState *script) {
l &= 0x7fff;
- MonsterInPlay *m = &_monsters[l];
+ LolMonsterInPlay *m = &_monsters[l];
setMonsterMode(m, 14);
checkSceneUpdateNeed(m->block);
@@ -1582,8 +1562,8 @@ int LoLEngine::olol_moveBlockObjects(EMCState *script) {
placeMoveLevelItem(l, level, destBlock, _itemsInPlay[l].x & 0xff, _itemsInPlay[l].y & 0xff, _itemsInPlay[l].flyingHeight);
res = 1;
- if (!runScript || level != _currentLevel)
- continue;
+ if (!runScript || level != _currentLevel)
+ continue;
runLevelScriptCustom(destBlock, 0x80, -1, l, 0, 0);
}
@@ -1638,7 +1618,7 @@ int LoLEngine::olol_dummy1(EMCState *script) {
int LoLEngine::olol_suspendMonster(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_suspendMonster(%p) (%d)", (const void *)script, stackPos(0));
- MonsterInPlay *m = &_monsters[stackPos(0) & 0x7fff];
+ LolMonsterInPlay *m = &_monsters[stackPos(0) & 0x7fff];
setMonsterMode(m, 14);
checkSceneUpdateNeed(m->block);
placeMonster(m, 0, 0);
@@ -1889,9 +1869,9 @@ int LoLEngine::olol_checkBlockForMonster(EMCState *script) {
return -1;
}
-int LoLEngine::olol_transformRegion(EMCState *script) {
- debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_transformRegion(%p) (%d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
- transformRegion(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+int LoLEngine::olol_crossFadeRegion(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_crossFadeRegion(%p) (%d, %d, %d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ _screen->crossFadeRegion(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
return 1;
}
@@ -1984,7 +1964,7 @@ int LoLEngine::olol_getAnimationLastPart(EMCState *script) {
int LoLEngine::olol_assignSpecialGuiShape(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_assignSpecialGuiShape(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
if (stackPos(0)) {
- _specialGuiShape = _levelShapes[_levelShapeProperties[_wllShapeMap[stackPos(0)]].shapeIndex[stackPos(1)]];
+ _specialGuiShape = _levelDecorationShapes[_levelDecorationProperties[_wllShapeMap[stackPos(0)]].shapeIndex[stackPos(1)]];
_specialGuiShapeX = stackPos(2);
_specialGuiShapeY = stackPos(3);
_specialGuiShapeMirrorFlag = stackPos(4);
@@ -2291,10 +2271,10 @@ int LoLEngine::olol_calcNewBlockPosition(EMCState *script) {
return calcNewBlockPosition(stackPos(0), stackPos(1));
}
-int LoLEngine::olol_fadeScene(EMCState *script) {
- debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_fadeScene(%p)", (const void *)script);
+int LoLEngine::olol_crossFadeScene(EMCState *script) {
+ debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_crossFadeScene(%p)", (const void *)script);
gui_drawScene(2);
- transformRegion(112, 0, 112, 0, 176, 120, 2, 0);
+ _screen->crossFadeRegion(112, 0, 112, 0, 176, 120, 2, 0);
updateDrawPage2();
return 1;
}
@@ -2700,7 +2680,7 @@ typedef Common::Functor2Mem<const TIM *, const uint16 *, int, LoLEngine> TIMOpco
#define OpcodeTimUnImpl() timTable->push_back(new TIMOpcodeLoL(this, 0))
void LoLEngine::setupOpcodeTable() {
- Common::Array<const Opcode *> *table = 0;
+ Common::Array<const Opcode*> *table = 0;
_opcodes.reserve(192);
SetOpcodeTable(_opcodes);
@@ -2784,7 +2764,7 @@ void LoLEngine::setupOpcodeTable() {
// 0x34
Opcode(olol_updateBlockAnimations);
- Opcode(olol_mapShapeToBlock);
+ Opcode(olol_assignLevelDecorationShape);
Opcode(olol_resetBlockShapeAssignment);
Opcode(olol_copyRegion);
@@ -2808,7 +2788,7 @@ void LoLEngine::setupOpcodeTable() {
// 0x44
Opcode(olol_moveMonster);
- Opcode(olol_dialogueBox);
+ Opcode(olol_setupDialogueButtons);
Opcode(olol_giveTakeMoney);
Opcode(olol_checkMoney);
@@ -2933,7 +2913,7 @@ void LoLEngine::setupOpcodeTable() {
Opcode(olol_checkBlockForMonster);
// 0x98
- Opcode(olol_transformRegion);
+ Opcode(olol_crossFadeRegion);
Opcode(olol_calcCoordinatesAddDirectionOffset);
Opcode(olol_resetPortraitsAndDisableSysTimer);
Opcode(olol_enableSysTimer);
@@ -2981,7 +2961,7 @@ void LoLEngine::setupOpcodeTable() {
Opcode(olol_calcNewBlockPosition);
// 0xB8
- Opcode(olol_fadeScene);
+ Opcode(olol_crossFadeScene);
Opcode(olol_updateDrawPage2);
Opcode(olol_setMouseCursor);
Opcode(olol_characterSays);
@@ -2992,7 +2972,7 @@ void LoLEngine::setupOpcodeTable() {
Opcode(olol_getLanguage);
Opcode(olol_dummy0);
- Common::Array<const TIMOpcode *> *timTable = 0;
+ Common::Array<const TIMOpcode*> *timTable = 0;
_timIntroOpcodes.reserve(8);
SetTimOpcodeTable(_timIntroOpcodes);
diff --git a/engines/kyra/script_mr.cpp b/engines/kyra/script_mr.cpp
index afe11aba02..56b2a48b89 100644
--- a/engines/kyra/script_mr.cpp
+++ b/engines/kyra/script_mr.cpp
@@ -1129,7 +1129,7 @@ typedef Common::Functor1Mem<EMCState *, int, KyraEngine_MR> OpcodeV3;
#define Opcode(x) table->push_back(new OpcodeV3(this, &KyraEngine_MR::x))
#define OpcodeUnImpl() table->push_back(new OpcodeV3(this, 0))
void KyraEngine_MR::setupOpcodeTable() {
- Common::Array<const Opcode *> *table = 0;
+ Common::Array<const Opcode*> *table = 0;
_opcodes.reserve(176);
SetOpcodeTable(_opcodes);
diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp
index 83d03d1f63..75977fc87c 100644
--- a/engines/kyra/script_tim.cpp
+++ b/engines/kyra/script_tim.cpp
@@ -135,7 +135,7 @@ bool TIMInterpreter::callback(Common::IFFChunk &chunk) {
return false;
}
-TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpcode *> *opcodes) {
+TIM *TIMInterpreter::load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes) {
if (!_vm->resource()->exists(filename))
return 0;
@@ -833,18 +833,6 @@ int TIMInterpreter::cmd_stopFuncNow(const uint16 *param) {
return 1;
}
-int TIMInterpreter::cmd_stopAllFuncs(const uint16 *param) {
- while (_currentTim->dlgFunc == -1 && _currentTim->clickedButton == 0 && !_vm->shouldQuit()) {
- update();
- _currentTim->clickedButton = processDialogue();
- }
-
- for (int i = 0; i < TIM::kCountFuncs; ++i)
- _currentTim->func[i].ip = 0;
-
- return -1;
-}
-
// TODO: Consider moving to another file
#ifdef ENABLE_LOL
@@ -908,9 +896,6 @@ TIMInterpreter_LoL::TIMInterpreter_LoL(LoLEngine *engine, Screen_v2 *screen_v2,
_animator = new TimAnimator(engine, screen_v2, system, true);
_drawPage2 = 0;
-
- memset(_dialogueButtonString, 0, 3 * sizeof(const char *));
- _dialogueButtonPosX = _dialogueButtonPosY = _dialogueNumButtons = _dialogueButtonXoffs = _dialogueHighlightedButton = 0;
}
int TIMInterpreter_LoL::initAnimStruct(int index, const char *filename, int x, int y, int frameDelay, int, uint16 wsaFlags) {
@@ -978,157 +963,12 @@ void TIMInterpreter_LoL::advanceToOpcode(int opcode) {
f->nextTime = _system->getMillis();
}
-void TIMInterpreter_LoL::drawDialogueBox(int numStr, const char *s1, const char *s2, const char *s3) {
- _screen->setScreenDim(5);
-
- if (numStr == 1 && _vm->speechEnabled()) {
- _dialogueNumButtons = 0;
- _dialogueButtonString[0] = _dialogueButtonString[1] = _dialogueButtonString[2] = 0;
- } else {
- _dialogueNumButtons = numStr;
- _dialogueButtonString[0] = s1;
- _dialogueButtonString[1] = s2;
- _dialogueButtonString[2] = s3;
- _dialogueHighlightedButton = 0;
-
- const ScreenDim *d = _screen->getScreenDim(5);
- _dialogueButtonPosY = d->sy + d->h - 9;
-
- if (numStr == 1) {
- _dialogueButtonXoffs = 0;
- _dialogueButtonPosX = d->sx + d->w - 77;
- } else {
- _dialogueButtonXoffs = d->w / numStr;
- _dialogueButtonPosX = d->sx + (_dialogueButtonXoffs >> 1) - 37;
- }
-
- drawDialogueButtons();
- }
-
- if (!_vm->shouldQuit())
- _vm->removeInputTop();
-}
-
-void TIMInterpreter_LoL::drawDialogueButtons() {
- int cp = _screen->setCurPage(0);
- Screen::FontId of = _screen->setFont(_vm->gameFlags().use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_6_FNT);
-
- int x = _dialogueButtonPosX;
-
- for (int i = 0; i < _dialogueNumButtons; i++) {
- if (_vm->gameFlags().use16ColorMode) {
- _vm->gui_drawBox(x, (_dialogueButtonPosY & ~7) - 1, 74, 10, 0xee, 0xcc, -1);
- _screen->printText(_dialogueButtonString[i], (x + 37 - (_screen->getTextWidth(_dialogueButtonString[i])) / 2) & ~3,
- (_dialogueButtonPosY + 2) & ~7, _dialogueHighlightedButton == i ? 0xc1 : 0xe1, 0);
- } else {
- _vm->gui_drawBox(x, _dialogueButtonPosY, 74, 9, 136, 251, -1);
- _screen->printText(_dialogueButtonString[i], x + 37 - (_screen->getTextWidth(_dialogueButtonString[i])) / 2,
- _dialogueButtonPosY + 2, _dialogueHighlightedButton == i ? 144 : 254, 0);
- }
-
- x += _dialogueButtonXoffs;
- }
- _screen->setFont(of);
- _screen->setCurPage(cp);
-}
-
-uint16 TIMInterpreter_LoL::processDialogue() {
- int df = _dialogueHighlightedButton;
- int res = 0;
- int x = _dialogueButtonPosX;
- int y = (_vm->gameFlags().use16ColorMode ? (_dialogueButtonPosY & ~7) - 1 : _dialogueButtonPosY);
-
- for (int i = 0; i < _dialogueNumButtons; i++) {
- Common::Point p = _vm->getMousePos();
- if (_vm->posWithinRect(p.x, p.y, x, y, x + 74, y + 9)) {
- _dialogueHighlightedButton = i;
- break;
- }
- x += _dialogueButtonXoffs;
- }
-
- if (_dialogueNumButtons == 0) {
- int e = _vm->checkInput(0, false) & 0xFF;
- _vm->removeInputTop();
-
- if (e) {
- _vm->gui_notifyButtonListChanged();
-
- if (e == 43 || e == 61) {
- _vm->snd_stopSpeech(true);
- }
- }
-
- if (_vm->snd_updateCharacterSpeech() != 2) {
- res = 1;
- if (!_vm->shouldQuit()) {
- _vm->removeInputTop();
- _vm->gui_notifyButtonListChanged();
- }
- }
- } else {
- int e = _vm->checkInput(0, false) & 0xFF;
- _vm->removeInputTop();
- if (e)
- _vm->gui_notifyButtonListChanged();
-
- if (e == 200 || e == 202) {
- x = _dialogueButtonPosX;
-
- for (int i = 0; i < _dialogueNumButtons; i++) {
- Common::Point p = _vm->getMousePos();
- if (_vm->posWithinRect(p.x, p.y, x, y, x + 74, y + 9)) {
- _dialogueHighlightedButton = i;
- res = _dialogueHighlightedButton + 1;
- break;
- }
- x += _dialogueButtonXoffs;
- }
- } else if (e == _vm->_keyMap[Common::KEYCODE_SPACE] || e == _vm->_keyMap[Common::KEYCODE_RETURN]) {
- _vm->snd_stopSpeech(true);
- res = _dialogueHighlightedButton + 1;
- } else if (e == _vm->_keyMap[Common::KEYCODE_LEFT] || e == _vm->_keyMap[Common::KEYCODE_DOWN]) {
- if (_dialogueNumButtons > 1 && _dialogueHighlightedButton > 0)
- _dialogueHighlightedButton--;
- } else if (e == _vm->_keyMap[Common::KEYCODE_RIGHT] || e == _vm->_keyMap[Common::KEYCODE_UP]) {
- if (_dialogueNumButtons > 1 && _dialogueHighlightedButton < (_dialogueNumButtons - 1))
- _dialogueHighlightedButton++;
- }
- }
-
- if (df != _dialogueHighlightedButton)
- drawDialogueButtons();
-
- _screen->updateScreen();
-
- if (res == 0)
- return 0;
-
- _vm->stopPortraitSpeechAnim();
-
- if (!_vm->textEnabled() && _vm->_currentControlMode) {
- _screen->setScreenDim(5);
- const ScreenDim *d = _screen->getScreenDim(5);
- _screen->fillRect(d->sx, d->sy + d->h - 9, d->sx + d->w - 1, d->sy + d->h - 1, d->unkA);
- } else {
- const ScreenDim *d = _screen->_curDim;
- if (_vm->gameFlags().use16ColorMode)
- _screen->fillRect(d->sx, d->sy, d->sx + d->w - 3, d->sy + d->h - 2, d->unkA);
- else
- _screen->fillRect(d->sx, d->sy, d->sx + d->w - 2, d->sy + d->h - 1, d->unkA);
- _vm->_txt->clearDim(4);
- _vm->_txt->resetDimTextPositions(4);
- }
-
- return res;
-}
-
void TIMInterpreter_LoL::resetDialogueState(TIM *tim) {
if (!tim)
return;
tim->procFunc = 0;
- tim->procParam = _dialogueNumButtons ? _dialogueNumButtons : 1;
+ tim->procParam = _vm->_dialogueNumButtons ? _vm->_dialogueNumButtons : 1;
tim->clickedButton = 0;
tim->dlgFunc = -1;
}
@@ -1168,6 +1008,18 @@ int TIMInterpreter_LoL::execCommand(int cmd, const uint16 *param) {
return (this->*_commands[cmd].proc)(param);
}
+int TIMInterpreter_LoL::cmd_stopAllFuncs(const uint16 *param) {
+ while (_currentTim->dlgFunc == -1 && _currentTim->clickedButton == 0 && !_vm->shouldQuit()) {
+ update();
+ _currentTim->clickedButton = _vm->processDialogue();
+ }
+
+ for (int i = 0; i < TIM::kCountFuncs; ++i)
+ _currentTim->func[i].ip = 0;
+
+ return -1;
+}
+
int TIMInterpreter_LoL::cmd_setLoopIp(const uint16 *param) {
if (_vm->speechEnabled()) {
if (_vm->snd_updateCharacterSpeech() == 2)
@@ -1201,7 +1053,7 @@ int TIMInterpreter_LoL::cmd_continueLoop(const uint16 *param) {
}
int TIMInterpreter_LoL::cmd_processDialogue(const uint16 *param) {
- int res = processDialogue();
+ int res = _vm->processDialogue();
if (!res || !_currentTim->procParam)
return res;
@@ -1238,7 +1090,7 @@ int TIMInterpreter_LoL::cmd_dialogueBox(const uint16 *param) {
}
}
- drawDialogueBox(cnt, tmpStr[0], tmpStr[1], tmpStr[2]);
+ _vm->setupDialogueButtons(cnt, tmpStr[0], tmpStr[1], tmpStr[2]);
_vm->gui_notifyButtonListChanged();
return -3;
diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h
index 11b716c3a9..e132ed78c5 100644
--- a/engines/kyra/script_tim.h
+++ b/engines/kyra/script_tim.h
@@ -146,7 +146,7 @@ struct TIM {
uint16 *avtl;
uint8 *text;
- const Common::Array<const TIMOpcode *> *opcodes;
+ const Common::Array<const TIMOpcode*> *opcodes;
// TODO: Get rid of this ugly HACK to allow the
// Lands of Lore outro to be working properly.
@@ -159,7 +159,7 @@ public:
TIMInterpreter(KyraEngine_v1 *engine, Screen_v2 *screen_v2, OSystem *system);
virtual ~TIMInterpreter();
- TIM *load(const char *filename, const Common::Array<const TIMOpcode *> *opcodes);
+ TIM *load(const char *filename, const Common::Array<const TIMOpcode*> *opcodes);
void unload(TIM *&tim) const;
bool callback(Common::IFFChunk &chunk);
@@ -186,8 +186,6 @@ public:
void displayText(uint16 textId, int16 flags, uint8 color);
void setupTextPalette(uint index, int fadePalette);
- virtual void drawDialogueBox(int numStr, const char *s1, const char *s2, const char *s3) {}
- virtual uint16 processDialogue() { return 1; }
virtual void resetDialogueState(TIM *tim) {}
int _drawPage2;
@@ -255,7 +253,6 @@ protected:
int cmd_execOpcode(const uint16 *param);
int cmd_initFuncNow(const uint16 *param);
int cmd_stopFuncNow(const uint16 *param);
- int cmd_stopAllFuncs(const uint16 *param);
#define cmd_return(n, v) \
int cmd_return_##n(const uint16 *){ return v; }
cmd_return( 1, 1)
@@ -273,8 +270,6 @@ public:
int initAnimStruct(int index, const char *filename, int x, int y, int frameDelay, int, uint16 wsaCopyParams);
int freeAnimStruct(int index);
- void drawDialogueBox(int numStr, const char *s1, const char *s2, const char *s3);
- uint16 processDialogue();
void resetDialogueState(TIM *tim);
private:
@@ -284,18 +279,9 @@ private:
char *getTableString(int id);
void advanceToOpcode(int opcode);
- void drawDialogueButtons();
-
LoLEngine *_vm;
Screen_LoL *_screen;
- const char *_dialogueButtonString[3];
- uint16 _dialogueButtonPosX;
- uint16 _dialogueButtonPosY;
- int _dialogueNumButtons;
- uint16 _dialogueButtonXoffs;
- int _dialogueHighlightedButton;
-
virtual int execCommand(int cmd, const uint16 *param);
typedef int (TIMInterpreter_LoL::*CommandProc)(const uint16 *);
@@ -307,6 +293,7 @@ private:
const CommandEntry *_commands;
int _commandsSize;
+ int cmd_stopAllFuncs(const uint16 *param);
int cmd_setLoopIp(const uint16 *param);
int cmd_continueLoop(const uint16 *param);
int cmd_processDialogue(const uint16 *param);
diff --git a/engines/kyra/sequences_eob1.cpp b/engines/kyra/sequences_eob1.cpp
new file mode 100644
index 0000000000..0606742421
--- /dev/null
+++ b/engines/kyra/sequences_eob1.cpp
@@ -0,0 +1,140 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/eob1.h"
+#include "kyra/screen_eob.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+#include "common/system.h"
+
+#include "base/version.h"
+
+namespace Kyra {
+
+int EobEngine::mainMenu() {
+ int menuChoice = 4;
+
+ Screen::FontId of = _screen->_currentFont;
+ Common::SeekableReadStream *s = 0;
+
+ while (menuChoice >= 0 && !shouldQuit()) {
+ switch (menuChoice) {
+ case 0:
+ _screen->loadPalette("EOBPAL.COL", _screen->getPalette(0));
+ _screen->loadEobCpsFileToPage("INTRO", 0, 5, 3, 2);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->_curPage = 2;
+ of = _screen->setFont(Screen::FID_6_FNT);
+ _screen->printText(gScummVMVersion, 280 - strlen(gScummVMVersion) * 6, 153, _screen->getPagePixel(2, 0, 0), 0);
+ _screen->setFont(of);
+ _screen->fillRect(0, 159, 319, 199, _screen->getPagePixel(2, 0, 0));
+ gui_drawBox(77, 165, 173, 29, 13, 14, 12);
+ gui_drawBox(76, 164, 175, 31, 13, 14, -1);
+ _screen->_curPage = 0;
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ menuChoice = mainMenuLoop();
+ break;
+
+ case 1:
+ // load game in progress
+ //
+ menuChoice = -1;
+ break;
+
+ case 2:
+ // create new party
+ menuChoice = -2;
+ break;
+
+ case 3:
+ // quit
+ menuChoice = -5;
+ break;
+
+ case 4:
+ // intro
+ _sound->loadSoundFile("SOUND");
+ _screen->hideMouse();
+ seq_playOpeningCredits();
+ seq_playIntro();
+ _screen->showMouse();
+ _sound->loadSoundFile("ADLIB");
+ menuChoice = 0;
+ break;
+ }
+ }
+
+ return shouldQuit() ? -5 : menuChoice;
+}
+
+int EobEngine::mainMenuLoop() {
+ int sel = -1;
+ do {
+ _screen->setScreenDim(28);
+ _gui->setupMenu(8, 0, _mainMenuStrings, -1, 0, 0);
+
+ while (sel == -1 && !shouldQuit())
+ sel = _gui->handleMenu(8, _mainMenuStrings, 0, -1, 0);
+ } while ((sel < 0 || sel > 5) && !shouldQuit());
+
+ return sel + 1;
+}
+
+void EobEngine::seq_playOpeningCredits() {
+ static const char *cmpList[] = { "WESTWOOD.CMP", "AND.CMP", "SSI.CMP", "PRESENT.CMP", "DAND.CMP" };
+ static const uint8 frameDelay[] = { 140, 50, 100, 50, 140 };
+
+ _screen->loadPalette("WESTWOOD.COL", _screen->getPalette(0));
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ _screen->loadBitmap(cmpList[0], 5, 3, 0);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ _sound->playTrack(1);
+ delay(frameDelay[0] * _tickLength);
+
+ for (int i = 1; i < 5 && !shouldQuit() && !skipFlag(); i++) {
+ _screen->loadBitmap(cmpList[i], 5, 3, 0);
+ uint32 nextFrameTimer = _system->getMillis() + frameDelay[i] * _tickLength;
+ _screen->crossFadeRegion(0, 50, 0, 50, 320, 102, 2, 0);
+ delayUntil(nextFrameTimer);
+ }
+
+ delay(50 * _tickLength);
+}
+
+void EobEngine::seq_playIntro() {
+ //_sound->playTrack(2);
+}
+
+void EobEngine::seq_playFinale() {
+
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/sequences_eob2.cpp b/engines/kyra/sequences_eob2.cpp
new file mode 100644
index 0000000000..708e9cd23a
--- /dev/null
+++ b/engines/kyra/sequences_eob2.cpp
@@ -0,0 +1,1277 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifdef ENABLE_EOB
+
+#include "kyra/eob2.h"
+#include "kyra/screen_eob.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+#include "common/system.h"
+
+#include "base/version.h"
+
+namespace Kyra {
+
+class DarkmoonSequenceHelper {
+friend class DarkMoonEngine;
+public:
+ enum Mode {
+ kIntro,
+ kFinale
+ };
+
+ DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_Eob *screen, Mode mode, const char *const *strings, const char *const *cpsFiles, const char *const *palFiles, const EobShapeDef **shapeDefList, const EobSequenceStep **seqList);
+ ~DarkmoonSequenceHelper();
+
+ void loadScene(int index, int pageNum);
+ void runSequence(int index, int del = -1);
+
+ void printText(int index, int color);
+ void fadeText();
+
+ void update(int srcPage);
+
+ void setPalette(int index);
+ void fadePalette(int index, int del);
+ void copyPalette(int srcIndex, int destIndex);
+
+ void initDelayedPaletteFade(int palIndex, int rate);
+ bool processDelayedPaletteFade();
+
+ void delay(uint32 ticks);
+ void waitForSongNotifier(int index, bool introUpdateAnim = false);
+
+private:
+ void setPaletteWithoutTextColor(int index);
+
+ OSystem *_system;
+ DarkMoonEngine *_vm;
+ Screen_Eob *_screen;
+ Mode _mode;
+
+ uint8 _notifier;
+
+ const char *const *_strings;
+ const char *const *_cpsFiles;
+ const char *const *_palFiles;
+ const EobShapeDef **_shapeDefs;
+ const EobSequenceStep **_seqData;
+
+ Palette *_palettes[12];
+
+ const uint8 **_shapes;
+
+ uint32 _fadePalTimer;
+ int _fadePalRate;
+ int _fadePalIndex;
+};
+
+int DarkMoonEngine::mainMenu() {
+ int menuChoice = 4;
+
+ _sound->loadSoundFile("INTRO");
+ Screen::FontId of = _screen->_currentFont;
+ int op = 0;
+ Common::SeekableReadStream *s = 0;
+
+ while (menuChoice >= 0 && !shouldQuit()) {
+ switch (menuChoice) {
+ case 0:
+ s = _res->createReadStream("XENU.CPS");
+ if (s) {
+ s->read(_screen->getPalette(0).getData(), 768);
+ _screen->loadFileDataToPage(s, 3, 64000);
+ delete s;
+ } else {
+ _screen->loadBitmap("MENU.CPS", 3, 2, &_screen->getPalette(0));
+ }
+
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ of = _screen->setFont(Screen::FID_6_FNT);
+ op = _screen->setCurPage(2);
+ _screen->printText(gScummVMVersion, 267 - strlen(gScummVMVersion) * 6, 160, 13, 0);
+ _screen->setFont(of);
+ _screen->_curPage = op;
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ menuChoice = mainMenuLoop();
+ break;
+
+ case 1:
+ // load game in progress
+ //
+ menuChoice = -1;
+ break;
+
+ case 2:
+ // create new party
+ menuChoice = -2;
+ break;
+
+ case 3:
+ // transfer party
+ seq_playFinale();
+ menuChoice = -3;
+ break;
+
+ case 4:
+ // play intro
+ seq_playIntro();
+ menuChoice = 0;
+ break;
+
+ case 5:
+ // quit
+ menuChoice = -5;
+ break;
+ }
+ }
+
+ return shouldQuit() ? -5 : menuChoice;
+}
+
+int DarkMoonEngine::mainMenuLoop() {
+ int sel = -1;
+ do {
+ _screen->setScreenDim(6);
+ _gui->setupMenu(6, 0, _mainMenuStrings, -1, 0, 0);
+
+ while (sel == -1 && !shouldQuit())
+ sel = _gui->handleMenu(6, _mainMenuStrings, 0, -1, 0);
+ } while ((sel < 0 || sel > 5) && !shouldQuit());
+
+ return sel + 1;
+}
+
+void DarkMoonEngine::seq_playIntro() {
+ DarkmoonSequenceHelper sq(_system, this, _screen, DarkmoonSequenceHelper::kIntro, _introStrings, _cpsFilesIntro, _palFilesIntro, _shapesIntro, _seqIntro);
+
+ _screen->setCurPage(0);
+ _screen->clearCurPage();
+
+ _sound->playTrack(0);
+
+ sq.loadScene(4, 2);
+ sq.loadScene(0, 2);
+
+ sq.delay(1);
+
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(12);
+
+ _screen->copyRegion(0, 0, 8, 8, 304, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ sq.setPalette(9);
+ sq.fadePalette(0, 3);
+
+ _screen->setCurPage(2);
+ _screen->setClearScreenDim(17);
+ _screen->setCurPage(0);
+
+ removeInputTop();
+ sq.delay(18);
+
+ sq.runSequence(3, 18);
+ sq.runSequence(6, 18);
+ sq.runSequence(0);
+
+ sq.waitForSongNotifier(1);
+
+ sq.runSequence(11);
+ sq.runSequence(7, 6);
+ sq.runSequence(2, 6);
+
+ sq.waitForSongNotifier(2);
+
+ sq.runSequence(38);
+ sq.runSequence(3);
+ sq.runSequence(8);
+ sq.runSequence(1, 10);
+ sq.runSequence(0, 6);
+ sq.runSequence(2);
+
+ sq.waitForSongNotifier(3);
+
+ _screen->setClearScreenDim(17);
+ _screen->setCurPage(2);
+ _screen->setClearScreenDim(17);
+ _screen->setCurPage(0);
+
+ sq.runSequence(40);
+ sq.runSequence(7, 18);
+
+ sq.printText(0, 16); // You were settling...
+ sq.runSequence(7, 90);
+ sq.fadeText();
+
+ sq.printText(1, 16); // Then a note was slipped to you
+ sq.runSequence(8);
+ sq.runSequence(2, 72);
+ sq.fadeText();
+
+ sq.printText(2, 16); // It was from your friend Khelben Blackstaff...
+ sq.runSequence(2);
+ sq.runSequence(6, 36);
+ sq.runSequence(3);
+ sq.fadeText();
+
+ sq.printText(3, 16); // The message was urgent.
+
+ sq.loadScene(1, 2);
+ sq.waitForSongNotifier(4);
+
+ //intro scroll
+ if (!skipFlag() && !shouldQuit()) {
+ for (int i = 0; i < 280; i += 3) {
+ uint32 endtime = _system->getMillis() + _tickLength;
+ _screen->copyRegion(11, 8, 8, 8, 301, 128, 0, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(i, 0, 309, 8, 3, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ if (i == 96)
+ sq.runSequence(42);
+ delayUntil(endtime);
+ }
+ }
+
+ _screen->copyRegion(8, 8, 0, 0, 304, 128, 0, 2, Screen::CR_NO_P_CHECK);
+ sq.runSequence(4);
+ sq.fadeText();
+ sq.delay(10);
+
+ sq.loadScene(2, 2);
+ sq.update(2);
+ sq.delay(10);
+
+ sq.printText(4, 16); // What could Khelben want?
+ sq.delay(25);
+
+ sq.loadScene(3, 2);
+ sq.delay(54);
+ sq.runSequence(13);
+ _screen->copyRegion(104, 16, 96, 8, 120, 100, 0, 2, Screen::CR_NO_P_CHECK);
+ sq.fadeText();
+
+ sq.printText(5, 15); // Welcome, please come in
+ sq.runSequence(10);
+ sq.runSequence(10);
+ sq.runSequence(9);
+ sq.runSequence(9);
+ sq.fadeText();
+
+ sq.printText(6, 15); // Khelben awaits you in his study
+ for (int i = 0; i < 3; i++)
+ sq.runSequence(10);
+ sq.runSequence(9);
+ sq.runSequence(14);
+ sq.loadScene(5, 2);
+
+ sq.waitForSongNotifier(5);
+
+ sq.fadeText();
+ _screen->clearCurPage();
+ _screen->updateScreen();
+
+ for (int i = 0; i < 6; i++)
+ sq.runSequence(15);
+
+ sq.loadScene(6, 2);
+ sq.loadScene(7, 2);
+ _screen->clearCurPage();
+ sq.update(2);
+
+ sq.runSequence(16);
+ sq.printText(7, 15); // Thank you for coming so quickly
+ sq.runSequence(16);
+ sq.runSequence(17);
+ for (int i = 0; i < 3; i++)
+ sq.runSequence(16);
+ sq.fadeText();
+ sq.runSequence(16);
+
+ sq.loadScene(8, 2);
+ sq.update(2);
+ sq.runSequence(32);
+ sq.printText(8, 15); // I am troubled my friend
+ sq.runSequence(33);
+ sq.runSequence(33);
+ for (int i = 0; i < 4; i++)
+ sq.runSequence(32);
+ sq.fadeText();
+
+ sq.printText(9, 15); // Ancient evil stirs in the Temple Darkmoon
+ sq.runSequence(33);
+ sq.runSequence(43);
+ sq.runSequence(33);
+ for (int i = 0; i < 3; i++)
+ sq.runSequence(32);
+ sq.fadeText();
+
+ sq.printText(10, 15); // I fear for the safety of our city
+ for (int i = 0; i < 4; i++)
+ sq.runSequence(33);
+ sq.runSequence(32);
+ sq.runSequence(32);
+
+ sq.loadScene(9, 2);
+ sq.fadeText();
+
+ sq.waitForSongNotifier(6);
+
+ sq.update(2);
+ sq.runSequence(34);
+
+ sq.printText(11, 15); // I need your help
+ for (int i = 0; i < 3; i++)
+ sq.runSequence(34);
+ sq.runSequence(35);
+ for (int i = 0; i < 4; i++)
+ sq.runSequence(34);
+ sq.fadeText();
+
+ sq.loadScene(12, 2);
+ sq.update(2);
+ sq.loadScene(6, 2);
+ sq.runSequence(18);
+
+ sq.printText(12, 15); // Three nights ago I sent forth a scout
+ sq.runSequence(19);
+ sq.runSequence(20);
+ sq.runSequence(22);
+ sq.runSequence(19);
+ sq.runSequence(20);
+ sq.runSequence(18);
+ sq.fadeText();
+
+ sq.printText(13, 15); // She has not yet returned
+ sq.runSequence(20);
+ sq.runSequence(19);
+ sq.runSequence(23);
+ sq.runSequence(24);
+ sq.runSequence(20);
+ sq.runSequence(19);
+ sq.runSequence(17);
+ sq.runSequence(18);
+ sq.fadeText();
+
+ sq.printText(14, 15); // I fear for her safety
+ sq.runSequence(19);
+ sq.runSequence(20);
+ sq.runSequence(20);
+ sq.runSequence(18);
+ sq.runSequence(25);
+ sq.runSequence(18);
+ sq.runSequence(18);
+ sq.fadeText();
+ sq.runSequence(18);
+ sq.runSequence(18);
+
+ sq.printText(15, 15); // Take this coin
+ sq.runSequence(28);
+ sq.runSequence(19);
+ sq.runSequence(20);
+ sq.runSequence(18);
+ sq.runSequence(18);
+ sq.fadeText();
+
+ sq.loadScene(10, 2);
+ _screen->clearCurPage();
+ _screen->updateScreen();
+
+ sq.runSequence(37, 18);
+ sq.runSequence(36, 36);
+
+ sq.loadScene(12, 2);
+ _screen->clearCurPage();
+ sq.update(2);
+
+ sq.loadScene(11, 2);
+ sq.printText(16, 15); // I will use it to contact you
+ sq.runSequence(19);
+ sq.runSequence(20);
+ sq.runSequence(20);
+ sq.runSequence(18);
+ sq.runSequence(18);
+ sq.fadeText();
+
+ sq.printText(17, 15); // You must act quickly
+ sq.runSequence(19);
+ sq.runSequence(20);
+ sq.runSequence(19);
+ sq.runSequence(18);
+ sq.runSequence(18);
+ sq.fadeText();
+ sq.runSequence(18);
+
+ sq.printText(18, 15); // I will teleport you near Darkmoon
+ sq.runSequence(20);
+ sq.runSequence(27);
+ sq.runSequence(20);
+ sq.runSequence(19);
+ sq.runSequence(18);
+ sq.runSequence(18);
+ sq.fadeText();
+ sq.runSequence(18);
+
+ sq.printText(19, 15); // May luck be with you my friend
+ sq.runSequence(19);
+ sq.runSequence(19);
+ sq.runSequence(20);
+ sq.runSequence(18);
+ sq.fadeText();
+ sq.runSequence(29);
+
+ sq.waitForSongNotifier(7);
+
+ sq.runSequence(30);
+ sq.runSequence(31);
+
+ sq.waitForSongNotifier(8, true);
+
+ if (skipFlag() || shouldQuit()) {
+ _sound->playTrack(15);
+ } else {
+ _screen->setScreenDim(17);
+ _screen->clearCurDim();
+ _sound->playTrack(14);
+ sq.fadePalette(10, 1);
+ _screen->setClearScreenDim(18);
+ sq.delay(6);
+ sq.fadePalette(9, 1);
+ _screen->clearCurPage();
+ }
+
+ sq.fadePalette(9, 10);
+}
+
+void DarkMoonEngine::seq_playFinale() {
+ DarkmoonSequenceHelper sq(_system, this, _screen, DarkmoonSequenceHelper::kFinale, _finaleStrings, _cpsFilesFinale, _palFilesFinale, _shapesFinale, _seqFinale);
+
+ _screen->setCurPage(0);
+
+ _sound->loadSoundFile("FINALE1");
+ _sound->playTrack(0);
+
+ sq.delay(3);
+
+ _screen->clearCurPage();
+ _screen->updateScreen();
+
+ sq.loadScene(0, 2);
+ sq.delay(18);
+
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(1);
+ sq.update(2);
+
+ sq.loadScene(1, 2);
+
+ sq.runSequence(0);
+ sq.runSequence(0);
+ for (int i = 0; i < 3; i++)
+ sq.runSequence(2);
+ sq.runSequence(1);
+ sq.runSequence(2);
+ sq.runSequence(2);
+
+ sq.printText(0, 10); // Finally, Dran has been defeated
+ for (int i = 0; i < 7; i++)
+ sq.runSequence(2);
+ sq.fadeText();
+ sq.runSequence(2);
+
+ sq.waitForSongNotifier(1);
+
+ sq.printText(1, 10); // Suddenly, your friend Khelben appears
+ sq.runSequence(4);
+ for (int i = 0; i < 3; i++)
+ sq.runSequence(2);
+ sq.fadeText();
+
+ sq.printText(2, 15); // Greetings, my victorious friends
+ for (int i = 0; i < 4; i++)
+ sq.runSequence(5);
+ sq.runSequence(2);
+ sq.runSequence(2);
+ sq.fadeText();
+ sq.runSequence(6);
+
+ sq.printText(3, 15); // You have defeated Dran
+ for (int i = 0; i < 5; i++)
+ sq.runSequence(5);
+ sq.runSequence(2);
+ sq.runSequence(2);
+ sq.fadeText();
+
+ sq.printText(4, 15); // I did not know Dran was a dragon
+ for (int i = 0; i < 4; i++)
+ sq.runSequence(5);
+ sq.runSequence(2);
+ sq.runSequence(2);
+ sq.fadeText();
+
+ sq.printText(5, 15); // He must have been over 300 years old
+ for (int i = 0; i < 4; i++)
+ sq.runSequence(5);
+ sq.runSequence(2);
+ sq.runSequence(2);
+ sq.fadeText();
+
+ sq.printText(6, 15); // His power is gone
+ for (int i = 0; i < 3; i++)
+ sq.runSequence(5);
+ sq.runSequence(2);
+ sq.runSequence(2);
+ sq.fadeText();
+
+ sq.printText(7, 15); // But Darkmoon is still a source of great evil
+ for (int i = 0; i < 4; i++)
+ sq.runSequence(5);
+ sq.runSequence(2);
+ sq.runSequence(2);
+ sq.fadeText();
+
+ sq.printText(8, 15); // And many of his minions remain
+ for (int i = 0; i < 4; i++)
+ sq.runSequence(5);
+ sq.runSequence(2);
+ sq.runSequence(2);
+ sq.fadeText();
+
+ sq.loadScene(2, 2);
+ sq.update(2);
+ sq.loadScene(3, 2);
+ _screen->copyRegion(8, 8, 0, 0, 304, 128, 0, 2, Screen::CR_NO_P_CHECK);
+
+ sq.printText(9, 15); // Now we must leave this place
+ sq.runSequence(7);
+ sq.runSequence(8);
+ sq.runSequence(7);
+ sq.runSequence(7, 36);
+ sq.fadeText();
+
+ sq.printText(10, 15); // So my forces can destroy it..
+ for (int i = 0; i < 3; i++)
+ sq.runSequence(7);
+ sq.runSequence(8);
+ sq.runSequence(7);
+ sq.runSequence(7, 36);
+ sq.runSequence(8, 18);
+ sq.fadeText();
+
+ sq.printText(11, 15); // Follow me
+ sq.runSequence(7, 18);
+ sq.runSequence(9, 18);
+ sq.runSequence(8, 18);
+ sq.fadeText();
+
+ sq.loadScene(7, 2);
+ sq.copyPalette(3, 0);
+ sq.loadScene(4, 2);
+
+ sq.waitForSongNotifier(2);
+
+ _screen->clearCurPage();
+ sq.update(2);
+
+ sq.loadScene(8, 2);
+ sq.loadScene(6, 6);
+ sq.delay(10);
+
+ sq.printText(12, 10); // Powerful mages stand ready for the final assault...
+ sq.delay(90);
+ sq.fadeText();
+
+ sq.waitForSongNotifier(3);
+
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(7);
+ sq.delay(8);
+
+ sq.runSequence(10);
+ sq.runSequence(13);
+ sq.initDelayedPaletteFade(4, 1);
+
+ sq.runSequence(14);
+ sq.runSequence(13);
+ sq.runSequence(14);
+ sq.runSequence(14);
+ sq.runSequence(13);
+ sq.initDelayedPaletteFade(2, 1);
+
+ sq.runSequence(15);
+ sq.runSequence(14);
+ sq.runSequence(13);
+ sq.runSequence(15);
+ sq.runSequence(15);
+ sq.runSequence(11);
+
+ sq.printText(13, 10); // The temple's evil is very strong
+ sq.delay(72);
+ sq.fadeText();
+
+ sq.printText(14, 10); // It must not be allowed...
+ sq.delay(72);
+ sq.fadeText();
+
+ sq.waitForSongNotifier(4);
+
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(7);
+ sq.delay(8);
+
+ sq.runSequence(10);
+ sq.initDelayedPaletteFade(5, 1);
+ sq.runSequence(13);
+ sq.runSequence(14);
+ sq.runSequence(13);
+ sq.runSequence(14);
+ sq.runSequence(13);
+ sq.runSequence(13);
+ sq.runSequence(14);
+ sq.runSequence(14);
+ sq.runSequence(13);
+ sq.runSequence(12);
+ for (int i = 0; i < 4; i++)
+ sq.runSequence(16);
+ sq.runSequence(17);
+ sq.runSequence(18);
+
+ sq.printText(15, 10); // The temple ceases to exist
+ sq.initDelayedPaletteFade(6, 1);
+ sq.delay(36);
+
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(11);
+
+ sq.delay(54);
+ sq.fadeText();
+ sq.loadScene(12, 2);
+
+ sq.waitForSongNotifier(5);
+
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(6);
+
+ if (!skipFlag() && !shouldQuit())
+ _screen->crossFadeRegion(0, 0, 8, 8, 304, 128, 2, 0);
+ sq.delay(18);
+
+ sq.printText(16, 15); // My friends, our work is done
+ sq.runSequence(20);
+ sq.runSequence(19);
+ sq.runSequence(19, 36);
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(12);
+ sq.fadeText();
+
+ sq.printText(17, 15); // Thank you
+ sq.runSequence(19);
+ sq.runSequence(20, 36);
+ sq.fadeText();
+
+ sq.printText(18, 15); // You have earned my deepest respect
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(11);
+ sq.runSequence(20);
+ sq.runSequence(19);
+ sq.runSequence(19);
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(11);
+ sq.delay(36);
+ sq.fadeText();
+
+ sq.printText(19, 15); // We will remember you always
+ sq.runSequence(19);
+ sq.runSequence(19, 18);
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(11);
+ sq.runSequence(20, 18);
+ sq.fadeText();
+
+ sq.delay(28);
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(12);
+ sq.delay(3);
+
+ sq.loadScene(5, 2);
+ if (skipFlag() || shouldQuit()) {
+ _screen->copyRegion(0, 0, 8, 8, 304, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ _sound->playTrack(6);
+ _screen->crossFadeRegion(0, 0, 8, 8, 304, 128, 2, 0);
+ }
+
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(12);
+ sq.delay(5);
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(11);
+ sq.delay(11);
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(12);
+ sq.delay(7);
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(11);
+ sq.delay(12);
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(12);
+
+ removeInputTop();
+ resetSkipFlag(true);
+
+ sq.loadScene(10, 2);
+ sq.loadScene(9, 2);
+ _sound->playTrack(0);
+ sq.delay(3);
+
+ _sound->loadSoundFile("FINALE2");
+
+ sq.delay(18);
+ if (!skipFlag() && !shouldQuit())
+ _sound->playTrack(1);
+
+ seq_playCredits(&sq, _creditsData, 18, 2, 6, 2);
+
+ sq.delay(90);
+
+ resetSkipFlag(true);
+
+ sq.setPalette(11);
+ sq.fadePalette(9, 10);
+
+ _screen->clearCurPage();
+ sq.loadScene(11, 2);
+
+ static const uint8 finPortraitPos[] = { 0x50, 0x50, 0xD0, 0x50, 0x50, 0x90, 0xD0, 0x90, 0x90, 0x50, 0x90, 0x90 };
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ if (i > 3)
+ _screen->drawShape(2, sq._shapes[6 + i], finPortraitPos[i << 1] - 16, finPortraitPos[(i << 1) + 1] - 16, 0);
+ _screen->drawShape(2, _characters[i].faceShape, finPortraitPos[i << 1], finPortraitPos[(i << 1) + 1], 0);
+ }
+
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+
+ sq.setPalette(9);
+ sq.fadePalette(0, 18);
+
+ while (!skipFlag() && !shouldQuit())
+ delay(_tickLength);
+
+ _sound->playTrack(0);
+ sq.fadePalette(9, 10);
+}
+
+void DarkMoonEngine::seq_playCredits(DarkmoonSequenceHelper *sq, const uint8 *data, int sd, int backupPage, int tempPage, int speed) {
+ if (!data)
+ return;
+
+ _screen->setScreenDim(sd);
+ const ScreenDim *dm = _screen->_curDim;
+
+ _screen->copyRegion(dm->sx << 3, dm->sy, dm->sx << 3, dm->sy, dm->w << 3, dm->h, 0, backupPage, Screen::CR_NO_P_CHECK);
+
+ struct CreditsDataItem {
+ int16 x;
+ int16 y;
+ const void *data;
+ char *str;
+ uint8 crlf;
+ uint8 size;
+ uint8 dataType;
+ } items[36];
+ memset(items, 0, sizeof(items));
+
+ const char *pos = (const char *)data;
+ uint32 end = _system->getMillis();
+ uint32 cur = 0;
+ int i = 0;
+
+ do {
+ for (bool loop = true; loop; ) {
+ sq->processDelayedPaletteFade();
+ cur = _system->getMillis();
+ if (end <= cur)
+ break;
+ delay(MIN<uint32>(_tickLength, end - cur));
+ }
+
+ end = _system->getMillis() + speed * _tickLength;
+
+ for (; i < 35 && *pos; i++) {
+ int16 nextY = i ? items[i].y + items[i].size + (items[i].size >> 2) : dm->h;
+
+ const char *posOld = pos;
+ pos = strchr(pos, 0x0d);
+ if (!pos)
+ pos = strchr(posOld, 0x00);
+
+ items[i + 1].crlf = *pos++;
+
+ if (*posOld == 2) {
+ const uint8 *shp = sq->_shapes[(*++posOld) - 1];
+ items[i + 1].data = shp;
+ items[i + 1].size = shp[1];
+ items[i + 1].x = (dm->w - shp[2]) << 2 ;
+ items[i + 1].dataType = 1;
+ delete[] items[i + 1].str;
+ items[i + 1].str = 0;
+
+ } else {
+ if (*posOld == 1) {
+ posOld++;
+ items[i + 1].size = 6;
+ } else {
+ items[i + 1].size = _screen->getFontWidth();
+ }
+
+ items[i + 1].dataType = 0;
+
+ int l = pos - posOld;
+ if (items[i + 1].crlf != 0x0d)
+ l++;
+
+ delete[] items[i + 1].str;
+ items[i + 1].str = new char[l];
+ memcpy(items[i + 1].str, posOld, l);
+ items[i + 1].str[l - 1] = 0;
+ items[i + 1].data = 0;
+ items[i + 1].x = (((dm->w << 3) - (strlen(items[i + 1].str) * items[i + 1].size)) >> 1) + 1;
+ }
+
+ items[i + 1].y = nextY;
+ }
+
+ _screen->copyRegion(dm->sx << 3, dm->sy, dm->sx << 3, dm->sy, dm->w << 3, dm->h, backupPage, tempPage, Screen::CR_NO_P_CHECK);
+
+ for (int h = 0; h < i; h++) {
+ if (items[h + 1].y < dm->h) {
+ if (items[h + 1].dataType == 1) {
+ _screen->drawShape(tempPage, (const uint8*)items[h + 1].data, items[h + 1].x, items[h + 1].y, sd);
+ } else {
+ _screen->setCurPage(tempPage);
+
+ if (items[h + 1].size == 6)
+ _screen->setFont(Screen::FID_6_FNT);
+
+ _screen->printText(items[h + 1].str, (dm->sx << 3) + items[h + 1].x - 1, dm->sy + items[h + 1].y + 1, 12, 0);
+ _screen->printText(items[h + 1].str, (dm->sx << 3) + items[h + 1].x, dm->sy + items[h + 1].y, 240, 0);
+
+ if (items[h + 1].size == 6)
+ _screen->setFont(Screen::FID_8_FNT);
+
+ _screen->setCurPage(0);
+ }
+ }
+
+ items[h + 1].y -= 2;
+ }
+
+ _screen->copyRegion(dm->sx << 3, dm->sy, dm->sx << 3, dm->sy, dm->w << 3, dm->h, tempPage, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ if (-items[1].size > items[1].y) {
+ delete[] items[1].str;
+ --i;
+ for (int t = 1; t <= i; t++)
+ memcpy(&items[t], &items[t + 1], sizeof(CreditsDataItem));
+ items[i + 1].str = 0;
+ }
+
+ if (i < 35 && ((items[i].y + items[i].size) < (dm->sy + dm->h))) {
+ resetSkipFlag(true);
+ break;
+ }
+
+ sq->processDelayedPaletteFade();
+ } while (!skipFlag() && i && !shouldQuit());
+
+ for (i = 0; i < 35; i++)
+ delete[] items[i].str;
+}
+
+DarkmoonSequenceHelper::DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_Eob *screen, Mode mode, const char *const *strings, const char *const *cpsFiles, const char *const *palFiles, const EobShapeDef **shapeDefList, const EobSequenceStep **seqList) :
+ _system(system), _vm(vm), _screen(screen), _mode(mode), _strings(strings), _cpsFiles(cpsFiles), _palFiles(palFiles), _shapeDefs(shapeDefList), _seqData(seqList) {
+
+ for (int i = 0; _palFiles[i]; i++) {
+ if (i < 4)
+ _palettes[i] = &_screen->getPalette(i);
+ else
+ _palettes[i] = new Palette(256);
+ _screen->loadPalette(_palFiles[i], *_palettes[i]);
+ }
+
+ _palettes[9] = new Palette(256);
+ _palettes[9]->fill(0, 256, 0);
+ _palettes[10] = new Palette(256);
+ _palettes[10]->fill(0, 256, 63);
+ _palettes[11] = new Palette(256);
+ _palettes[11]->fill(0, 256, 0);
+
+ _shapes = new const uint8*[30];
+ memset(_shapes, 0, 30 * sizeof(uint8*));
+
+ _fadePalTimer = 0;
+ _fadePalRate = 0;
+
+ _screen->setScreenPalette(*_palettes[0]);
+ _screen->hideMouse();
+
+ _system->delayMillis(150);
+ _vm->resetSkipFlag(true);
+}
+
+DarkmoonSequenceHelper::~DarkmoonSequenceHelper() {
+ for (int i = 4; _palFiles[i]; i++)
+ delete _palettes[i];
+ delete _palettes[9];
+ delete _palettes[10];
+ delete _palettes[11];
+
+ for (int i = 0; i < 30; i++)
+ delete _shapes[i];
+ delete[] _shapes;
+
+ _screen->clearCurPage();
+ _screen->showMouse();
+ _screen->updateScreen();
+
+ _system->delayMillis(150);
+ _vm->resetSkipFlag(true);
+}
+
+void DarkmoonSequenceHelper::loadScene(int index, int pageNum) {
+ char file[13];
+ strcpy(file, _cpsFiles[index]);
+
+ Common::SeekableReadStream *s = _vm->resource()->createReadStream(file);
+ if (s && file[0] != 'X') {
+ delete s;
+ _screen->loadBitmap(_cpsFiles[index], pageNum | 1, pageNum | 1, _palettes[0]);
+ } else {
+ if (!s) {
+ file[0] = 'X';
+ s = _vm->resource()->createReadStream(file);
+ }
+
+ if (!s)
+ error("DarkmoonSequenceHelper::loadScene(): Sequence CPS file loading failed.");
+
+ if (_mode == kFinale)
+ s->read(_palettes[0]->getData(), 768);
+ else
+ s->seek(768);
+ _screen->loadFileDataToPage(s, 3, 64000);
+ delete s;
+ }
+
+ int cp = _screen->setCurPage(pageNum);
+
+ if (_shapeDefs[index]) {
+ for (const EobShapeDef *df = _shapeDefs[index]; df->w; df++ ) {
+ uint16 shapeIndex = (df->index < 0) ? df->index * -1 : df->index;
+ if (_shapes[shapeIndex])
+ delete[] _shapes[shapeIndex];
+ _shapes[shapeIndex] = _screen->encodeShape(df->x, df->y, df->w, df->h, (df->index >> 8) != 0);
+ }
+ }
+
+ _screen->setCurPage(cp);
+ _screen->copyPage(pageNum | 1, pageNum);
+
+ if ((pageNum == 0 || pageNum == 1) && !_vm->skipFlag() && !_vm->shouldQuit())
+ _screen->updateScreen();
+}
+
+void DarkmoonSequenceHelper::runSequence(int index, int del) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ uint32 end = 0;
+
+ for (const EobSequenceStep *s = _seqData[index]; s->command != 0xff && !_vm->skipFlag() && !_vm->shouldQuit(); s++) {
+ int palIndex = _mode == kFinale ? (s->pal + 1) : s->pal;
+ int x = s->x1;
+ int y = s->y1;
+ int x2 = 0;
+ uint16 shapeW = 0;
+ uint16 shapeH = 0;
+
+ switch(s->command) {
+ case 0:
+ // flash palette
+ if (s->pal)
+ setPaletteWithoutTextColor(palIndex);
+ delay(s->delay);
+ if (_mode == DarkmoonSequenceHelper::kIntro && s->pal)
+ setPaletteWithoutTextColor(0);
+ break;
+
+ case 1:
+ // draw shape, then restore beackground
+ shapeW = _shapes[s->obj][2];
+ shapeH = _shapes[s->obj][3];
+
+ if (_mode == DarkmoonSequenceHelper::kFinale) {
+ _screen->setScreenDim(18);
+ x -= (_screen->_curDim->sx << 3);
+ y -= _screen->_curDim->sy;
+ if (x < 0)
+ shapeW -= ((-x >> 3) + 1);
+ else
+ x2 = x;
+ }
+
+ _screen->drawShape(0, _shapes[s->obj], x, y, _mode == DarkmoonSequenceHelper::kIntro ? 0 : 18);
+
+ if (s->pal)
+ setPaletteWithoutTextColor(palIndex);
+ else
+ _screen->updateScreen();
+
+ delay(s->delay);
+
+ if (_mode == DarkmoonSequenceHelper::kIntro) {
+ if (s->pal)
+ setPaletteWithoutTextColor(0);
+ _screen->copyRegion(x - 8, y - 8, x, y, (shapeW + 1) << 3, shapeH, 2, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ _screen->copyRegion(x2, y, x2 + (_screen->_curDim->sx << 3), y + _screen->_curDim->sy, (shapeW + 1) << 3, shapeH, 2, 0, Screen::CR_NO_P_CHECK);
+ }
+
+ _screen->updateScreen();
+ break;
+
+ case 2:
+ // draw shape
+ _screen->drawShape(_screen->_curPage, _shapes[s->obj], x, y, 0);
+
+ if (s->pal)
+ setPaletteWithoutTextColor(palIndex);
+ else if(!_screen->_curPage)
+ _screen->updateScreen();
+
+ delay(s->delay);
+
+ if (_mode == DarkmoonSequenceHelper::kIntro && s->pal)
+ setPaletteWithoutTextColor(0);
+ break;
+
+ case 3:
+ case 4:
+ // fade shape in or out or restore background
+ if (_mode == DarkmoonSequenceHelper::kFinale)
+ break;
+
+ _screen->setShapeFadeMode(0, true);
+ _screen->setShapeFadeMode(1, true);
+
+ end = _system->getMillis() + s->delay * _vm->tickLength();
+
+ if (palIndex) {
+ _screen->setFadeTableIndex(palIndex - 1);
+
+ _screen->copyRegion(s->x1 - 8, s->y1 - 8, 0, 0, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 4, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(4, _shapes[s->obj], s->x1 & 7, 0, 0);
+ _screen->copyRegion(0, 0, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 4, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ _screen->copyRegion(s->x1 - 8, s->y1 - 8, s->x1, s->y1, (_shapes[s->obj][2] + 1) << 3, _shapes[s->obj][3], 2, 0, Screen::CR_NO_P_CHECK);
+ }
+ _screen->updateScreen();
+
+ _vm->delayUntil(end);
+ _screen->setShapeFadeMode(0, false);
+ _screen->setShapeFadeMode(1, false);
+ break;
+
+ case 5:
+ // copyregion
+ if (_mode == DarkmoonSequenceHelper::kFinale && s->pal)
+ setPaletteWithoutTextColor(palIndex);
+
+ _screen->copyRegion(s->x2 << 3, s->y2, s->x1, s->y1, s->w << 3, s->h, (s->obj && _mode == DarkmoonSequenceHelper::kFinale) ? 6 : 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ delay(s->delay);
+ break;
+
+ case 6:
+ // play sound effect
+ if (s->obj != 0xff)
+ _vm->sound()->playSoundEffect(s->obj);
+ break;
+
+ default:
+ error("DarkmoonSequenceHelper::runSequence(): Unknown animation opcode encountered.");
+ break;
+ }
+ }
+
+ if (del > 0)
+ delay(del);
+}
+
+void DarkmoonSequenceHelper::printText(int index, int color) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ _screen->setClearScreenDim(17);
+ _palettes[0]->copy(*_palettes[0], color, 1, 255);
+ setPalette(0);
+
+ char *temp = new char[strlen(_strings[index]) + 1];
+ char *str = temp;
+ strcpy(str, _strings[index]);
+
+ const ScreenDim *dm = _screen->_curDim;
+
+ for (int yOffs = 0; *str; yOffs += 9) {
+ char *cr = strchr(str, 13);
+
+ if (cr)
+ *cr = 0;
+
+ uint32 len = strlen(str);
+ _screen->printText(str, (dm->sx + ((dm->w - len) >> 1)) << 3, dm->sy + yOffs, 255, dm->unkA);
+
+ if (cr) {
+ *cr = 13;
+ str = cr + 1;
+ } else {
+ str += len;
+ }
+ }
+
+ delete[] temp;
+ _screen->updateScreen();
+}
+
+void DarkmoonSequenceHelper::fadeText() {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ _screen->fadeTextColor(_palettes[0], 255, 2);
+ _screen->clearCurDim();
+}
+
+void DarkmoonSequenceHelper::update(int srcPage) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ _screen->copyRegion(0, 0, 8, 8, 304, 128, srcPage, 0, Screen::CR_NO_P_CHECK);
+ setPaletteWithoutTextColor(0);
+}
+
+void DarkmoonSequenceHelper::setPaletteWithoutTextColor(int index) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ if (!memcmp(_palettes[11]->getData(), _palettes[index]->getData(), 765))
+ return;
+
+ _palettes[11]->copy(*_palettes[index], 0, 255);
+ _palettes[11]->copy(*_palettes[0], 255, 1, 255);
+ setPalette(11);
+
+ _screen->updateScreen();
+}
+
+void DarkmoonSequenceHelper::setPalette(int index) {
+ _screen->setScreenPalette(*_palettes[index]);
+}
+
+void DarkmoonSequenceHelper::fadePalette(int index, int del) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ _screen->fadePalette(*_palettes[index], del * _vm->tickLength());
+}
+
+void DarkmoonSequenceHelper::copyPalette(int srcIndex, int destIndex) {
+ _palettes[destIndex]->copy(*_palettes[srcIndex]);
+}
+
+void DarkmoonSequenceHelper::initDelayedPaletteFade(int palIndex, int rate) {
+ _palettes[11]->copy(*_palettes[0]);
+
+ _fadePalIndex = palIndex;
+ _fadePalRate = rate;
+ _fadePalTimer = _system->getMillis() + 2 * _vm->_tickLength;
+}
+
+bool DarkmoonSequenceHelper::processDelayedPaletteFade() {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return true;
+
+ if (!_fadePalRate || (_system->getMillis() <= _fadePalTimer))
+ return false;
+
+ if (_screen->delayedFadePalStep(_palettes[_fadePalIndex], _palettes[0], _fadePalRate)) {
+ setPaletteWithoutTextColor(0);
+ _fadePalTimer = _system->getMillis() + 3 * _vm->_tickLength;
+ } else {
+ _fadePalRate = 0;
+ }
+
+ return false;
+}
+
+void DarkmoonSequenceHelper::delay(uint32 ticks) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ uint32 end = _system->getMillis() + ticks * _vm->_tickLength;
+
+ if (_mode == kFinale) {
+ do {
+ if (processDelayedPaletteFade())
+ break;
+ _vm->updateInput();
+ } while (end > _system->getMillis());
+ processDelayedPaletteFade();
+
+ } else {
+ _vm->delayUntil(end);
+ }
+}
+
+void DarkmoonSequenceHelper::waitForSongNotifier(int index, bool introUpdateAnim) {
+ int seq = 0;
+ while (_notifier < index && !(_vm->skipFlag() || _vm->shouldQuit())) {
+ if (introUpdateAnim) {
+ runSequence(30 | seq);
+ seq ^= 1;
+ }
+
+ if (_mode == kFinale)
+ processDelayedPaletteFade();
+
+ _vm->updateInput();
+ }
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index 9325513066..73c20ee6df 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -266,7 +266,7 @@ void KyraEngine_v1::snd_playTheme(int file, int track) {
}
void KyraEngine_v1::snd_playSoundEffect(int track, int volume) {
- _sound->playSoundEffect(track);
+ _sound->playSoundEffect(track, volume);
}
void KyraEngine_v1::snd_playWanderScoreViaMap(int command, int restart) {
diff --git a/engines/kyra/sound_lol.cpp b/engines/kyra/sound_lol.cpp
index 968488eef3..6bf047fe35 100644
--- a/engines/kyra/sound_lol.cpp
+++ b/engines/kyra/sound_lol.cpp
@@ -197,24 +197,9 @@ void LoLEngine::snd_playSoundEffect(int track, int volume) {
}
}
-void LoLEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) {
- if (!_sound->sfxEnabled() || shouldQuit())
- return;
-
- if (_environmentSfx)
- snd_playSoundEffect(_environmentSfx, _environmentSfxVol);
-
- int dist = 0;
- if (block) {
- dist = getMonsterDistance(_currentBlock, block);
- if (dist > _envSfxDistThreshold) {
- _environmentSfx = 0;
- return;
- }
- }
-
- _environmentSfx = soundId;
- _environmentSfxVol = (15 - ((block || dist < 2) ? dist : 0)) << 4;
+bool LoLEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) {
+ if (!LolEobBaseEngine::snd_processEnvironmentalSoundEffect(soundId, block))
+ return false;
if (block != _currentBlock) {
static const int8 blockShiftTable[] = { -32, -31, 1, 33, 32, 31, -1, -33 };
@@ -231,9 +216,9 @@ void LoLEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) {
}
if (!soundId || _sceneUpdateRequired)
- return;
+ return false;
- snd_processEnvironmentalSoundEffect(0, 0);
+ return snd_processEnvironmentalSoundEffect(0, 0);
}
void LoLEngine::snd_queueEnvironmentalSoundEffect(int soundId, int block) {
diff --git a/engines/kyra/sprites_eob.cpp b/engines/kyra/sprites_eob.cpp
new file mode 100644
index 0000000000..aac3c274db
--- /dev/null
+++ b/engines/kyra/sprites_eob.cpp
@@ -0,0 +1,1249 @@
+/* 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.
+ *
+ */
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#include "kyra/eobcommon.h"
+#include "kyra/script_eob.h"
+#include "kyra/resource.h"
+#include "kyra/timer.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+int LolEobBaseEngine::getBlockDistance(uint16 block1, uint16 block2) {
+ int b1x = block1 & 0x1f;
+ int b1y = block1 >> 5;
+ int b2x = block2 & 0x1f;
+ int b2y = block2 >> 5;
+
+ uint8 dy = ABS(b2y - b1y);
+ uint8 dx = ABS(b2x - b1x);
+
+ if (dx > dy)
+ SWAP(dx, dy);
+
+ return (dx >> 1) + dy;
+}
+
+} // namespace Kyra
+
+#endif
+#ifdef ENABLE_EOB
+
+namespace Kyra {
+
+void EobCoreEngine::loadMonsterShapes(const char *filename, int monsterIndex, bool hasDecorations, int encodeTableIndex) {
+ _screen->loadEobBitmap(filename, 3, 3);
+ const uint16 *enc = &_encodeMonsterShpTable[encodeTableIndex << 2];
+
+ for (int i = 0; i < 6; i++, enc += 4)
+ _monsterShapes[monsterIndex + i] = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3]);
+
+ generateMonsterPalettes(filename, monsterIndex);
+
+ if (hasDecorations)
+ loadMonsterDecoration(filename, monsterIndex);
+
+ _screen->_curPage = 0;
+}
+
+void EobCoreEngine::releaseMonsterShapes(int first, int num) {
+ for (int i = first; i < first + num; i++) {
+ delete[] _monsterShapes[i];
+ _monsterShapes[i] = 0;
+ delete[] _monsterDecorations[i].shp;
+ _monsterDecorations[i].shp = 0;
+ }
+}
+
+const uint8 *EobCoreEngine::loadMonsterProperties(const uint8 *data) {
+ uint8 cmd = *data++;
+ while (cmd != 0xff) {
+ EobMonsterProperty *d = &_monsterProps[cmd];
+ d->armorClass = (int8)*data++;
+ d->hitChance = (int8)*data++;
+ d->level = *data++;
+ d->hpDcTimes = *data++;
+ d->hpDcPips = *data++;
+ d->hpDcBase = *data++;
+ d->attacksPerRound = *data++;
+ d->dmgDc[0].times = *data++;
+ d->dmgDc[0].pips = *data++;
+ d->dmgDc[0].base = (int8)*data++;
+ d->dmgDc[1].times = *data++;
+ d->dmgDc[1].pips = *data++;
+ d->dmgDc[1].base = (int8)*data++;
+ d->dmgDc[2].times = *data++;
+ d->dmgDc[2].pips = *data++;
+ d->dmgDc[3].base = (int8)*data++;
+ d->statusFlags = READ_LE_UINT16(data);
+ data += 2;
+ d->flags = READ_LE_UINT16(data);
+ data += 2;
+ d->u22 = (int16)READ_LE_UINT16(data);
+ data += 2;
+ d->experience = READ_LE_UINT16(data);
+ data += 2;
+
+ d->u30 = *data++;
+ d->sound1 = *data++;
+ d->sound2 = *data++;
+ d->numRemoteAttacks = *data++;
+
+ if (*data++ != 0xff) {
+ d->remoteWeaponChangeMode = *data++;
+ d->numRemoteWeapons = *data++;
+
+ for (int i = 0; i < d->numRemoteWeapons; i++) {
+ d->remoteWeapons[i] = (int8)*data;
+ data += 2;
+ }
+ }
+
+ d->u41 = *data++;
+ d->dmgModifierEvade = *data++;
+
+ for (int i = 0; i < 3; i++)
+ d->decorations[i] = *data++;
+
+ cmd = *data++;
+ }
+
+ return data;
+}
+
+const uint8 *EobCoreEngine::loadActiveMonsterData(const uint8 *data, int level) {
+ for (uint8 p = *data++; p != 0xff; p = *data++) {
+ uint8 v = *data++;
+ _timer->setCountdown(0x20 + (p << 1), v);
+ _timer->setCountdown(0x21 + (p << 1), v);
+ }
+
+ if (_hasTempDataFlags & (1 << (level - 1)))
+ return data + 420;
+
+ memset(_monsters, 0, 30 * sizeof(EobMonsterInPlay));
+
+ for (int i = 0; i < 30; i++, data += 14) {
+ if (*data == 0xff)
+ continue;
+
+ initMonster(data[0], data[1], READ_LE_UINT16(&data[2]), data[4], (int8)data[5], data[6], data[7], data[8], data[9], READ_LE_UINT16(&data[10]), READ_LE_UINT16(&data[12]));
+ _monsters[data[0]].flags |= 0x40;
+ }
+
+ return data;
+}
+
+void EobCoreEngine::initMonster(int index, int unit, uint16 block, int pos, int dir, int type, int shpIndex, int mode, int i, int randItem, int fixedItem) {
+ EobMonsterInPlay *m = &_monsters[index];
+ EobMonsterProperty *p = &_monsterProps[type];
+ memset(m, 0, sizeof(EobMonsterInPlay));
+
+ if (!block)
+ return;
+
+ unit <<= 1;
+ if (index & 1)
+ unit++;
+
+ m->stepsTillRemoteAttack = _flags.gameID == GI_EOB2 ? rollDice(1, 3, 0) : 0;
+ m->type = type;
+ m->numRemoteAttacks = p->numRemoteAttacks;
+ m->curRemoteWeapon = 0;
+ m->unit = unit;
+ m->pos = pos;
+ m->shpIndex = shpIndex;
+ m->mode = mode;
+ m->f_b = i;
+ m->dir = dir;
+ m->palette = _flags.gameID == GI_EOB2 ? (index % 3) : 0;
+ m->hitPointsCur = m->hitPointsMax = _flags.gameID == GI_EOB2 ? rollDice(p->hpDcTimes, p->hpDcPips, p->hpDcBase) : (p->hpDcTimes == 255 ? rollDice(1, 4, 0) : rollDice(p->hpDcTimes, 8, 0));
+ m->randItem = randItem;
+ m->fixedItem = fixedItem;
+ m->sub = _currentSub;
+
+ placeMonster(m, block, dir);
+}
+
+void EobCoreEngine::placeMonster(EobMonsterInPlay *m, uint16 block, int dir) {
+ if (block != 0xffff){
+ checkSceneUpdateNeed(m->block);
+ if (_levelBlockProperties[m->block].flags & 7) {
+ _levelBlockProperties[m->block].flags--;
+ if (_flags.gameID == GI_EOB2)
+ runLevelScript(m->block, 0x400);
+ }
+ m->block = block;
+ _levelBlockProperties[block].flags++;
+ if (_flags.gameID == GI_EOB2)
+ runLevelScript(m->block, 0x200);
+ }
+
+ if (dir != -1) {
+ m->dir = dir;
+ block = m->block;
+ }
+
+ checkSceneUpdateNeed(block);
+}
+
+void EobCoreEngine::killMonster(EobMonsterInPlay *m, bool giveExperience) {
+ m->hitPointsCur = -1;
+ int pos = (m->pos == 4) ? rollDice(1, 4, -1) : m->pos;
+
+ if (m->randItem) {
+ if (rollDice(1, 10, 0) == 1)
+ setItemPosition((Item*)&_levelBlockProperties[m->block & 0x3ff].drawObjects, m->block, duplicateItem(m->randItem), pos);
+ }
+
+ if (m->fixedItem)
+ setItemPosition((Item*)&_levelBlockProperties[m->block & 0x3ff].drawObjects, m->block, duplicateItem(m->fixedItem), pos);
+
+ if (giveExperience)
+ increasePartyExperience(_monsterProps[m->type].experience);
+
+ if ((_flags.gameID == GI_EOB2) && (_currentLevel == 16) && (_currentSub == 1) && (_monsterProps[m->type].flags & 4)) {
+ if (m->type) {
+ _playFinale = true;
+ _runFlag = false;
+ } else {
+ m->hitPointsCur = 150;
+ m->curRemoteWeapon = 0;
+ m->numRemoteAttacks = 255;
+ m->shpIndex++;
+ m->type++;
+ //// TODO
+ // dranDragonTransformation();
+ }
+ } else {
+ placeMonster(m, 0, -1);
+
+ if ((_flags.gameID == GI_EOB1) && (m->type == 21)) {
+ _playFinale = true;
+ _runFlag = false;
+ }
+
+ if (m->mode == 8)
+ updateAttackingMonsterFlags();
+ }
+}
+
+int EobCoreEngine::countSpecificMonsters(int type) {
+ int res = 0;
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].type != type || _monsters[i].sub != _currentSub || _monsters[i].hitPointsCur < 0)
+ continue;
+ res++;
+ }
+ return res;
+}
+
+void EobCoreEngine::updateAttackingMonsterFlags() {
+ EobMonsterInPlay *m2 = 0;
+ for (EobMonsterInPlay *m = _monsters; m < &_monsters[30]; m++) {
+ if (m->mode != 8)
+ continue;
+ m->mode = 0;
+ m->dest = _currentBlock;
+ m2 = m;
+ }
+
+ if (m2->type == 7)
+ _inf->setFlag(4);
+
+ if (m2->type == 12)
+ _inf->setFlag(0x800);
+}
+
+const int8 *EobCoreEngine::getMonsterBlockPositions(uint16 block) {
+ static int8 pos[6];
+ memset(pos, -1, sizeof(pos));
+ for (int8 i = 0; i < 30; i++) {
+ if (_monsters[i].block != block)
+ continue;
+ pos[_monsters[i].pos] = i;
+ }
+ return pos;
+}
+
+int EobCoreEngine::getClosestMonsterPos(int charIndex, int block) {
+ const int8 *pos = getMonsterBlockPositions(block);
+ if (pos[4] != -1)
+ return pos[4];
+
+ const uint8 *p = &_monsterProximityTable[(_currentDirection << 3) + ((charIndex & 1) << 2)];
+ for (int i = 0; i < 4; i++) {
+ if (pos[p[i]] != -1)
+ return pos[p[i]];
+ }
+ return -1;
+}
+
+bool EobCoreEngine::blockHasMonsters(uint16 block) {
+ return _levelBlockProperties[block].flags & 7 ? true : false;
+}
+
+bool EobCoreEngine::isMonsterOnPos(EobMonsterInPlay *m, uint16 block, int pos, int checkPos4) {
+ return (m->block == block && (m->pos == pos || (m->pos == 4 && checkPos4))) ? true : false;
+}
+
+const int16 *EobCoreEngine::findBlockMonsters(uint16 block, int pos, int dir, int blockDamage, int singleTargetCheckAdjacent) {
+ static const uint8 cpos4[] = { 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1 };
+ int checkPos4 = (pos <= 4) ? cpos4[(dir << 2) + pos] : 1;
+ int16 *dst = _foundMonstersArray;
+
+ if (blockDamage) {
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].block == block && (_monsters[i].pos != 4 || checkPos4))
+ *dst++ = i;
+ }
+
+ } else if (singleTargetCheckAdjacent) {
+ int16 r = -1;
+ int f = 5;
+
+ for (int i = 0; i < 30; i++) {
+ const uint8 *tbl = &_findBlockMonstersTable[(dir << 4) + (pos << 2)];
+
+ if (_monsters[i].block != block)
+ continue;
+
+ if (_monsters[i].pos == pos) {
+ r = i;
+ break;
+ }
+
+ for (int ii = 0; ii < 4; ii++) {
+ if (_monsters[i].pos == tbl[ii] && ii < f) {
+ f = ii;
+ r = i;
+ }
+ }
+ }
+
+ *dst++ = r;
+
+ } else {
+ for (int i = 0; i < 30; i++) {
+ if (isMonsterOnPos(&_monsters[i], block, pos, checkPos4))
+ *dst++ = i;
+ }
+ }
+
+ *dst = -1;
+ return _foundMonstersArray;
+}
+
+void EobCoreEngine::drawBlockObject(int flipped, int page, const uint8 *shape, int x, int y, int sd, uint8 *ovl) {
+ const ScreenDim *d = _screen->getScreenDim(sd);
+ _screen->drawShape(page, shape, x - (d->sx << 3), y - d->sy, sd, flipped | (ovl ? 2 : 0), ovl);
+}
+
+void EobCoreEngine::drawMonsterShape(const uint8 *shape, int x, int y, int flipped, int flags, int palIndex) {
+ uint8 *ovl = 0;
+
+ if (flags & 2)
+ ovl = _monsterOvl1;
+ else if (_flags.gameID == GI_EOB2 && flags & 0x20)
+ ovl = _monsterOvl2;
+ else if (palIndex != -1)
+ ovl = _monsterPalettes[palIndex];
+
+ drawBlockObject(flipped, 2, shape, x, y, 5, ovl);
+}
+
+void EobCoreEngine::flashMonsterShape(EobMonsterInPlay *m) {
+ disableSysTimer(2);
+ _flashShapeTimer = 0;
+ drawScene(1);
+ m->flags &= 0xfd;
+ _flashShapeTimer = _system->getMillis() + _tickLength;
+ enableSysTimer(2);
+
+ _sceneUpdateRequired = true;
+}
+
+void EobCoreEngine::updateAllMonsterShapes() {
+ drawScene(1);
+ bool update = false;
+
+ for (EobMonsterInPlay *m = _monsters; m < &_monsters[30]; m++) {
+ if (m->flags & 2) {
+ m->flags &= ~2;
+ update = true;
+ if (m->hitPointsCur <= 0)
+ killMonster(m, true);
+ }
+ }
+
+ if (update) {
+ _sceneUpdateRequired = true;
+ _flashShapeTimer = _system->getMillis() + _tickLength;
+ } else {
+ _sceneUpdateRequired = false;
+ }
+ _inflictMonsterDamageUnk = 0;
+}
+
+void EobCoreEngine::drawBlockItems(int index) {
+ uint16 o = _visibleBlocks[index]->drawObjects;
+ uint8 w = _visibleBlocks[index]->walls[_sceneDrawVarDown];
+ uint8 flg = (index == 16) ? 0x80 : _wllWallFlags[w];
+
+ if (_wllVmpMap[w] && !(flg & 0x80))
+ return;
+
+ uint16 o2 = o = _items[o].next;
+ bool forceLoop = true;
+ static const int8 itemPosYNiche[] = { 0x25, 0x31, 0x38, 0x00 };
+ static const int8 itemPosFin[] = { 0, -2, 1, -1, 2, 0, 1, -1 };
+ int tile2 = 0;
+
+ while (o != o2 || forceLoop) {
+ EobItem *itm = &_items[o];
+ if (itm->pos == 8 || itm->pos < 4) {
+ tile2 = -1;
+
+ uint8 ps = (itm->pos == 8) ? 4 : _dscItemPosIndex[(_currentDirection << 2) + (itm->pos & 3)];
+ uint16 wo = (index * 5 + ps) << 1;
+ int x = _dscShapeCoords[wo] + 88;
+ int y = 0;
+
+ if (itm->pos == 8) {
+ x = _dscItemShpX[index];
+ y = itemPosYNiche[_dscDimMap[index]];
+ ps = 0;
+ } else {
+ y = _dscShapeCoords[wo + 1] + 124;
+ }
+
+ int8 scaleSteps = (int8)_dscItemScaleIndex[(_dscDimMap[index] << 2) + ps];
+ if (flg & 8 && ps < 2 && scaleSteps) {
+ tile2 = _dscItemTileIndex[index];
+ if (tile2 != -1)
+ setLevelShapesDim(tile2, _shpDmX1, _shpDmX2, 5);
+ y -= 4;
+ }
+
+ if (scaleSteps >= 0) {
+ const uint8 *shp = _screen->scaleShape(_dscItemShapeMap[itm->icon] < _numLargeItemShapes ? _largeItemShapes[_dscItemShapeMap[itm->icon]] : (_dscItemShapeMap[itm->icon] < 15 ? 0 : _smallItemShapes[_dscItemShapeMap[itm->icon] - 15]), scaleSteps);
+ x = x + itemPosFin[o & 7] - (shp[2] << 2);
+ y -= shp[1];
+
+ if (itm->pos != 8)
+ y += itemPosFin[(o >> 1) & 7];
+
+ drawBlockObject(0, 2, shp, x, y, 5);
+ _screen->setShapeFadeMode(1, false);
+ }
+ }
+
+ o = itm->next;
+ forceLoop = false;
+ if(tile2 != -1)
+ setLevelShapesDim(index, _shpDmX1, _shpDmX2, 5);
+ }
+}
+
+void EobCoreEngine::drawDoor(int index) {
+ int s = _visibleBlocks[index]->walls[_sceneDrawVarDown];
+ int type = _dscDoorShpIndex[s];
+ int d = _dscDimMap[index];
+ int w = _dscShapeCoords[(index * 5 + 4) << 1];
+
+ int x = 88 + w;
+ int y = 0;
+
+ int16 y1 = 0;
+ int16 y2 = 0;
+ scaleLevelShapesDim(index, y1, y2, 5);
+ drawDoorIntern(type, index, x, y, w, s, d, y1, y2);
+ drawLevelModifyScreenDim(5, _shpDmX1, 0, _shpDmX2, 15);
+}
+
+void EobCoreEngine::drawMonsters(int index) {
+ static const uint8 distMap[] = { 2, 1, 0, 4 };
+ static const uint8 yAdd[] = { 20, 12, 4, 4, 2, 0, 0 };
+
+ int blockDistance = distMap[_dscDimMap[index]];
+
+ uint16 bl = _visibleBlockIndex[index];
+ if (!bl)
+ return;
+
+ int drawObjDirIndex = _currentDirection * 5;
+ int cDirOffs = _currentDirection << 2;
+
+ EobMonsterInPlay *drawObj[5];
+ memset(drawObj, 0, 5 * sizeof(EobMonsterInPlay*));
+
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].block != bl)
+ continue;
+ drawObj[_drawObjPosIndex[drawObjDirIndex + _monsters[i].pos]] = &_monsters[i];
+ }
+
+ for (int i = 0; i < 5; i++) {
+ EobMonsterInPlay *d = drawObj[i];
+ if (!d)
+ continue;
+
+ EobMonsterProperty *p = &_monsterProps[d->type];
+
+ if (_flags.gameID == GI_EOB2 && (p->flags & 0x100) && !(_partyEffectFlags & 0x220) && !(d->flags & 2))
+ continue;
+
+ int f = (d->animStep << 4) + cDirOffs + d->dir;
+ f = (p->flags & 2) ? _monsterFrmOffsTable1[f] : _monsterFrmOffsTable2[f];
+
+ if (!blockDistance && d->curAttackFrame < 0)
+ f = d->curAttackFrame + 7;
+
+ int subFrame = ABS(f);
+ int shpIndex = d->shpIndex ? 18 : 0;
+ int palIndex = d->palette ? ((((shpIndex == 18) ? subFrame + 5 : subFrame - 1) << 1) + (d->palette - 1)) : -1;
+
+ const uint8 *shp = _screen->scaleShape(_monsterShapes[subFrame + shpIndex - 1], blockDistance);
+
+ int v30 = (subFrame == 1 || subFrame > 3) ? 1 : 0;
+ int v1e = (d->pos == 4) ? 4 : _dscItemPosIndex[cDirOffs + d->pos];
+ int posIndex = (index * 5 + v1e) << 1;
+
+ int x = _dscShapeCoords[posIndex] + 88;
+ int y = _dscShapeCoords[posIndex + 1] + 127;
+
+ if (p->u30 == 1) {
+ if (v30) {
+ if (_flags.gameID == GI_EOB2)
+ posIndex = ((posIndex >> 1) - v1e) << 1;
+ y = _dscShapeCoords[posIndex + 1] + 127 + yAdd[blockDistance + ((v1e == 4 || _flags.gameID == GI_EOB1) ? 0 : 3)];
+ } else {
+ if (_flags.gameID == GI_EOB2)
+ posIndex = ((posIndex >> 1) - v1e + 4) << 1;
+ x = _dscShapeCoords[posIndex] + 88;
+ }
+ }
+
+ int w = shp[2] << 3;
+ int h = shp[1];
+
+ x = x - (w >> 1) + (d->idleAnimState >> 4);
+ y = y - h + (d->idleAnimState & 0x0f);
+
+ drawMonsterShape(shp, x, y, f >= 0 ? 0 : 1, d->flags, palIndex);
+
+ if (_flags.gameID == GI_EOB1) {
+ _screen->setShapeFadeMode(1, false);
+ continue;
+ }
+
+ for (int ii = 0; ii < 3; ii++) {
+ if (!p->decorations[ii])
+ continue;
+
+ SpriteDecoration *dcr = &_monsterDecorations[(p->decorations[ii] - 1) * 6 + subFrame + shpIndex - 1];
+
+ if (!dcr)
+ continue;
+ if (!dcr->shp)
+ continue;
+
+ shp = _screen->scaleShape(dcr->shp, blockDistance);
+ int dx = dcr->x;
+ int dy = dcr->y;
+
+ for (int iii = 0; iii < blockDistance; iii++) {
+ dx = (dx << 1) / 3;
+ dy = (dy << 1) / 3;
+ }
+
+ drawMonsterShape(shp, x + ((f < 0) ? (w - dx - (shp[2] << 3)) : dx), y + dy, f >= 0 ? 0 : 1, d->flags, -1);
+ }
+ _screen->setShapeFadeMode(1, false);
+ }
+}
+
+void EobCoreEngine::drawWallOfForce(int index) {
+
+}
+
+void EobCoreEngine::drawFlyingObjects(int index) {
+ LevelBlockProperty *bl = _visibleBlocks[index];
+ int blockIndex = _visibleBlockIndex[index];
+ int w = bl->walls[_sceneDrawVarDown];
+
+ if (_wllVmpMap[w] && !(_wllWallFlags[w] & 0x80))
+ return;
+
+ EobFlyingObject *drawObj[5];
+ memset(drawObj, 0, 5 * sizeof(EobFlyingObject*));
+
+ for (int i = 0; i < 10; i++) {
+ if (!_flyingObjects[i].enable || blockIndex != _flyingObjects[i].curBlock)
+ continue;
+ drawObj[_drawObjPosIndex[_currentDirection * 5 + (_flyingObjects[i].curPos & 3)]] = &_flyingObjects[i];
+ }
+
+ for (int i = 0; i < 5; i++) {
+ EobFlyingObject *fo = drawObj[i];
+ if (!fo)
+ continue;
+
+ int p = _dscItemPosIndex[(_currentDirection << 2) + (fo->curPos & 3)];
+ int x = _dscShapeCoords[(index * 5 + p) << 1] + 88;
+ int y = 39;
+
+ int sclValue = _flightObjSclIndex[(index << 2) + p];
+ int flipped = 0;
+
+ if (sclValue < 0) {
+ _screen->setShapeFadeMode(1, false);
+ continue;
+ }
+
+ const uint8 *shp = 0;
+ bool rstFade = false;
+
+ if (fo->enable == 1) {
+ int shpIx = _dscItemShapeMap[_items[fo->item].icon];
+ int dirOffs = (fo->direction == _currentDirection) ? 0 : ((fo->direction == (_currentDirection ^ 2)) ? 1 : -1);
+
+ if (dirOffs == -1 || _flightObjShpMap[shpIx] == -1) {
+ shp = shpIx < _numLargeItemShapes ? _largeItemShapes[shpIx] : (shpIx < 15 ? 0 : _smallItemShapes[shpIx - 15]);
+ flipped = fo->direction == ((_currentDirection + 1) & 3) ? 1 : 0;
+ } else {
+ shp = (_flightObjShpMap[shpIx] + dirOffs) < _numThrownItemShapes ? _thrownItemShapes[_flightObjShpMap[shpIx] + dirOffs] : _spellShapes[_flightObjShpMap[shpIx - _numThrownItemShapes] + dirOffs];
+ flipped = _flightObjFlipIndex[(fo->direction << 2) + fo->curPos];
+ }
+
+ } else {
+ rstFade = true;
+ shp = (fo->objectType < _numThrownItemShapes) ? _thrownItemShapes[fo->objectType] : _spellShapes[fo->objectType - _numThrownItemShapes];
+ flipped = _flightObjFlipIndex[(fo->direction << 2) + fo->curPos];
+
+ if (fo->flags & 0x40) {
+ x = _dscShapeCoords[(index * 5 + 4) << 1] + 88;
+ y = 44;
+ }
+ }
+
+ shp = _screen->scaleShape(shp, sclValue);
+
+ if (rstFade) {
+ _screen->setShapeFadeMode(1, false);
+ rstFade = false;
+ }
+
+ x -= (shp[2] << 2);
+ y -= (y == 44 ? (shp[1] >> 1) : shp[1]);
+
+ drawBlockObject(flipped, 2, shp, x, y, 5);
+ _screen->setShapeFadeMode(1, false);
+ }
+}
+
+void EobCoreEngine::drawTeleporter(int index) {
+ static const uint8 telprtX[] = { 0x28, 0x1C, 0x12 };
+ static const uint8 telprtY[] = { 0x0D, 0x15, 0x1A };
+
+ int t = 2 - _dscDimMap[index];
+ if (t < 0)
+ return;
+
+ int16 x1 = _dscItemShpX[index] - telprtX[t];
+ int16 y1 = telprtY[t];
+
+ for (int i = 0; i < 2; i++) {
+
+ int16 x2 = 0;
+ int16 y2 = 0;
+ int d = (t << 1) + i;
+ if (!d)
+ x2 = y2 = -4;
+
+ const uint8 *shp = _teleporterShapes[d ^ _teleporterPulse];
+
+ for (int ii = 0; ii < 13; ii++)
+ drawBlockObject(0, 2, shp, x1 + x2 + _teleporterShapeCoords[d * 26 + ii * 2], y1 + y2 + _teleporterShapeCoords[d * 26 + ii * 2 + 1], 5);
+ }
+}
+
+void EobCoreEngine::updateMonsters(int unit) {
+ for (int i = 0; i < 30; i++) {
+ EobMonsterInPlay *m = &_monsters[i];
+
+ if (m->unit == unit) {
+ if (m->hitPointsCur <= 0 || m->flags & 0x20)
+ continue;
+ if (m->directionChanged) {
+ m->directionChanged = 0;
+ continue;
+ }
+
+ updateMonsterDest(m);
+
+ if (m->mode > 0)
+ updateMonsterDest2(m);
+
+ switch (m->mode) {
+ case 0:
+ updateMoveMonster(m);
+ break;
+ case 1:
+ updateMonsterFollowPath(m, 2);
+ break;
+ case 2:
+ updateMonsterFollowPath(m, -1);
+ break;
+ case 3:
+ updateMonsterFollowPath(m, 1);
+ break;
+ case 5:
+ updateMonstersStraying(m, -1);
+ break;
+ case 6:
+ updateMonstersStraying(m, 1);
+ break;
+ case 7:
+ case 10:
+ updateMonsters_mode710(m);
+ break;
+ default:
+ break;
+ }
+
+ if (m->mode != 4 && m->mode != 7 && m->mode != 8)
+ m->animStep ^= 1;
+
+ if (_monsterProps[m->type].u30 == 1)
+ setBlockMonsterDirection(m->block, m->dir);
+ }
+ }
+ checkFlyingObjects();
+}
+
+void EobCoreEngine::updateMonsterDest(EobMonsterInPlay *m) {
+ if (m->mode >= 7 && m->mode <= 10)
+ return;
+ int dist = getBlockDistance(m->block, _currentBlock);
+ if (dist >= 4)
+ return;
+
+ int s = getNextMonsterDirection(m->block, _currentBlock) - (m->dir << 1) - 3;
+
+ if (s < 0)
+ s += 8;
+
+ if (s <= 2 && dist >= 2)
+ return;
+
+ m->mode = 0;
+ m->dest = _currentBlock;
+}
+
+void EobCoreEngine::updateMonsterDest2(EobMonsterInPlay *m) {
+ if (!(m->flags & 1) || m->mode == 10)
+ return;
+ if (m->mode == 8) {
+ turnFriendlyMonstersHostile();
+ return;
+ }
+ m->mode = 0;
+ m->dest = _currentBlock;
+}
+
+void EobCoreEngine::turnFriendlyMonstersHostile() {
+ EobMonsterInPlay *m = 0;
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].mode == 8) {
+ _monsters[i].mode = 0;
+ _monsters[i].dest = _currentBlock;
+ m = &_monsters[i];
+ }
+ }
+
+ if (m) {
+ if (m->type == 7)
+ _inf->setFlag(0x40000);
+ else if (m->type == 12)
+ _inf->setFlag(0x8000000);
+ }
+}
+
+int EobCoreEngine::getNextMonsterDirection(int curBlock, int destBlock) {
+ uint8 c = destBlock % 32;
+ uint8 d = destBlock / 32;
+ uint8 e = curBlock % 32;
+ uint8 f = curBlock / 32;
+
+ int r = 0;
+
+ int s1 = f - d;
+ int d1 = ABS(s1);
+ s1 <<= 1;
+ int s2 = c - e;
+ int d2 = ABS(s2);
+ s2 <<= 1;
+
+ if (s1 >= d2)
+ r |= 8;
+ if (-s1 >= d2)
+ r |= 4;
+ if (s2 >= d1)
+ r |= 2;
+ if (-s2 >= d1)
+ r |= 1;
+
+ return _monsterDirChangeTable[r];
+}
+
+int EobCoreEngine::getNextMonsterPos(EobMonsterInPlay *m, int block) {
+ if ((_flags.gameID == GI_EOB1 && _monsterProps[m->type].u30 != 0) || (_flags.gameID == GI_EOB2 && _monsterProps[m->type].u30 == 2))
+ return -1;
+ int d = findFreeMonsterPos(block, _monsterProps[m->type].u30);
+ if (d < 0)
+ return -1;
+
+ int dir = m->dir;
+ if (_flags.gameID == GI_EOB2) {
+ if (_monsterProps[m->type].u30 == 1) {
+ if (d == 9)
+ return -1;
+
+ int v = _monsterCloseAttUnkTable[d];
+ if (v != -1)
+ //////
+ m->dir = 0;
+ return v;
+ }
+ } else {
+ dir &= 1;
+ }
+
+ for (int i = 0; i < 4; i++) {
+ int v = m->dir ^ _monsterCloseAttPosTable2[(dir << 2) + i];
+ if (!(d & (1 << v)))
+ return v;
+ }
+
+ return -1;
+}
+
+int EobCoreEngine::findFreeMonsterPos(int block, int size) {
+ int nm = _levelBlockProperties[block].flags & 7;
+ if (nm == 4)
+ return -2;
+
+ int res = 0;
+
+ for (int i = 0; i < 30; i++) {
+ EobMonsterInPlay *m = &_monsters[i];
+ if (m->block != block)
+ continue;
+ if (_monsterProps[m->type].u30 != size)
+ return -1;
+
+ if (m->pos == 4 && !(_flags.gameID == GI_EOB2 && m->flags & 0x20))
+ m->pos = (_flags.gameID == GI_EOB2 && _monsterProps[m->type].u30 == 1) ? 0 : _monsterCloseAttPosTable1[m->dir];
+
+ res |= (1 << m->pos);
+ if (--nm == 0)
+ break;
+ }
+
+ return res;
+}
+
+void EobCoreEngine::updateMoveMonster(EobMonsterInPlay *m) {
+ EobMonsterProperty *p = &_monsterProps[m->type];
+ int d = getNextMonsterDirection(m->block, _currentBlock);
+
+ if ((p->flags & 0x800) && !(d & 1))
+ d >>= 1;
+ else
+ d = m->dir;
+
+ d = calcNewBlockPosition(m->block, d);
+
+ if (m->dest == d && _currentBlock != d) {
+ m->mode = rollDice(1, 2, -1) + 5;
+ return;
+ }
+
+ if (updateMonsterTryDistanceAttack(m))
+ return;
+
+ if (updateMonsterTryCloseAttack(m, d))
+ return;
+
+ m->curAttackFrame = 0;
+ walkMonster(m, m->dest);
+
+ if (p->flags & 8)
+ updateMonsterTryCloseAttack(m, -1);
+}
+
+bool EobCoreEngine::updateMonsterTryDistanceAttack(EobMonsterInPlay *m) {
+ EobMonsterProperty *p = &_monsterProps[m->type];
+ if (!m->numRemoteAttacks || ((_flags.gameID == GI_EOB1) && !(p->flags & 0x40)))
+ return false;
+
+ if ((_flags.gameID == GI_EOB1 && m->stepsTillRemoteAttack == 5) || (_flags.gameID == GI_EOB2 && rollDice(1, 3) > m->stepsTillRemoteAttack)) {
+ m->stepsTillRemoteAttack++;
+ return false;
+ }
+
+ if (getBlockDistance(m->block, _currentBlock) > 3 || getNextMonsterDirection(m->block, _currentBlock) != (m->dir << 1))
+ return false;
+
+ int d = m->dir;
+ int bl = calcNewBlockPosition(m->block, d);
+
+ while (bl != _currentBlock) {
+ if (!(_wllWallFlags[_levelBlockProperties[bl].walls[d ^ 2]] & 3) || (_levelBlockProperties[bl].flags & 7))
+ return false;
+ bl = calcNewBlockPosition(bl, d);
+ }
+
+ Item itm = 0;
+ if (_flags.gameID == GI_EOB1) {
+ switch (m->type - 4) {
+ case 0:
+ launchMagicObject(-1, 9, m->block, m->pos, m->dir);
+ snd_processEnvironmentalSoundEffect(31, m->block);
+ break;
+ case 10:
+ launchMagicObject(-1, _monsterDistAttType10[m->numRemoteAttacks], m->block, m->pos, m->dir);
+ snd_processEnvironmentalSoundEffect(_monsterDistAttSfx10[m->numRemoteAttacks], m->block);
+ break;
+ case 11:
+ itm = duplicateItem(60);
+ if (itm) {
+ if (launchObject(-1, itm, m->block, m->pos, m->dir, _items[itm].type))
+ _items[itm].block = -1;
+ }
+ break;
+ case 12:
+ launchMagicObject(-1, 0, m->block, m->pos, m->dir);
+ snd_processEnvironmentalSoundEffect(85, m->block);
+ break;
+ case 13:
+ snd_processEnvironmentalSoundEffect(83, m->block);
+ _txt->printMessage(_monsterSpecAttStrings[1]);
+ for (int i = 0; i < 6; i++)
+ statusAttack(i, 4, _monsterSpecAttStrings[2], 1, 5, 9, 1);
+ break;
+ case 17:
+ d = rollDice(1, 4, -1);
+ if (d >= 3) {
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 3))
+ continue;
+ _txt->printMessage(_monsterSpecAttStrings[0], -1, _characters[i].name);
+ inflictCharacterDamage(i, rollDice(2, 8, 1));
+ }
+ snd_processEnvironmentalSoundEffect(108, m->block);
+ } else {
+ launchMagicObject(-1, _monsterDistAttType17[m->numRemoteAttacks], m->block, m->pos, m->dir);
+ snd_processEnvironmentalSoundEffect(_monsterDistAttSfx17[m->numRemoteAttacks], m->block);
+ }
+ break;
+ default:
+ break;
+ }
+
+ } else {
+ int cw = 0;
+ if (p->remoteWeaponChangeMode == 1) {
+ cw = m->curRemoteWeapon++;
+ if (m->curRemoteWeapon == p->numRemoteWeapons)
+ m->curRemoteWeapon = 0;
+ } else if (p->remoteWeaponChangeMode == 2) {
+ cw = rollDice(1, p->numRemoteWeapons, -1);
+ }
+
+ int s = p->remoteWeapons[cw];
+ if (s >= 0) {
+ if (s < 20) {
+ monsterSpellCast(m, s);
+ } else if (s == 20) {
+ snd_processEnvironmentalSoundEffect(103, m->block);
+ _txt->printMessage(_monsterSpecAttStrings[0]);
+ for (int i = 0; i < 6; i++)
+ statusAttack(i, 4, _monsterSpecAttStrings[1], 1, 5, 9, 1);
+ }
+ } else {
+ Item itm = duplicateItem(-s);
+ if (itm) {
+ if (launchObject(-1, itm, m->block, m->pos, m->dir, _items[itm].type))
+ _items[itm].block = -1;
+ }
+ }
+ }
+
+ if (m->numRemoteAttacks != 255)
+ m->numRemoteAttacks--;
+ m->stepsTillRemoteAttack = 0;
+ return true;
+}
+
+bool EobCoreEngine::updateMonsterTryCloseAttack(EobMonsterInPlay *m, int block) {
+ if (block == -1)
+ block = calcNewBlockPosition(m->block, m->dir);
+
+ if (block != _currentBlock)
+ return false;
+
+ int r = (m->pos == 4 || (_flags.gameID == GI_EOB2 && _monsterProps[m->type].u30 == 1)) ? 1 : _monsterCloseAttChkTable1[(m->dir << 2) + m->pos];
+
+ if (r) {
+ m->flags ^= 4;
+ if (!(m->flags & 4))
+ return true;
+
+ bool facing = (m->block == _visibleBlockIndex[13]);
+
+ if (facing) {
+ disableSysTimer(2);
+ if (m->type == 4)
+ updateEnvironmentalSfx(_monsterProps[m->type].sound1);
+ m->curAttackFrame = -2;
+ _flashShapeTimer = 0;
+ drawScene(1);
+ m->curAttackFrame = -1;
+ if (m->type != 4)
+ updateEnvironmentalSfx(_monsterProps[m->type].sound1);
+ _flashShapeTimer = _system->getMillis() + 8 * _tickLength;
+ drawScene(1);
+ } else {
+ updateEnvironmentalSfx(_monsterProps[m->type].sound1);
+ }
+
+ monsterCloseAttack(m);
+
+ if (facing) {
+ m->curAttackFrame = 0;
+ m->animStep ^= 1;
+ _sceneUpdateRequired = 1;
+ enableSysTimer(2);
+ _flashShapeTimer = _system->getMillis() + 8 * _tickLength;
+ }
+ } else {
+ int b = m->block;
+ if ((_levelBlockProperties[b].flags & 7) == 1) {
+ m->pos = 4;
+ } else {
+ b = getNextMonsterPos(m, b);
+ if (b >= 0)
+ m->pos = b;
+ }
+ checkSceneUpdateNeed(m->block);
+ }
+
+ return true;
+}
+
+void EobCoreEngine::walkMonster(EobMonsterInPlay *m, int destBlock) {
+ if (++_monsterStepCounter > 10) {
+ _monsterStepCounter = 0;
+ _monsterStepMode ^= 1;
+ }
+
+ const int8 *tbl = _monsterStepMode ? _monsterStepTable3 : _monsterStepTable2;
+
+ int s = m->dir << 1;
+ int b = m->block;
+ int d = getNextMonsterDirection(b, destBlock);
+ if (d == -1)
+ return;
+
+ if (m->flags & 8) {
+ if (_flags.gameID == GI_EOB1 ) {
+ d ^= 4;
+ } else if (--m->f_b <= 0) {
+ m->f_b = 0;
+ m->flags &= ~8;
+ } else {
+ d ^= 4;
+ }
+ }
+
+ int d2 = (d - s) & 7;
+
+ if (b + _monsterStepTable0[_flags.gameID == GI_EOB1 ? (d >> 1) : d] == destBlock) {
+ if (_flags.gameID == GI_EOB1 && !(d & 1)) {
+ if (d2 >= 5) {
+ s = m->dir - 1;
+ } else if (d2 != 0) {
+ s = m->dir + 1;
+ }
+ walkMonsterNextStep(m, -1, s & 3);
+ return;
+ } else if (_flags.gameID == GI_EOB2) {
+ if (d & 1) {
+ int e = _monsterStepTable1[((d - 1) << 1) + m->dir];
+ if (e && !((_monsterProps[m->type].flags & 0x200) && (rollDice(1, 4) == 4))) {
+ if (walkMonsterNextStep(m, b + e, -1))
+ return;
+ }
+ } else {
+ walkMonsterNextStep(m, -1, d >> 1);
+ return;
+ }
+ }
+ }
+
+ if (d2) {
+ if (d2 >= 5)
+ s -= (1 + ((d & 1) ^ 1));
+ else
+ s += (1 + ((d & 1) ^ 1));
+ s &= 7;
+ }
+
+ for (int i = 7; i > -1; i--) {
+ s = (s + tbl[i]) & 7;
+ uint16 b2 = (s & 1) ? 0 : calcNewBlockPosition(b, s >> 1);
+ if (!b2)
+ continue;
+ if (walkMonsterNextStep(m, b2, s >> 1))
+ return;
+ }
+}
+
+bool EobCoreEngine::walkMonsterNextStep(EobMonsterInPlay *m, int destBlock, int direction) {
+ EobMonsterProperty *p = &_monsterProps[m->type];
+ int obl = m->block;
+
+ if (destBlock != m->block && destBlock != -1) {
+ if (m->flags & 8) {
+ if (getBlockDistance(destBlock, _currentBlock) < getBlockDistance(m->block, _currentBlock))
+ return false;
+ }
+
+ if (destBlock == _currentBlock)
+ return false;
+
+ if (direction == -1)
+ direction = m->dir;
+
+ LevelBlockProperty *l = &_levelBlockProperties[destBlock];
+ uint8 w = l->walls[direction ^ 2];
+
+ if (!(_wllWallFlags[w] & 4)) {
+ if (_flags.gameID == GI_EOB1 ||!(p->flags & 0x1000) || _wllShapeMap[w] != -1)
+ return false;
+
+ if (_wllWallFlags[w] & 0x20) {
+ if (p->flags & 4 && m->type == 1)
+ l->walls[direction] = l->walls[direction ^ 2] = 72;
+ else
+ openDoor(destBlock);
+ }
+
+ if (direction != -1) {
+ m->dir = direction;
+ checkSceneUpdateNeed(m->block);
+ }
+ return true;
+ }
+
+ if ((l->flags & 7) && destBlock) {
+ int pos = getNextMonsterPos(m, destBlock);
+ if (pos == -1)
+ return false;
+ m->pos = pos;
+ }
+
+ placeMonster(m, destBlock, direction);
+ direction = -1;
+ }
+
+ if (direction != -1)
+ m->dir = direction;
+
+ checkSceneUpdateNeed(obl);
+ if (!_partyResting && p->sound2)
+ snd_processEnvironmentalSoundEffect(p->sound2, m->block);
+
+ return true;
+}
+
+void EobCoreEngine::updateMonsterFollowPath(EobMonsterInPlay *m, int turnSteps) {
+ if (!walkMonsterNextStep(m, calcNewBlockPosition(m->block, m->dir), -1)) {
+ m->dir = (m->dir + turnSteps) & 3;
+ walkMonsterNextStep(m, -1, m->dir);
+ }
+}
+
+void EobCoreEngine::updateMonstersStraying(EobMonsterInPlay *m, int a) {
+ if (m->f_9 >= 0) {
+ if (m->f_9 == 0)
+ updateMonsterFollowPath(m, -a);
+
+ int8 d = (m->dir + a) & 3;
+ uint16 bl = calcNewBlockPosition(m->block, d);
+ uint8 flg = _wllWallFlags[_levelBlockProperties[bl].walls[_dscBlockMap[d]]] & 4;
+
+ if (m->f_9 == 0) {
+ if (!flg)
+ m->f_9 = -1;
+ return;
+ }
+
+ if (flg) {
+ walkMonsterNextStep(m, -1, d);
+ m->f_9 = -1;
+ return;
+ }
+ }
+
+ if (walkMonsterNextStep(m, calcNewBlockPosition(m->block, m->dir), -1)) {
+ m->f_9 = 1;
+ } else {
+ walkMonsterNextStep(m, -1, (m->dir - a) & 3);
+ m->f_9 = 0;
+ }
+}
+
+void EobCoreEngine::updateMonsters_mode710(EobMonsterInPlay *m) {
+ if (m->f_b) {
+ if (!--m->f_b)
+ m->mode = 0;
+ }
+}
+
+void EobCoreEngine::setBlockMonsterDirection(int block, int dir) {
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].block != block || _monsters[i].dir == dir)
+ continue;
+ _monsters[i].dir = dir;
+ _monsters[i].directionChanged == 1;
+ }
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp
index fbf4c7c5c2..9f7e05627b 100644
--- a/engines/kyra/sprites_lol.cpp
+++ b/engines/kyra/sprites_lol.cpp
@@ -59,7 +59,7 @@ void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int animTy
for (int i = 0; i < 4; i++) {
for (int ii = 0; ii < 16; ii++) {
- uint8 **of = &_monsterShapesEx[monsterIndex * 192 + i * 48 + ii * 3];
+ uint8 **of = &_monsterDecorationShapes[monsterIndex * 192 + i * 48 + ii * 3];
int s = (i << 4) + ii + 17;
of[0] = _screen->makeShapeCopy(p, s);
of[1] = _screen->makeShapeCopy(p, s + 1);
@@ -140,9 +140,9 @@ void LoLEngine::releaseMonsterShapes(int monsterIndex) {
for (int i = 0; i < 192; i++) {
int pos = (monsterIndex * 192) + i;
- if (_monsterShapesEx[pos]) {
- delete[] _monsterShapesEx[pos];
- _monsterShapesEx[pos] = 0;
+ if (_monsterDecorationShapes[pos]) {
+ delete[] _monsterDecorationShapes[pos];
+ _monsterDecorationShapes[pos] = 0;
}
}
}
@@ -159,7 +159,7 @@ int LoLEngine::deleteMonstersFromBlock(int block) {
continue;
}
- MonsterInPlay *m = &_monsters[i & 0x7fff];
+ LolMonsterInPlay *m = &_monsters[i & 0x7fff];
cnt++;
setMonsterMode(m, 14);
@@ -173,7 +173,7 @@ int LoLEngine::deleteMonstersFromBlock(int block) {
return cnt;
}
-void LoLEngine::setMonsterMode(MonsterInPlay *monster, int mode) {
+void LoLEngine::setMonsterMode(LolMonsterInPlay *monster, int mode) {
if (monster->mode == 13 && mode != 14)
return;
@@ -210,7 +210,7 @@ void LoLEngine::setMonsterMode(MonsterInPlay *monster, int mode) {
}
}
-bool LoLEngine::updateMonsterAdjustBlocks(MonsterInPlay *monster) {
+bool LoLEngine::updateMonsterAdjustBlocks(LolMonsterInPlay *monster) {
static const uint8 dims[] = { 0, 13, 9, 3 };
if (monster->properties->flags & 8)
return true;
@@ -251,7 +251,7 @@ bool LoLEngine::updateMonsterAdjustBlocks(MonsterInPlay *monster) {
return (fx1 >= fx2) ? false : true;
}
-void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) {
+void LoLEngine::placeMonster(LolMonsterInPlay *monster, uint16 x, uint16 y) {
bool cont = true;
int t = monster->block;
if (monster->block) {
@@ -329,7 +329,7 @@ int LoLEngine::calcMonsterDirection(uint16 x1, uint16 y1, uint16 x2, uint16 y2)
return retVal[r];
}
-void LoLEngine::setMonsterDirection(MonsterInPlay *monster, int dir) {
+void LoLEngine::setMonsterDirection(LolMonsterInPlay *monster, int dir) {
monster->direction = dir;
if (!(dir & 1) || ((monster->direction - (monster->facing << 1)) >= 2))
@@ -338,7 +338,7 @@ void LoLEngine::setMonsterDirection(MonsterInPlay *monster, int dir) {
checkSceneUpdateNeed(monster->block);
}
-void LoLEngine::monsterDropItems(MonsterInPlay *monster) {
+void LoLEngine::monsterDropItems(LolMonsterInPlay *monster) {
uint16 a = monster->assignedItems;
while (a) {
uint16 b = a;
@@ -503,7 +503,7 @@ int LoLEngine::checkBlockForWallsAndSufficientSpace(int block, int x, int y, int
uint16 b = _levelBlockProperties[block].assignedObjects;
while (b & 0x8000) {
- MonsterInPlay *monster = &_monsters[b & 0x7fff];
+ LolMonsterInPlay *monster = &_monsters[b & 0x7fff];
if (monster->mode < 13) {
int r = checkDrawObjectSpace(x, y, monster->x, monster->y);
@@ -645,7 +645,7 @@ void LoLEngine::drawBlockObjects(int blockArrayIndex) {
}
void LoLEngine::drawMonster(uint16 id) {
- MonsterInPlay *m = &_monsters[id];
+ LolMonsterInPlay *m = &_monsters[id];
int16 flg = _monsterDirFlags[(_currentDirection << 2) + m->facing];
int curFrm = getMonsterCurFrame(m, flg & 0xffef);
uint8 *shp = 0;
@@ -670,7 +670,7 @@ void LoLEngine::drawMonster(uint16 id) {
if (v == -1)
break;
- uint8 *shp2 = _monsterShapesEx[m->properties->shapeIndex * 192 + v * 48 + curFrm * 3];
+ uint8 *shp2 = _monsterDecorationShapes[m->properties->shapeIndex * 192 + v * 48 + curFrm * 3];
if (!shp2)
continue;
@@ -721,7 +721,7 @@ void LoLEngine::drawMonster(uint16 id) {
delete[] tbl;
}
-int LoLEngine::getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags) {
+int LoLEngine::getMonsterCurFrame(LolMonsterInPlay *m, uint16 dirFlags) {
int tmp = 0;
switch (_monsterAnimType[m->properties->shapeIndex]) {
case 0:
@@ -901,7 +901,7 @@ void LoLEngine::drawDoor(uint8 *shape, uint8 *doorPalette, int index, int unk2,
if (!shape)
return;
- uint8 c = _dscDoor1[(_currentDirection << 5) + unk2];
+ uint8 c = _dscDoorY2[(_currentDirection << 5) + unk2];
int r = (c / 5) + 5 * _dscDimMap[index];
uint16 d = _dscShapeOvlIndex[r];
uint16 t = (index << 5) + c;
@@ -1080,7 +1080,7 @@ int LoLEngine::calcDrawingLayerParameters(int x1, int y1, int &x2, int &y2, uint
return l;
}
-void LoLEngine::updateMonster(MonsterInPlay *monster) {
+void LoLEngine::updateMonster(LolMonsterInPlay *monster) {
static const uint8 flags[] = { 1, 0, 1, 3, 3, 0, 0, 3, 4, 1, 0, 0, 4, 0, 0 };
if (monster->mode > 14)
return;
@@ -1228,7 +1228,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) {
monster->flags &= 0xffef;
}
-void LoLEngine::moveMonster(MonsterInPlay *monster) {
+void LoLEngine::moveMonster(LolMonsterInPlay *monster) {
static const int8 turnPos[] = { 0, 2, 6, 6, 0, 2, 4, 4, 2, 2, 4, 6, 0, 0, 4, 6, 0 };
if (monster->x != monster->destX || monster->y != monster->destY) {
walkMonster(monster);
@@ -1238,7 +1238,7 @@ void LoLEngine::moveMonster(MonsterInPlay *monster) {
}
}
-void LoLEngine::walkMonster(MonsterInPlay *monster) {
+void LoLEngine::walkMonster(LolMonsterInPlay *monster) {
if (monster->properties->flags & 0x400)
return;
@@ -1253,7 +1253,7 @@ void LoLEngine::walkMonster(MonsterInPlay *monster) {
} else {
setMonsterDirection(monster, s);
if (monster->numDistAttacks) {
- if (getMonsterDistance(monster->block, _currentBlock) >= 2) {
+ if (getBlockDistance(monster->block, _currentBlock) >= 2) {
if (checkForPossibleDistanceAttack(monster->block, monster->direction, 3, _currentBlock) != 5) {
if (monster->distAttackTick)
return;
@@ -1269,7 +1269,7 @@ void LoLEngine::walkMonster(MonsterInPlay *monster) {
placeMonster(monster, fx, fy);
}
-bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) {
+bool LoLEngine::chasePartyWithDistanceAttacks(LolMonsterInPlay *monster) {
if (!monster->numDistAttacks)
return false;
@@ -1295,7 +1295,7 @@ bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) {
int flyingObject = monster->properties->distWeapons[s];
if (flyingObject & 0xc000) {
- if (getMonsterDistance(monster->block, _currentBlock) > 1) {
+ if (getBlockDistance(monster->block, _currentBlock) > 1) {
int type = flyingObject & 0x4000 ? 0 : 1;
flyingObject = makeItem(flyingObject & 0x3fff, 0, 0);
@@ -1305,7 +1305,7 @@ bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) {
}
}
} else if (!(flyingObject & 0x2000)) {
- if (getMonsterDistance(monster->block, _currentBlock) > 1)
+ if (getBlockDistance(monster->block, _currentBlock) > 1)
return false;
if (flyingObject == 1) {
@@ -1326,7 +1326,7 @@ bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) {
} else if (flyingObject == 3) {
// shriek
for (int i = 0; i < 30; i++) {
- if (getMonsterDistance(monster->block, _monsters[i].block) < 7)
+ if (getBlockDistance(monster->block, _monsters[i].block) < 7)
setMonsterMode(monster, 7);
}
_txt->printMessage(2, "%s", getLangString(0x401a));
@@ -1347,7 +1347,7 @@ bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) {
return true;
}
-void LoLEngine::chasePartyWithCloseAttacks(MonsterInPlay *monster) {
+void LoLEngine::chasePartyWithCloseAttacks(LolMonsterInPlay *monster) {
if (!(monster->flags & 8)) {
int dir = calcMonsterDirection(monster->x & 0xff00, monster->y & 0xff00, _partyPosX & 0xff00, _partyPosY & 0xff00);
int x1 = _partyPosX;
@@ -1389,7 +1389,7 @@ void LoLEngine::chasePartyWithCloseAttacks(MonsterInPlay *monster) {
}
}
-int LoLEngine::walkMonsterCalcNextStep(MonsterInPlay *monster) {
+int LoLEngine::walkMonsterCalcNextStep(LolMonsterInPlay *monster) {
static const int8 walkMonsterTable1[] = { 7, -6, 5, -4, 3, -2, 1, 0 };
static const int8 walkMonsterTable2[] = { -7, 6, -5, 4, -3, 2, -1, 0 };
@@ -1445,23 +1445,8 @@ int LoLEngine::walkMonsterCalcNextStep(MonsterInPlay *monster) {
return -1;
}
-int LoLEngine::getMonsterDistance(uint16 block1, uint16 block2) {
- int b1x = block1 & 0x1f;
- int b1y = block1 >> 5;
- int b2x = block2 & 0x1f;
- int b2y = block2 >> 5;
-
- uint8 dy = ABS(b2y - b1y);
- uint8 dx = ABS(b2x - b1x);
-
- if (dx > dy)
- SWAP(dx, dy);
-
- return (dx >> 1) + dy;
-}
-
int LoLEngine::checkForPossibleDistanceAttack(uint16 monsterBlock, int direction, int distance, uint16 curBlock) {
- int mdist = getMonsterDistance(curBlock, monsterBlock);
+ int mdist = getBlockDistance(curBlock, monsterBlock);
if (mdist > distance)
return 5;
@@ -1494,7 +1479,7 @@ int LoLEngine::checkForPossibleDistanceAttack(uint16 monsterBlock, int direction
return 5;
}
-int LoLEngine::walkMonsterCheckDest(int x, int y, MonsterInPlay *monster, int unk) {
+int LoLEngine::walkMonsterCheckDest(int x, int y, LolMonsterInPlay *monster, int unk) {
uint8 m = monster->mode;
monster->mode = 15;
@@ -1512,7 +1497,7 @@ void LoLEngine::getNextStepCoords(int16 srcX, int16 srcY, int &newX, int &newY,
newY = (srcY + shiftTableY[direction]) & 0x1fff;
}
-void LoLEngine::rearrangeAttackingMonster(MonsterInPlay *monster) {
+void LoLEngine::rearrangeAttackingMonster(LolMonsterInPlay *monster) {
int t = (monster->direction >> 1);
uint16 mx = monster->x;
uint16 my = monster->y;
@@ -1579,7 +1564,7 @@ void LoLEngine::rearrangeAttackingMonster(MonsterInPlay *monster) {
placeMonster(monster, mx, my);
}
-void LoLEngine::moveStrayingMonster(MonsterInPlay *monster) {
+void LoLEngine::moveStrayingMonster(LolMonsterInPlay *monster) {
int x = 0;
int y = 0;
@@ -1616,13 +1601,13 @@ void LoLEngine::moveStrayingMonster(MonsterInPlay *monster) {
}
}
-void LoLEngine::killMonster(MonsterInPlay *monster) {
+void LoLEngine::killMonster(LolMonsterInPlay *monster) {
setMonsterMode(monster, 14);
monsterDropItems(monster);
checkSceneUpdateNeed(monster->block);
uint8 w = _levelBlockProperties[monster->block].walls[0];
- uint8 f = _levelBlockProperties[monster->block].flags;
+ uint16 f = _levelBlockProperties[monster->block].flags;
if (_wllVmpMap[w] == 0 && _wllShapeMap[w] == 0 && !(f & 0x40) && !(monster->properties->flags & 0x1000))
_levelBlockProperties[monster->block].flags |= 0x80;
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index e03369f700..acc61353f4 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -75,7 +75,9 @@ const IndexTable iGameTable[] = {
{ GI_KYRA1, 0 },
{ GI_KYRA2, 1 },
{ GI_KYRA3, 2 },
- { GI_LOL, 3 },
+ { GI_EOB1, 3 },
+ { GI_EOB2, 4 },
+ { GI_LOL, 5 },
{ -1, -1 }
};
@@ -257,6 +259,12 @@ bool StaticResource::init() {
{ kLolButtonData, proc(loadButtonDefs), proc(freeButtonDefs) },
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+ { kEob2SequenceData, proc(loadEob2SeqData), proc(freeEob2SeqData) },
+ { kEob2ShapeData, proc(loadEob2ShapeData), proc(freeEob2ShapeData) },
+ { kEobNpcData, proc(loadEobNpcData), proc(freeEobNpcData) },
+#endif // ENABLE_EOB
+
{ 0, 0, 0 }
};
#undef proc
@@ -503,9 +511,9 @@ bool StaticResource::loadHofSequenceData(Common::SeekableReadStream &stream, voi
tmp_s[i].flags = stream.readUint16BE();
tmp_s[i].wsaFile = new char[14];
- stream.read(const_cast<char *>(tmp_s[i].wsaFile), 14);
+ stream.read(const_cast<char*>(tmp_s[i].wsaFile), 14);
tmp_s[i].cpsFile = new char[14];
- stream.read(const_cast<char *>(tmp_s[i].cpsFile), 14);
+ stream.read(const_cast<char*>(tmp_s[i].cpsFile), 14);
tmp_s[i].startupCommand = stream.readByte();
tmp_s[i].finalCommand = stream.readByte();
tmp_s[i].stringIndex1 = stream.readUint16BE();
@@ -529,7 +537,7 @@ bool StaticResource::loadHofSequenceData(Common::SeekableReadStream &stream, voi
tmp_n[i].flags = stream.readUint16BE();
tmp_n[i].wsaFile = new char[14];
- stream.read(const_cast<char *>(tmp_n[i].wsaFile), 14);
+ stream.read(const_cast<char*>(tmp_n[i].wsaFile), 14);
tmp_n[i].startframe = stream.readUint16BE();
tmp_n[i].endFrame = stream.readUint16BE();
tmp_n[i].frameDelay = stream.readUint16BE();
diff --git a/engines/kyra/staticres_eob.cpp b/engines/kyra/staticres_eob.cpp
new file mode 100644
index 0000000000..88bfbd8f08
--- /dev/null
+++ b/engines/kyra/staticres_eob.cpp
@@ -0,0 +1,1062 @@
+/* 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 "kyra/eob1.h"
+#include "kyra/eob2.h"
+#include "kyra/resource.h"
+
+
+namespace Kyra {
+
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+const uint16 *StaticResource::loadRawDataBe16(int id, int &entries) {
+ return (const uint16 *)getData(id, kLolRawDataBe16, entries);
+}
+
+const uint32 *StaticResource::loadRawDataBe32(int id, int &entries) {
+ return (const uint32 *)getData(id, kLolRawDataBe32, entries);
+}
+#endif // defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#ifdef ENABLE_EOB
+const EobSequenceStep *StaticResource::loadEob2SeqData(int id, int &entries) {
+ return (const EobSequenceStep *)getData(id, kEob2SequenceData, entries);
+}
+
+const EobShapeDef *StaticResource::loadEob2ShapeData(int id, int &entries) {
+ return (const EobShapeDef *)getData(id, kEob2ShapeData, entries);
+}
+
+const EobCharacter *StaticResource::loadEobNpcData(int id, int &entries) {
+ return (const EobCharacter *)getData(id, kEobNpcData, entries);
+}
+#endif // ENABLE_EOB
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+bool StaticResource::loadRawDataBe16(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() >> 1;
+
+ uint16 *r = new uint16[size];
+
+ for (int i = 0; i < size; i++)
+ r[i] = stream.readUint16BE();
+
+ ptr = r;
+ return true;
+}
+
+bool StaticResource::loadRawDataBe32(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() >> 2;
+
+ uint32 *r = new uint32[size];
+
+ for (int i = 0; i < size; i++)
+ r[i] = stream.readUint32BE();
+
+ ptr = r;
+ return true;
+}
+#endif // defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#ifdef ENABLE_EOB
+bool StaticResource::loadEob2SeqData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 11;
+
+ EobSequenceStep *s = new EobSequenceStep[size];
+
+ for (int i = 0; i < size; i++) {
+ s[i].command = stream.readByte();
+ s[i].obj = stream.readByte();
+ s[i].x1 = stream.readSint16BE();
+ s[i].y1 = stream.readByte();
+ s[i].delay = stream.readByte();
+ s[i].pal = stream.readByte();
+ s[i].x2 = stream.readByte();
+ s[i].y2 = stream.readByte();
+ s[i].w = stream.readByte();
+ s[i].h = stream.readByte();
+ }
+
+ ptr = s;
+ return true;
+}
+
+bool StaticResource::loadEob2ShapeData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 6;
+
+ EobShapeDef *s = new EobShapeDef[size];
+
+ for (int i = 0; i < size; i++) {
+ s[i].index = stream.readSint16BE();
+ s[i].x = stream.readByte();
+ s[i].y = stream.readByte();
+ s[i].w = stream.readByte();
+ s[i].h = stream.readByte();
+ }
+
+ ptr = s;
+ return true;
+}
+
+bool StaticResource::loadEobNpcData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.readUint16BE();
+
+ EobCharacter *e = new EobCharacter[size];
+ memset(e, 0, size * sizeof(EobCharacter));
+ EobCharacter *s = e;
+
+ for (int i = 0; i < size; i++, s++) {
+ s->id = stream.readByte();
+ s->flags = stream.readByte();
+ stream.read(s->name, 11);
+ s->strengthCur = stream.readSByte();
+ s->strengthMax = stream.readSByte();
+ s->strengthExtCur = stream.readSByte();
+ s->strengthExtMax = stream.readSByte();
+ s->intelligenceCur = stream.readSByte();
+ s->intelligenceMax = stream.readSByte();
+ s->wisdomCur = stream.readSByte();
+ s->wisdomMax = stream.readSByte();
+ s->dexterityCur = stream.readSByte();
+ s->dexterityMax = stream.readSByte();
+ s->constitutionCur = stream.readSByte();
+ s->constitutionMax = stream.readSByte();
+ s->charismaCur = stream.readSByte();
+ s->charismaMax = stream.readSByte();
+ s->hitPointsCur = stream.readSint16BE();
+ s->hitPointsMax = stream.readSint16BE();
+ s->armorClass = stream.readSByte();
+ s->disabledSlots = stream.readByte();
+ s->raceSex = stream.readByte();
+ s->cClass = stream.readByte();
+ s->alignment = stream.readByte();
+ s->portrait = stream.readByte();
+ s->food = stream.readByte();
+ stream.read(s->level, 3);
+ s->experience[0] = stream.readUint32BE();
+ s->experience[1] = stream.readUint32BE();
+ s->experience[2] = stream.readUint32BE();
+ s->mageSpellsAvailabilityFlags = stream.readUint32BE();
+ for (int ii = 0; ii < 27; ii++)
+ s->inventory[i] = stream.readUint16BE();
+ }
+
+ ptr = e;
+ return true;
+}
+#endif // ENABLE_EOB
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+void StaticResource::freeRawDataBe16(void *&ptr, int &size) {
+ uint16 *data = (uint16 *)ptr;
+ delete[] data;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeRawDataBe32(void *&ptr, int &size) {
+ uint32 *data = (uint32 *)ptr;
+ delete[] data;
+ ptr = 0;
+ size = 0;
+}
+#endif // defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#ifdef ENABLE_EOB
+void StaticResource::freeEob2SeqData(void *&ptr, int &size) {
+ EobSequenceStep *d = (EobSequenceStep *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeEob2ShapeData(void *&ptr, int &size) {
+ EobShapeDef *d = (EobShapeDef *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeEobNpcData(void *&ptr, int &size) {
+ EobCharacter *d = (EobCharacter *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+const ScreenDim Screen_Eob::_screenDimTable[] = {
+ { 0x00, 0x00, 0x28, 0xC8, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x08, 0x48, 0x18, 0x38, 0x0E, 0x0C, 0x00, 0x00 },
+ { 0x13, 0x40, 0x14, 0x80, 0x06, 0x0C, 0x00, 0x00 },
+ { 0x1D, 0x78, 0x08, 0x40, 0x0F, 0x0D, 0x00, 0x00 },
+ { 0x02, 0x18, 0x14, 0x78, 0x0F, 0x02, 0x03, 0x00 },
+ { 0x00, 0x00, 0x16, 0x78, 0x0F, 0x0D, 0x00, 0x00 },
+ { 0x0A, 0x6C, 0x15, 0x28, 0x0F, 0x00, 0x00, 0x00 },
+ { 0x01, 0xB4, 0x22, 0x12, 0x0F, 0x0C, 0x00, 0x00 },
+ { 0x02, 0x18, 0x14, 0x00, 0x0F, 0x02, 0x03, 0x00 },
+ { 0x01, 0x7D, 0x26, 0x40, 0x0F, 0x00, 0x03, 0x00 },
+ { 0x00, 0x00, 0x16, 0x90, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x14, 0x14, 0x38, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x04, 0x14, 0x9C, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x19, 0x26, 0x64, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x14, 0x14, 0x58, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x02, 0x06, 0x23, 0x78, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x09, 0x14, 0x16, 0x38, 0x0F, 0x02, 0x00, 0x00 },
+ { 0x01, 0x96, 0x26, 0x31, 0x0F, 0x00, 0x00, 0x00 },
+ { 0x01, 0x08, 0x26, 0x80, 0x0C, 0x0F, 0x00, 0x00 },
+ { 0x01, 0x10, 0x26, 0x14, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x10, 0x10, 0x0C, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x10, 0x17, 0x00, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x10, 0x10, 0x00, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x10, 0x07, 0x04, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x00, 0x11, 0x05, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x00, 0x15, 0x05, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x00, 0x11, 0x08, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x00, 0x00, 0x15, 0x03, 0x00, 0x0F, 0x06, 0x00 },
+ { 0x0A, 0xA8, 0x15, 0x18, 0x0F, 0x0C, 0x00, 0x00 }
+};
+
+const int Screen_Eob::_screenDimTableCount = ARRAYSIZE(Screen_Eob::_screenDimTable);
+#endif
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+const uint8 LolEobBaseEngine::_dropItemDirIndex[] = { 0, 1, 2, 3, 1, 3, 0, 2, 3, 2, 1, 0, 2, 0, 3, 1 };
+
+void LolEobBaseEngine::initStaticResource() {
+ int temp;
+ _dscShapeX = (const int16 *)_staticres->loadRawDataBe16(kLolEobCommonDscX, temp);
+ _dscShapeIndex = (const int8 *)_staticres->loadRawData(kLolEobCommonDscShapeIndex, temp);
+ _dscTileIndex = _staticres->loadRawData(kLolEobCommonDscTileIndex, temp);
+ _dscDim1 = (const int8 *)_staticres->loadRawData(kLolEobCommonDscDimData1, temp);
+ _dscDim2 = (const int8 *)_staticres->loadRawData(kLolEobCommonDscDimData2, temp);
+ _dscUnk2 = _staticres->loadRawData(kLolEobCommonDscUnk2, temp);
+ _dscBlockMap = _staticres->loadRawData(kLolEobCommonDscBlockMap, temp);
+ _dscBlockIndex = (const int8 *)_staticres->loadRawData(kLolEobCommonDscBlockIndex, temp);
+ _dscDimMap = _staticres->loadRawData(kLolEobCommonDscDimMap, temp);
+ _dscDoorShpIndex = _staticres->loadRawData(kLolEobCommonDscDoorShapeIndex, temp);
+ _dscDoorY2 = _staticres->loadRawData(kLolEobCommonDscDoorY2, temp);
+ _moreStrings = _staticres->loadStrings(kLolEobCommonMoreStrings, temp);
+}
+
+#endif // (ENABLE_EOB || ENABLE_LOL)
+#ifdef ENABLE_EOB
+
+const uint8 EobCoreEngine::_hpIncrPerLevel[] = { 10, 4, 8, 6, 10, 10, 9, 10, 9, 10, 9, 9, 3, 1, 2, 2, 3, 3 };
+
+const uint8 EobCoreEngine::_numLevelsPerClass[] = { 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 2, 2, 3, 2, 2 };
+
+const int8 EobCoreEngine::_classHpIncreaseType[] = {
+ 0, -1, -1, 5, -1, -1, 4, -1, -1, 1, -1, -1, 2, -1, -1, 3, -1, -1, 0,
+ 2, -1, 0, 3, -1, 0, 1, -1, 0, 1, 3, 3, 1, -1, 2, 3, -1, 0, 2, 1, 5,
+ 2, -1, 2, 1, -1
+};
+
+const int16 EobCoreEngine::_hpConstModifiers[] = { -1, -3, -2, -2, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 7, 7 };
+
+const uint8 EobCoreEngine::_charClassModUnk[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02,
+ 0x00, 0x00, 0x02
+};
+
+const uint8 EobCoreEngine::_teleporterShapeDefs[] = {
+ 0x0C, 0x58, 0x02, 0x0E,
+ 0x0C, 0x67, 0x01, 0x07,
+ 0x0C, 0x6F, 0x01, 0x07,
+ 0x0C, 0x77, 0x01, 0x05,
+ 0x0C, 0x7D, 0x01, 0x05,
+ 0x0C, 0x83, 0x01, 0x03
+};
+
+const uint8 EobCoreEngine::_wallOfForceShapeDefs[] = {
+ 0x00, 0x00, 0x04, 0x08,
+ 0x00, 0x08, 0x04, 0x08,
+ 0x04, 0x00, 0x04, 0x08,
+ 0x04, 0x08, 0x04, 0x08,
+ 0x08, 0x00, 0x05, 0x10,
+ 0x0C, 0x00, 0x05, 0x10
+};
+
+const int16 EobCoreEngine::_buttonList1[] = {
+ 58, 0, 1, 2, 3, 90, 91, 4, 5, 6, 7, 8, 9, 10, 11, 12, 78, 79, 13, 14, 15, 16,
+ 80, 81, 17, 18, 19, 20, 82, 83, 49, 50, 51, 52, 53, 54, 56, 57, -1
+};
+
+const int16 EobCoreEngine::_buttonList2[] = {
+ 58, 61, 62, 63, 64, 65, 93, 94, 66, 67, 68, 69, 70, 71, 76, 77, 88, 0, 1, 2, 3,
+ 90, 91, 4, 5, 6, 7, 8, 9, 10, 11, 12, 78, 79, 13, 14, 15, 16, 80, 81, 17, 18,
+ 19, 20, 82, 83, 49, 50, 51, 52, 53, 54, 56, 57, -1
+};
+
+const int16 EobCoreEngine::_buttonList3[] = {
+ 58, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 84, 85, 46, 47, 48, 60, 59, 92, 4, 5, 6, 7, 8, 49, 50,
+ 51, 52, 53, 54, 56, 57, -1
+};
+
+const int16 EobCoreEngine::_buttonList4[] = {
+ 58, 47, 48, 60, 59, 92, 4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 56, 57, -1
+};
+
+const int16 EobCoreEngine::_buttonList5[] = {
+ 58, 61, 62, 63, 64, 65, 93, 66, 67, 68, 69, 70, 71, 88, 21, 22, 23, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 84,
+ 85, 46, 47, 48, 60, 59, 92, 4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 56, 57, -1
+};
+
+const int16 EobCoreEngine::_buttonList6[] = {
+ 58, 61, 62, 63, 64, 65, 93, 66, 67, 68, 69, 70, 71, 88, 46, 47, 48, 60, 59, 92,
+ 4, 5, 6, 7, 8, 49, 50, 51, 52, 53, 54, 56, 57, -1
+};
+
+const int16 EobCoreEngine::_buttonList7[] = {
+ 17, 18, 19, 20, 82, 83, 55, -1
+};
+
+const int16 EobCoreEngine::_buttonList8[] = {
+ 72, 73, 74, 75, 86, 87, 89, -1
+};
+
+const uint8 EobCoreEngine::_clock2Timers[] = {
+ 0x00, 0x01, 0x20, 0x21, 0x22, 0x22,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
+ 0x04, 0x05, 0x06, 0x07
+};
+
+const uint8 EobCoreEngine::_numClock2Timers = ARRAYSIZE(EobCoreEngine::_clock2Timers);
+
+void EobCoreEngine::initStaticResource() {
+ int temp;
+ _chargenStatStrings = _staticres->loadStrings(kEobBaseChargenStatStrings, temp);
+ _chargenRaceSexStrings = _staticres->loadStrings(kEobBaseChargenRaceSexStrings, temp);
+ _chargenClassStrings = _staticres->loadStrings(kEobBaseChargenClassStrings, temp);
+ _chargenAlignmentStrings = _staticres->loadStrings(kEobBaseChargenAlignmentStrings, temp);
+
+ _pryDoorStrings = _staticres->loadStrings(kEobBasePryDoorStrings, temp);
+ _warningStrings = _staticres->loadStrings(kEobBaseWarningStrings, temp);
+ _itemSuffixStrings = _staticres->loadStrings(kEobBaseItemSuffixStrings, temp);
+ _itemExtraStrings = _staticres->loadStrings(kEobBaseItemExtraStrings, temp);
+ _takenStrings = _staticres->loadStrings(kEobBaseTakenStrings, temp);
+ _potionEffectStrings = _staticres->loadStrings(kEobBasePotionEffectStrings, temp);
+
+ _yesNoStrings = _staticres->loadStrings(kEobBaseYesNoStrings, temp);
+ _npcMaxStrings = _staticres->loadStrings(kEobBaseNpcMaxStrings, temp);
+ _okStrings = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEobBaseOkStrings : kLolEobCommonMoreStrings, temp);
+ _npcJoinStrings = _staticres->loadStrings(kEobBaseNpcJoinStrings, temp);
+ _cancelStrings = _staticres->loadStrings(kEobBaseCancelStrings, temp);
+ _abortStrings = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEobBaseAbortStrings : kEobBaseCancelStrings, temp);
+
+ _characterGuiStringsHp = _staticres->loadStrings(kEobBaseCharGuiStringsHp, temp);
+ _characterGuiStringsWp = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEobBaseCharGuiStringsWp2 : kEobBaseCharGuiStringsWp1, temp);
+ _characterGuiStringsWr = _staticres->loadStrings(kEobBaseCharGuiStringsWr, temp);
+ _characterGuiStringsSt = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEobBaseCharGuiStringsSt2 : kEobBaseCharGuiStringsSt1, temp);
+ _characterGuiStringsIn = _staticres->loadStrings(kEobBaseCharGuiStringsIn, temp);
+
+ _characterStatusStrings7 = _staticres->loadStrings(kEobBaseCharStatusStrings7, temp);
+ _characterStatusStrings8 = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEobBaseCharStatusStrings82 : kEobBaseCharStatusStrings81, temp);
+ _characterStatusStrings9 = _staticres->loadStrings(kEobBaseCharStatusStrings9, temp);
+ _characterStatusStrings12 = _staticres->loadStrings(kEobBaseCharStatusStrings12, temp);
+ _characterStatusStrings13 = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEobBaseCharStatusStrings132 : kEobBaseCharStatusStrings131, temp);
+
+ _levelGainStrings = _staticres->loadStrings(kEobBaseLevelGainStrings, temp);
+ _expRequirementTables[0] = _staticres->loadRawDataBe32(kEobBaseExperienceTable0, temp);
+ _expRequirementTables[1] = _staticres->loadRawDataBe32(kEobBaseExperienceTable1, temp);
+ _expRequirementTables[2] = _staticres->loadRawDataBe32(kEobBaseExperienceTable2, temp);
+ _expRequirementTables[3] = _staticres->loadRawDataBe32(kEobBaseExperienceTable3, temp);
+ _expRequirementTables[4] = _staticres->loadRawDataBe32(kEobBaseExperienceTable4, temp);
+ _expRequirementTables[5] = _staticres->loadRawDataBe32(kEobBaseExperienceTable4, temp);
+
+ _classModifierFlags = _staticres->loadRawData(kEobBaseClassModifierFlags, temp);
+
+ _constModTables[0] = _constModTables[4] = _constModTables[5] = _staticres->loadRawData(kEobBaseConstModTable1, temp);
+ _constModTables[1] = _staticres->loadRawData(kEobBaseConstModTable2, temp);
+ _constModTables[2] = _staticres->loadRawData(kEobBaseConstModTable3, temp);
+ _constModTables[3] = _staticres->loadRawData(kEobBaseConstModTable4, temp);
+ _constModLevelIndex = _staticres->loadRawData(kEobBaseConstModLvlIndex, temp);
+ _constModDiv = _staticres->loadRawData(kEobBaseConstModDiv, temp);
+ _constModExt = _staticres->loadRawData(kEobBaseConstModExt, temp);
+
+ _encodeMonsterShpTable = _staticres->loadRawDataBe16(kEobBaseEncodeMonsterDefs, temp);
+ _npcPreset = _staticres->loadEobNpcData(kEobBaseNpcPresets, temp);
+
+ _teleporterShapeCoords = _staticres->loadRawData(kEobBaseDscTelptrShpCoords, temp);
+
+ _monsterStepTable0 = (int8*) _staticres->loadRawData(_flags.gameID == GI_EOB2 ? kEobBaseMonsterStepTable02 : kEobBaseMonsterStepTable01, temp);
+ _monsterStepTable1 = (int8*)_staticres->loadRawData(kEobBaseMonsterStepTable1, temp);
+ _monsterStepTable2 = (int8*)_staticres->loadRawData(kEobBaseMonsterStepTable2, temp);
+ _monsterStepTable3 = (int8*)_staticres->loadRawData(kEobBaseMonsterStepTable3, temp);
+ _monsterCloseAttPosTable1 = _staticres->loadRawData(kEobBaseMonsterCloseAttPosTable1, temp);
+ _monsterCloseAttPosTable2 = _staticres->loadRawData(_flags.gameID == GI_EOB2 ? kEobBaseMonsterCloseAttPosTable22 : kEobBaseMonsterCloseAttPosTable21, temp);
+ _monsterCloseAttUnkTable = (int8*)_staticres->loadRawData(kEobBaseMonsterCloseAttUnkTable, temp);
+ _monsterCloseAttChkTable1 = _staticres->loadRawData(kEobBaseMonsterCloseAttChkTable1, temp);
+ _monsterCloseAttChkTable2 = _staticres->loadRawData(kEobBaseMonsterCloseAttChkTable2, temp);
+ _monsterCloseAttDstTable1 = _staticres->loadRawData(kEobBaseMonsterCloseAttDstTable1, temp);
+ _monsterCloseAttDstTable2 = _staticres->loadRawData(kEobBaseMonsterCloseAttDstTable2, temp);
+
+ _monsterProximityTable = _staticres->loadRawData(kEobBaseMonsterProximityTable, temp);
+ _findBlockMonstersTable = _staticres->loadRawData(kEobBaseFindBlockMonstersTable, temp);
+ _monsterDirChangeTable = (const int8*)_staticres->loadRawData(kEobBaseMonsterDirChangeTable, temp);
+ _monsterSpecAttStrings = _staticres->loadStrings(kEobBaseMonsterDistAttStrings, temp);
+
+ _monsterFrmOffsTable1 = (const int8*)_staticres->loadRawData(kEobBaseDscMonsterFrmOffsTbl1, temp);
+ _monsterFrmOffsTable2 = (const int8*)_staticres->loadRawData(kEobBaseDscMonsterFrmOffsTbl2, temp);
+
+ _inventorySlotsX = _staticres->loadRawDataBe16(kEobBaseInvSlotX, temp);
+ _inventorySlotsY = _staticres->loadRawData(kEobBaseInvSlotY, temp);
+ _slotValidationFlags = _staticres->loadRawDataBe16(kEobBaseSlotValidationFlags, temp);
+
+ _drawObjPosIndex = _staticres->loadRawData(kEobBaseDrawObjPosIndex, temp);
+ _flightObjFlipIndex = _staticres->loadRawData(kEobBaseFlightObjFlipIndex, temp);
+ _flightObjShpMap = (const int8*)_staticres->loadRawData(kEobBaseFlightObjShpMap, temp);
+ _flightObjSclIndex = (const int8*)_staticres->loadRawData(kEobBaseFlightObjSclIndex, temp);
+
+ _wllFlagPreset = _staticres->loadRawData(kEobBaseWllFlagPreset, _wllFlagPresetSize);
+ _dscShapeCoords = (const int16*)_staticres->loadRawDataBe16(kEobBaseDscShapeCoords, temp);
+
+ _dscDoorScaleOffs = _staticres->loadRawData(kEobBaseDscDoorScaleOffs, temp);
+ _dscDoorScaleMult1 = _staticres->loadRawData(kEobBaseDscDoorScaleMult1, temp);
+ _dscDoorScaleMult2 = _staticres->loadRawData(kEobBaseDscDoorScaleMult2, temp);
+ _dscDoorScaleMult3 = _staticres->loadRawData(kEobBaseDscDoorScaleMult3, temp);
+ _dscDoorY1 = _staticres->loadRawData(kEobBaseDscDoorY1, temp);
+
+ _dscItemPosIndex= _staticres->loadRawData(kEobBaseDscItemPosIndex, temp);
+ _dscItemShpX = (const int16*)_staticres->loadRawDataBe16(kEobBaseDscItemShpX, temp);
+ _dscItemScaleIndex = _staticres->loadRawData(kEobBaseDscItemScaleIndex, temp);
+ _dscItemTileIndex = _staticres->loadRawData(kEobBaseDscItemTileIndex, temp);
+ _dscItemShapeMap = _staticres->loadRawData(kEobBaseDscItemShapeMap, temp);
+
+ _bookNumbers = _staticres->loadStrings(kEobBaseBookNumbers, temp);
+ _mageSpellList = _staticres->loadStrings(kEobBaseMageSpellsList, _mageSpellListSize);
+ _clericSpellList = _staticres->loadStrings(kEobBaseClericSpellsList, temp);
+ _spellNames = _staticres->loadStrings(kEobBaseSpellNames, temp);
+
+ _magicStrings1 = _staticres->loadStrings(kEobBaseMagicStrings1, temp);
+ _magicStrings2 = _staticres->loadStrings(kEobBaseMagicStrings2, temp);
+ _magicStrings3 = _staticres->loadStrings(kEobBaseMagicStrings3, temp);
+ _magicStrings4 = _staticres->loadStrings(kEobBaseMagicStrings4, temp);
+ _magicStrings5 = _staticres->loadStrings(kEobBaseMagicStrings5, temp);
+ _magicStrings6 = _staticres->loadStrings(kEobBaseMagicStrings6, temp);
+ _magicStrings7 = _staticres->loadStrings(kEobBaseMagicStrings7, temp);
+ _magicStrings8 = _staticres->loadStrings(kEobBaseMagicStrings8, temp);
+
+ _sparkEffectDefSteps = _staticres->loadRawData(kEobBaseSparkDefSteps, temp);
+ _sparkEffectDefSubSteps = _staticres->loadRawData(kEobBaseSparkDefSubSteps, temp);
+ _sparkEffectDefShift = _staticres->loadRawData(kEobBaseSparkDefShift, temp);
+ _sparkEffectDefAdd = _staticres->loadRawData(kEobBaseSparkDefAdd, temp);
+ _sparkEffectDefX = _staticres->loadRawData(kEobBaseSparkDefX, temp);
+ _sparkEffectDefY = _staticres->loadRawData(kEobBaseSparkDefY, temp);
+ _sparkEffectOfFlags1 = _staticres->loadRawDataBe32(kEobBaseSparkOfFlags1, temp);
+ _sparkEffectOfFlags2 = _staticres->loadRawDataBe32(kEobBaseSparkOfFlags2, temp);
+ _sparkEffectOfShift = _staticres->loadRawData(kEobBaseSparkOfShift, temp);
+ _sparkEffectOfX = _staticres->loadRawData(kEobBaseSparkOfX, temp);
+ _sparkEffectOfY = _staticres->loadRawData(kEobBaseSparkOfY, temp);
+ _magicFlightObjectProperties = _staticres->loadRawData(kEobBaseMagicFlightProps, temp);
+}
+
+void EobCoreEngine::initButtonData() {
+ #define EOB_CB(x) BUTTON_FUNCTOR(EobCoreEngine, this, &EobCoreEngine::x)
+ static const EobGuiButtonDef buttonDefs[] = {
+ { 112, 0, 0x1100, 184, 2, 63, 50, EOB_CB(clickedCharPortraitDefault), 0 },
+ { 113, 0, 0x1100, 256, 2, 63, 50, EOB_CB(clickedCharPortraitDefault), 1 },
+ { 114, 0, 0x1100, 184, 54, 63, 50, EOB_CB(clickedCharPortraitDefault), 2 },
+ { 115, 0, 0x1100, 256, 54, 63, 50, EOB_CB(clickedCharPortraitDefault), 3 },
+ { 48, 110, 0x1100, 289, 177, 31, 21, EOB_CB(clickedCamp), 0 },
+ { 0, 0, 0x1100, 0, 102, 88, 18, EOB_CB(clickedSceneDropPickupItem), 0 },
+ { 0, 0, 0x1100, 89, 102, 88, 18, EOB_CB(clickedSceneDropPickupItem), 1 },
+ { 0, 0, 0x1100, 0, 72, 88, 29, EOB_CB(clickedSceneDropPickupItem), 2 },
+ { 0, 0, 0x1100, 89, 72, 88, 29, EOB_CB(clickedSceneDropPickupItem), 3 },
+ { 24, 0, 0x1100, 184, 10, 33, 33, EOB_CB(clickedCharPortrait2), 0 },
+ { 0, 0, 0x1100, 256, 10, 33, 33, EOB_CB(clickedCharPortrait2), 1 },
+ { 0, 0, 0x1100, 184, 62, 33, 33, EOB_CB(clickedCharPortrait2), 2 },
+ { 0, 0, 0x1100, 256, 62, 33, 33, EOB_CB(clickedCharPortrait2), 3 },
+ { 0, 0, 0x1100, 216, 10, 31, 33, EOB_CB(clickedWeaponSlot), 0 },
+ { 0, 0, 0x1100, 288, 10, 31, 33, EOB_CB(clickedWeaponSlot), 1 },
+ { 0, 0, 0x1100, 216, 62, 31, 33, EOB_CB(clickedWeaponSlot), 2 },
+ { 0, 0, 0x1100, 288, 62, 31, 33, EOB_CB(clickedWeaponSlot), 3 },
+ { 368, 0, 0x1000, 184, 2, 63, 8, EOB_CB(clickedCharNameLabelRight), 0 },
+ { 369, 0, 0x1000, 256, 2, 63, 8, EOB_CB(clickedCharNameLabelRight), 1 },
+ { 370, 0, 0x1000, 184, 54, 63, 8, EOB_CB(clickedCharNameLabelRight), 2 },
+ { 371, 0, 0x1000, 256, 54, 63, 8, EOB_CB(clickedCharNameLabelRight), 3 },
+ { 0, 0, 0x1100, 230, 116, 16, 16, EOB_CB(clickedInventorySlot), 0 },
+ { 0, 0, 0x1100, 278, 116, 16, 16, EOB_CB(clickedInventorySlot), 1 },
+ { 0, 0, 0x1100, 181, 40, 16, 16, EOB_CB(clickedInventorySlot), 2 },
+ { 0, 0, 0x1100, 199, 40, 16, 16, EOB_CB(clickedInventorySlot), 3 },
+ { 0, 0, 0x1100, 181, 58, 16, 16, EOB_CB(clickedInventorySlot), 4 },
+ { 0, 0, 0x1100, 199, 58, 16, 16, EOB_CB(clickedInventorySlot), 5 },
+ { 0, 0, 0x1100, 181, 76, 16, 16, EOB_CB(clickedInventorySlot), 6 },
+ { 0, 0, 0x1100, 199, 76, 16, 16, EOB_CB(clickedInventorySlot), 7 },
+ { 0, 0, 0x1100, 181, 94, 16, 16, EOB_CB(clickedInventorySlot), 8 },
+ { 0, 0, 0x1100, 199, 94, 16, 16, EOB_CB(clickedInventorySlot), 9 },
+ { 0, 0, 0x1100, 181, 112, 16, 16, EOB_CB(clickedInventorySlot), 10 },
+ { 0, 0, 0x1100, 199, 112, 16, 16, EOB_CB(clickedInventorySlot), 11 },
+ { 0, 0, 0x1100, 181, 130, 16, 16, EOB_CB(clickedInventorySlot), 12 },
+ { 0, 0, 0x1100, 199, 130, 16, 16, EOB_CB(clickedInventorySlot), 13 },
+ { 0, 0, 0x1100, 181, 148, 16, 16, EOB_CB(clickedInventorySlot), 14 },
+ { 0, 0, 0x1100, 199, 148, 16, 16, EOB_CB(clickedInventorySlot), 15 },
+ { 0, 0, 0x1100, 225, 55, 16, 16, EOB_CB(clickedInventorySlot), 16 },
+ { 0, 0, 0x1100, 224, 76, 16, 16, EOB_CB(clickedInventorySlot), 17 },
+ { 0, 0, 0x1100, 225, 96, 16, 16, EOB_CB(clickedInventorySlot), 18 },
+ { 0, 0, 0x1100, 298, 55, 16, 16, EOB_CB(clickedInventorySlot), 19 },
+ { 0, 0, 0x1100, 287, 75, 16, 16, EOB_CB(clickedInventorySlot), 20 },
+ { 0, 0, 0x1100, 277, 137, 16, 16, EOB_CB(clickedInventorySlot), 21 },
+ { 0, 0, 0x1100, 300, 94, 16, 16, EOB_CB(clickedInventorySlot), 22 },
+ { 0, 0, 0x1100, 300, 112, 16, 16, EOB_CB(clickedInventorySlot), 23 },
+ { 0, 0, 0x1100, 300, 130, 16, 16, EOB_CB(clickedInventorySlot), 24 },
+ { 0, 0, 0x1100, 236, 37, 31, 16, EOB_CB(clickedEatItem), 25 },
+ { 26, 0, 0x1100, 291, 149, 25, 17, EOB_CB(clickedInventoryNextPage), 25 },
+ { 110, 24, 0x1100, 181, 3, 32, 32, EOB_CB(clickedPortraitRestore), 25 },
+ { 96, 352, 0x1100, 24, 128, 21, 16, EOB_CB(clickedUpArrow), 25 },
+ { 98, 97, 0x1100, 24, 144, 21, 16, EOB_CB(clickedDownArrow), 25 },
+ { 92, 348, 0x1100, 3, 144, 21, 16, EOB_CB(clickedLeftArrow), 25 },
+ { 102, 358, 0x1100, 45, 144, 21, 16, EOB_CB(clickedRightArrow), 25 },
+ { 91, 0, 0x1100, 3, 128, 21, 16, EOB_CB(clickedTurnLeftArrow), 25 },
+ { 101, 0, 0x1100, 45, 128, 21, 16, EOB_CB(clickedTurnRightArrow), 25 },
+ { 110, 0, 0x1100, 184, 0, 136, 120, EOB_CB(clickedAbortCharSwitch), 0 },
+ { 0, 0, 0x1100, 0, 8, 88, 48, EOB_CB(clickedSceneThrowItem), 0 },
+ { 0, 0, 0x1100, 88, 8, 88, 48, EOB_CB(clickedSceneThrowItem), 1 },
+ { 0, 0, 0x1100, 24, 8, 128, 96, EOB_CB(clickedSceneSpecial), 1 },
+ { 112, 113, 0x1100, 274, 35, 20, 15, EOB_CB(clickedInventoryPrevChar), 1 },
+ { 114, 115, 0x1100, 297, 35, 20, 15, EOB_CB(clickedInventoryNextChar), 1 },
+ { 2, 0, 0x1100, 68, 121, 18, 10, EOB_CB(clickedSpellbookTab), 0 },
+ { 3, 0, 0x1100, 86, 121, 18, 10, EOB_CB(clickedSpellbookTab), 1 },
+ { 4, 0, 0x1100, 104, 121, 15, 10, EOB_CB(clickedSpellbookTab), 2 },
+ { 5, 0, 0x1100, 122, 121, 15, 10, EOB_CB(clickedSpellbookTab), 3 },
+ { 6, 0, 0x1100, 140, 121, 15, 10, EOB_CB(clickedSpellbookTab), 4 },
+ { 0, 0, 0x1100, 75, 131, 97, 6, EOB_CB(clickedSpellbookList), 0 },
+ { 0, 0, 0x1100, 75, 137, 97, 6, EOB_CB(clickedSpellbookList), 1 },
+ { 0, 0, 0x1100, 75, 143, 97, 6, EOB_CB(clickedSpellbookList), 2 },
+ { 0, 0, 0x1100, 75, 149, 97, 6, EOB_CB(clickedSpellbookList), 3 },
+ { 0, 0, 0x1100, 75, 155, 97, 6, EOB_CB(clickedSpellbookList), 4 },
+ { 0, 0, 0x1100, 75, 161, 97, 6, EOB_CB(clickedSpellbookList), 5 },
+ { 112, 0, 0x1100, 184, 2, 63, 50, EOB_CB(clickedCastSpellOnCharacter), 0 },
+ { 113, 0, 0x1100, 256, 2, 63, 50, EOB_CB(clickedCastSpellOnCharacter), 1 },
+ { 114, 0, 0x1100, 184, 54, 63, 50, EOB_CB(clickedCastSpellOnCharacter), 2 },
+ { 115, 0, 0x1100, 256, 54, 63, 50, EOB_CB(clickedCastSpellOnCharacter), 3 },
+ { 53, 54, 0x1100, 320, 200, 0, 0, EOB_CB(clickedSpellbookList), 6 },
+ { 61, 0, 0x1100, 320, 200, 0, 0, EOB_CB(clickedSpellbookList), 7 },
+ { 0, 0, 0x1100, 184, 114, 33, 33, EOB_CB(clickedCharPortrait2), 4 },
+ { 0, 0, 0x1100, 256, 114, 33, 33, EOB_CB(clickedCharPortrait2), 5 },
+ { 0, 0, 0x1100, 216, 114, 31, 33, EOB_CB(clickedWeaponSlot), 4 },
+ { 0, 0, 0x1100, 288, 114, 31, 33, EOB_CB(clickedWeaponSlot), 5 },
+ { 372, 0, 0x1000, 184, 106, 63, 8, EOB_CB(clickedCharNameLabelRight), 4 },
+ { 373, 0, 0x1000, 256, 106, 63, 8, EOB_CB(clickedCharNameLabelRight), 5 },
+ { 0, 0, 0x1100, 227, 135, 10, 10, EOB_CB(clickedInventorySlot), 25 },
+ { 0, 0, 0x1100, 239, 135, 10, 10, EOB_CB(clickedInventorySlot), 26 },
+ { 116, 0, 0x1100, 184, 106, 63, 50, EOB_CB(clickedCastSpellOnCharacter), 4 },
+ { 117, 0, 0x1100, 256, 106, 63, 50, EOB_CB(clickedCastSpellOnCharacter), 5 },
+ { 110, 0, 0x1100, 68, 168, 78, 10, EOB_CB(clickedSpellbookAbort), 0 },
+ { 110, 0, 0x1100, 68, 168, 78, 10, EOB_CB(clickedCastSpellOnCharacter), 65535 },
+ { 116, 0, 0x1100, 184, 106, 63, 50, EOB_CB(clickedCharPortraitDefault), 4 },
+ { 117, 0, 0x1100, 256, 106, 63, 50, EOB_CB(clickedCharPortraitDefault), 5 },
+ { 116, 117, 0x1100, 320, 200, 1, 1, EOB_CB(clickedInventoryNextChar), 2 },
+ { 7, 0, 0x1100, 158, 121, 15, 10, EOB_CB(clickedSpellbookTab), 5 },
+ { 0, 0, 0x1100, 146, 168, 32, 10, EOB_CB(clickedSpellbookScroll), 0 },
+
+ // EOB1 spellbook modifications
+ { 2, 0, 0x1100, 71, 122, 20, 8, EOB_CB(clickedSpellbookTab), 0 },
+ { 3, 0, 0x1100, 92, 122, 20, 8, EOB_CB(clickedSpellbookTab), 1 },
+ { 4, 0, 0x1100, 113, 122, 20, 8, EOB_CB(clickedSpellbookTab), 2 },
+ { 5, 0, 0x1100, 134, 122, 20, 8, EOB_CB(clickedSpellbookTab), 3 },
+ { 6, 0, 0x1100, 155, 122, 20, 8, EOB_CB(clickedSpellbookTab), 4 },
+ { 110, 0, 0x1100, 75, 168, 97, 6, EOB_CB(clickedSpellbookAbort), 0 },
+ };
+
+ _buttonDefs = buttonDefs;
+}
+
+void EobCoreEngine::initSpells() {
+#define mpn magicTimingParaAssign.push_back(0);
+#define mp1n if (_flags.gameID == GI_EOB1) magicTimingParaAssign.push_back(0);
+#define mp2n if (_flags.gameID == GI_EOB2) magicTimingParaAssign.push_back(0);
+#define mp(x) magicTimingParaAssign.push_back(&magicTimingPara[x << 2]);
+#define mp1(x) if (_flags.gameID == GI_EOB1) magicTimingParaAssign.push_back(&magicTimingPara[x << 2]);
+#define mp2(x) if (_flags.gameID == GI_EOB2) magicTimingParaAssign.push_back(&magicTimingPara[x << 2]);
+
+#define sc(x) startCallback.push_back(&EobCoreEngine::spellCallback_start_##x);
+#define sc1(x) if (_flags.gameID == GI_EOB1) startCallback.push_back(&EobCoreEngine::spellCallback_start_##x);
+#define sc2(x) if (_flags.gameID == GI_EOB2) startCallback.push_back(&EobCoreEngine::spellCallback_start_##x);
+#define ec(x) endCallback.push_back(&EobCoreEngine::spellCallback_end_##x);
+#define ec1(x) if (_flags.gameID == GI_EOB1) endCallback.push_back(&EobCoreEngine::spellCallback_end_##x);
+#define ec2(x) if (_flags.gameID == GI_EOB2) endCallback.push_back(&EobCoreEngine::spellCallback_end_##x);
+
+ static const uint16 magicTimingPara[] = {
+ 0, 546, 2, 1, // 0 detect magic
+ 0, 546, 5, 1, // 1 shield, detect invis, magical vestment
+ 0, 546, 1, 1, // 2 shocking grasp, vamp touch, true seeing, prayer
+ 3, 546, 1, 1, // 3 blur, haste
+ 5, 546, 1, 1, // 4 imp invisibility
+ 6, 546, 0, 1, // 5 bless
+ 0, 546, 3, 1, // 6 prot from evil
+ 1, 546, 1, 1, // 7 aid
+ 4, 546, 1, 1, // 8 flame blade
+ 0, 32760, 1, 1, // 9 slow poison
+ 1, 546, 0, 1, // 10 mystic defense
+ };
+
+ Common::Array<const uint16*> magicTimingParaAssign;
+ mpn;
+ mpn;
+ mpn;
+ mp(0); // Detect Magic
+ mpn; // Magic Missile
+ mp1n; ///
+ mp(1); // Shield
+ mp(2); // Shocking Grasp
+ mp2(3); // Blur ///
+ mp2(1); // Detect Invis ///
+ mp2n; // Imp Identify ///
+ mpn; // Invis
+ mp1n; ///
+ mpn; // Melf
+ mp1n; // Stinking Cloud ///
+ mpn; // Dispel Magic
+ mpn; // Fireball
+ mp1n; // Flame Arrow ///
+ mp(3); // Haste
+ mpn; // Hold Person
+ mpn; // Invisibility
+ mpn; // Lightning Bolt
+ mp(2); // Vampiric Touch
+ mpn; // Fear
+ mpn; // Ice Storm
+ mp1n; // Stone Skin /// --- para required?
+ mp1n; // Cloud Kill ///
+ mp2(4); // Improved Invisibility ///
+ mp2n; // remove Curse ///
+ mpn; // Cone of Cold
+ mpn; // Hold Monster
+ mp2n; // Wall of Force ///
+ mp2n; // Disintegrate ///
+ mp2n; // Flesh To Stone ///
+ mp2n; // Stone To Flesh ///
+ mp2(2); // True Seeing ///
+ mp2n; // Finger of Death ///
+ mp2n; // Power Word Stun ///
+ mp2n; // Bigby's Fist ///
+ mp2n; // empty ///
+ mp(5); // Bless
+ mpn; /// EOB1: cure, EOB2: cause
+ mpn; /// EOB1: cause, EOB2: cure
+ mp(0); // Detect Magic
+ mp(6); // Prot from Evil
+ mp(7); // Aid
+ mp(8); // Flame Blad
+ mpn; // Hold Person
+ mp(9); // Slow Poison
+ mpn; // Create Food
+ mpn; // Dispel Magic
+ mp(1); // Magical Vestment
+ mp(2); // Prayer
+ mpn; // Remove Paralysis
+ mpn; /// EOB1: cure, EOB2: cause
+ mpn; /// EOB1: cause, EOB2: cure
+ mpn; // Neutral Poison
+ mp(6); // Prot From Evil 10'
+ mp1n; // Prot From Lightning /// --- para required?
+ mpn; /// EOB1: cure, EOB2: cause
+ mpn; /// EOB1: cause, EOB2: cure
+ mpn; // Flame Strike
+ mpn; // Raise Dead
+ mp2n; // Slay Living ///
+ mp2(2); // True Seeing ///
+ mp2n; // Harm ///
+ mp2n; // Heal ///
+ mp2n; // Resurrect ///
+ mpn; // Lay on Hands
+ mp2n; // Turn Undead ///
+ mpn; // UNK 1 passive
+ mp2(10);// Mystic Defense ///
+ mp2n; // UNK 2 passive ///
+ mpn; // death spell passive
+ mpn; // disintegrate passive
+ mp2n; // cause critical passive
+ mp2n; // flesh to stone passive
+
+ Common::Array<SpellStartCallback> startCallback;
+ sc(empty);
+ sc(armor);
+ sc(burningHands);
+ sc(detectMagic);
+ sc(magicMissile);
+ sc1(empty);
+ sc(empty);
+ sc(shockingGrasp);
+ sc(empty);
+ sc2(empty);
+ sc2(improvedIdentify);
+ sc(empty);
+ sc(melfsAcidArrow);
+ sc1(empty); // Stinking Cloud
+ sc(dispelMagic);
+ sc(fireball);
+ sc1(flameArrow);
+ sc(empty);
+ sc(holdPerson);
+ sc(empty);
+ sc(lightningBolt);
+ sc(vampiricTouch);
+ sc(fear);
+ sc(iceStorm);
+ sc(empty); // EOB1: stone skin, EOB2: imp invisibility
+ sc1(empty); // Cloudkill
+ sc2(removeCurse);
+ sc(coneOfCold);
+ sc(holdMonster);
+ sc2(wallOfForce);
+ sc2(disintegrate);
+ sc2(fleshToStone);
+ sc2(stoneToFlesh);
+ sc2(trueSeeing);
+ sc2(slayLiving);
+ sc2(powerWordStun);
+ sc2(empty);
+ sc2(empty);
+ sc(empty); // Bless
+ sc2(causeLightWounds);
+ sc(cureLightWounds);
+ sc1(causeLightWounds);
+ sc(detectMagic);
+ sc(empty);
+ sc(aid);
+ sc(flameBlade);
+ sc(holdPerson);
+ sc(slowPoison);
+ sc(createFood);
+ sc(dispelMagic);
+ sc(empty);
+ sc(empty);
+ sc(removeParalysis);
+ sc2(causeSeriousWounds);
+ sc(cureSeriousWounds);
+ sc1(causeSeriousWounds);
+ sc(neutralizePoison);
+ sc(empty);
+ sc1(empty); // Prot from Lightning
+ sc2(causeCriticalWounds);
+ sc(cureCriticalWounds);
+ sc1(causeCriticalWounds);
+ sc(flameStrike);
+ sc(raiseDead);
+ sc2(slayLiving);
+ sc2(trueSeeing);
+ sc2(harm);
+ sc2(heal);
+ sc2(empty);
+ sc(layOnHands);
+ sc2(turnUndead);
+ sc(empty);
+ sc2(empty);
+ sc2(empty);
+ sc(empty);
+ sc(empty);
+ sc2(empty);
+ sc2(empty);
+
+ Common::Array<SpellEndCallback> endCallback;
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(detectMagic);
+ ec(magicMissile);
+ ec1(empty);
+ ec(empty);
+ ec(shockingGraspFlameBlade);
+ ec(empty);
+ ec(empty);
+ ec2(empty);
+ ec2(empty);
+ ec(melfsAcidArrow);
+ ec1(empty); // Stinking Cloud
+ ec(empty);
+ ec(fireball);
+ ec1(flameArrow);
+ ec(empty);
+ ec(holdPerson);
+ ec(empty);
+ ec(lightningBolt);
+ ec(vampiricTouch);
+ ec(empty);
+ ec(iceStorm);
+ ec(empty); // EOB1: stone skin, EOB2: imp invisibility
+ ec(empty); // EOB1: cloud kill, EOB2: remove curse
+ ec(empty);
+ ec(holdMonster);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec2(trueSeeing);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec(empty); // Bless
+ ec(empty);
+ ec(empty);
+ ec(detectMagic);
+ ec(empty);
+ ec(aid);
+ ec(shockingGraspFlameBlade);
+ ec(holdPerson);
+ ec(slowPoison);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec(empty);
+ ec1(empty); // Prot from Lightning
+ ec(empty);
+ ec(empty);
+ ec(flameStrike);
+ ec(empty);
+ ec2(empty);
+ ec2(trueSeeing);
+ ec2(empty);
+ ec2(empty);
+ ec2(empty);
+ ec(empty);
+ ec2(empty);
+ ec(unk1Passive);
+ ec2(empty);
+ ec2(unk2Passive);
+ ec(deathSpellPassive);
+ ec(disintegratePassive);
+ ec2(causeCriticalWoundsPassive);
+ ec2(fleshToStonePassive);
+
+ _spells = new EobSpell[_numSpells];
+ memset(_spells, 0, _numSpells * sizeof(EobSpell));
+
+ for (int i = 0; i < _numSpells; i++) {
+ EobSpell *s = &_spells[i];
+ s->name = _flags.gameID == GI_EOB2 ? ((i == 0 || i == _mageSpellListSize) ? _mageSpellList[0] : ((i < (_mageSpellListSize + 1)) ? _spellNames[i - 1] : _spellNames[i - 2])) : _spellNames[i];
+ s->startCallback = startCallback[i];
+ s->timingPara = magicTimingParaAssign[i];
+ s->endCallback = endCallback[i];
+ }
+
+ magicTimingParaAssign.clear();
+ startCallback.clear();
+ endCallback.clear();
+
+ _clericSpellOffset = _mageSpellListSize;
+
+#undef mpn
+#undef mp1n
+#undef mp2n
+#undef mp
+#undef mp1
+#undef mp2
+#undef sc
+#undef sc1
+#undef sc2
+#undef ec
+#undef ec1
+#undef ec2
+}
+
+void EobEngine::initStaticResource() {
+ int temp;
+ _mainMenuStrings = _staticres->loadStrings(kEob1MainMenuStrings, temp);
+
+ _doorShapeEncodeDefs = _staticres->loadRawData(kEob1DoorShapeDefs, temp);
+ _doorSwitchShapeEncodeDefs = _staticres->loadRawData(kEob1DoorSwitchShapeDefs, temp);
+ _doorSwitchCoords = _staticres->loadRawData(kEob1DoorSwitchCoords, temp);
+
+ _dscDoorScaleMult4 = _staticres->loadRawData(kEobBaseDscDoorScaleMult4, temp);
+ _dscDoorScaleMult5 = _staticres->loadRawData(kEobBaseDscDoorScaleMult5, temp);
+ _dscDoorScaleMult6 = _staticres->loadRawData(kEobBaseDscDoorScaleMult6, temp);
+ _dscDoorY3 = _staticres->loadRawData(kEobBaseDscDoorY3, temp);
+ _dscDoorY4 = _staticres->loadRawData(kEobBaseDscDoorY4, temp);
+ _dscDoorY5 = _staticres->loadRawData(kEobBaseDscDoorY5, temp);
+ _dscDoorY6 = _staticres->loadRawData(kEobBaseDscDoorY6, temp);
+ _dscDoorCoordsExt = (const int16*)_staticres->loadRawDataBe16(kEobBaseDscDoorCoordsExt, temp);
+
+ _monsterDistAttType10 = _staticres->loadRawData(kEob1MonsterDistAttType10, temp);
+ _monsterDistAttSfx10 = _staticres->loadRawData(kEob1MonsterDistAttSfx10, temp);
+ _monsterDistAttType17 = _staticres->loadRawData(kEob1MonsterDistAttType17, temp);
+ _monsterDistAttSfx17 = _staticres->loadRawData(kEob1MonsterDistAttSfx17, temp);
+
+ const uint8 *ps = _staticres->loadRawData(kEob1MonsterProperties, temp);
+ temp /= 27;
+ _monsterProps = new EobMonsterProperty[temp];
+ memset(_monsterProps, 0, temp * sizeof(EobMonsterProperty));
+ // Try to convert EOB1 (hard coded) monster properties to EOB2 type monster properties.
+ // This is still WIP, since most properties are unknown for now.
+ for (int i = 0; i < temp; i++) {
+ EobMonsterProperty *p = &_monsterProps[i];
+ p->armorClass = (int8)*ps++;
+ p->hitChance = (int8)*ps++;
+ p->hpDcTimes = *ps++;
+ p->attacksPerRound = *ps++;
+ p->dmgDc[0].times = *ps++;
+ p->dmgDc[0].pips = *ps++;
+ p->dmgDc[0].base = (int8)*ps++;
+ p->dmgDc[1].times = *ps++;
+ p->dmgDc[1].pips = *ps++;
+ p->dmgDc[1].base =(int8) *ps++;
+ p->dmgDc[2].times = *ps++;
+ p->dmgDc[2].pips = *ps++;
+ p->dmgDc[2].base = (int8)*ps++;
+ ps++;
+ p->flags = *ps++;
+ ps++;
+ ps++;
+ ps++;
+ ps++;
+ p->experience = READ_LE_UINT16(ps);
+ ps += 2;
+ p->u30 = *ps++;
+ p->sound1 = *ps++;
+ p->sound2 = *ps++;
+ p->numRemoteAttacks = *ps++;
+ ps++;
+ p->dmgModifierEvade = *ps++;
+ }
+}
+
+void EobEngine::initSpells() {
+ EobCoreEngine::initSpells();
+
+ static const uint32 eflags[] = {
+ 0x0000, 0x0001, 0x0000, 0x0002, 0x0000, 0x0000, 0x0008, 0x0000, 0x0040, 0x0000,
+ 0x0000, 0x0000 /*stinking cloud*/, 0x0000, 0x0000, 0x0000 /*flame arrow*/, 0x10000,0x0000, 0x0040, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000 /*stone skin*/, 0x0000 /*cloud kill*/, 0x0000, 0x0000, 0x0400, 0x0000, 0x0000, 0x0002,
+ 0x0800, 0x0000, 0x0000, 0x0000, 0x2000, 0x0000, 0x0000, 0x4000, 0x8000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0800, 0x0000 /*Prot From Lightning*/, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000
+ };
+
+ static const uint8 dflags[] = {
+ 0x00, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x11, 0x00 /*stinking cloud*/, 0x00, 0x21, 0x11 /*flame arrow*/, 0x00, 0x00, 0x00, 0x03, 0x01,
+ 0x00, 0x41, 0x00 /*stone skin*/, 0x00 /*cloud kill*/, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00,
+ 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00, 0x00 /*Prot From Lightning*/, 0x00, 0x01, 0x21, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+ };
+
+ int temp;
+ const uint8 *src = _staticres->loadRawData(kEobBaseSpellProperties, temp);
+ _clericSpellOffset -= 3;
+
+ for (int i = 0; i < _numSpells; i++) {
+ EobSpell *s = &_spells[i];
+ src += 4;
+ s->flags = convertSpellFlagToEob2Format(src[0], src[14]);
+ s->damageFlags = dflags[i];
+ s->effectFlags = eflags[i];
+ s->sound = src[13];
+ src += 15;
+ }
+}
+
+void DarkMoonEngine::initStaticResource() {
+ int temp;
+ _mainMenuStrings = _staticres->loadStrings(kEob2MainMenuStrings, temp);
+ _introStrings = _staticres->loadStrings(kEob2IntroStrings, temp);
+ _cpsFilesIntro = _staticres->loadStrings(kEob2IntroCPSFiles, temp);
+
+ _seqIntro = new const EobSequenceStep*[44];
+ for (int i = 0; i < 44; i++)
+ _seqIntro[i] = _staticres->loadEob2SeqData(kEob2IntroSeqData00 + i, temp);
+
+ _shapesIntro = new const EobShapeDef*[13];
+ memset(_shapesIntro, 0, sizeof(EobShapeDef*) * 13);
+ _shapesIntro[0] = _staticres->loadEob2ShapeData(kEob2IntroShapes00, temp);
+ _shapesIntro[1] = _staticres->loadEob2ShapeData(kEob2IntroShapes01, temp);
+ _shapesIntro[4] = _staticres->loadEob2ShapeData(kEob2IntroShapes04, temp);
+ _shapesIntro[7] = _staticres->loadEob2ShapeData(kEob2IntroShapes07, temp);
+
+ _finaleStrings = _staticres->loadStrings(kEob2FinaleStrings, temp);
+ _creditsData = _staticres->loadRawData(kEob2CreditsData, temp);
+ _cpsFilesFinale = _staticres->loadStrings(kEob2FinaleCPSFiles, temp);
+
+ _seqFinale = new const EobSequenceStep*[21];
+ for (int i = 0; i < 21; i++)
+ _seqFinale[i] = _staticres->loadEob2SeqData(kEob2FinaleSeqData00 + i, temp);
+
+ _shapesFinale = new const EobShapeDef*[13];
+ memset(_shapesFinale, 0, sizeof(EobShapeDef*) * 13);
+ _shapesFinale[0] = _staticres->loadEob2ShapeData(kEob2FinaleShapes00, temp);
+ _shapesFinale[3] = _staticres->loadEob2ShapeData(kEob2FinaleShapes03, temp);
+ _shapesFinale[7] = _staticres->loadEob2ShapeData(kEob2FinaleShapes07, temp);
+ _shapesFinale[9] = _staticres->loadEob2ShapeData(kEob2FinaleShapes09, temp);
+ _shapesFinale[10] = _staticres->loadEob2ShapeData(kEob2FinaleShapes10, temp);
+
+ _dscDoorType5Offs = _staticres->loadRawData(kEobBaseDscDoorType5Offs, temp);
+
+ _npcShpData = _staticres->loadRawData(kEob2NpcShapeData, temp);
+ _npc1Strings = _staticres->loadStrings(kEob2Npc1Strings, temp);
+ _npc2Strings = _staticres->loadStrings(kEob2Npc2Strings, temp);
+ _monsterDustStrings = _staticres->loadStrings(kEob2MonsterDustStrings, temp);
+}
+
+void DarkMoonEngine::initSpells() {
+ EobCoreEngine::initSpells();
+
+ int temp;
+ const uint8 *src = _staticres->loadRawData(kEobBaseSpellProperties, temp);
+
+ for (int i = 0; i < _numSpells; i++) {
+ EobSpell *s = &_spells[i];
+ src += 8;
+ s->flags = READ_LE_UINT16(src);
+ src += 10;
+ s->sound = *src++;
+ s->effectFlags = READ_LE_UINT32(src);
+ src += 4;
+ s->damageFlags = READ_LE_UINT16(src);
+ src += 2;
+ }
+}
+
+const char *DarkMoonEngine::_palFilesIntro[] = {
+ "PALETTE1.PAL", // EGA: palette0.pal
+ "PALETTE3.PAL",
+ "PALETTE2.PAL",
+ "PALETTE4.PAL",
+ 0
+};
+
+const char *DarkMoonEngine::_palFilesFinale[] = {
+ "FINALE_0.PAL",
+ "FINALE_0.PAL",
+ "FINALE_1.PAL",
+ "FINALE_2.PAL",
+ "FINALE_3.PAL",
+ "FINALE_4.PAL",
+ "FINALE_5.PAL",
+ "FINALE_6.PAL",
+ "FINALE_7.PAL",
+ 0
+};
+
+#endif // ENABLE_EOB
+
+} // End of namespace Kyra
+
diff --git a/engines/kyra/staticres_lol.cpp b/engines/kyra/staticres_lol.cpp
index bf838cd572..44b82ceb00 100644
--- a/engines/kyra/staticres_lol.cpp
+++ b/engines/kyra/staticres_lol.cpp
@@ -45,16 +45,8 @@ const FlyingObjectShape *StaticResource::loadFlyingObjectData(int id, int &entri
return (const FlyingObjectShape *)getData(id, kLolFlightShpData, entries);
}
-const uint16 *StaticResource::loadRawDataBe16(int id, int &entries) {
- return (const uint16 *)getData(id, kLolRawDataBe16, entries);
-}
-
-const uint32 *StaticResource::loadRawDataBe32(int id, int &entries) {
- return (const uint32 *)getData(id, kLolRawDataBe32, entries);
-}
-
-const ButtonDef *StaticResource::loadButtonDefs(int id, int &entries) {
- return (const ButtonDef *)getData(id, kLolButtonData, entries);
+const LoLButtonDef *StaticResource::loadButtonDefs(int id, int &entries) {
+ return (const LoLButtonDef *)getData(id, kLolButtonData, entries);
}
bool StaticResource::loadCharData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
@@ -164,34 +156,10 @@ bool StaticResource::loadFlyingObjectData(Common::SeekableReadStream &stream, vo
return true;
}
-bool StaticResource::loadRawDataBe16(Common::SeekableReadStream &stream, void *&ptr, int &size) {
- size = stream.size() >> 1;
-
- uint16 *r = new uint16[size];
-
- for (int i = 0; i < size; i++)
- r[i] = stream.readUint16BE();
-
- ptr = r;
- return true;
-}
-
-bool StaticResource::loadRawDataBe32(Common::SeekableReadStream &stream, void *&ptr, int &size) {
- size = stream.size() >> 2;
-
- uint32 *r = new uint32[size];
-
- for (int i = 0; i < size; i++)
- r[i] = stream.readUint32BE();
-
- ptr = r;
- return true;
-}
-
bool StaticResource::loadButtonDefs(Common::SeekableReadStream &stream, void *&ptr, int &size) {
size = stream.size() / 18;
- ButtonDef *r = new ButtonDef[size];
+ LoLButtonDef *r = new LoLButtonDef[size];
for (int i = 0; i < size; i++) {
r[i].buttonflags = stream.readUint16BE();
@@ -237,23 +205,8 @@ void StaticResource::freeFlyingObjectData(void *&ptr, int &size) {
size = 0;
}
-
-void StaticResource::freeRawDataBe16(void *&ptr, int &size) {
- uint16 *data = (uint16 *)ptr;
- delete[] data;
- ptr = 0;
- size = 0;
-}
-
-void StaticResource::freeRawDataBe32(void *&ptr, int &size) {
- uint32 *data = (uint32 *)ptr;
- delete[] data;
- ptr = 0;
- size = 0;
-}
-
void StaticResource::freeButtonDefs(void *&ptr, int &size) {
- ButtonDef *d = (ButtonDef *)ptr;
+ LoLButtonDef *d = (LoLButtonDef *)ptr;
delete[] d;
ptr = 0;
size = 0;
@@ -289,67 +242,59 @@ void LoLEngine::initStaticResource() {
if (_flags.isDemo)
return;
+ int tempSize;
_pakFileList = _staticres->loadStrings(kLolIngamePakFiles, _pakFileListSize);
_charDefaults = _staticres->loadCharData(kLolCharacterDefs, _charDefaultsSize);
- _ingameSoundIndex = (const uint16 *)_staticres->loadRawData(kLolIngameSfxIndex, _ingameSoundIndexSize);
- _musicTrackMap = _staticres->loadRawData(kLolMusicTrackMap, _musicTrackMapSize);
+ _ingameSoundIndex = (const uint16 *)_staticres->loadRawData(kLolIngameSfxIndex, tempSize);
+ _musicTrackMap = _staticres->loadRawData(kLolMusicTrackMap, tempSize);
_ingameGMSoundIndex = _staticres->loadRawData(kLolIngameGMSfxIndex, _ingameGMSoundIndexSize);
_ingameMT32SoundIndex = _staticres->loadRawData(kLolIngameMT32SfxIndex, _ingameMT32SoundIndexSize);
_ingamePCSpeakerSoundIndex = _staticres->loadRawData(kLolIngamePcSpkSfxIndex, _ingamePCSpeakerSoundIndexSize);
- _spellProperties = _staticres->loadSpellData(kLolSpellProperties, _spellPropertiesSize);
- _gameShapeMap = (const int8 *)_staticres->loadRawData(kLolGameShapeMap, _gameShapeMapSize);
- _sceneItemOffs = (const int8 *)_staticres->loadRawData(kLolSceneItemOffs, _sceneItemOffsSize);
- _charInvIndex = _staticres->loadRawData(kLolCharInvIndex, _charInvIndexSize);
- _charInvDefs = _staticres->loadRawData(kLolCharInvDefs, _charInvDefsSize);
- _charDefsMan = _staticres->loadRawDataBe16(kLolCharDefsMan, _charDefsManSize);
- _charDefsWoman = _staticres->loadRawDataBe16(kLolCharDefsWoman, _charDefsWomanSize);
- _charDefsKieran = _staticres->loadRawDataBe16(kLolCharDefsKieran, _charDefsKieranSize);
- _charDefsAkshel = _staticres->loadRawDataBe16(kLolCharDefsAkshel, _charDefsAkshelSize);
- _expRequirements = (const int32 *)_staticres->loadRawDataBe32(kLolExpRequirements, _expRequirementsSize);
- _monsterModifiers = _staticres->loadRawDataBe16(kLolMonsterModifiers, _monsterModifiersSize);
- _monsterShiftOffs = (const int8 *)_staticres->loadRawData(kLolMonsterShiftOffsets, _monsterShiftOffsSize);
- _monsterDirFlags = _staticres->loadRawData(kLolMonsterDirFlags, _monsterDirFlagsSize);
- _monsterScaleX = _staticres->loadRawData(kLolMonsterScaleX, _monsterScaleXSize);
- _monsterScaleY = _staticres->loadRawData(kLolMonsterScaleY, _monsterScaleYSize);
- _monsterScaleWH = _staticres->loadRawDataBe16(kLolMonsterScaleWH, _monsterScaleWHSize);
- _inventorySlotDesc = _staticres->loadRawDataBe16(kLolInventoryDesc, _inventorySlotDescSize);
- _levelShpList = _staticres->loadStrings(kLolLevelShpList, _levelShpListSize);
- _levelDatList = _staticres->loadStrings(kLolLevelDatList, _levelDatListSize);
- _compassDefs = _staticres->loadCompassData(kLolCompassDefs, _compassDefsSize);
- _flyingItemShapes = _staticres->loadFlyingObjectData(kLolFlyingObjectShp, _flyingItemShapesSize);
- _itemCost = _staticres->loadRawDataBe16(kLolItemPrices, _itemCostSize);
- _stashSetupData = _staticres->loadRawData(kLolStashSetup, _stashSetupDataSize);
-
- _dscUnk1 = (const int8 *)_staticres->loadRawData(kLolDscUnk1, _dscUnk1Size);
- _dscShapeIndex = (const int8 *)_staticres->loadRawData(kLolDscShapeIndex, _dscShapeIndexSize);
- _dscOvlMap = _staticres->loadRawData(kLolDscOvlMap, _dscOvlMapSize);
- _dscShapeScaleW = _staticres->loadRawDataBe16(kLolDscScaleWidthData, _dscShapeScaleWSize);
- _dscShapeScaleH = _staticres->loadRawDataBe16(kLolDscScaleHeightData, _dscShapeScaleHSize);
- _dscShapeX = (const int16 *)_staticres->loadRawDataBe16(kLolDscX, _dscShapeXSize);
- _dscShapeY = (const int8 *)_staticres->loadRawData(kLolDscY, _dscShapeYSize);
- _dscTileIndex = _staticres->loadRawData(kLolDscTileIndex, _dscTileIndexSize);
- _dscUnk2 = _staticres->loadRawData(kLolDscUnk2, _dscUnk2Size);
- _dscDoorShpIndex = _staticres->loadRawData(kLolDscDoorShapeIndex, _dscDoorShpIndexSize);
- _dscDim1 = (const int8 *)_staticres->loadRawData(kLolDscDimData1, _dscDim1Size);
- _dscDim2 = (const int8 *)_staticres->loadRawData(kLolDscDimData2, _dscDim2Size);
- _dscBlockMap = _staticres->loadRawData(kLolDscBlockMap, _dscBlockMapSize);
- _dscDimMap = _staticres->loadRawData(kLolDscDimMap, _dscDimMapSize);
- _dscDoorMonsterScaleTable = _staticres->loadRawDataBe16(kLolDscDoorScale, _dscDoorMonsterScaleTableSize);
- _dscShapeOvlIndex = _staticres->loadRawData(kLolDscOvlIndex, _dscShapeOvlIndexSize);
- _dscDoor4 = _staticres->loadRawDataBe16(kLolDscDoor4, _dscDoor4Size);
- _dscBlockIndex = (const int8 *)_staticres->loadRawData(kLolDscBlockIndex, _dscBlockIndexSize);
- _dscDoor1 = _staticres->loadRawData(kLolDscDoor1, _dscDoor1Size);
- _dscDoorMonsterX = (const int16 *)_staticres->loadRawDataBe16(kLolDscDoorX, _dscDoorMonsterXSize);
- _dscDoorMonsterY = (const int16 *)_staticres->loadRawDataBe16(kLolDscDoorY, _dscDoorMonsterYSize);
-
- _scrollXTop = _staticres->loadRawData(kLolScrollXTop, _scrollXTopSize);
- _scrollYTop = _staticres->loadRawData(kLolScrollYTop, _scrollYTopSize);
- _scrollXBottom = _staticres->loadRawData(kLolScrollXBottom, _scrollXBottomSize);
- _scrollYBottom = _staticres->loadRawData(kLolScrollYBottom, _scrollYBottomSize);
+ _spellProperties = _staticres->loadSpellData(kLolSpellProperties, tempSize);
+ _gameShapeMap = (const int8 *)_staticres->loadRawData(kLolGameShapeMap, tempSize);
+ _sceneItemOffs = (const int8 *)_staticres->loadRawData(kLolSceneItemOffs, tempSize);
+ _charInvIndex = _staticres->loadRawData(kLolCharInvIndex, tempSize);
+ _charInvDefs = _staticres->loadRawData(kLolCharInvDefs, tempSize);
+ _charDefsMan = _staticres->loadRawDataBe16(kLolCharDefsMan, tempSize);
+ _charDefsWoman = _staticres->loadRawDataBe16(kLolCharDefsWoman, tempSize);
+ _charDefsKieran = _staticres->loadRawDataBe16(kLolCharDefsKieran, tempSize);
+ _charDefsAkshel = _staticres->loadRawDataBe16(kLolCharDefsAkshel, tempSize);
+ _expRequirements = (const int32 *)_staticres->loadRawDataBe32(kLolExpRequirements, tempSize);
+ _monsterModifiers = _staticres->loadRawDataBe16(kLolMonsterModifiers, tempSize);
+ _monsterShiftOffs = (const int8 *)_staticres->loadRawData(kLolMonsterShiftOffsets, tempSize);
+ _monsterDirFlags = _staticres->loadRawData(kLolMonsterDirFlags, tempSize);
+ _monsterScaleX = _staticres->loadRawData(kLolMonsterScaleX, tempSize);
+ _monsterScaleY = _staticres->loadRawData(kLolMonsterScaleY, tempSize);
+ _monsterScaleWH = _staticres->loadRawDataBe16(kLolMonsterScaleWH, tempSize);
+ _inventorySlotDesc = _staticres->loadRawDataBe16(kLolInventoryDesc, tempSize);
+ _levelShpList = _staticres->loadStrings(kLolLevelShpList, tempSize);
+ _levelDatList = _staticres->loadStrings(kLolLevelDatList, tempSize);
+ _compassDefs = _staticres->loadCompassData(kLolCompassDefs, tempSize);
+ _flyingItemShapes = _staticres->loadFlyingObjectData(kLolFlyingObjectShp, tempSize);
+ _itemCost = _staticres->loadRawDataBe16(kLolItemPrices, tempSize);
+ _stashSetupData = _staticres->loadRawData(kLolStashSetup, tempSize);
+
+ _dscWalls = (const int8 *)_staticres->loadRawData(kLolDscWalls, tempSize);
+
+ _dscOvlMap = _staticres->loadRawData(kLolDscOvlMap, tempSize);
+ _dscShapeOvlIndex = _staticres->loadRawData(kLolDscOvlIndex, tempSize);
+ _dscShapeScaleW = _staticres->loadRawDataBe16(kLolDscScaleWidthData, tempSize);
+ _dscShapeScaleH = _staticres->loadRawDataBe16(kLolDscScaleHeightData, tempSize);
+ _dscShapeY = (const int8 *)_staticres->loadRawData(kLolBaseDscY, tempSize);
+
+ _dscDoorMonsterScaleTable = _staticres->loadRawDataBe16(kLolDscDoorScale, tempSize);
+ _dscDoor4 = _staticres->loadRawDataBe16(kLolDscDoor4, tempSize);
+ _dscDoorMonsterX = (const int16 *)_staticres->loadRawDataBe16(kLolDscDoorX, tempSize);
+ _dscDoorMonsterY = (const int16 *)_staticres->loadRawDataBe16(kLolDscDoorY, tempSize);
+
+ _scrollXTop = _staticres->loadRawData(kLolScrollXTop, tempSize);
+ _scrollYTop = _staticres->loadRawData(kLolScrollYTop, tempSize);
+ _scrollXBottom = _staticres->loadRawData(kLolScrollXBottom, tempSize);
+ _scrollYBottom = _staticres->loadRawData(kLolScrollYBottom, tempSize);
const char *const *tmpSndList = _staticres->loadStrings(kLolIngameSfxFiles, _ingameSoundListSize);
if (tmpSndList) {
- _ingameSoundList = new char *[_ingameSoundListSize];
+ _ingameSoundList = new char*[_ingameSoundListSize];
for (int i = 0; i < _ingameSoundListSize; i++) {
_ingameSoundList[i] = new char[strlen(tmpSndList[i]) + 1];
strcpy(_ingameSoundList[i], tmpSndList[i]);
@@ -357,19 +302,18 @@ void LoLEngine::initStaticResource() {
_staticres->unloadId(kLolIngameSfxFiles);
}
- _buttonData = _staticres->loadButtonDefs(kLolButtonDefs, _buttonDataSize);
- _buttonList1 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList1, _buttonList1Size);
- _buttonList2 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList2, _buttonList2Size);
- _buttonList3 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList3, _buttonList3Size);
- _buttonList4 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList4, _buttonList4Size);
- _buttonList5 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList5, _buttonList5Size);
- _buttonList6 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList6, _buttonList6Size);
- _buttonList7 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList7, _buttonList7Size);
- _buttonList8 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList8, _buttonList8Size);
+ _buttonData = _staticres->loadButtonDefs(kLolButtonDefs, tempSize);
+ _buttonList1 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList1, tempSize);
+ _buttonList2 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList2, tempSize);
+ _buttonList3 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList3, tempSize);
+ _buttonList4 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList4, tempSize);
+ _buttonList5 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList5, tempSize);
+ _buttonList6 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList6, tempSize);
+ _buttonList7 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList7, tempSize);
+ _buttonList8 = (const int16 *)_staticres->loadRawDataBe16(kLolButtonList8, tempSize);
- _autoMapStrings = _staticres->loadRawDataBe16(kLolMapStringId, _autoMapStringsSize);
+ _autoMapStrings = _staticres->loadRawDataBe16(kLolMapStringId, tempSize);
- int tempSize;
const uint8 *tmp = _staticres->loadRawData(kLolLegendData, tempSize);
uint8 entrySize = tempSize / 12;
tempSize /= entrySize;
@@ -386,13 +330,15 @@ void LoLEngine::initStaticResource() {
}
tmp = _staticres->loadRawData(kLolMapCursorOvl, tempSize);
- _mapCursorOverlay = new uint8[tempSize];
- memcpy(_mapCursorOverlay, tmp, tempSize);
- _staticres->unloadId(kLolMapCursorOvl);
+ if (tmp) {
+ _mapCursorOverlay = new uint8[tempSize];
+ memcpy(_mapCursorOverlay, tmp, tempSize);
+ _staticres->unloadId(kLolMapCursorOvl);
+ }
- _updateSpellBookCoords = _staticres->loadRawData(kLolSpellbookCoords, _updateSpellBookCoordsSize);
- _updateSpellBookAnimData = _staticres->loadRawData(kLolSpellbookAnim, _updateSpellBookAnimDataSize);
- _healShapeFrames = _staticres->loadRawData(kLolHealShapeFrames, _healShapeFramesSize);
+ _updateSpellBookCoords = _staticres->loadRawData(kLolSpellbookCoords, tempSize);
+ _updateSpellBookAnimData = _staticres->loadRawData(kLolSpellbookAnim, tempSize);
+ _healShapeFrames = _staticres->loadRawData(kLolHealShapeFrames, tempSize);
tmp = _staticres->loadRawData(kLolLightningDefs, tempSize);
if (tmp) {
@@ -405,7 +351,7 @@ void LoLEngine::initStaticResource() {
_staticres->unloadId(kLolLightningDefs);
}
- _fireBallCoords = (const int16 *)_staticres->loadRawDataBe16(kLolFireballCoords, _fireBallCoordsSize);
+ _fireBallCoords = (const int16*)_staticres->loadRawDataBe16(kLolFireballCoords, tempSize);
_buttonCallbacks.clear();
_buttonCallbacks.reserve(95);
diff --git a/engines/kyra/text_eob.cpp b/engines/kyra/text_eob.cpp
new file mode 100644
index 0000000000..dc53ae295a
--- /dev/null
+++ b/engines/kyra/text_eob.cpp
@@ -0,0 +1,649 @@
+/* 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.
+ *
+ *
+ */
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#include "kyra/loleobbase.h"
+#include "kyra/screen.h"
+#include "kyra/timer.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+TextDisplayer_Eob::TextDisplayer_Eob(LolEobBaseEngine *engine, Screen *sScreen) : _vm(engine), _screen(sScreen),
+ _lineCount(0), _printFlag(false), _lineWidth(0), _numCharsTotal(0), _allowPageBreak(true),
+ _numCharsLeft(0), _numCharsPrinted(0), _sjisLineBreakFlag(false), _waitButtonMode(1) {
+
+ _dialogueBuffer = new char[1024];
+ memset(_dialogueBuffer, 0, 1024);
+
+ _currentLine = new char[85];
+ memset(_currentLine, 0, 85);
+
+ _textDimData = new TextDimData[_screen->screenDimTableCount()];
+
+ for (int i = 0; i < _screen->screenDimTableCount(); i++){
+ const ScreenDim *d = _screen->getScreenDim(i);
+ _textDimData[i].color1 = d->unk8;
+ _textDimData[i].color2 = d->unkA;
+ _textDimData[i].line = d->unkC;
+ _textDimData[i].column = d->unkE;
+ }
+
+ _waitButtonSpace = 0;
+}
+
+TextDisplayer_Eob::~TextDisplayer_Eob() {
+ delete[] _dialogueBuffer;
+ delete[] _currentLine;
+ delete[] _textDimData;
+}
+
+void TextDisplayer_Eob::setupField(int dim, bool mode) {
+ setPageBreakFlag();
+
+ _textDimData[dim].color2 = _vm->_bkgColor_1;
+ _screen->setScreenDim(dim);
+
+ if (mode)
+ clearCurDim();
+ else
+ resetDimTextPositions(dim);
+
+ //_textPageBreakFunc = textPageBreakMore; + 0x25
+}
+
+void TextDisplayer_Eob::resetDimTextPositions(int dim) {
+ _textDimData[dim].column = 0;
+ _textDimData[dim].line = 0;
+}
+
+void TextDisplayer_Eob::resetPageBreakString() {
+ if (vm()->_moreStrings)
+ strcpy(_pageBreakString, vm()->_moreStrings[0]);
+}
+
+void TextDisplayer_Eob::setPageBreakFlag() {
+ _allowPageBreak = true;
+ _lineCount = 0;
+}
+
+void TextDisplayer_Eob::removePageBreakFlag() {
+ _allowPageBreak = false;
+}
+
+void TextDisplayer_Eob::displayText(char *str, ...) {
+ const bool isPc98 = (_vm->gameFlags().platform == Common::kPlatformPC98);
+
+ _printFlag = false;
+
+ _lineWidth = 0;
+ _numCharsLeft = 0;
+ _numCharsPrinted = 0;
+
+ _tempString1 = str;
+ _tempString2 = 0;
+
+ _currentLine[0] = 0;
+
+ memset(_ctrl, 0, 3);
+
+ char c = parseCommand();
+
+ va_list args;
+ va_start(args, str);
+
+ const ScreenDim *sd = _screen->_curDim;
+ int sdx = _screen->curDimIndex();
+
+ bool pc98PrintFlag = (isPc98 && (sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15)) ? true : false;
+ uint16 charsPerLine = (sd->w << 3) / (_screen->getFontWidth() + _screen->_charWidth);
+
+ while (c) {
+ char a = tolower(_ctrl[1]);
+
+ if (!_tempString2 && c == '%') {
+ if (a == 'd') {
+ snprintf(_scriptParaString, 11, "%d", va_arg(args, int));
+ _tempString2 = _scriptParaString;
+ } else if (a == 's') {
+ _tempString2 = va_arg(args, char *);
+ } else {
+ break;
+ }
+
+ _ctrl[0] = _ctrl[2];
+ _ctrl[2] = _ctrl[1] = 0;
+ c = parseCommand();
+ }
+
+ if (isPc98) {
+ uint8 cu = (uint8) c;
+ if (cu >= 0xE0 || (cu > 0x80 && cu < 0xA0)) {
+ _currentLine[_numCharsLeft++] = c;
+ _currentLine[_numCharsLeft++] = parseCommand();
+ _currentLine[_numCharsLeft] = '\0';
+ _lineWidth += 8;
+ if ((_textDimData[sdx].column + _lineWidth) > (sd->w << 3))
+ printLine(_currentLine);
+ c = parseCommand();
+ continue;
+ }
+ }
+
+ uint16 dv = _textDimData[sdx].column / (_screen->getFontWidth() + _screen->_charWidth);
+
+ switch (c - 1) {
+ case 0:
+ printLine(_currentLine);
+ textPageBreak();
+ _numCharsPrinted = 0;
+ break;
+
+ case 1:
+ printLine(_currentLine);
+ _textDimData[sdx].color2 = parseCommand();
+ break;
+
+ case 5:
+ printLine(_currentLine);
+ _textDimData[sdx].color1 = parseCommand();
+ break;
+
+ case 8:
+ printLine(_currentLine);
+ dv = _textDimData[sdx].column / (_screen->getFontWidth() + _screen->_charWidth);
+ dv = ((dv + 8) & 0xfff8) - 1;
+ if (dv >= charsPerLine)
+ dv = 0;
+ _textDimData[sdx].column = (_screen->getFontWidth() + _screen->_charWidth) * dv;
+ break;
+
+ case 11:
+ _sjisLineBreakFlag=_sjisLineBreakFlag;
+ // TODO (UNUSED)
+ break;
+
+ case 12:
+ if (isPc98)
+ _sjisLineBreakFlag = true;
+ printLine(_currentLine);
+ _sjisLineBreakFlag = false;
+ _lineCount++;
+ _textDimData[sdx].column = 0;
+ _textDimData[sdx].line++;
+ break;
+
+ case 18:
+ _sjisLineBreakFlag=_sjisLineBreakFlag;
+ // TODO (UNUSED)
+ break;
+
+ case 23:
+ _sjisLineBreakFlag=_sjisLineBreakFlag;
+ // TODO (UNUSED)
+ break;
+
+ case 24:
+ _sjisLineBreakFlag=_sjisLineBreakFlag;
+ // TODO (UNUSED)
+ break;
+
+ case 26:
+ _sjisLineBreakFlag=_sjisLineBreakFlag;
+ // TODO (UNUSED)
+ break;
+
+ case 28:
+ _sjisLineBreakFlag=_sjisLineBreakFlag;
+ // TODO (UNUSED)
+ break;
+
+ default:
+ _lineWidth += (pc98PrintFlag ? 4 : _screen->getCharWidth((uint8)c));
+ _currentLine[_numCharsLeft++] = c;
+ _currentLine[_numCharsLeft] = 0;
+
+ if ((_textDimData[sdx].column + _lineWidth) > (sd->w << 3))
+ printLine(_currentLine);
+ }
+
+ c = parseCommand();
+ }
+
+ va_end(args);
+
+ if (_numCharsLeft)
+ printLine(_currentLine);
+}
+
+char TextDisplayer_Eob::parseCommand() {
+ if (!_ctrl[1])
+ readNextPara();
+
+ char res = _ctrl[1];
+ _ctrl[1] = _ctrl[2];
+ _ctrl[2] = 0;
+
+ if (!_ctrl[1])
+ readNextPara();
+
+ return res;
+}
+
+void TextDisplayer_Eob::readNextPara() {
+ char d = 0;
+
+ if (_tempString2) {
+ if (*_tempString2) {
+ d = *_tempString2++;
+ } else {
+ _tempString2 = 0;
+ d = _ctrl[0];
+ }
+ }
+
+ if (!d && _tempString1) {
+ if (*_tempString1)
+ d = *_tempString1++;
+ else
+ _tempString1 = 0;
+ }
+
+ _ctrl[1] = d;
+ _ctrl[2] = 0;
+}
+
+void TextDisplayer_Eob::printLine(char *str) {
+ const bool isPc98 = (_vm->gameFlags().platform == Common::kPlatformPC98);
+ const ScreenDim *sd = _screen->_curDim;
+ int sdx = _screen->curDimIndex();
+ bool pc98PrintFlag = (isPc98 && (sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15)) ? true : false;
+
+ int fh = (_screen->_currentFont == Screen::FID_SJIS_FNT) ? 9 : (_screen->getFontHeight() + _screen->_charOffset);
+ int lines = (sd->h - _screen->_charOffset) / fh;
+
+ while (_textDimData[sdx].line >= lines) {
+ if ((lines - _waitButtonSpace) <= _lineCount && _allowPageBreak) {
+ _lineCount = 0;
+ textPageBreak();
+ _numCharsPrinted = 0;
+ }
+
+ int h1 = ((sd->h / fh) - 1) * fh;
+ int h2 = sd->h - fh;
+
+ if (h2)
+ _screen->copyRegion(sd->sx << 3, sd->sy + fh, sd->sx << 3, sd->sy, sd->w << 3, h2, _screen->_curPage, _screen->_curPage, Screen::CR_NO_P_CHECK);
+
+ _screen->fillRect(sd->sx << 3, sd->sy + h1, ((sd->sx + sd->w) << 3) - 1, sd->sy + sd->h - 1, _textDimData[sdx].color2);
+ if (_textDimData[sdx].line)
+ _textDimData[sdx].line--;
+ }
+
+ int x1 = (sd->sx << 3) + _textDimData[sdx].column;
+ int y = sd->sy + (pc98PrintFlag ? (_textDimData[sdx].line << 3) : (fh * _textDimData[sdx].line));
+ int w = sd->w << 3;
+ int lw = _lineWidth;
+ int s = _numCharsLeft;
+ char c = 0;
+
+ if (pc98PrintFlag) {
+ bool ct = true;
+
+ if ((lw + _textDimData[sdx].column) > w) {
+ if ((lines - 1 - (_waitButtonSpace << 1)) <= _lineCount)
+ // cut off line to leave space for "MORE" button
+ w -= 80;
+ } else {
+ if (!_sjisLineBreakFlag || (_lineCount + 1 < lines - 1))
+ ct = false;
+ else
+ // cut off line to leave space for "MORE" button
+ w -= 80;
+ }
+
+ if (ct) {
+ w -= _textDimData[sdx].column;
+
+ int n2 = 0;
+ int n1 = (w / 4) - 1;
+
+ while (n2 < n1 && n2 < s) {
+ c = str[n2];
+ uint8 cu = (uint8) c;
+ if (cu >= 0xE0 || (cu > 0x80 && cu < 0xA0))
+ n2++;
+ n2++;
+ }
+ s = n2;
+ }
+ } else {
+ if ((lw + _textDimData[sdx].column) > w) {
+ if ((lines - 1) <= _lineCount && _allowPageBreak)
+ // cut off line to leave space for "MORE" button
+ w -= (10 * (_screen->getFontWidth() + _screen->_charWidth));
+
+ w -= _textDimData[sdx].column;
+
+ int n2 = 0;
+ int n1 = s - 1;
+
+ while (n1 > 0) {
+ //cut off line after last space
+ c = str[n1];
+
+ lw -= _screen->getCharWidth((uint8)c);
+
+ if (!n2 && lw <= w)
+ n2 = n1;
+
+ if (n2 && c == ' ') {
+ s = n1;
+ _printFlag = false;
+ break;
+ }
+ n1--;
+ }
+
+ if (!n1) {
+ if (_textDimData[sdx].column && !_printFlag) {
+ s = lw = 0;
+ _printFlag = true;
+ } else {
+ s = n2;
+ }
+ }
+ }
+ }
+
+ c = str[s];
+ str[s] = 0;
+
+ uint8 col = _textDimData[sdx].color1;
+ if (isPc98 && (sdx == 2 || sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15)) {
+ switch (_textDimData[sdx].color1) {
+ case 0x88:
+ col = 0x41;
+ break;
+ case 0x55:
+ col = 0x81;
+ break;
+ case 0xaa:
+ col = 0x21;
+ break;
+ case 0x99:
+ col = 0xa1;
+ break;
+ case 0x33:
+ col = 0xe1;
+ break;
+ case 0x18:
+ col = 0x61;
+ break;
+ default:
+ col = 1;
+ break;
+ }
+ _screen->printText(str, x1 & ~3, (y + 8) & ~7, col, 0);
+ } else {
+ _screen->printText(str, x1, y, col, _textDimData[sdx].color2);
+ }
+
+ _textDimData[sdx].column += lw;
+ _numCharsPrinted += strlen(str);
+
+ str[s] = c;
+
+ if (c == ' ')
+ s++;
+
+ if (str[s] == ' ')
+ s++;
+
+ uint32 len = strlen(&str[s]);
+ for (uint32 i = 0; i < len; i++)
+ str[i] = str[s + i];
+ str[len] = 0;
+
+ _numCharsLeft = strlen(str);
+ _lineWidth = pc98PrintFlag ? (_numCharsLeft << 2) : _screen->getTextWidth(str);
+
+ if (!_numCharsLeft && _textDimData[sdx].column < (sd->w << 3))
+ return;
+
+ _textDimData[sdx].column = 0;
+ _textDimData[sdx].line++;
+ _lineCount++;
+
+ printLine(str);
+}
+
+void TextDisplayer_Eob::printDialogueText(int stringId, const char *pageBreakString) {
+ strcpy(_dialogueBuffer, (const char *)(screen()->getCPagePtr(5) + READ_LE_UINT16(&screen()->getCPagePtr(5)[(stringId - 1) << 1])));
+ displayText(_dialogueBuffer);
+
+ if (pageBreakString) {
+ strcpy(_pageBreakString, pageBreakString);
+ displayWaitButton();
+ resetPageBreakString();
+ }
+}
+
+void TextDisplayer_Eob::printDialogueText(const char *str, bool wait) {
+ strcpy(_dialogueBuffer, str);
+ displayText(_dialogueBuffer);
+ if (wait)
+ displayWaitButton();
+}
+
+void TextDisplayer_Eob::printMessage(const char *str, int textColor, ...) {
+ int tc = _textDimData[screen()->curDimIndex()].color1;
+
+ if (textColor != -1)
+ _textDimData[screen()->curDimIndex()].color1 = textColor;
+
+ va_list args;
+ va_start(args, textColor);
+ vsnprintf(_dialogueBuffer, 240, str, args);
+ va_end(args);
+
+ displayText(_dialogueBuffer);
+
+ //if (textColor != -1)
+ _textDimData[screen()->curDimIndex()].color1 = tc;
+
+ if (!screen()->_curPage)
+ screen()->updateScreen();
+}
+
+int TextDisplayer_Eob::clearDim(int dim) {
+ int res = screen()->curDimIndex();
+ screen()->setScreenDim(dim);
+ _textDimData[dim].color1 = screen()->_curDim->unk8;
+ _textDimData[dim].color2 = vm()->game() == GI_LOL ? screen()->_curDim->unkA : vm()->_bkgColor_1;
+ clearCurDim();
+ return res;
+}
+
+void TextDisplayer_Eob::clearCurDim() {
+ int d = screen()->curDimIndex();
+ const ScreenDim *tmp = screen()->getScreenDim(d);
+ if (vm()->gameFlags().use16ColorMode) {
+ screen()->fillRect(tmp->sx << 3, tmp->sy, ((tmp->sx + tmp->w) << 3) - 2, (tmp->sy + tmp->h) - 2, _textDimData[d].color2);
+ } else
+ screen()->fillRect(tmp->sx << 3, tmp->sy, ((tmp->sx + tmp->w) << 3) - 1, (tmp->sy + tmp->h) - 1, _textDimData[d].color2);
+
+ _lineCount = 0;
+ _textDimData[d].column = _textDimData[d].line = 0;
+}
+
+void TextDisplayer_Eob::textPageBreak() {
+ if (vm()->game() != GI_LOL)
+ SWAP(vm()->_dialogueButtonLabelCol1, vm()->_dialogueButtonLabelCol2);
+
+ int cp = _screen->setCurPage(0);
+ Screen::FontId cf = screen()->setFont(vm()->gameFlags().use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_6_FNT);
+
+ vm()->_timer->pauseSingleTimer(11, true);
+
+ vm()->_fadeText = false;
+ int resetPortraitAfterSpeechAnim = 0;
+ int updatePortraitSpeechAnimDuration = 0;
+
+ if (vm()->_updateCharNum != -1) {
+ resetPortraitAfterSpeechAnim = vm()->_resetPortraitAfterSpeechAnim;
+ vm()->_resetPortraitAfterSpeechAnim = 0;
+ updatePortraitSpeechAnimDuration = vm()->_updatePortraitSpeechAnimDuration;
+ if (vm()->_updatePortraitSpeechAnimDuration > 36)
+ vm()->_updatePortraitSpeechAnimDuration = 36;
+ }
+
+ uint32 speechPartTime = 0;
+ if (vm()->speechEnabled() && vm()->_activeVoiceFileTotalTime && _numCharsTotal)
+ speechPartTime = vm()->_system->getMillis() + ((_numCharsPrinted * vm()->_activeVoiceFileTotalTime) / _numCharsTotal);
+
+ const ScreenDim *dim = screen()->getScreenDim(screen()->curDimIndex());
+
+ int x = ((dim->sx + dim->w) << 3) - (_vm->_dialogueButtonW + 3);
+ int y = 0;
+
+ if (vm()->_needSceneRestore && (vm()->_updateFlags & 2)) {
+ if (vm()->_currentControlMode || !(vm()->_updateFlags & 2)) {
+ y = dim->sy + dim->h - 5;
+ } else {
+ x += 6;
+ y = dim->sy + dim->h - 2;
+ }
+ } else if (vm()->game() == GI_LOL) {
+ y = dim->sy + dim->h - 10;
+ } else {
+ y = _waitButtonMode ? 162 : 189;
+ x = _waitButtonMode ? 76 : 221;
+ }
+
+ if (vm()->gameFlags().use16ColorMode) {
+ vm()->gui_drawBox(x + 8, (y & ~7) - 1, 66, 10, 0xee, 0xcc, -1);
+ screen()->printText(_pageBreakString, (x + 37 - (strlen(_pageBreakString) << 1) + 4) & ~3, (y + 2) & ~7, 0xc1, 0);
+ } else {
+ vm()->gui_drawBox(x, y, vm()->_dialogueButtonW, vm()->_dialogueButtonH, vm()->_color1_1, vm()->_color2_1, vm()->_bkgColor_1);
+ screen()->printText(_pageBreakString, x + (vm()->_dialogueButtonW >> 1) - (vm()->screen()->getTextWidth(_pageBreakString) >> 1), y + 2, vm()->_dialogueButtonLabelCol1, 0);
+ }
+
+ vm()->removeInputTop();
+
+ bool loop = true;
+ bool target = false;
+
+ do {
+ int inputFlag = vm()->checkInput(0, false) & 0xFF;
+ vm()->removeInputTop();
+
+ while (!inputFlag) {
+ vm()->update();
+
+ if (vm()->speechEnabled()) {
+ if (((vm()->_system->getMillis() > speechPartTime) || (vm()->snd_updateCharacterSpeech() != 2)) && speechPartTime) {
+ loop = false;
+ inputFlag = vm()->_keyMap[Common::KEYCODE_RETURN];
+ break;
+ }
+ }
+
+ inputFlag = vm()->checkInput(0, false) & 0xFF;
+ vm()->removeInputTop();
+ }
+
+ vm()->gui_notifyButtonListChanged();
+
+ if (inputFlag == vm()->_keyMap[Common::KEYCODE_SPACE] || inputFlag == vm()->_keyMap[Common::KEYCODE_RETURN]) {
+ loop = false;
+ } else if (inputFlag == 199 || inputFlag == 201) {
+ if (vm()->posWithinRect(vm()->_mouseX, vm()->_mouseY, x, y, x + _vm->_dialogueButtonW, y + 9)) {
+ if (_vm->game() == GI_LOL)
+ target = true;
+ else
+ loop = false;
+ }
+ } else if (inputFlag == 200 || inputFlag == 202) {
+ if (target)
+ loop = false;
+ }
+ } while (loop);
+
+ if (vm()->gameFlags().use16ColorMode)
+ screen()->fillRect(x + 8, y, x + 57, y + 9, _textDimData[screen()->curDimIndex()].color2);
+ else
+ screen()->fillRect(x, y, x + 73, y + 8, _textDimData[screen()->curDimIndex()].color2);
+
+ clearCurDim();
+
+ vm()->_timer->pauseSingleTimer(11, false);
+
+ if (vm()->_updateCharNum != -1) {
+ vm()->_resetPortraitAfterSpeechAnim = resetPortraitAfterSpeechAnim;
+ if (updatePortraitSpeechAnimDuration > 36)
+ updatePortraitSpeechAnimDuration -= 36;
+ else
+ updatePortraitSpeechAnimDuration >>= 1;
+
+ vm()->_updatePortraitSpeechAnimDuration = updatePortraitSpeechAnimDuration;
+ }
+
+ screen()->setFont(cf);
+ screen()->setCurPage(cp);
+
+ if (vm()->game() != GI_LOL)
+ SWAP(vm()->_dialogueButtonLabelCol1, vm()->_dialogueButtonLabelCol2);
+
+ vm()->removeInputTop();
+}
+
+void TextDisplayer_Eob::displayWaitButton() {
+ vm()->_dialogueNumButtons = 1;
+ vm()->_dialogueButtonString[0] = _pageBreakString;
+ vm()->_dialogueButtonString[1] = 0;
+ vm()->_dialogueButtonString[2] = 0;
+ vm()->_dialogueHighlightedButton = 0;
+
+ static const uint16 posX[] = { 221, 76 };
+ static const uint8 posY[] = { 189, 162 };
+
+ vm()->_dialogueButtonPosX = &posX[_waitButtonMode];
+ vm()->_dialogueButtonPosY = &posY[_waitButtonMode];
+ vm()->_dialogueButtonYoffs = 0;
+
+ SWAP(_vm->_dialogueButtonLabelCol1, _vm->_dialogueButtonLabelCol2);
+ vm()->drawDialogueButtons();
+
+ if (!vm()->shouldQuit())
+ vm()->removeInputTop();
+
+ while (!vm()->processDialogue() && !vm()->shouldQuit()) {}
+ SWAP(_vm->_dialogueButtonLabelCol1, _vm->_dialogueButtonLabelCol2);
+}
+
+} // End of namespace Kyra
+
+#endif // (ENABLE_EOB || ENABLE_LOL)
diff --git a/engines/kyra/text_eob.h b/engines/kyra/text_eob.h
new file mode 100644
index 0000000000..eb4957448b
--- /dev/null
+++ b/engines/kyra/text_eob.h
@@ -0,0 +1,112 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are to 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.
+ *
+ */
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#ifndef KYRA_TEXT_EOB_H
+#define KYRA_TEXT_EOB_H
+
+#include "common/scummsys.h"
+
+namespace Kyra {
+
+class Screen;
+class LolEobBaseEngine;
+
+class TextDisplayer_Eob {
+public:
+ TextDisplayer_Eob(LolEobBaseEngine *engine, Screen *sScreen);
+ virtual ~TextDisplayer_Eob();
+
+ virtual void setupField(int dim, bool mode);
+
+ void printDialogueText(int stringId, const char *pageBreakString);
+ void printDialogueText(const char *str, bool wait = false);
+ void printMessage(const char *str, int textColor = -1, ...);
+
+ int clearDim(int dim);
+ void clearCurDim();
+
+ void resetDimTextPositions(int dim);
+ void resetPageBreakString();
+ void setPageBreakFlag();
+ void removePageBreakFlag();
+
+ void allowPageBreak(bool mode) { _allowPageBreak = mode; }
+ void setWaitButtonMode(int mode) { _waitButtonMode = mode; }
+ int lineCount() { return _lineCount; }
+
+protected:
+ virtual LolEobBaseEngine *vm() { return _vm; }
+ virtual Screen *screen() { return _screen; }
+
+ void displayText(char *str, ...);
+ char parseCommand();
+ void readNextPara();
+ void printLine(char *str);
+ virtual void textPageBreak();
+ void displayWaitButton();
+
+ char *_dialogueBuffer;
+
+ char *_tempString1;
+ char *_tempString2;
+ char *_currentLine;
+ char _ctrl[3];
+
+ uint16 _lineWidth;
+ uint32 _numCharsTotal;
+ uint32 _numCharsLeft;
+ uint32 _numCharsPrinted;
+
+ bool _printFlag;
+ bool _sjisLineBreakFlag;
+
+ char _pageBreakString[20];
+ char _scriptParaString[11];
+ int _lineCount;
+
+ bool _allowPageBreak;
+ int _waitButtonSpace;
+ int _waitButtonMode;
+
+ static const char _pageBreakDefault[3][5];
+
+ struct TextDimData {
+ uint8 color1;
+ uint8 color2;
+ uint16 column;
+ uint8 line;
+ };
+
+ TextDimData *_textDimData;
+
+private:
+ LolEobBaseEngine *_vm;
+ Screen *_screen;
+};
+
+} // End of namespace Kyra
+
+#endif
+
+#endif // ENABLE_EOB || ENABLE_LOL
diff --git a/engines/kyra/text_lol.cpp b/engines/kyra/text_lol.cpp
index 1c2167b892..3127e6d54b 100644
--- a/engines/kyra/text_lol.cpp
+++ b/engines/kyra/text_lol.cpp
@@ -32,36 +32,18 @@
namespace Kyra {
-TextDisplayer_LoL::TextDisplayer_LoL(LoLEngine *vm, Screen_LoL *screen) : _vm(vm), _screen(screen),
- _scriptTextParameter(0), _lineCount(0), _printFlag(false), _lineWidth(0), _numCharsTotal(0),
- _numCharsLeft(0), _numCharsPrinted(0), _sjisLineBreakFlag(false) {
+TextDisplayer_LoL::TextDisplayer_LoL(LoLEngine *engine, Screen_LoL *screenLoL) : TextDisplayer_Eob(engine, engine->screen()),
+ _vm(engine), _screen(screenLoL), _scriptTextParameter(0) {
memset(_stringParameters, 0, 15 * sizeof(char *));
_buffer = new char[600];
memset(_buffer, 0, 600);
- _dialogueBuffer = new char[1024];
- memset(_dialogueBuffer, 0, 1024);
-
- _currentLine = new char[85];
- memset(_currentLine, 0, 85);
-
- _textDimData = new TextDimData[_screen->screenDimTableCount()];
-
- for (int i = 0; i < _screen->screenDimTableCount(); i++){
- const ScreenDim *d = _screen->getScreenDim(i);
- _textDimData[i].color1 = d->unk8;
- _textDimData[i].color2 = d->unkA;
- _textDimData[i].line = d->unkC;
- _textDimData[i].column = d->unkE;
- }
+ _waitButtonSpace = 0;
}
TextDisplayer_LoL::~TextDisplayer_LoL() {
delete[] _buffer;
- delete[] _dialogueBuffer;
- delete[] _currentLine;
- delete[] _textDimData;
}
void TextDisplayer_LoL::setupField(bool mode) {
@@ -151,20 +133,6 @@ void TextDisplayer_LoL::expandField() {
}
}
-int TextDisplayer_LoL::clearDim(int dim) {
- int res = _screen->curDimIndex();
- _screen->setScreenDim(dim);
- _textDimData[dim].color1 = _screen->_curDim->unk8;
- _textDimData[dim].color2 = _screen->_curDim->unkA;
- clearCurDim();
- return res;
-}
-
-void TextDisplayer_LoL::resetDimTextPositions(int dim) {
- _textDimData[dim].column = 0;
- _textDimData[dim].line = 0;
-}
-
void TextDisplayer_LoL::printDialogueText(int dim, char *str, EMCState *script, const uint16 *paramList, int16 paramIndex) {
int oldDim = 0;
@@ -201,10 +169,9 @@ void TextDisplayer_LoL::printDialogueText(int dim, char *str, EMCState *script,
displayText(_dialogueBuffer);
_screen->setScreenDim(oldDim);
- _lineCount = 0;
_screen->setCurPage(cp);
_screen->setFont(of);
-
+ _lineCount = 0;
_vm->_fadeText = false;
}
@@ -366,465 +333,17 @@ void TextDisplayer_LoL::preprocessString(char *str, EMCState *script, const uint
*dst = 0;
}
-void TextDisplayer_LoL::displayText(char *str, ...) {
- const bool isPc98 = (_vm->gameFlags().platform == Common::kPlatformPC98);
-
- _printFlag = false;
-
- _lineWidth = 0;
- _numCharsLeft = 0;
- _numCharsPrinted = 0;
-
- _tempString1 = str;
- _tempString2 = 0;
-
- _currentLine[0] = 0;
- memset(_ctrl, 0, 3);
-
- char c = parseCommand();
-
- va_list args;
- va_start(args, str);
-
- const ScreenDim *sd = _screen->_curDim;
- int sdx = _screen->curDimIndex();
-
- bool pc98PrintFlag = (isPc98 && (sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15)) ? true : false;
- uint16 charsPerLine = (sd->w << 3) / (_screen->getFontWidth() + _screen->_charWidth);
-
- while (c) {
- char a = tolower(_ctrl[1]);
-
- if (!_tempString2 && c == '%') {
- if (a == 'd') {
- snprintf(_scriptParaString, 11, "%d", va_arg(args, int));
- _tempString2 = _scriptParaString;
- } else if (a == 's') {
- _tempString2 = va_arg(args, char *);
- } else {
- break;
- }
-
- _ctrl[0] = _ctrl[2];
- _ctrl[2] = _ctrl[1] = 0;
- c = parseCommand();
- }
-
- if (isPc98) {
- uint8 cu = (uint8) c;
- if (cu >= 0xE0 || (cu > 0x80 && cu < 0xA0)) {
- _currentLine[_numCharsLeft++] = c;
- _currentLine[_numCharsLeft++] = parseCommand();
- _currentLine[_numCharsLeft] = '\0';
- _lineWidth += 8;
- if ((_textDimData[sdx].column + _lineWidth) > (sd->w << 3))
- printLine(_currentLine);
- c = parseCommand();
- continue;
- }
- }
-
- uint16 dv = _textDimData[sdx].column / (_screen->getFontWidth() + _screen->_charWidth);
-
- switch (c - 1) {
- case 0:
- printLine(_currentLine);
- textPageBreak();
- _numCharsPrinted = 0;
- break;
-
- case 1:
- printLine(_currentLine);
- _textDimData[sdx].color2 = parseCommand();
- break;
-
- case 5:
- printLine(_currentLine);
- _textDimData[sdx].color1 = parseCommand();
- break;
-
- case 8:
- printLine(_currentLine);
- dv = _textDimData[sdx].column / (_screen->getFontWidth() + _screen->_charWidth);
- dv = ((dv + 8) & 0xfff8) - 1;
- if (dv >= charsPerLine)
- dv = 0;
- _textDimData[sdx].column = (_screen->getFontWidth() + _screen->_charWidth) * dv;
- break;
-
- case 11:
- // TODO (UNUSED)
- break;
-
- case 12:
- if (isPc98)
- _sjisLineBreakFlag = true;
- printLine(_currentLine);
- _sjisLineBreakFlag = false;
- _lineCount++;
- _textDimData[sdx].column = 0;
- _textDimData[sdx].line++;
- break;
-
- case 18:
- // TODO (UNUSED)
- break;
-
- case 23:
- // TODO (UNUSED)
- break;
-
- case 24:
- // TODO (UNUSED)
- break;
-
- case 26:
- // TODO (UNUSED)
- break;
-
- case 28:
- // TODO (UNUSED)
- break;
-
- default:
- _lineWidth += (pc98PrintFlag ? 4 : _screen->getCharWidth((uint8)c));
- _currentLine[_numCharsLeft++] = c;
- _currentLine[_numCharsLeft] = 0;
-
- if ((_textDimData[sdx].column + _lineWidth) > (sd->w << 3))
- printLine(_currentLine);
- }
-
- c = parseCommand();
- }
-
- va_end(args);
-
- if (_numCharsLeft)
- printLine(_currentLine);
-}
-
-char TextDisplayer_LoL::parseCommand() {
- if (!_ctrl[1])
- readNextPara();
-
- char res = _ctrl[1];
- _ctrl[1] = _ctrl[2];
- _ctrl[2] = 0;
-
- if (!_ctrl[1])
- readNextPara();
-
- return res;
+LolEobBaseEngine *TextDisplayer_LoL::vm() {
+ return _vm;
}
-void TextDisplayer_LoL::readNextPara() {
- char d = 0;
-
- if (_tempString2) {
- if (*_tempString2) {
- d = *_tempString2++;
- } else {
- _tempString2 = 0;
- d = _ctrl[0];
- }
- }
-
- if (!d && _tempString1) {
- if (*_tempString1)
- d = *_tempString1++;
- else
- _tempString1 = 0;
- }
-
- _ctrl[1] = d;
- _ctrl[2] = 0;
-}
-
-void TextDisplayer_LoL::printLine(char *str) {
- const bool isPc98 = (_vm->gameFlags().platform == Common::kPlatformPC98);
- const ScreenDim *sd = _screen->_curDim;
- int sdx = _screen->curDimIndex();
- bool pc98PrintFlag = (isPc98 && (sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15)) ? true : false;
-
- int fh = (_screen->_currentFont == Screen::FID_SJIS_FNT) ? 9 : (_screen->getFontHeight() + _screen->_charOffset);
- int lines = (sd->h - _screen->_charOffset) / fh;
-
- while (_textDimData[sdx].line >= lines) {
- if (lines <= _lineCount) {
- _lineCount = 0;
- textPageBreak();
- _numCharsPrinted = 0;
- }
-
- int h1 = ((sd->h / fh) - 1) * fh;
- int h2 = sd->h - fh;
-
- if (h2)
- _screen->copyRegion(sd->sx << 3, sd->sy + fh, sd->sx << 3, sd->sy, sd->w << 3, h2, _screen->_curPage, _screen->_curPage, Screen::CR_NO_P_CHECK);
-
- _screen->fillRect(sd->sx << 3, sd->sy + h1, (sd->sx + sd->w - 1) << 3, sd->sy + sd->h - 1, _textDimData[sdx].color2);
- if (_textDimData[sdx].line)
- _textDimData[sdx].line--;
- }
-
- int x1 = (sd->sx << 3) + _textDimData[sdx].column;
- int y = sd->sy + (pc98PrintFlag ? (_textDimData[sdx].line << 3) : (fh * _textDimData[sdx].line));
- int w = sd->w << 3;
- int lw = _lineWidth;
- int s = _numCharsLeft;
- char c = 0;
-
- if (pc98PrintFlag) {
- bool ct = true;
-
- if ((lw + _textDimData[sdx].column) > w) {
- if ((lines - 1) <= _lineCount)
- // cut off line to leave space for "MORE" button
- w -= 80;
- } else {
- if (!_sjisLineBreakFlag || (_lineCount + 1 < lines - 1))
- ct = false;
- else
- // cut off line to leave space for "MORE" button
- w -= 80;
- }
-
- if (ct) {
- w -= _textDimData[sdx].column;
-
- int n2 = 0;
- int n1 = (w / 4) - 1;
-
- while (n2 < n1 && n2 < s) {
- c = str[n2];
- uint8 cu = (uint8) c;
- if (cu >= 0xE0 || (cu > 0x80 && cu < 0xA0))
- n2++;
- n2++;
- }
- s = n2;
- }
- } else {
- if ((lw + _textDimData[sdx].column) > w) {
- if ((lines - 1) <= _lineCount)
- // cut off line to leave space for "MORE" button
- w -= (10 * (_screen->getFontWidth() + _screen->_charWidth));
-
- w -= _textDimData[sdx].column;
-
- int n2 = 0;
- int n1 = s - 1;
-
- while (n1 > 0) {
- //cut off line after last space
- c = str[n1];
-
- lw -= _screen->getCharWidth((uint8)c);
-
- if (!n2 && lw <= w)
- n2 = n1;
-
- if (n2 && c == ' ') {
- s = n1;
- _printFlag = false;
- break;
- }
- n1--;
- }
-
- if (!n1) {
- if (_textDimData[sdx].column && !_printFlag) {
- s = lw = 0;
- _printFlag = true;
- } else {
- s = n2;
- }
- }
- }
- }
-
- c = str[s];
- str[s] = 0;
-
- uint8 col = _textDimData[sdx].color1;
- if (isPc98 && (sdx == 2 || sdx == 3 || sdx == 4 || sdx == 5 || sdx == 15)) {
- switch (_textDimData[sdx].color1) {
- case 0x88:
- col = 0x41;
- break;
- case 0x55:
- col = 0x81;
- break;
- case 0xaa:
- col = 0x21;
- break;
- case 0x99:
- col = 0xa1;
- break;
- case 0x33:
- col = 0xe1;
- break;
- case 0x18:
- col = 0x61;
- break;
- default:
- col = 1;
- break;
- }
- _screen->printText(str, x1 & ~3, (y + 8) & ~7, col, 0);
- } else {
- _screen->printText(str, x1, y, col, _textDimData[sdx].color2);
- }
-
- _textDimData[sdx].column += lw;
- _numCharsPrinted += strlen(str);
-
- str[s] = c;
-
- if (c == ' ')
- s++;
-
- if (str[s] == ' ')
- s++;
-
- uint32 len = strlen(&str[s]);
- for (uint32 i = 0; i < len; i++)
- str[i] = str[s + i];
- str[len] = 0;
-
- _numCharsLeft = strlen(str);
- _lineWidth = pc98PrintFlag ? (_numCharsLeft << 2) : _screen->getTextWidth(str);
-
- if (!_numCharsLeft && _textDimData[sdx].column < (sd->w << 3))
- return;
-
- _textDimData[sdx].column = 0;
- _textDimData[sdx].line++;
- _lineCount++;
-
- printLine(str);
+Screen *TextDisplayer_LoL::screen() {
+ return _screen;
}
void TextDisplayer_LoL::textPageBreak() {
- int cp = _screen->setCurPage(0);
- Screen::FontId cf = _screen->setFont(_vm->gameFlags().use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_6_FNT);
-
- _vm->_timer->pauseSingleTimer(11, true);
-
- _vm->_fadeText = false;
- int resetPortraitAfterSpeechAnim = 0;
- int updatePortraitSpeechAnimDuration = 0;
-
- if (_vm->_updateCharNum != -1) {
- resetPortraitAfterSpeechAnim = _vm->_resetPortraitAfterSpeechAnim;
- _vm->_resetPortraitAfterSpeechAnim = 0;
- updatePortraitSpeechAnimDuration = _vm->_updatePortraitSpeechAnimDuration;
- if (_vm->_updatePortraitSpeechAnimDuration > 36)
- _vm->_updatePortraitSpeechAnimDuration = 36;
- }
-
- uint32 speechPartTime = 0;
- if (_vm->speechEnabled() && _vm->_activeVoiceFileTotalTime && _numCharsTotal)
- speechPartTime = _vm->_system->getMillis() + ((_numCharsPrinted * _vm->_activeVoiceFileTotalTime) / _numCharsTotal);
-
- const ScreenDim *dim = _screen->getScreenDim(_screen->curDimIndex());
-
- int x = ((dim->sx + dim->w) << 3) - 77;
- int y = 0;
-
- if (_vm->_needSceneRestore && (_vm->_updateFlags & 2)) {
- if (_vm->_currentControlMode || !(_vm->_updateFlags & 2)) {
- y = dim->sy + dim->h - 5;
- } else {
- x += 6;
- y = dim->sy + dim->h - 2;
- }
- } else {
- y = dim->sy + dim->h - 10;
- }
-
- char *txt = _vm->getLangString(0x4073);
- if (_vm->gameFlags().use16ColorMode) {
- _vm->gui_drawBox(x + 8, (y & ~7) - 1, 66, 10, 0xee, 0xcc, -1);
- _vm->_screen->printText(txt, (x + 37 - (strlen(txt) << 1) + 4) & ~3, (y + 2) & ~7, 0xc1, 0);
- } else {
- _vm->gui_drawBox(x, y, 74, 9, 136, 251, -1);
- _vm->_screen->printText(txt, x + 37 - (_vm->_screen->getTextWidth(txt) >> 1), y + 2, 144, 0);
- }
-
- _vm->removeInputTop();
-
- bool loop = true;
- bool target = false;
-
- do {
- int inputFlag = _vm->checkInput(0, false) & 0xFF;
- _vm->removeInputTop();
-
- while (!inputFlag) {
- _vm->update();
-
- if (_vm->speechEnabled()) {
- if (((_vm->_system->getMillis() > speechPartTime) || (_vm->snd_updateCharacterSpeech() != 2)) && speechPartTime) {
- loop = false;
- inputFlag = _vm->_keyMap[Common::KEYCODE_RETURN];
- break;
- }
- }
-
- inputFlag = _vm->checkInput(0, false) & 0xFF;
- _vm->removeInputTop();
- }
-
- _vm->gui_notifyButtonListChanged();
-
- if (inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN]) {
- loop = false;
- } else if (inputFlag == 199 || inputFlag == 201) {
- if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, x, y, x + 74, y + 9))
- target = true;
- } else if (inputFlag == 200 || inputFlag == 202) {
- if (target)
- loop = false;
- }
- } while (loop);
-
-
- if (_vm->gameFlags().use16ColorMode)
- _screen->fillRect(x + 8, y, x + 57, y + 9, _textDimData[_screen->curDimIndex()].color2);
- else
- _screen->fillRect(x, y, x + 73, y + 8, _textDimData[_screen->curDimIndex()].color2);
-
- clearCurDim();
-
- _vm->_timer->pauseSingleTimer(11, false);
-
- if (_vm->_updateCharNum != -1) {
- _vm->_resetPortraitAfterSpeechAnim = resetPortraitAfterSpeechAnim;
- if (updatePortraitSpeechAnimDuration > 36)
- updatePortraitSpeechAnimDuration -= 36;
- else
- updatePortraitSpeechAnimDuration >>= 1;
-
- _vm->_updatePortraitSpeechAnimDuration = updatePortraitSpeechAnimDuration;
- }
-
- _screen->setFont(cf);
- _screen->setCurPage(cp);
- _vm->removeInputTop();
-}
-
-void TextDisplayer_LoL::clearCurDim() {
- int d = _screen->curDimIndex();
- const ScreenDim *tmp = _screen->getScreenDim(d);
- if (_vm->gameFlags().use16ColorMode) {
- _screen->fillRect(tmp->sx << 3, tmp->sy, ((tmp->sx + tmp->w) << 3) - 2, (tmp->sy + tmp->h) - 2, _textDimData[d].color2);
- } else
- _screen->fillRect(tmp->sx << 3, tmp->sy, ((tmp->sx + tmp->w) << 3) - 1, (tmp->sy + tmp->h) - 1, _textDimData[d].color2);
-
- _lineCount = 0;
- _textDimData[d].column = _textDimData[d].line = 0;
+ strcpy(_pageBreakString, _vm->getLangString(0x4073));
+ TextDisplayer_Eob::textPageBreak();
}
} // End of namespace Kyra
diff --git a/engines/kyra/text_lol.h b/engines/kyra/text_lol.h
index 3e59bc90fe..0dcc4b73b3 100644
--- a/engines/kyra/text_lol.h
+++ b/engines/kyra/text_lol.h
@@ -20,80 +20,52 @@
*
*/
-#ifdef ENABLE_LOL
-
#ifndef KYRA_TEXT_LOL_H
#define KYRA_TEXT_LOL_H
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+#include "kyra/text_eob.h"
+#endif
#include "common/scummsys.h"
+#ifdef ENABLE_LOL
+
namespace Kyra {
class Screen_LoL;
class LoLEngine;
struct EMCState;
-class TextDisplayer_LoL {
-friend class LoLEngine;
+class TextDisplayer_LoL : public TextDisplayer_Eob {
public:
- TextDisplayer_LoL(LoLEngine *vm, Screen_LoL *screen);
+ TextDisplayer_LoL(LoLEngine *engine, Screen_LoL *screenLoL);
~TextDisplayer_LoL();
void setupField(bool mode);
void expandField();
- int clearDim(int dim);
- void resetDimTextPositions(int dim);
-
void printDialogueText(int dim, char *str, EMCState *script, const uint16 *paramList, int16 paramIndex);
void printMessage(uint16 type, const char *str, ...) GCC_PRINTF(3, 4);
int16 _scriptTextParameter;
private:
- void displayText(char *str, ...);
- char parseCommand();
- void readNextPara();
- void printLine(char *str);
+ LolEobBaseEngine *vm();
+ Screen *screen();
+
void preprocessString(char *str, EMCState *script, const uint16 *paramList, int16 paramIndex);
void textPageBreak();
- void clearCurDim();
-
char *_stringParameters[15];
char *_buffer;
- char *_dialogueBuffer;
- char *_tempString1;
- char *_tempString2;
- char *_currentLine;
- char _ctrl[3];
-
- char _scriptParaString[11];
-
- uint16 _lineWidth;
- int _lineCount;
- uint32 _numCharsTotal;
- uint32 _numCharsLeft;
- uint32 _numCharsPrinted;
-
- bool _printFlag;
- bool _sjisLineBreakFlag;
LoLEngine *_vm;
Screen_LoL *_screen;
-
- struct TextDimData {
- uint8 color1;
- uint8 color2;
- uint16 column;
- uint8 line;
- };
-
- TextDimData *_textDimData;
};
} // End of namespace Kyra
+#endif // ENABLE_LOL
+
#endif
-#endif // ENABLE_LOL
diff --git a/engines/kyra/timer.cpp b/engines/kyra/timer.cpp
index 9834646a45..2ab2b621f3 100644
--- a/engines/kyra/timer.cpp
+++ b/engines/kyra/timer.cpp
@@ -217,7 +217,7 @@ void TimerManager::pauseSingleTimer(uint8 id, bool p) {
bool TimerManager::isEnabled(uint8 id) const {
CIterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id));
if (timer != _timers.end())
- return (timer->enabled == 1);
+ return (timer->enabled & 1);
warning("TimerManager::isEnabled: No timer %d", id);
return false;
diff --git a/engines/kyra/timer_eob.cpp b/engines/kyra/timer_eob.cpp
new file mode 100644
index 0000000000..92c7f34ee6
--- /dev/null
+++ b/engines/kyra/timer_eob.cpp
@@ -0,0 +1,378 @@
+/* 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.
+ *
+ */
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+
+#include "kyra/eobcommon.h"
+#include "kyra/timer.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void LolEobBaseEngine::enableSysTimer(int sysTimer) {
+ if (sysTimer != 2)
+ return;
+
+ for (int i = 0; i < getNumClock2Timers(); i++)
+ _timer->pauseSingleTimer(getClock2Timer(i), false);
+}
+
+void LolEobBaseEngine::disableSysTimer(int sysTimer) {
+ if (sysTimer != 2)
+ return;
+
+ for (int i = 0; i < getNumClock2Timers(); i++)
+ _timer->pauseSingleTimer(getClock2Timer(i), true);
+}
+
+void LolEobBaseEngine::enableTimer(int id) {
+ _timer->enable(id);
+ _timer->setCountdown(id, _timer->getDelay(id));
+}
+
+void LolEobBaseEngine::timerProcessDoors(int timerNum) {
+ for (int i = 0; i < 3; i++) {
+ uint16 b = _openDoorState[i].block;
+ if (!b)
+ continue;
+
+ int v = _openDoorState[i].state;
+ int c = _openDoorState[i].wall;
+
+ _levelBlockProperties[b].walls[c] += v;
+ _levelBlockProperties[b].walls[c ^ 2] += v;
+
+ int snd = 3;
+ int flg = _wllWallFlags[_levelBlockProperties[b].walls[c]];
+ if (flg & 0x20)
+ snd = 5;
+ else if (v == -1)
+ snd = 4;
+
+ if (_flags.gameID == GI_LOL) {
+ if (!(_updateFlags & 1)) {
+ snd_processEnvironmentalSoundEffect(snd + 28, b);
+ if (!checkSceneUpdateNeed(b))
+ updateEnvironmentalSfx(0);
+ }
+ } else {
+ checkSceneUpdateNeed(b);
+ updateEnvironmentalSfx(snd);
+ }
+
+ if (flg & 0x30)
+ _openDoorState[i].block = 0;
+ }
+}
+
+} // namespace Kyra
+
+#endif
+#ifdef ENABLE_EOB
+
+namespace Kyra {
+
+#define TimerV2(x) new Common::Functor1Mem<int, void, EobCoreEngine>(this, &EobCoreEngine::x)
+
+void EobCoreEngine::setupTimers() {
+ _timer->addTimer(0, TimerV2(timerProcessCharacterExchange), 9, false);
+ _timer->addTimer(1, TimerV2(timerProcessFlyingObjects), 3, true);
+ _timer->addTimer(0x20, TimerV2(timerProcessMonsters), 20, true);
+ _timer->addTimer(0x21, TimerV2(timerProcessMonsters), 20, true);
+ _timer->addTimer(0x22, TimerV2(timerProcessMonsters), 20, true);
+ _timer->addTimer(0x23, TimerV2(timerProcessMonsters), 20, true);
+ _timer->setNextRun(0x21, _system->getMillis() + 7 * _tickLength);
+ _timer->setNextRun(0x22, _system->getMillis() + 14 * _tickLength);
+ _timer->setNextRun(0x23, _system->getMillis() + 14 * _tickLength);
+ _timer->addTimer(0x30, TimerV2(timerSpecialCharacterUpdate), 50, false);
+ _timer->addTimer(0x31, TimerV2(timerSpecialCharacterUpdate), 50, false);
+ _timer->addTimer(0x32, TimerV2(timerSpecialCharacterUpdate), 50, false);
+ _timer->addTimer(0x33, TimerV2(timerSpecialCharacterUpdate), 50, false);
+ _timer->addTimer(0x34, TimerV2(timerSpecialCharacterUpdate), 50, false);
+ _timer->addTimer(0x35, TimerV2(timerSpecialCharacterUpdate), 50, false);
+ _timer->addTimer(4, TimerV2(timerProcessDoors), 5, true);
+ _timer->addTimer(5, TimerV2(timerUpdateTeleporters), 10, true);
+ _timer->addTimer(6, TimerV2(timerUpdateFoodStatus), 1080, true);
+ _timer->addTimer(7, TimerV2(timerUpdateMonsterIdleAnim), 25, true);
+}
+
+void EobCoreEngine::setCharEventTimer(int charIndex, uint32 countdown, int evnt, int updateExistingTimer) {
+ uint32 ntime = _system->getMillis() + countdown * _tickLength;
+ uint8 timerId = 0x30 | (charIndex & 0x0f);
+ EobCharacter *c = &_characters[charIndex];
+
+ if (!_timer->isEnabled(timerId)) {
+ c->timers[0] = ntime;
+ c->events[0] = evnt;
+ _timer->setCountdown(timerId, countdown);
+ enableTimer(timerId);
+ return;
+ }
+
+ if (ntime < _timer->getNextRun(timerId))
+ _timer->setNextRun(timerId, ntime);
+
+ if (updateExistingTimer) {
+ bool br = false;
+ int d = -1;
+
+ for (int i = 0; i < 10 && br == false; i++) {
+ if (d == -1 && !c->timers[i])
+ d = i;
+
+ if (!br && c->events[i] == evnt) {
+ d = i;
+ br = true;
+ }
+ }
+
+ c->timers[d] = ntime;
+ c->events[d] = evnt;
+ } else {
+ for (int i = 0; i < 10; i++) {
+ if (c->timers[i])
+ continue;
+ c->timers[i] = ntime;
+ c->events[i] = evnt;
+ return;
+ }
+ }
+}
+
+void EobCoreEngine::deleteCharEventTimer(int charIndex, int evnt) {
+ EobCharacter *c = &_characters[charIndex];
+ for (int i = 0; i < 10; i++) {
+ if (c->events[i] == evnt) {
+ c->events[i] = 0;
+ c->timers[i] = 0;
+ }
+ }
+ setupCharacterTimers();
+}
+
+void EobCoreEngine::setupCharacterTimers() {
+ for (int i = 0; i < 6; i++) {
+ EobCharacter *c = &_characters[i];
+ if (!testCharacter(i, 1))
+ continue;
+
+ uint32 nextTimer = 0xffffffff;
+
+ for (int ii = 0; ii < 10; ii++) {
+ if (c->timers[ii] < nextTimer)
+ nextTimer = c->timers[ii];
+ }
+ uint32 ctime = _system->getMillis();
+
+ if (nextTimer == 0xffffffff)
+ _timer->disable(0x30 | i);
+ else {
+ enableTimer(0x30 | i);
+ _timer->setCountdown(0x30 | i, (nextTimer - ctime) / _tickLength);
+ }
+ }
+}
+
+void EobCoreEngine::timerProcessCharacterExchange(int timerNum) {
+ _charExchangeSwap ^= 1;
+ if (_charExchangeSwap) {
+ int index = _exchangeCharacterId;
+ _exchangeCharacterId = -1;
+ gui_drawCharPortraitWithStats(index);
+ _exchangeCharacterId = index;
+ } else {
+ gui_drawCharPortraitWithStats(_exchangeCharacterId);
+ }
+}
+
+void EobCoreEngine::timerProcessFlyingObjects(int timerNum) {
+ static const uint8 dirPosIndex[] = { 0x82, 0x83, 0x00, 0x01, 0x01, 0x80, 0x03, 0x82, 0x02, 0x03, 0x80, 0x81, 0x81, 0x00, 0x83, 0x02 };
+ for (int i = 0; i < 10; i++) {
+ EobFlyingObject *fo = &_flyingObjects[i];
+ if (!fo->enable)
+ continue;
+
+ bool endFlight = fo->distance ? false : true;
+
+ uint8 pos = dirPosIndex[(fo->direction << 2) + (fo->curPos & 3)];
+ uint16 bl = fo->curBlock;
+ bool newBl = (pos & 0x80) ? true : false;
+
+ if (newBl) {
+ bl = calcNewBlockPosition(fo->curBlock, fo->direction);
+ pos &= 3;
+ fo->u2 = 0;
+ }
+
+ if (updateObjectFlight(fo, bl, pos)) {
+ if (newBl)
+ runLevelScript(bl, 0x10);
+ if (updateFlyingObjectHitTest(fo, bl, pos))
+ endFlight = true;
+ } else {
+ if (fo->flags & 0x20) {
+ if (!updateFlyingObjectHitTest(fo, fo->curBlock, fo->curPos))
+ updateFlyingObject_s3(fo);
+ }
+ endFlight = true;
+ }
+
+ if (endFlight)
+ endObjectFlight(fo);
+
+ _sceneUpdateRequired = true;
+ }
+}
+
+void EobCoreEngine::timerProcessMonsters(int timerNum) {
+ updateMonsters(timerNum & 0x0f);
+}
+
+
+void EobCoreEngine::timerSpecialCharacterUpdate(int timerNum) {
+ int charIndex = timerNum & 0x0f;
+ EobCharacter *c = &_characters[charIndex];
+ uint32 ctime = _system->getMillis();
+
+ for (int i = 0; i < 10; i++) {
+ if (!c->timers[i])
+ continue;
+ if (c->timers[i] > ctime)
+ continue;
+
+ c->timers[i] = 0;
+ int evt = c->events[i];
+
+ if (evt < 0) {
+ removeCharacterEffect(evt, charIndex, 1);
+ continue;
+ }
+
+ switch (evt) {
+ case 2:
+ case 3:
+ setCharEventTimer(charIndex, (c->effectFlags & 0x10000) ? 9 : 36, evt + 2, 1);
+ case 0:
+ case 1:
+ case 4:
+ case 5:
+ setWeaponSlotStatus(charIndex, evt / 2, evt & 1);
+ break;
+
+ case 6:
+ c->damageTaken = 0;
+ gui_drawCharPortraitWithStats(charIndex);
+ break;
+
+ case 7:
+ _txt->printMessage(_characterStatusStrings7[0], -1, c->name);
+ c->strengthCur = c->strengthMax;
+ c->strengthExtCur = c->strengthExtMax;
+ if (_currentControlMode == 2)
+ gui_drawCharPortraitWithStats(charIndex);
+ break;
+
+ case 8:
+ if (c->flags & 2) {
+ calcAndInflictCharacterDamage(charIndex, 0, 0, 5, 0x400, 5, 3);
+ setCharEventTimer(charIndex, 546, 8, 1);
+ } else {
+ c->flags &= 0xfd;
+ gui_drawCharPortraitWithStats(charIndex);
+ }
+ break;
+
+ case 9:
+ if (c->flags & 4) {
+ _txt->printMessage(_characterStatusStrings9[0], -1, c->name);
+ c->flags &= 0xfb;
+ gui_drawCharPortraitWithStats(charIndex);
+ }
+ break;
+
+ case 11:
+ if (c->disabledSlots & 4) {
+ c->disabledSlots &= 0xfb;
+ if (_openBookChar == charIndex && _updateFlags)
+ gui_drawSpellbook();
+ }
+ break;
+
+ case 12:
+ c->effectFlags &= ~0x1000;
+ _txt->printMessage(_characterStatusStrings12[0], -1, c->name);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ uint32 nextTimer = (uint32)(-1);
+ for (int i = 0; i < 10; i++) {
+ if (c->timers[i] && c->timers[i] < nextTimer)
+ nextTimer = c->timers[i];
+ }
+
+ if (nextTimer == (uint32)(-1))
+ _timer->disable(timerNum);
+ else
+ _timer->setCountdown(timerNum, (nextTimer - ctime) / _tickLength);
+}
+
+void EobCoreEngine::timerUpdateTeleporters(int timerNum) {
+ _teleporterPulse ^= 1;
+ for (int i = 0; i < 18; i++) {
+ uint8 w = _visibleBlocks[i]->walls[_sceneDrawVarDown];
+ if (w == 44 || w == 74) {
+ _sceneUpdateRequired = true;
+ return;
+ }
+ }
+}
+
+void EobCoreEngine::timerUpdateFoodStatus(int timerNum) {
+ for (int i = 0; i < 6; i++) {
+ if (checkInventoryForRings(i, 2))
+ continue;
+ EobCharacter *c = &_characters[i];
+ if (c->food != 0 && c->flags & 1 && c->hitPointsCur > -10) {
+ c->food--;
+ gui_drawFoodStatusGraph(i);
+ }
+ }
+}
+
+void EobCoreEngine::timerUpdateMonsterIdleAnim(int timerNum) {
+ for (int i = 0; i < 18; i++) {
+ EobMonsterInPlay *m = &_monsters[i];
+ if (m->mode == 7 || m->mode == 10 || (m->flags & 0x20) || (rollDice(1, 2, 0) != 1))
+ continue;
+ m->idleAnimState = (rollDice(1, 2, 0) << 4) | rollDice(1, 2, 0);
+ checkSceneUpdateNeed(m->block);
+ }
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/timer_lol.cpp b/engines/kyra/timer_lol.cpp
index 3221556e6d..5a6677a4f6 100644
--- a/engines/kyra/timer_lol.cpp
+++ b/engines/kyra/timer_lol.cpp
@@ -47,58 +47,6 @@ void LoLEngine::setupTimers() {
_timer->addTimer(11, TimerV2(timerFadeMessageText), 360, false);
}
-void LoLEngine::enableTimer(int id) {
- _timer->enable(id);
- _timer->setCountdown(id, _timer->getDelay(id));
-}
-
-void LoLEngine::enableSysTimer(int sysTimer) {
- if (sysTimer != 2)
- return;
-
- for (int i = 0; i < _numClock2Timers; i++)
- _timer->pauseSingleTimer(_clock2Timers[i], false);
-}
-
-void LoLEngine::disableSysTimer(int sysTimer) {
- if (sysTimer != 2)
- return;
-
- for (int i = 0; i < _numClock2Timers; i++)
- _timer->pauseSingleTimer(_clock2Timers[i], true);
-}
-
-void LoLEngine::timerProcessDoors(int timerNum) {
- for (int i = 0; i < 3; i++) {
- uint16 b = _openDoorState[i].block;
- if (!b)
- continue;
-
- int v = _openDoorState[i].state;
- int c = _openDoorState[i].wall;
-
- _levelBlockProperties[b].walls[c] += v;
- _levelBlockProperties[b].walls[c ^ 2] += v;
-
- int snd = 31;
-
- int flg = _wllWallFlags[_levelBlockProperties[b].walls[c]];
- if (flg & 0x20)
- snd = 33;
- else if (v == -1)
- snd = 32;
-
- if (!(_updateFlags & 1)) {
- snd_processEnvironmentalSoundEffect(snd, b);
- if (!checkSceneUpdateNeed(b))
- updateEnvironmentalSfx(0);
- }
-
- if (flg & 0x30)
- _openDoorState[i].block = 0;
- }
-}
-
void LoLEngine::timerProcessMonsters(int timerNum) {
for (int i = timerNum & 0x0f; i < 30; i += 2)
updateMonster(&_monsters[i]);