aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
authorMatthew Hoops2012-03-20 14:18:57 -0400
committerMatthew Hoops2012-03-20 14:49:16 -0400
commit71756bdf4eae5ba9cc3f329b85e894f04640aaef (patch)
tree40d464262da107ab5eed82f198685209161ebac1 /engines/kyra
parent03eba05b09e5c9e5a351f8111185934b92a3fed3 (diff)
parent3c3576a224b92c703b4e8ea20008ac8a069980dd (diff)
downloadscummvm-rg350-71756bdf4eae5ba9cc3f329b85e894f04640aaef.tar.gz
scummvm-rg350-71756bdf4eae5ba9cc3f329b85e894f04640aaef.tar.bz2
scummvm-rg350-71756bdf4eae5ba9cc3f329b85e894f04640aaef.zip
Merge remote branch 'upstream/master' into pegasus
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/animator_hof.cpp11
-rw-r--r--engines/kyra/animator_lok.cpp22
-rw-r--r--engines/kyra/animator_mr.cpp9
-rw-r--r--engines/kyra/animator_v2.cpp4
-rw-r--r--engines/kyra/chargen.cpp1951
-rw-r--r--engines/kyra/darkmoon.cpp471
-rw-r--r--engines/kyra/darkmoon.h147
-rw-r--r--engines/kyra/debugger.cpp91
-rw-r--r--engines/kyra/debugger.h15
-rw-r--r--engines/kyra/detection.cpp60
-rw-r--r--engines/kyra/detection_tables.h262
-rw-r--r--engines/kyra/eob.cpp562
-rw-r--r--engines/kyra/eob.h121
-rw-r--r--engines/kyra/eobcommon.cpp2420
-rw-r--r--engines/kyra/eobcommon.h1164
-rw-r--r--engines/kyra/gui.cpp642
-rw-r--r--engines/kyra/gui.h169
-rw-r--r--engines/kyra/gui_eob.cpp4093
-rw-r--r--engines/kyra/gui_eob.h165
-rw-r--r--engines/kyra/gui_hof.cpp2
-rw-r--r--engines/kyra/gui_lok.cpp54
-rw-r--r--engines/kyra/gui_lok.h4
-rw-r--r--engines/kyra/gui_lol.cpp174
-rw-r--r--engines/kyra/gui_lol.h11
-rw-r--r--engines/kyra/gui_mr.cpp2
-rw-r--r--engines/kyra/gui_rpg.cpp134
-rw-r--r--engines/kyra/gui_v1.cpp629
-rw-r--r--engines/kyra/gui_v1.h197
-rw-r--r--engines/kyra/gui_v2.cpp20
-rw-r--r--engines/kyra/gui_v2.h4
-rw-r--r--engines/kyra/items_eob.cpp731
-rw-r--r--engines/kyra/items_lok.cpp48
-rw-r--r--engines/kyra/items_lol.cpp89
-rw-r--r--engines/kyra/kyra_hof.cpp8
-rw-r--r--engines/kyra/kyra_hof.h28
-rw-r--r--engines/kyra/kyra_lok.cpp60
-rw-r--r--engines/kyra/kyra_mr.h2
-rw-r--r--engines/kyra/kyra_rpg.cpp367
-rw-r--r--engines/kyra/kyra_rpg.h392
-rw-r--r--engines/kyra/kyra_v1.cpp93
-rw-r--r--engines/kyra/kyra_v1.h18
-rw-r--r--engines/kyra/kyra_v2.cpp6
-rw-r--r--engines/kyra/kyra_v2.h8
-rw-r--r--engines/kyra/lol.cpp497
-rw-r--r--engines/kyra/lol.h356
-rw-r--r--engines/kyra/magic_eob.cpp1382
-rw-r--r--engines/kyra/module.mk36
-rw-r--r--engines/kyra/resource.cpp22
-rw-r--r--engines/kyra/resource.h635
-rw-r--r--engines/kyra/resource_intern.cpp39
-rw-r--r--engines/kyra/resource_intern.h18
-rw-r--r--engines/kyra/saveload.cpp37
-rw-r--r--engines/kyra/saveload_eob.cpp909
-rw-r--r--engines/kyra/saveload_lok.cpp2
-rw-r--r--engines/kyra/saveload_lol.cpp289
-rw-r--r--engines/kyra/saveload_rpg.cpp127
-rw-r--r--engines/kyra/scene_eob.cpp890
-rw-r--r--engines/kyra/scene_lok.cpp42
-rw-r--r--engines/kyra/scene_lol.cpp750
-rw-r--r--engines/kyra/scene_rpg.cpp637
-rw-r--r--engines/kyra/scene_v1.cpp14
-rw-r--r--engines/kyra/scene_v2.cpp40
-rw-r--r--engines/kyra/screen.cpp446
-rw-r--r--engines/kyra/screen.h108
-rw-r--r--engines/kyra/screen_eob.cpp1781
-rw-r--r--engines/kyra/screen_eob.h129
-rw-r--r--engines/kyra/screen_hof.cpp12
-rw-r--r--engines/kyra/screen_hof.h4
-rw-r--r--engines/kyra/screen_lok.cpp74
-rw-r--r--engines/kyra/screen_lok.h4
-rw-r--r--engines/kyra/screen_lol.cpp44
-rw-r--r--engines/kyra/screen_lol.h15
-rw-r--r--engines/kyra/screen_mr.cpp13
-rw-r--r--engines/kyra/screen_mr.h4
-rw-r--r--engines/kyra/screen_v2.cpp17
-rw-r--r--engines/kyra/screen_v2.h2
-rw-r--r--engines/kyra/script.h17
-rw-r--r--engines/kyra/script_eob.cpp1611
-rw-r--r--engines/kyra/script_eob.h132
-rw-r--r--engines/kyra/script_lok.cpp47
-rw-r--r--engines/kyra/script_lol.cpp136
-rw-r--r--engines/kyra/script_tim.cpp179
-rw-r--r--engines/kyra/script_tim.h15
-rw-r--r--engines/kyra/script_v1.cpp4
-rw-r--r--engines/kyra/script_v2.cpp22
-rw-r--r--engines/kyra/seqplayer.cpp19
-rw-r--r--engines/kyra/sequences_darkmoon.cpp1436
-rw-r--r--engines/kyra/sequences_eob.cpp1152
-rw-r--r--engines/kyra/sequences_hof.cpp18
-rw-r--r--engines/kyra/sequences_lok.cpp8
-rw-r--r--engines/kyra/sequences_lol.cpp72
-rw-r--r--engines/kyra/sound.cpp6
-rw-r--r--engines/kyra/sound.h14
-rw-r--r--engines/kyra/sound_adlib.cpp244
-rw-r--r--engines/kyra/sound_adlib.h9
-rw-r--r--engines/kyra/sound_amiga.cpp2
-rw-r--r--engines/kyra/sound_intern.h10
-rw-r--r--engines/kyra/sound_lol.cpp31
-rw-r--r--engines/kyra/sound_midi.cpp2
-rw-r--r--engines/kyra/sound_towns.cpp34
-rw-r--r--engines/kyra/sprites_eob.cpp1259
-rw-r--r--engines/kyra/sprites_lol.cpp172
-rw-r--r--engines/kyra/sprites_rpg.cpp46
-rw-r--r--engines/kyra/staticres.cpp207
-rw-r--r--engines/kyra/staticres_eob.cpp1356
-rw-r--r--engines/kyra/staticres_lol.cpp235
-rw-r--r--engines/kyra/staticres_rpg.cpp100
-rw-r--r--engines/kyra/text_lok.cpp21
-rw-r--r--engines/kyra/text_lol.cpp505
-rw-r--r--engines/kyra/text_lol.h53
-rw-r--r--engines/kyra/text_rpg.cpp671
-rw-r--r--engines/kyra/text_rpg.h115
-rw-r--r--engines/kyra/timer.cpp6
-rw-r--r--engines/kyra/timer_eob.cpp360
-rw-r--r--engines/kyra/timer_lok.cpp2
-rw-r--r--engines/kyra/timer_lol.cpp55
-rw-r--r--engines/kyra/timer_rpg.cpp90
-rw-r--r--engines/kyra/vqa.cpp2
-rw-r--r--engines/kyra/wsamovie.cpp12
119 files changed, 30865 insertions, 4457 deletions
diff --git a/engines/kyra/animator_hof.cpp b/engines/kyra/animator_hof.cpp
index 741e358143..5a2378f4d0 100644
--- a/engines/kyra/animator_hof.cpp
+++ b/engines/kyra/animator_hof.cpp
@@ -115,15 +115,14 @@ void KyraEngine_HoF::refreshAnimObjects(int force) {
void KyraEngine_HoF::updateItemAnimations() {
bool nextFrame = false;
- if (_itemAnimData[0].itemIndex == -1 || _inventorySaved)
+ if (_itemAnimDefinition[0].itemIndex == -1 || _inventorySaved)
return;
- const ItemAnimData_v2 *s = &_itemAnimData[_nextAnimItem];
+ const ItemAnimDefinition *s = &_itemAnimDefinition[_nextAnimItem];
ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem];
- _nextAnimItem = (_nextAnimItem + 1) % _itemAnimDataSize;
+ _nextAnimItem = (_nextAnimItem + 1) % _itemAnimDefinitionSize;
- uint32 ctime = _system->getMillis();
- if (ctime < a->nextFrame)
+ if (_system->getMillis() < a->nextFrameTime)
return;
uint16 shpIdx = s->frames[a->currentFrame].index + 64;
@@ -164,7 +163,7 @@ void KyraEngine_HoF::updateItemAnimations() {
}
if (nextFrame) {
- a->nextFrame = _system->getMillis() + (s->frames[a->currentFrame].delay * _tickLength);
+ a->nextFrameTime = _system->getMillis() + (s->frames[a->currentFrame].delay * _tickLength);
a->currentFrame = (a->currentFrame + 1) % s->numFrames;
}
}
diff --git a/engines/kyra/animator_lok.cpp b/engines/kyra/animator_lok.cpp
index 4126681bbe..c246eebd46 100644
--- a/engines/kyra/animator_lok.cpp
+++ b/engines/kyra/animator_lok.cpp
@@ -100,7 +100,7 @@ void Animator_LoK::initAnimStateList() {
for (int i = 16; i < 28; ++i) {
animStates[i].index = i;
animStates[i].flags = 0;
- animStates[i].background = _vm->_shapes[345+i];
+ animStates[i].background = _vm->_shapes[345 + i];
animStates[i].rectSize = _screen->getRectSize(3, 24);
animStates[i].width = 3;
animStates[i].height = 16;
@@ -352,10 +352,10 @@ void Animator_LoK::copyChangedObjectsForward(int refreshFlag) {
if (curObject->active) {
if (curObject->refreshFlag || refreshFlag) {
int xpos = 0, ypos = 0, width = 0, height = 0;
- xpos = (curObject->x1>>3) - (curObject->width2>>3) - 1;
+ xpos = (curObject->x1 >> 3) - (curObject->width2 >> 3) - 1;
ypos = curObject->y1 - curObject->height2;
- width = curObject->width + (curObject->width2>>3) + 2;
- height = curObject->height + curObject->height2*2;
+ width = curObject->width + (curObject->width2 >> 3) + 2;
+ height = curObject->height + curObject->height2 * 2;
if (xpos < 1)
xpos = 1;
@@ -412,7 +412,7 @@ void Animator_LoK::animAddGameItem(int index, uint16 sceneId) {
animObj->refreshFlag = 1;
animObj->bkgdChangeFlag = 1;
animObj->drawY = currentRoom->itemsYPos[index];
- animObj->sceneAnimPtr = _vm->_shapes[216+currentRoom->itemsTable[index]];
+ animObj->sceneAnimPtr = _vm->_shapes[216 + currentRoom->itemsTable[index]];
animObj->animFrameNumber = -1;
animObj->x1 = currentRoom->itemsXPos[index];
animObj->y1 = currentRoom->itemsYPos[index];
@@ -438,8 +438,8 @@ void Animator_LoK::animAddNPC(int character) {
animObj->bkgdChangeFlag = 1;
animObj->drawY = ch->y1;
animObj->sceneAnimPtr = _vm->_shapes[ch->currentAnimFrame];
- animObj->x1 = animObj->x2 = ch->x1 + _vm->_defaultShapeTable[ch->currentAnimFrame-7].xOffset;
- animObj->y1 = animObj->y2 = ch->y1 + _vm->_defaultShapeTable[ch->currentAnimFrame-7].yOffset;
+ animObj->x1 = animObj->x2 = ch->x1 + _vm->_defaultShapeTable[ch->currentAnimFrame - 7].xOffset;
+ animObj->y1 = animObj->y2 = ch->y1 + _vm->_defaultShapeTable[ch->currentAnimFrame - 7].yOffset;
if (ch->facing >= 1 && ch->facing <= 3)
animObj->flags |= 1;
@@ -543,13 +543,13 @@ void Animator_LoK::makeBrandonFaceMouse() {
int16 Animator_LoK::fetchAnimWidth(const uint8 *shape, int16 mult) {
if (_vm->gameFlags().useAltShapeHeader)
shape += 2;
- return (((int16)READ_LE_UINT16((shape+3))) * mult) >> 8;
+ return (((int16)READ_LE_UINT16((shape + 3))) * mult) >> 8;
}
int16 Animator_LoK::fetchAnimHeight(const uint8 *shape, int16 mult) {
if (_vm->gameFlags().useAltShapeHeader)
shape += 2;
- return (int16)(((int8)*(shape+2)) * mult) >> 8;
+ return (int16)(((int8)*(shape + 2)) * mult) >> 8;
}
void Animator_LoK::setBrandonAnimSeqSize(int width, int height) {
@@ -603,8 +603,8 @@ void Animator_LoK::animRefreshNPC(int character) {
}
}
- int xOffset = _vm->_defaultShapeTable[ch->currentAnimFrame-7].xOffset;
- int yOffset = _vm->_defaultShapeTable[ch->currentAnimFrame-7].yOffset;
+ int xOffset = _vm->_defaultShapeTable[ch->currentAnimFrame - 7].xOffset;
+ int yOffset = _vm->_defaultShapeTable[ch->currentAnimFrame - 7].yOffset;
if (_vm->_scaleMode) {
animObj->x1 = ch->x1;
diff --git a/engines/kyra/animator_mr.cpp b/engines/kyra/animator_mr.cpp
index 31c5cd1a53..29fa3aba80 100644
--- a/engines/kyra/animator_mr.cpp
+++ b/engines/kyra/animator_mr.cpp
@@ -187,15 +187,14 @@ void KyraEngine_MR::refreshAnimObjects(int force) {
void KyraEngine_MR::updateItemAnimations() {
bool nextFrame = false;
- if (_itemAnimData[0].itemIndex == -1)
+ if (_itemAnimDefinition[0].itemIndex == -1)
return;
- const ItemAnimData_v2 *s = &_itemAnimData[_nextAnimItem];
+ const ItemAnimDefinition *s = &_itemAnimDefinition[_nextAnimItem];
ActiveItemAnim *a = &_activeItemAnim[_nextAnimItem];
_nextAnimItem = (_nextAnimItem + 1) % 10;
- uint32 ctime = _system->getMillis();
- if (ctime < a->nextFrame)
+ if (_system->getMillis() < a->nextFrameTime)
return;
uint16 shpIdx = s->frames[a->currentFrame].index + 248;
@@ -230,7 +229,7 @@ void KyraEngine_MR::updateItemAnimations() {
}
if (nextFrame) {
- a->nextFrame = _system->getMillis() + (s->frames[a->currentFrame].delay * _tickLength);
+ a->nextFrameTime = _system->getMillis() + (s->frames[a->currentFrame].delay * _tickLength);
a->currentFrame = (a->currentFrame + 1) % s->numFrames;
}
}
diff --git a/engines/kyra/animator_v2.cpp b/engines/kyra/animator_v2.cpp
index 334356e261..f7ae6749cf 100644
--- a/engines/kyra/animator_v2.cpp
+++ b/engines/kyra/animator_v2.cpp
@@ -26,10 +26,10 @@
namespace Kyra {
void KyraEngine_v2::allocAnimObjects(int actors, int anims, int items) {
- _animObjects = new AnimObj[actors+anims+items];
+ _animObjects = new AnimObj[actors + anims + items];
assert(_animObjects);
- memset(_animObjects, 0, sizeof(AnimObj)*(actors+anims+items));
+ memset(_animObjects, 0, sizeof(AnimObj) * (actors + anims + items));
_animActor = _animObjects;
_animAnims = _animObjects + actors;
diff --git a/engines/kyra/chargen.cpp b/engines/kyra/chargen.cpp
new file mode 100644
index 0000000000..54e1abcc2c
--- /dev/null
+++ b/engines/kyra/chargen.cpp
@@ -0,0 +1,1951 @@
+/* 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"
+
+#include "common/savefile.h"
+#include "common/str-array.h"
+
+#include "common/config-manager.h"
+#include "base/plugins.h"
+#include "engines/metaengine.h"
+#include "engines/game.h"
+
+namespace Kyra {
+
+// Character Generator
+
+class CharacterGenerator {
+public:
+ CharacterGenerator(EoBCoreEngine *vm, Screen_EoB *screen);
+ ~CharacterGenerator();
+
+ bool 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);
+ int viewDeleteCharacter();
+ void createPartyMember();
+ int raceSexMenu();
+ int classMenu(int raceSex);
+ int alignmentMenu(int cClass);
+ int getInput(Button *buttonList);
+ 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[17];
+ int _activeBox;
+ int _magicShapesBox;
+ int _updateBoxShapesIndex;
+ int _lastUpdateBoxShapesIndex;
+ 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 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;
+};
+
+CharacterGenerator::CharacterGenerator(EoBCoreEngine *vm, Screen_EoB *screen) : _vm(vm), _screen(screen),
+ _characters(0), _faceShapes(0), _chargenMagicShapes(0), _chargenMagicShapeTimer(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;
+ }
+
+ for (int i = 0; i < 17; i++)
+ delete[] _chargenButtonLabels[i];
+}
+
+bool CharacterGenerator::start(EoBCharacter *characters, uint8 ***faceShapes) {
+ if (!characters && !faceShapes)
+ return true;
+
+ _characters = characters;
+ _faceShapes = *faceShapes;
+
+ _vm->snd_stopSound();
+ _vm->delay(_vm->_tickLength);
+
+ init();
+
+ _screen->setScreenDim(2);
+
+ checkForCompleteParty();
+ initButtonsFromList(0, 5);
+
+ _vm->snd_playSong(_vm->game() == GI_EOB1 ? 20 : 13);
+ _activeBox = 0;
+
+ for (bool loop = true; loop && (!_vm->shouldQuit());) {
+ _vm->_gui->updateBoxFrameHighLight(_activeBox + 6);
+ int inputFlag = getInput(_vm->_activeButtons);
+ _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;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE]) {
+ // Unlike the original we allow returning to the main menu
+ _vm->snd_stopSound();
+ return false;
+ }
+ _vm->_gui->updateBoxFrameHighLight(-1);
+ }
+
+ if (inputFlag & 0x8000) {
+ inputFlag = (inputFlag & 0x0f) - 1;
+ if (inputFlag == 4) {
+ loop = false;
+ } else {
+ _activeBox = inputFlag;
+ inputFlag = _vm->_keyMap[Common::KEYCODE_RETURN];
+ }
+ }
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN] || inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP5]) {
+ _vm->_gui->updateBoxFrameHighLight(-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();
+ }
+
+ if (_vm->game() == GI_EOB2)
+ _vm->snd_fadeOut();
+
+ *faceShapes = _faceShapes;
+ return true;
+}
+
+void CharacterGenerator::init() {
+ _screen->loadShapeSetBitmap("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, _vm->_cgaMappingDefault);
+ _screen->_curPage = 0;
+
+ _screen->loadEoBBitmap("CHARGEN", _vm->_cgaMappingDefault, 3, 3, 0);
+ _screen->loadShapeSetBitmap("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, _vm->_cgaMappingDefault);
+
+ 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, _vm->_cgaMappingDefault) : 0;
+ }
+
+ _screen->convertPage(3, 2, _vm->_cgaMappingDefault);
+ _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->snd_playSoundEffect(76);
+ _vm->_system->delayMillis(80);
+ toggleSpecialButton(index, 0, 0);
+}
+
+int CharacterGenerator::viewDeleteCharacter() {
+ initButtonsFromList(0, 7);
+ _vm->removeInputTop();
+
+ _vm->_gui->updateBoxFrameHighLight(-1);
+ printStats(_activeBox, 2);
+
+ int res = 0;
+ for (bool loop = true; loop && _characters[_activeBox].name[0] && !_vm->shouldQuit();) {
+ _vm->_gui->updateBoxFrameHighLight(_activeBox + 6);
+ int inputFlag = getInput(_vm->_activeButtons);
+ 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)
+ _vm->_gui->updateBoxFrameHighLight(-1);
+
+ if (!_characters[cbx].name[0])
+ loop = false;
+
+ if (cbx != _activeBox) {
+ _activeBox = cbx;
+ _vm->_gui->updateBoxFrameHighLight(-1);
+ if (loop)
+ printStats(_activeBox, 2);
+ }
+ }
+
+ return res;
+}
+
+void CharacterGenerator::createPartyMember() {
+ _screen->setScreenDim(2);
+ assert(_vm->_gui);
+
+ 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->simpleMenu_setup(1, 0, _chargenRaceSexStrings, -1, 0, 0);
+ int16 res = -1;
+
+ while (res == -1 && !_vm->shouldQuit()) {
+ res = _vm->_gui->simpleMenu_process(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->simpleMenu_setup(2, 15, _chargenClassStrings, itemsMask, 0, 0);
+
+ _vm->_mouseX = _vm->_mouseY = 0;
+ int16 res = -1;
+
+ while (res == -1 && !_vm->shouldQuit()) {
+ updateMagicShapes();
+ int in = getInput(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->simpleMenu_process(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->simpleMenu_setup(3, 9, _chargenAlignmentStrings, itemsMask, 0, 0);
+
+ _vm->_mouseX = _vm->_mouseY = 0;
+ int16 res = -1;
+
+ while (res == -1 && !_vm->shouldQuit()) {
+ updateMagicShapes();
+ int in = getInput(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->simpleMenu_process(3, _chargenAlignmentStrings, 0, itemsMask, 0);
+ }
+ }
+
+ _vm->removeInputTop();
+
+ if (res == _vm->_keyMap[Common::KEYCODE_ESCAPE])
+ processSpecialButton(5);
+
+ return res;
+}
+
+int CharacterGenerator::getInput(Button *buttonList) {
+ if (_vm->game() == GI_EOB1 && _vm->sound()->checkTrigger()) {
+ _vm->sound()->resetTrigger();
+ _vm->snd_playSong(20);
+ } else if (_vm->game() == GI_EOB2 && !_vm->sound()->isPlaying()) {
+ // WORKAROUND for EOB II: The original implements the same sound trigger check as in EOB I.
+ // However, Westwood seems to have forgotten to set the trigger at the end of the AdLib song,
+ // so that the music will not loop. We simply check whether the sound driver is still playing.
+ _vm->delay(3 * _vm->_tickLength);
+ _vm->snd_playSong(13);
+ }
+ return _vm->checkInput(buttonList, false, 0);
+}
+
+void CharacterGenerator::updateMagicShapes() {
+ 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->_charClassModifier[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 = getInput(_vm->_activeButtons);
+ _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;
+ }
+ }
+
+ _vm->_gui->updateBoxFrameHighLight(6 + _activeBox);
+ _vm->_gui->updateBoxFrameHighLight(-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);
+ _vm->_gui->updateBoxFrameHighLight(-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 = getInput(_vm->_activeButtons);
+ _vm->removeInputTop();
+
+ _vm->_gui->updateBoxFrameHighLight(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;
+ }
+ }
+
+ _vm->_gui->updateBoxFrameHighLight(-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()) {
+ _vm->_gui->updateBoxFrameHighLight(-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) {
+ _vm->_gui->updateBoxFrameHighLight(-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);
+
+ Common::String str = Common::String::format(_chargenStrings1[3], _vm->getCharStrength(c->strengthCur, c->strengthExtCur).c_str(), c->intelligenceCur, c->wisdomCur, c->dexterityCur, c->constitutionCur, c->charismaCur);
+ _screen->printShadedText(str.c_str(), 192, 64, 15, 0);
+
+ str = Common::String::format(_chargenStrings1[4], c->armorClass, c->hitPointsMax);
+ _screen->printShadedText(str.c_str(), 280, 64, 15, 0);
+
+ const char *lvlStr = c->level[2] ? _chargenStrings1[7] : (c->level[1] ? _chargenStrings1[6] : _chargenStrings1[5]);
+ str = Common::String::format(lvlStr, c->level[0], c->level[1], c->level[2]);
+ _screen->printShadedText(str.c_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();
+
+ Common::String statStr = index ? Common::String::format("%d", *s1) : _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.c_str(), 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 = getInput(_vm->_activeButtons);
+ _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 - 1) % 7;
+ loop = false;
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP2]) {
+ ci = (ci + 1) % 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;
+
+ statStr = index ? Common::String::format("%d", *s1) : _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.c_str(), 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) {
+ statStr = Common::String::format("%d", c->hitPointsCur);
+ _screen->copyRegion(120, 72, 264, 136, 40, 8, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(statStr.c_str(), 264, 136, 15, 0);
+ _screen->updateScreen();
+ }
+
+ } else if (index == 3) {
+ int oldVal = c->armorClass;
+ c->armorClass = _vm->getDexterityArmorClassModifier(v1) + 10;
+
+ if (c->armorClass != oldVal) {
+ statStr = Common::String::format("%d", c->armorClass);
+ _screen->copyRegion(120, 64, 264, 128, 40, 8, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(statStr.c_str(), 264, 128, 15, 0);
+ _screen->updateScreen();
+ }
+ }
+
+ if (loop == false) {
+ statStr = index ? Common::String::format("%d", *s1) : _vm->getCharStrength(*s1, *s2);
+ _screen->printText(statStr.c_str(), 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->getCharacterClassType(cclass, 0);
+ if (m != -1)
+ res = _vm->getModifiedHpLimits(m, constitution, level1, false);
+
+ m = _vm->getCharacterClassType(cclass, 1);
+ if (m != -1)
+ res += _vm->getModifiedHpLimits(m, constitution, level2, false);
+
+ m = _vm->getCharacterClassType(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->getCharacterClassType(cclass, 0);
+ if (m != -1)
+ res = _vm->getModifiedHpLimits(m, constitution, level1, true);
+
+ m = _vm->getCharacterClassType(cclass, 1);
+ if (m != -1)
+ res += _vm->getModifiedHpLimits(m, constitution, level2, true);
+
+ m = _vm->getCharacterClassType(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].mageSpellsAvailableFlags = (_vm->game() == GI_EOB2) ? 0x81CB6 : 0x26C;
+
+ if (_vm->_classModifierFlags[_characters[i].cClass] & 0x14 && _vm->game() == GI_EOB2) {
+ // Cleric/Paladin: Add Turn Undead spell
+ _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;
+ }
+
+ for (int i = 0; i < 17; i++) {
+ delete[] _chargenButtonLabels[i];
+ _chargenButtonLabels[i] = 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 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
+};
+
+// Transfer Party
+
+class TransferPartyWiz {
+public:
+ TransferPartyWiz(EoBCoreEngine *vm, Screen_EoB *screen);
+ ~TransferPartyWiz();
+
+ bool start();
+
+private:
+ bool selectAndLoadTransferFile();
+ bool transferFileDialogue(Common::String &dest);
+
+
+ int selectCharactersMenu();
+ void drawCharPortraitWithStats(int charIndex, bool enabled);
+ void updateHighlight(int index);
+
+ void convertStats();
+ void convertInventory();
+ Item convertItem(Item eob1Item);
+ void giveKhelbensCoin();
+
+ EoBCoreEngine *_vm;
+ Screen_EoB *_screen;
+
+ int _highlight;
+ EoBItem *_oldItems;
+
+ const uint16 *_portraitFrames;
+ const uint8 *_convertTable;
+ const uint8 *_itemTable;
+ const uint32 *_expTable;
+ const char *const *_strings1;
+ const char *const *_strings2;
+ const char *const *_labels;
+};
+
+TransferPartyWiz::TransferPartyWiz(EoBCoreEngine *vm, Screen_EoB *screen) : _vm(vm), _screen(screen) {
+ int temp;
+ _portraitFrames = _vm->staticres()->loadRawDataBe16(kEoB2TransferPortraitFrames, temp);
+ _convertTable = _vm->staticres()->loadRawData(kEoB2TransferConvertTable, temp);
+ _itemTable = _vm->staticres()->loadRawData(kEoB2TransferItemTable, temp);
+ _expTable = _vm->staticres()->loadRawDataBe32(kEoB2TransferExpTable, temp);
+ _strings1 = _vm->staticres()->loadStrings(kEoB2TransferStrings1, temp);
+ _strings2 = _vm->staticres()->loadStrings(kEoB2TransferStrings2, temp);
+ _labels = _vm->staticres()->loadStrings(kEoB2TransferLabels, temp);
+ _highlight = -1;
+ _oldItems = 0;
+}
+
+TransferPartyWiz::~TransferPartyWiz() {
+ delete[] _oldItems;
+}
+
+bool TransferPartyWiz::start() {
+ _screen->copyPage(0, _vm->_useHiResDithering ? 1 : 12);
+
+ if (!selectAndLoadTransferFile())
+ return false;
+
+ convertStats();
+
+ _oldItems = new EoBItem[600];
+ memcpy(_oldItems, _vm->_items, sizeof(EoBItem) * 600);
+ _vm->loadItemDefs();
+
+ int selection = selectCharactersMenu();
+ if (selection == 0) {
+ for (int i = 0; i < 6; i++)
+ delete[] _vm->_characters[i].faceShape;
+ memset(_vm->_characters, 0, sizeof(EoBCharacter) * 6);
+ return false;
+ }
+
+ int ch = 0;
+ for (int i = 0; i < 6; i++) {
+ if (selection & (1 << i)) {
+ if (ch != i) {
+ delete[] _vm->_characters[ch].faceShape;
+ memcpy(&_vm->_characters[ch], &_vm->_characters[i], sizeof(EoBCharacter));
+ _vm->_characters[i].faceShape = 0;
+ }
+ ch++;
+ }
+ }
+ memset(&_vm->_characters[4], 0, sizeof(EoBCharacter) * 2);
+
+ convertInventory();
+ giveKhelbensCoin();
+
+ return true;
+}
+
+bool TransferPartyWiz::selectAndLoadTransferFile() {
+ do {
+ _screen->copyPage(_vm->_useHiResDithering ? 1 : 12, 0);
+ if (transferFileDialogue(_vm->_savegameFilename))
+ break;
+ } while (_vm->_gui->confirmDialogue2(15, 68, 1));
+
+ if (_vm->_savegameFilename.empty())
+ return false;
+
+ if (_vm->loadGameState(-1).getCode() != Common::kNoError)
+ return false;
+
+ return true;
+}
+
+ bool TransferPartyWiz::transferFileDialogue(Common::String &dest) {
+ _vm->_gui->transferWaitBox();
+
+ Common::Array<Common::String> eobTargets;
+ const Common::ConfigManager::DomainMap dom = ConfMan.getGameDomains();
+
+ for (Common::ConfigManager::DomainMap::const_iterator i = dom.begin(); i != dom.end(); ++i) {
+ if (ConfMan.get("gameid", i->_key).equals("eob"))
+ eobTargets.push_back(i->_key);
+ _vm->updateInput();
+ }
+
+ if (eobTargets.empty())
+ return false;
+
+ Common::String target = _vm->_gui->transferTargetMenu(eobTargets);
+ _screen->copyPage(_vm->_useHiResDithering ? 1 : 12, 0);
+
+ if (target.empty())
+ return true;
+
+ dest = target + ".fin";
+ Common::InSaveFile *in = _vm->_saveFileMan->openForLoading(dest);
+ if (in) {
+ delete in;
+ if (_vm->_gui->confirmDialogue2(15, -2, 1))
+ return true;
+ }
+
+ _screen->copyPage(_vm->_useHiResDithering ? 1 : 12, 0);
+
+ bool result = _vm->_gui->transferFileMenu(target, dest);
+ _screen->copyPage(_vm->_useHiResDithering ? 1 : 12, 0);
+
+ return result;
+}
+
+int TransferPartyWiz::selectCharactersMenu() {
+ _screen->setCurPage(2);
+ _screen->setFont(Screen::FID_6_FNT);
+ _screen->clearCurPage();
+
+ _vm->gui_drawBox(0, 0, 320, 163, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill);
+ _screen->printText(_strings2[0], 5, 3, 15, 0);
+ _screen->printText(_strings2[1], 5, 10, 15, 0);
+
+ for (int i = 0; i < 6; i++)
+ drawCharPortraitWithStats(i, 0);
+
+ _vm->gui_drawBox(4, 148, 43, 12, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill);
+ _vm->gui_drawBox(272, 148, 43, 12, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill);
+
+ _screen->printShadedText(_labels[0], 9, 151, 15, 0);
+ _screen->printShadedText(_labels[1], 288, 151, 15, 0);
+
+ _screen->setCurPage(0);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ int selection = 0;
+ int highlight = 0;
+ bool update = false;
+
+ for (bool loop = true; loop && (!_vm->shouldQuit());) {
+ int inputFlag = _vm->checkInput(0, false, 0) & 0x8ff;
+ _vm->removeInputTop();
+
+ if (inputFlag) {
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_LEFT] || inputFlag == _vm->_keyMap[Common::KEYCODE_RIGHT]) {
+ highlight ^= 1;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_UP]) {
+ highlight -= 2;
+ if (highlight < 0)
+ highlight += 8;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN]) {
+ highlight += 2;
+ if (highlight >= 8)
+ highlight -= 8;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN] || inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE]) {
+ update = true;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE]) {
+ update = true;
+ highlight = 6;
+ } else if (inputFlag == 199) {
+ for (int i = 0; i < 8; i++) {
+ int t = i << 2;
+ if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, _portraitFrames[t], _portraitFrames[t + 1], _portraitFrames[t + 2], _portraitFrames[t + 3])) {
+ highlight = i;
+ update = true;
+ break;
+ }
+ }
+ }
+ }
+
+ updateHighlight(highlight);
+
+ if (!update)
+ continue;
+
+ update = false;
+
+ if (highlight < 6) {
+ if (_vm->_characters[highlight].flags & 1) {
+ selection ^= (1 << highlight);
+ drawCharPortraitWithStats(highlight, (selection & (1 << highlight)) ? true : false);
+ _screen->updateScreen();
+ }
+ continue;
+ }
+
+ int x = (highlight - 6) * 268 + 4;
+ _vm->gui_drawBox(x, 148, 43, 12, _vm->guiSettings()->colors.fill, _vm->guiSettings()->colors.fill, -1);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(80);
+ _vm->gui_drawBox(x, 148, 43, 12, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, -1);
+ _screen->updateScreen();
+
+ if (highlight == 6 || _vm->shouldQuit()) {
+ _screen->setFont(Screen::FID_8_FNT);
+ return 0;
+ }
+
+ int count = 0;
+ for (int i = 0; i < 6; i++) {
+ if (selection & (1 << i))
+ count++;
+ }
+
+ if (count == 4 || _vm->shouldQuit())
+ loop = false;
+ else
+ _vm->_gui->messageDialogue(16, count < 4 ? 69 : 70, 6);
+
+ _screen->updateScreen();
+ }
+
+ _screen->setFont(Screen::FID_8_FNT);
+ if (_vm->shouldQuit())
+ return 0;
+ else
+ _vm->_gui->messageDialogue(16, 71, 6);
+
+ return selection;
+}
+
+void TransferPartyWiz::drawCharPortraitWithStats(int charIndex, bool enabled) {
+ int16 x = (charIndex % 2) * 159;
+ int16 y = (charIndex / 2) * 40;
+ EoBCharacter *c = &_vm->_characters[charIndex];
+
+ _screen->fillRect(x + 4, y + 24, x + 36, y + 57, 12);
+ _vm->gui_drawBox(x + 40, y + 24, 118, 34, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill);
+
+ if (!(c->flags & 1))
+ return;
+
+ _screen->drawShape(_screen->_curPage, c->faceShape, x + 4, y + 25, 0);
+
+ int color1 = 15;
+ int color2 = 12;
+
+ if (enabled) {
+ color1 = 6;
+ color2 = 15;
+ } else {
+ _screen->drawShape(_screen->_curPage, _vm->_disabledCharGrid, x + 4, y + 25, 0);
+ }
+
+ _screen->printShadedText(c->name, x + 44, y + 27, color1, 0);
+ _screen->printText(_vm->_chargenRaceSexStrings[c->raceSex], x + 43, y + 36, color2, 0);
+ _screen->printText(_vm->_chargenClassStrings[c->cClass], x + 43, y + 43, color2, 0);
+
+ Common::String tmp = Common::String::format(_strings1[0], c->level[0]);
+ for (int i = 1; i < _vm->_numLevelsPerClass[c->cClass]; i++)
+ tmp += Common::String::format(_strings1[1], c->level[i]);
+ _screen->printText(tmp.c_str(), x + 43, y + 50, color2, 0);
+}
+
+void TransferPartyWiz::updateHighlight(int index) {
+ static const int16 xPos[] = { 9, 288 };
+ if (_highlight > 5 && _highlight != index)
+ _screen->printText(_labels[_highlight - 6], xPos[_highlight - 6], 151, 15, 0);
+
+ if (index < 6) {
+ _vm->_gui->updateBoxFrameHighLight(14 + index);
+ _highlight = index;
+ return;
+ }
+
+ if (_highlight == index)
+ return;
+
+ if (_highlight < 6)
+ _vm->_gui->updateBoxFrameHighLight(-1);
+
+ _screen->printText(_labels[index - 6], xPos[index - 6], 151, 6, 0);
+ _screen->updateScreen();
+ _highlight = index;
+}
+
+void TransferPartyWiz::convertStats() {
+ for (int i = 0; i < 6; i++) {
+ EoBCharacter *c = &_vm->_characters[i];
+ uint32 aflags = 0;
+
+ for (int ii = 0; ii < 25; ii++) {
+ if (c->mageSpellsAvailableFlags & (1 << ii)) {
+ int8 f = (int8)_convertTable[ii + 1] - 1;
+ if (f != -1)
+ aflags |= (1 << f);
+ }
+ }
+ c->mageSpellsAvailableFlags = aflags;
+
+ c->armorClass = 0;
+ c->disabledSlots = 0;
+ c->flags &= 1;
+ c->hitPointsCur = c->hitPointsMax;
+ c->food = 100;
+
+ c->effectFlags = 0;
+ c->damageTaken = 0;
+ memset(c->clericSpells, 0, sizeof(int8) * 80);
+ memset(c->mageSpells, 0, sizeof(int8) * 80);
+ memset(c->timers, 0, sizeof(uint32) * 10);
+ memset(c->events, 0, sizeof(int8) * 10);
+ memset(c->effectsRemainder, 0, sizeof(uint8) * 4);
+ memset(c->slotStatus, 0, sizeof(int8) * 5);
+
+ for (int ii = 0; ii < 3; ii++) {
+ int t = _vm->getCharacterClassType(c->cClass, ii);
+ if (t == -1)
+ continue;
+ if (c->experience[ii] > _expTable[t])
+ c->experience[ii] = _expTable[t];
+ }
+ }
+}
+
+void TransferPartyWiz::convertInventory() {
+ for (int i = 0; i < 4; i++) {
+ EoBCharacter *c = &_vm->_characters[i];
+
+ for (int slot = 0; slot < 27; slot++) {
+ Item itm = c->inventory[slot];
+ if (slot == 16) {
+ Item first = itm;
+ c->inventory[slot] = 0;
+
+ for (bool forceLoop = true; (itm && (itm != first)) || forceLoop; itm = _oldItems[itm].prev) {
+ forceLoop = false;
+ _vm->setItemPosition(&c->inventory[slot], -2, convertItem(itm), 0);
+ }
+ } else {
+ c->inventory[slot] = convertItem(itm);
+ }
+ }
+ }
+}
+
+Item TransferPartyWiz::convertItem(Item eob1Item) {
+ if (!eob1Item)
+ return 0;
+
+ EoBItem *itm1 = &_oldItems[eob1Item];
+
+ if (!_itemTable[itm1->type])
+ return 0;
+
+ Item newItem = _vm->duplicateItem(1);
+ EoBItem *itm2 = &_vm->_items[newItem];
+ bool match = false;
+
+ itm2->flags = itm1->flags | 0x40;
+ itm2->icon = itm1->icon;
+ itm2->type = itm1->type;
+ itm2->level = 0xff;
+
+ switch (itm2->type) {
+ case 35:
+ itm1->value += 25;
+ // fall through
+ case 34:
+ itm2->value = _convertTable[itm1->value];
+ if (!itm2->value) {
+ itm2->block = -1;
+ return 0;
+ }
+ break;
+ case 39:
+ itm2->value = itm1->value - 1;
+ break;
+ case 48:
+ if (itm1->value == 5) {
+ memset(itm2, 0, sizeof(EoBItem));
+ itm2->block = -1;
+ return 0;
+ }
+ itm2->value = itm1->value;
+ itm2->flags = ((itm1->flags & 0x3f) + 3) | 0x40;
+ break;
+ case 18:
+ itm2->icon = 19;
+ // fall through
+ default:
+ itm2->value = itm1->value;
+ break;
+ }
+
+ switch ((_vm->_itemTypes[itm2->type].extraProperties & 0x7f) - 1) {
+ case 0:
+ case 1:
+ case 2:
+ if (itm2->value)
+ itm2->flags |= 0x80;
+ break;
+ case 4:
+ case 5:
+ case 8:
+ case 9:
+ case 13:
+ case 15:
+ case 17:
+ itm2->flags |= 0x80;
+ break;
+ default:
+ break;
+ }
+
+ for (int i = 1; i < 600; i++) {
+ if (i == 60 || i == 62 || i == 63 || i == 83)
+ continue;
+ EoBItem *tmp = &_vm->_items[i];
+ if (tmp->level || tmp->block == -2 || tmp->type != itm2->type || tmp->icon != itm2->icon)
+ continue;
+ itm2->nameUnid = tmp->nameUnid;
+ itm2->nameId = tmp->nameId;
+ match = true;
+ break;
+ }
+
+ if (!match) {
+ for (int i = 1; i < 600; i++) {
+ if (i == 60 || i == 62 || i == 63 || i == 83)
+ continue;
+ EoBItem *tmp = &_vm->_items[i];
+ if (tmp->level || tmp->block == -2 || tmp->type != itm2->type)
+ continue;
+ itm2->nameUnid = tmp->nameUnid;
+ itm2->nameId = tmp->nameId;
+ match = true;
+ break;
+ }
+ }
+
+ if (!match) {
+ memset(itm2, 0, sizeof(EoBItem));
+ itm2->block = -1;
+ return 0;
+ }
+
+ itm2->level = 0;
+ return newItem;
+}
+
+void TransferPartyWiz::giveKhelbensCoin() {
+ bool success = false;
+ for (int i = 0; i < 4 && !success; i++) {
+ EoBCharacter *c = &_vm->_characters[i];
+
+ for (int slot = 2; slot < 16; slot++) {
+ if (c->inventory[slot])
+ continue;
+ _vm->createInventoryItem(c, 93, -1, slot);
+ success = true;
+ break;
+ }
+ }
+
+ if (!success) {
+ _vm->_characters[0].inventory[2] = 0;
+ _vm->createInventoryItem(&_vm->_characters[0], 93, -1, 2);
+ }
+}
+
+// Start functions
+
+bool EoBCoreEngine::startCharacterGeneration() {
+ return CharacterGenerator(this, _screen).start(_characters, &_faceShapes);
+}
+
+bool EoBCoreEngine::startPartyTransfer() {
+ return TransferPartyWiz(this, _screen).start();
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/darkmoon.cpp b/engines/kyra/darkmoon.cpp
new file mode 100644
index 0000000000..16bd3dad58
--- /dev/null
+++ b/engines/kyra/darkmoon.cpp
@@ -0,0 +1,471 @@
+/* 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/darkmoon.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+namespace Kyra {
+
+DarkMoonEngine::DarkMoonEngine(OSystem *system, const GameFlags &flags) : EoBCoreEngine(system, flags) {
+ _animIntro = _animFinale = 0;
+ _shapesIntro = _shapesFinale = 0;
+ _dscDoorType5Offs = 0;
+ _numSpells = 70;
+ _menuChoiceInit = 4;
+
+ _introStrings = _cpsFilesIntro = _cpsFilesFinale = _finaleStrings = _kheldranStrings = _npcStrings[0] = _npcStrings[1] = _hornStrings = 0;
+ _shapesIntro = _shapesFinale = 0;
+ _creditsData = _npcShpData = _dscDoorType5Offs = _hornSounds = 0;
+ _dreamSteps = 0;
+}
+
+DarkMoonEngine::~DarkMoonEngine() {
+ delete[] _animIntro;
+ delete[] _animFinale;
+ 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];
+
+ if (_configRenderMode == Common::kRenderEGA) {
+ Palette pal(16);
+ _screen->loadPalette(_egaDefaultPalette, pal, 16);
+ _screen->setScreenPalette(pal);
+ }
+
+ _screen->loadPalette("PALETTE.COL", _screen->getPalette(0));
+ _screen->setScreenPalette(_screen->getPalette(0));
+
+ return Common::kNoError;
+}
+
+void DarkMoonEngine::startupNew() {
+ _currentLevel = 4;
+ _currentSub = 0;
+ loadLevel(4, 0);
+ _currentBlock = 171;
+ _currentDirection = 2;
+ setHandItem(0);
+ EoBCoreEngine::startupNew();
+}
+
+void DarkMoonEngine::drawNpcScene(int npcIndex) {
+ 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;
+ }
+}
+
+void DarkMoonEngine::runNpcDialogue(int npcIndex) {
+ if (npcIndex == 0) {
+ snd_playSoundEffect(57);
+ if (npcJoinDialogue(0, 1, 3, 2))
+ setScriptFlags(0x40);
+ } else if (npcIndex == 1) {
+ snd_playSoundEffect(53);
+ gui_drawDialogueBox();
+
+ _txt->printDialogueText(4, 0);
+ int r = runDialogue(-1, 2, _npcStrings[0][0], _npcStrings[0][1]) - 1;
+
+ if (r == 0) {
+ snd_stopSound();
+ delay(3 * _tickLength);
+ snd_playSoundEffect(91);
+ npcJoinDialogue(1, 5, 6, 7);
+ } else if (r == 1) {
+ setScriptFlags(0x20);
+ }
+
+ } else if (npcIndex == 2) {
+ snd_playSoundEffect(55);
+ gui_drawDialogueBox();
+
+ _txt->printDialogueText(8, 0);
+ int r = runDialogue(-1, 2, _npcStrings[1][0], _npcStrings[1][1]) - 1;
+
+ if (r == 0) {
+ if (rollDice(1, 2, -1))
+ _txt->printDialogueText(9, _okStrings[0]);
+ else
+ npcJoinDialogue(2, 102, 103, 104);
+ setScriptFlags(8);
+ } else if (r == 1) {
+ _currentDirection = 0;
+ }
+ }
+}
+
+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->loadShapeSetBitmap(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++) {
+ // Don't use getPagePixel() here, since in EGA mode it will try to
+ // undither the pixel (although the shape bitmap is undithered already)
+ uint8 col = _screen->getCPagePtr(_screen->_curPage | 1)[(184 + ii) * Screen::SCREEN_W + colx];
+
+ 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++) {
+ // Don't use getPagePixel() here, since in EGA mode it will try to
+ // undither the pixel (although the shape bitmap is undithered already)
+ uint8 col = _screen->getCPagePtr(_screen->_curPage | 1)[(184 + iii) * Screen::SCREEN_W + colx + ii];
+ if (newPal[iii])
+ tmpPal[newPal[iii]] = col;
+ }
+
+ int c = i;
+ if (monsterIndex >= 18)
+ c += 6;
+
+ c = (c << 1) + (ii - 1);
+ assert(c < 24);
+ memcpy(_monsterPalettes[c], tmpPal, 16);
+ }
+ }
+
+ _screen->setCurPage(cp);
+}
+
+void DarkMoonEngine::loadMonsterDecoration(const char *file, int16 monsterIndex) {
+ Common::SeekableReadStream *s = _res->createReadStream(Common::String::format("%s.dcr", file));
+ 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 = (int8)dc[4];
+ m->y = (int8)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);
+}
+
+bool DarkMoonEngine::killMonsterExtra(EoBMonsterInPlay *m) {
+ if (_currentLevel == 16 && _currentSub == 1 && (_monsterProps[m->type].capsFlags & 4)) {
+ if (m->type) {
+ _playFinale = true;
+ _runFlag = false;
+ delay(850);
+ } else {
+ m->hitPointsCur = 150;
+ m->curRemoteWeapon = 0;
+ m->numRemoteAttacks = 255;
+ m->shpIndex++;
+ m->type++;
+ seq_dranDragonTransformation();
+ }
+ return false;
+ }
+ return true;
+}
+
+const uint8 *DarkMoonEngine::loadDoorShapes(const char *filename, int doorIndex, const uint8 *shapeDefs) {
+ _screen->loadShapeSetBitmap(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 (!shp)
+ return;
+
+ 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::restParty_npc() {
+ int insalId = -1;
+ int numChar = 0;
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ if (testCharacter(i, 2) && _characters[i].portrait == -1)
+ insalId = i;
+ numChar++;
+ }
+
+ if (insalId == -1 || numChar < 5)
+ return;
+
+ removeCharacterFromParty(insalId);
+ if (insalId < 4)
+ exchangeCharacters(insalId, testCharacter(5, 1) ? 5 : 4);
+
+ clearScriptFlags(6);
+
+ if (!stripPartyItems(1, 1, 1, 1))
+ stripPartyItems(2, 1, 1, 1);
+ stripPartyItems(31, 0, 1, 3);
+ stripPartyItems(39, 1, 0, 3);
+ stripPartyItems(47, 0, 1, 2);
+
+ _items[createItemOnCurrentBlock(28)].value = 26;
+
+ gui_drawPlayField(false);
+ gui_drawAllCharPortraitsWithStats();
+
+ _screen->setClearScreenDim(10);
+ _gui->messageDialogue2(11, 63, 6);
+ _gui->messageDialogue2(11, 64, 6);
+}
+
+bool DarkMoonEngine::restParty_extraAbortCondition() {
+ if (_currentLevel != 3)
+ return false;
+
+ seq_nightmare();
+
+ return true;
+}
+
+void DarkMoonEngine::useHorn(int charIndex, int weaponSlot) {
+ int v = _items[_characters[charIndex].inventory[weaponSlot]].value - 1;
+ _txt->printMessage(_hornStrings[v]);
+ snd_playSoundEffect(_hornSounds[v]);
+}
+
+bool DarkMoonEngine::checkPartyStatusExtra() {
+ if (checkScriptFlags(0x100000))
+ seq_kheldran();
+ return _gui->confirmDialogue2(14, 67, 1);
+}
+
+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() {
+ countResurrectionCandidates();
+
+ _rrNames[_rrCount] = _abortStrings[0];
+ _rrId[_rrCount++] = 99;
+
+ int r = _rrId[runDialogue(-1, 9, _rrNames[0], _rrNames[1], _rrNames[2], _rrNames[3], _rrNames[4], _rrNames[5], _rrNames[6], _rrNames[7], _rrNames[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, 7, namesList[0], namesList[1], namesList[2], namesList[3], namesList[4], namesList[5], namesList[6]) - 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] + 1);
+ }
+}
+
+const KyraRpgGUISettings *DarkMoonEngine::guiSettings() {
+ return &_guiSettings;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/darkmoon.h b/engines/kyra/darkmoon.h
new file mode 100644
index 0000000000..f6e7b3ed2c
--- /dev/null
+++ b/engines/kyra/darkmoon.h
@@ -0,0 +1,147 @@
+/* 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 DarkMoonAnimCommand {
+ 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();
+
+ int _menuChoiceInit;
+
+ // 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 DarkMoonAnimCommand **_animIntro;
+ const DarkMoonShapeDef **_shapesIntro;
+
+ const char * const *_finaleStrings;
+ const uint8 *_creditsData;
+ const char * const *_cpsFilesFinale;
+ const DarkMoonAnimCommand **_animFinale;
+ const DarkMoonShapeDef **_shapesFinale;
+
+ static const char *_palFilesIntroVGA[];
+ static const char *_palFilesIntroEGA[];
+ static const char *_palFilesFinaleVGA[];
+ static const char *_palFilesFinaleEGA[];
+
+ // Ingame sequence
+ void seq_nightmare();
+ void seq_kheldran();
+ void seq_dranDragonTransformation();
+
+ const int8 *_dreamSteps;
+ const char *const *_kheldranStrings;
+
+ // characters
+ void drawNpcScene(int npcIndex);
+ void runNpcDialogue(int npcIndex);
+
+ const uint8 *_npcShpData;
+ const char *const *_npcStrings[2];
+
+ // 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);
+ bool killMonsterExtra(EoBMonsterInPlay *m);
+
+ // Level
+ void loadDoorShapes(int doorType1, int shapeId1, int doorType2, int shapeId2) {}
+ 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;
+
+ // Rest party
+ void restParty_npc();
+ bool restParty_extraAbortCondition();
+
+ // misc
+ void useHorn(int charIndex, int weaponSlot);
+ bool checkPartyStatusExtra();
+ void drawLightningColumn();
+ int resurrectionSelectDialogue();
+ int charSelectDialogue();
+ void characterLevelGain(int charIndex);
+
+ const KyraRpgGUISettings *guiSettings();
+
+ const char *const *_hornStrings;
+ const uint8 *_hornSounds;
+
+ static const KyraRpgGUISettings _guiSettings;
+ static const uint8 _egaDefaultPalette[];
+};
+
+} // End of namespace Kyra
+
+#endif
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/debugger.cpp b/engines/kyra/debugger.cpp
index 35b4d8ba7f..c0a91ac098 100644
--- a/engines/kyra/debugger.cpp
+++ b/engines/kyra/debugger.cpp
@@ -26,8 +26,12 @@
#include "kyra/timer.h"
#include "kyra/resource.h"
#include "kyra/lol.h"
+#include "kyra/eobcommon.h"
#include "common/system.h"
+#include "common/config-manager.h"
+
+#include "gui/message.h"
namespace Kyra {
@@ -36,16 +40,16 @@ Debugger::Debugger(KyraEngine_v1 *vm)
}
void Debugger::initialize() {
- DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit));
- DCmd_Register("screen_debug_mode", WRAP_METHOD(Debugger, cmd_setScreenDebug));
- DCmd_Register("load_palette", WRAP_METHOD(Debugger, cmd_loadPalette));
- DCmd_Register("facings", WRAP_METHOD(Debugger, cmd_showFacings));
- DCmd_Register("gamespeed", WRAP_METHOD(Debugger, cmd_gameSpeed));
- DCmd_Register("flags", WRAP_METHOD(Debugger, cmd_listFlags));
- DCmd_Register("toggleflag", WRAP_METHOD(Debugger, cmd_toggleFlag));
- DCmd_Register("queryflag", WRAP_METHOD(Debugger, cmd_queryFlag));
- DCmd_Register("timers", WRAP_METHOD(Debugger, cmd_listTimers));
- DCmd_Register("settimercountdown", WRAP_METHOD(Debugger, cmd_setTimerCountdown));
+ DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit));
+ DCmd_Register("screen_debug_mode", WRAP_METHOD(Debugger, cmd_setScreenDebug));
+ DCmd_Register("load_palette", WRAP_METHOD(Debugger, cmd_loadPalette));
+ DCmd_Register("facings", WRAP_METHOD(Debugger, cmd_showFacings));
+ DCmd_Register("gamespeed", WRAP_METHOD(Debugger, cmd_gameSpeed));
+ DCmd_Register("flags", WRAP_METHOD(Debugger, cmd_listFlags));
+ DCmd_Register("toggleflag", WRAP_METHOD(Debugger, cmd_toggleFlag));
+ DCmd_Register("queryflag", WRAP_METHOD(Debugger, cmd_queryFlag));
+ DCmd_Register("timers", WRAP_METHOD(Debugger, cmd_listTimers));
+ DCmd_Register("settimercountdown", WRAP_METHOD(Debugger, cmd_setTimerCountdown));
}
bool Debugger::cmd_setScreenDebug(int argc, const char **argv) {
@@ -135,7 +139,7 @@ bool Debugger::cmd_gameSpeed(int argc, const char **argv) {
}
bool Debugger::cmd_listFlags(int argc, const char **argv) {
- for (int i = 0, p = 0; i < (int)sizeof(_vm->_flagsTable)*8; i++, ++p) {
+ for (int i = 0, p = 0; i < (int)sizeof(_vm->_flagsTable) * 8; i++, ++p) {
DebugPrintf("(%-3i): %-2i", i, _vm->queryGameFlag(i));
if (p == 5) {
DebugPrintf("\n");
@@ -200,10 +204,11 @@ Debugger_LoK::Debugger_LoK(KyraEngine_LoK *vm)
}
void Debugger_LoK::initialize() {
- DCmd_Register("enter", WRAP_METHOD(Debugger_LoK, cmd_enterRoom));
- DCmd_Register("scenes", WRAP_METHOD(Debugger_LoK, cmd_listScenes));
- DCmd_Register("give", WRAP_METHOD(Debugger_LoK, cmd_giveItem));
- DCmd_Register("birthstones", WRAP_METHOD(Debugger_LoK, cmd_listBirthstones));
+ DCmd_Register("enter", WRAP_METHOD(Debugger_LoK, cmd_enterRoom));
+ DCmd_Register("scenes", WRAP_METHOD(Debugger_LoK, cmd_listScenes));
+ DCmd_Register("give", WRAP_METHOD(Debugger_LoK, cmd_giveItem));
+ DCmd_Register("birthstones", WRAP_METHOD(Debugger_LoK, cmd_listBirthstones));
+ Debugger::initialize();
}
bool Debugger_LoK::cmd_enterRoom(int argc, const char **argv) {
@@ -213,7 +218,7 @@ bool Debugger_LoK::cmd_enterRoom(int argc, const char **argv) {
// game will crash if entering a non-existent room
if (room >= _vm->_roomTableSize) {
- DebugPrintf("room number must be any value between (including) 0 and %d\n", _vm->_roomTableSize-1);
+ DebugPrintf("room number must be any value between (including) 0 and %d\n", _vm->_roomTableSize - 1);
return true;
}
@@ -288,12 +293,13 @@ Debugger_v2::Debugger_v2(KyraEngine_v2 *vm) : Debugger(vm), _vm(vm) {
}
void Debugger_v2::initialize() {
- DCmd_Register("character_info", WRAP_METHOD(Debugger_v2, cmd_characterInfo));
- DCmd_Register("enter", WRAP_METHOD(Debugger_v2, cmd_enterScene));
- DCmd_Register("scenes", WRAP_METHOD(Debugger_v2, cmd_listScenes));
- DCmd_Register("scene_info", WRAP_METHOD(Debugger_v2, cmd_sceneInfo));
- DCmd_Register("scene_to_facing", WRAP_METHOD(Debugger_v2, cmd_sceneToFacing));
- DCmd_Register("give", WRAP_METHOD(Debugger_v2, cmd_giveItem));
+ DCmd_Register("character_info", WRAP_METHOD(Debugger_v2, cmd_characterInfo));
+ DCmd_Register("enter", WRAP_METHOD(Debugger_v2, cmd_enterScene));
+ DCmd_Register("scenes", WRAP_METHOD(Debugger_v2, cmd_listScenes));
+ DCmd_Register("scene_info", WRAP_METHOD(Debugger_v2, cmd_sceneInfo));
+ DCmd_Register("scene_to_facing", WRAP_METHOD(Debugger_v2, cmd_sceneToFacing));
+ DCmd_Register("give", WRAP_METHOD(Debugger_v2, cmd_giveItem));
+ Debugger::initialize();
}
bool Debugger_v2::cmd_enterScene(int argc, const char **argv) {
@@ -303,7 +309,7 @@ bool Debugger_v2::cmd_enterScene(int argc, const char **argv) {
// game will crash if entering a non-existent scene
if (scene >= _vm->_sceneListSize) {
- DebugPrintf("scene number must be any value between (including) 0 and %d\n", _vm->_sceneListSize-1);
+ DebugPrintf("scene number must be any value between (including) 0 and %d\n", _vm->_sceneListSize - 1);
return true;
}
@@ -365,8 +371,8 @@ bool Debugger_v2::cmd_sceneInfo(int argc, const char **argv) {
DebugPrintf("This scene has %d special exits.\n", _vm->_specialExitCount);
for (int i = 0; i < _vm->_specialExitCount; ++i) {
DebugPrintf("SpecialExit%d: facing %d, position (x1/y1/x2/y2): %d/%d/%d/%d\n", i,
- _vm->_specialExitTable[20+i], _vm->_specialExitTable[0+i], _vm->_specialExitTable[5+i],
- _vm->_specialExitTable[10+i], _vm->_specialExitTable[15+i]);
+ _vm->_specialExitTable[20 + i], _vm->_specialExitTable[0 + i], _vm->_specialExitTable[5 + i],
+ _vm->_specialExitTable[10 + i], _vm->_specialExitTable[15 + i]);
}
}
@@ -443,7 +449,8 @@ Debugger_HoF::Debugger_HoF(KyraEngine_HoF *vm) : Debugger_v2(vm), _vm(vm) {
}
void Debugger_HoF::initialize() {
- DCmd_Register("pass_codes", WRAP_METHOD(Debugger_HoF, cmd_passcodes));
+ DCmd_Register("pass_codes", WRAP_METHOD(Debugger_HoF, cmd_passcodes));
+ Debugger_v2::initialize();
}
bool Debugger_HoF::cmd_passcodes(int argc, const char **argv) {
@@ -470,4 +477,36 @@ Debugger_LoL::Debugger_LoL(LoLEngine *vm) : Debugger(vm), _vm(vm) {
}
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+Debugger_EoB::Debugger_EoB(EoBCoreEngine *vm) : Debugger(vm), _vm(vm) {
+}
+
+void Debugger_EoB::initialize() {
+ DCmd_Register("import_savefile", WRAP_METHOD(Debugger_EoB, cmd_importSaveFile));
+}
+
+bool Debugger_EoB::cmd_importSaveFile(int argc, const char **argv) {
+ if (!_vm->_allowImport) {
+ DebugPrintf("This command may only be used from the main menu.\n");
+ return true;
+ }
+
+ if (argc == 3) {
+ int slot = atoi(argv[1]);
+ if (slot < -1 || slot > 989) {
+ DebugPrintf("slot must be between (including) -1 and 989 \n");
+ return true;
+ }
+
+ DebugPrintf(_vm->importOriginalSaveFile(slot, argv[2]) ? "Success.\n" : "Failure.\n");
+ _vm->loadItemDefs();
+ } else {
+ DebugPrintf("Syntax: import_savefile <dest slot> <source file>\n (Imports source save game file to dest slot.)\n import_savefile -1\n (Imports all original save game files found and puts them into the first available slots.)\n\n");
+ }
+
+ return true;
+}
+
+#endif // ENABLE_EOB
+
} // End of namespace Kyra
diff --git a/engines/kyra/debugger.h b/engines/kyra/debugger.h
index e9c0a6a98a..2b1dcbe505 100644
--- a/engines/kyra/debugger.h
+++ b/engines/kyra/debugger.h
@@ -108,6 +108,21 @@ protected:
};
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+class EoBCoreEngine;
+
+class Debugger_EoB : public Debugger {
+public:
+ Debugger_EoB(EoBCoreEngine *vm);
+
+ virtual void initialize();
+protected:
+ EoBCoreEngine *_vm;
+
+ bool cmd_importSaveFile(int argc, const char **argv);
+};
+#endif // ENABLE_EOB
+
} // End of namespace Kyra
#endif
diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp
index 68eb08210e..46dfec84ff 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/eob.h"
+#include "kyra/darkmoon.h"
#include "common/config-manager.h"
#include "common/system.h"
@@ -42,7 +45,7 @@ struct KYRAGameDescription {
namespace {
-const char * const directoryGlobs[] = {
+const char *const directoryGlobs[] = {
"malcolm",
0
};
@@ -63,9 +66,12 @@ public:
const char *getOriginalCopyright() const {
return "The Legend of Kyrandia (C) Westwood Studios"
#ifdef ENABLE_LOL
- "\nLands of Lore (C) Westwood Studios"
+ "\nLands of Lore (C) Westwood Studios"
+#endif
+#ifdef ENABLE_EOB
+ "\nEye of the Beholder (C) TSR, Inc., (C) Strategic Simulations, Inc."
#endif
- ;
+ ;
}
bool hasFeature(MetaEngineFeature f) const;
@@ -78,19 +84,19 @@ public:
bool KyraMetaEngine::hasFeature(MetaEngineFeature f) const {
return
- (f == kSupportsListSaves) ||
- (f == kSupportsLoadingDuringStartup) ||
- (f == kSupportsDeleteSave) ||
- (f == kSavesSupportMetaInfo) ||
- (f == kSavesSupportThumbnail);
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail);
}
bool Kyra::KyraEngine_v1::hasFeature(EngineFeature f) const {
return
- (f == kSupportsRTL) ||
- (f == kSupportsLoadingDuringRuntime) ||
- (f == kSupportsSavingDuringRuntime) ||
- (f == kSupportsSubtitleOptions);
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime) ||
+ (f == kSupportsSubtitleOptions);
}
bool KyraMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
@@ -129,6 +135,16 @@ 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:
+ if (Common::parseRenderMode(ConfMan.get("render_mode")) == Common::kRenderEGA)
+ flags.useHiRes = true;
+ *engine = new Kyra::DarkMoonEngine(syst, flags);
+ break;
+#endif // ENABLE_EOB
default:
res = false;
warning("Kyra engine: unknown gameID");
@@ -145,10 +161,14 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const {
Common::StringArray filenames;
filenames = saveFileMan->listSavefiles(pattern);
- Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+ Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Skip automatic final saves made by EOB for the purpose of party transfer
+ if (!scumm_stricmp(file->c_str() + file->size() - 3, "fin"))
+ continue;
+
// Obtain the last 3 digits of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 3);
@@ -171,13 +191,15 @@ SaveStateList KyraMetaEngine::listSaves(const char *target) const {
return saveList;
}
-int KyraMetaEngine::getMaximumSaveSlot() const { return 999; }
+int KyraMetaEngine::getMaximumSaveSlot() const {
+ return 999;
+}
void KyraMetaEngine::removeSaveState(const char *target, int slot) const {
// In Kyra games slot 0 can't be deleted, it's for restarting the game(s).
// An exception makes Lands of Lore here, it does not have any way to restart the
// game except via its main menu.
- if (slot == 0 && !ConfMan.getDomain(target)->getVal("gameid").equalsIgnoreCase("lol"))
+ if (slot == 0 && !ConfMan.getDomain(target)->getVal("gameid").equalsIgnoreCase("lol") && !ConfMan.getDomain(target)->getVal("gameid").equalsIgnoreCase("eob") && !ConfMan.getDomain(target)->getVal("gameid").equalsIgnoreCase("eob2"))
return;
Common::String filename = Kyra::KyraEngine_v1::getSavegameFilename(target, slot);
@@ -187,7 +209,7 @@ void KyraMetaEngine::removeSaveState(const char *target, int slot) const {
SaveStateDescriptor KyraMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::String filename = Kyra::KyraEngine_v1::getSavegameFilename(target, slot);
Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename);
- const bool lolGame = ConfMan.getDomain(target)->getVal("gameid").equalsIgnoreCase("lol");
+ const bool nonKyraGame = ConfMan.getDomain(target)->getVal("gameid").equalsIgnoreCase("lol") || ConfMan.getDomain(target)->getVal("gameid").equalsIgnoreCase("eob") || ConfMan.getDomain(target)->getVal("gameid").equalsIgnoreCase("eob2");
if (in) {
Kyra::KyraEngine_v1::SaveHeader header;
@@ -201,12 +223,12 @@ SaveStateDescriptor KyraMetaEngine::querySaveMetaInfos(const char *target, int s
// Slot 0 is used for the 'restart game' save in all three Kyrandia games, thus
// we prevent it from being deleted.
- desc.setDeletableFlag(slot != 0 || lolGame);
+ desc.setDeletableFlag(slot != 0 || nonKyraGame);
// We don't allow quick saves (slot 990 till 998) to be overwritten.
// The same goes for the 'Autosave', which is slot 999. Slot 0 will also
// be protected in Kyra 1-3, since it's the 'restart game' save.
- desc.setWriteProtectedFlag((slot == 0 && !lolGame) || slot >= 990);
+ desc.setWriteProtectedFlag((slot == 0 && !nonKyraGame) || slot >= 990);
desc.setThumbnail(header.thumbnail);
return desc;
@@ -218,7 +240,7 @@ SaveStateDescriptor KyraMetaEngine::querySaveMetaInfos(const char *target, int s
// We don't allow quick saves (slot 990 till 998) to be overwritten.
// The same goes for the 'Autosave', which is slot 999. Slot 0 will also
// be protected in Kyra 1-3, since it's the 'restart game' save.
- desc.setWriteProtectedFlag((slot == 0 && !lolGame) || slot >= 990);
+ desc.setWriteProtectedFlag((slot == 0 && !nonKyraGame) || slot >= 990);
return desc;
}
diff --git a/engines/kyra/detection_tables.h b/engines/kyra/detection_tables.h
index ebf7c8eee7..204c49cd2c 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
{
@@ -94,7 +97,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_FLOPPY_FLAGS
},
@@ -107,7 +110,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_FLOPPY_FLAGS
},
@@ -119,7 +122,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_FLOPPY_FLAGS
},
@@ -131,7 +134,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_FLOPPY_FLAGS
},
@@ -143,7 +146,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_FLOPPY_FLAGS
},
@@ -155,7 +158,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::RU_RUS,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_OLDFLOPPY_FLAGS
},
@@ -167,7 +170,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::ES_ESP,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_FLOPPY_FLAGS
},
@@ -179,7 +182,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::ES_ESP,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_FLOPPY_FLAGS
},
@@ -191,7 +194,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::IT_ITA,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_FLOPPY_FLAGS
},
@@ -208,7 +211,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformAmiga,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDIAMIGA)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIAMIGA, GUIO_RENDERAMIGA)
},
KYRA1_AMIGA_FLAGS
},
@@ -225,7 +228,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformAmiga,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDIAMIGA)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIAMIGA, GUIO_RENDERAMIGA)
},
KYRA1_AMIGA_FLAGS
},
@@ -242,7 +245,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformMacintosh,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDIGM)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIGM, GUIO_RENDERVGA)
},
KYRA1_FLOPPY_FLAGS
},
@@ -259,7 +262,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformFMTowns,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDITOWNS)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_RENDERFMTOWNS)
},
KYRA1_TOWNS_FLAGS
},
@@ -275,7 +278,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::JA_JPN,
Common::kPlatformFMTowns,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDITOWNS)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_RENDERFMTOWNS)
},
KYRA1_TOWNS_SJIS_FLAGS
},
@@ -294,7 +297,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::JA_JPN,
Common::kPlatformPC98,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDIPC98)
+ GUIO4(GUIO_NOSPEECH, GUIO_MIDIPC98, GUIO_RENDERPC9821, GUIO_RENDERPC9801)
},
KYRA1_TOWNS_SJIS_FLAGS
},
@@ -307,7 +310,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_CD,
- GUIO3(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_CD_FLAGS
},
@@ -319,7 +322,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_CD,
- GUIO3(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_CD_FLAGS
},
@@ -331,7 +334,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_CD,
- GUIO3(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_CD_FLAGS
},
@@ -344,7 +347,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::IT_ITA,
Common::kPlatformPC,
ADGF_CD,
- GUIO3(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_CD_FLAGS
},
@@ -406,7 +409,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DEMO,
- GUIO4(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_DEMO_FLAGS
},
@@ -419,7 +422,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DEMO | ADGF_CD,
- GUIO3(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK)
+ GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA1_DEMO_CD_FLAGS
},
@@ -432,7 +435,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_FLOPPY_CMP_FLAGS
},
@@ -445,7 +448,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_FLOPPY_CMP_FLAGS
},
@@ -458,7 +461,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_FLOPPY_FLAGS
},
@@ -471,7 +474,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_FLOPPY_FLAGS
},
@@ -484,7 +487,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_FLOPPY_FLAGS
},
@@ -497,7 +500,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::IT_ITA,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_FLOPPY_FLAGS
},
@@ -510,7 +513,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::RU_RUS,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_FLOPPY_FAN_FLAGS(Common::RU_RUS, Common::EN_ANY)
},
@@ -523,7 +526,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::RU_RUS,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_FLOPPY_FAN_FLAGS(Common::RU_RUS, Common::EN_ANY)
},
@@ -536,7 +539,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_FLAGS
},
@@ -548,7 +551,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_FLAGS
},
@@ -560,7 +563,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_FLAGS
},
@@ -574,7 +577,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::IT_ITA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -586,7 +589,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -598,7 +601,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -611,7 +614,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::IT_ITA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -624,7 +627,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -637,11 +640,25 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
+ // Russian fan translation
+ { // CD version
+ {
+ "kyra2",
+ "CD",
+ AD_ENTRY1("FERRY.CPS", "763e2103858347d4ffffc329910d323f"),
+ Common::RU_RUS,
+ Common::kPlatformPC,
+ ADGF_DROPLANGUAGE | ADGF_CD,
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
+ },
+ KYRA2_CD_FAN_FLAGS(Common::RU_RUS, Common::EN_ANY)
+ },
+
{ // Interactive Demo
{
"kyra2",
@@ -650,7 +667,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD | ADGF_DEMO,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_DEMO_FLAGS
},
@@ -663,7 +680,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD | ADGF_DEMO,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_DEMO_FLAGS
},
@@ -676,7 +693,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD | ADGF_DEMO,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_CD_DEMO_FLAGS
},
@@ -689,7 +706,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DEMO,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
KYRA2_DEMO_FLAGS
},
@@ -702,7 +719,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformFMTowns,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDITOWNS)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_RENDERFMTOWNS)
},
KYRA2_TOWNS_FLAGS
},
@@ -714,7 +731,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::JA_JPN,
Common::kPlatformFMTowns,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDITOWNS)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDITOWNS, GUIO_RENDERFMTOWNS)
},
KYRA2_TOWNS_SJIS_FLAGS
},
@@ -726,7 +743,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC98,
ADGF_CD,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDIPC98)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIPC98, GUIO_RENDERPC9821)
},
KYRA2_TOWNS_FLAGS
},
@@ -738,7 +755,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::JA_JPN,
Common::kPlatformPC98,
ADGF_CD,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDIPC98)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIPC98, GUIO_RENDERPC9821)
},
KYRA2_TOWNS_SJIS_FLAGS
},
@@ -758,7 +775,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_FLAGS
},
@@ -774,7 +791,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_FLAGS
},
@@ -790,7 +807,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_FLAGS
},
@@ -808,7 +825,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_INS_FLAGS
},
@@ -824,7 +841,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_INS_FLAGS
},
@@ -840,7 +857,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_INS_FLAGS
},
@@ -858,7 +875,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformMacintosh,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_INS_FLAGS
},
@@ -874,7 +891,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformMacintosh,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_INS_FLAGS
},
@@ -890,7 +907,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformMacintosh,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_INS_FLAGS
},
@@ -908,7 +925,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::ES_ESP,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY)
},
@@ -924,7 +941,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY)
},
@@ -940,7 +957,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_FAN_FLAGS(Common::ES_ESP, Common::EN_ANY)
},
@@ -958,7 +975,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA)
},
@@ -974,7 +991,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA)
},
@@ -990,7 +1007,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::IT_ITA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE,
- GUIO1(GUIO_NOMIDI)
+ GUIO2(GUIO_NOMIDI, GUIO_RENDERVGA)
},
KYRA3_CD_FAN_FLAGS(Common::IT_ITA, Common::FR_FRA)
},
@@ -1009,7 +1026,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FLAGS
},
@@ -1026,7 +1043,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FLAGS
},
@@ -1043,7 +1060,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FLAGS
},
@@ -1060,7 +1077,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FLAGS
},
@@ -1077,7 +1094,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FLAGS
},
@@ -1094,7 +1111,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FLAGS
},
@@ -1112,7 +1129,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FAN_FLAGS(Common::RU_RUS, Common::DE_DEU)
},
@@ -1130,7 +1147,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FAN_FLAGS(Common::RU_RUS, Common::DE_DEU)
},
@@ -1147,7 +1164,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::RU_RUS,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FAN_FLAGS(Common::RU_RUS, Common::DE_DEU)
},
@@ -1165,7 +1182,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::IT_ITA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -1182,7 +1199,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -1199,7 +1216,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -1216,7 +1233,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::IT_ITA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -1233,7 +1250,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -1250,7 +1267,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::FR_FRA,
Common::kPlatformPC,
ADGF_DROPLANGUAGE | ADGF_CD,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_CD_FAN_FLAGS(Common::IT_ITA, Common::EN_ANY)
},
@@ -1266,7 +1283,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_FLOPPY_CMP_FLAGS
},
@@ -1282,7 +1299,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_FLOPPY_CMP_FLAGS
},
@@ -1298,7 +1315,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_FLOPPY_CMP_FLAGS
},
@@ -1315,7 +1332,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_FLOPPY_FLAGS
},
@@ -1332,7 +1349,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_FLOPPY_FLAGS
},
@@ -1349,7 +1366,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_FLOPPY_FLAGS
},
@@ -1366,7 +1383,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::DE_DEU,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_FLOPPY_FLAGS
},
@@ -1384,7 +1401,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::RU_RUS,
Common::kPlatformPC,
ADGF_NO_FLAGS,
- GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_FLOPPY_FAN_FLAGS(Common::RU_RUS, Common::EN_ANY)
},
@@ -1401,7 +1418,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::JA_JPN,
Common::kPlatformPC98,
ADGF_NO_FLAGS,
- GUIO2(GUIO_NOSPEECH, GUIO_MIDIPC98)
+ GUIO3(GUIO_NOSPEECH, GUIO_MIDIPC98, GUIO_RENDERPC9801)
},
LOL_PC98_SJIS_FLAGS
},
@@ -1418,7 +1435,7 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DEMO,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_DEMO_FLAGS
},
@@ -1434,11 +1451,78 @@ const KYRAGameDescription adGameDescs[] = {
Common::EN_ANY,
Common::kPlatformPC,
ADGF_DEMO,
- GUIO4(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK)
+ GUIO5(GUIO_MIDIADLIB, GUIO_MIDIMT32, GUIO_MIDIGM, GUIO_MIDIPCSPK, GUIO_RENDERVGA)
},
LOL_KYRA2_DEMO_FLAGS
},
#endif // ENABLE_LOL
+#ifdef ENABLE_EOB
+
+ {
+ {
+ "eob",
+ 0,
+ {
+ { "EOBDATA3.PAK", 0, "61aff543131bd61a8b7d7dc901a8278b", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ ADGF_TESTING,
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA)
+ },
+ EOB_FLAGS
+ },
+
+ {
+ {
+ "eob",
+ 0,
+ {
+ { "TEXT.DAT", 0, "fb59b50f97fd1806756911d986b9b2b5", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ ADGF_TESTING,
+ GUIO6(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA, GUIO_RENDERCGA)
+ },
+ EOB_FLAGS
+ },
+
+ {
+ {
+ "eob2",
+ 0,
+ {
+ { "LEVEL15.INF", 0, "10f19eab75c73d0476dc58bcf70fff7a", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ ADGF_TESTING,
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA)
+ },
+ EOB2_FLAGS
+ },
+
+ {
+ {
+ "eob2",
+ 0,
+ {
+ { "LEVEL15.INF", 0, "ce54243ad1ca4447f521340428da2c91", -1 },
+ { 0, 0, 0, 0 }
+ },
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ ADGF_TESTING,
+ GUIO5(GUIO_NOSPEECH, GUIO_MIDIADLIB, GUIO_MIDIPCSPK, GUIO_RENDERVGA, GUIO_RENDEREGA)
+ },
+ EOB2_FLAGS
+ },
+#endif // ENABLE_EOB
+
{ AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0) }
};
@@ -1449,6 +1533,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/eob.cpp b/engines/kyra/eob.cpp
new file mode 100644
index 0000000000..a7bde9f1ee
--- /dev/null
+++ b/engines/kyra/eob.cpp
@@ -0,0 +1,562 @@
+/* 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/eob.h"
+#include "kyra/resource.h"
+#include "kyra/sound.h"
+
+namespace Kyra {
+
+EoBEngine::EoBEngine(OSystem *system, const GameFlags &flags)
+ : EoBCoreEngine(system, flags) {
+ _numSpells = 53;
+ _menuChoiceInit = 4;
+
+ _turnUndeadString = 0;
+ _finBonusStrings = _npcStrings[1] = _npcStrings[2] = 0;
+ _npcStrings[3] = _npcStrings[4] = _npcStrings[5] = _npcStrings[6] = 0;
+ _npcStrings[7] = _npcStrings[8] = _npcStrings[9] = _npcStrings[10] = 0;
+ _npcShpData = _npcSubShpIndex1 = _npcSubShpIndex2 = _npcSubShpY = 0;
+ _dscDoorScaleMult4 = _dscDoorScaleMult5 = _dscDoorScaleMult6 = _dscDoorY3 = 0;
+ _dscDoorY4 = _dscDoorY5 = _dscDoorY6 = _dscDoorY7 = _doorShapeEncodeDefs = 0;
+ _doorSwitchShapeEncodeDefs = _doorSwitchCoords = 0;
+ _dscDoorCoordsExt = 0;
+}
+
+EoBEngine::~EoBEngine() {
+ delete[] _itemsOverlay;
+}
+
+Common::Error EoBEngine::init() {
+ Common::Error err = EoBCoreEngine::init();
+ if (err.getCode() != Common::kNoError)
+ return err;
+
+ initStaticResource();
+
+ if (_configRenderMode != Common::kRenderCGA)
+ _itemsOverlay = _res->fileData((_configRenderMode == Common::kRenderEGA) ? "ITEMRMP.EGA" : "ITEMRMP.VGA", 0);
+
+ _screen->modifyScreenDim(7, 0x01, 0xB3, 0x22, 0x12);
+ _screen->modifyScreenDim(9, 0x01, 0x7D, 0x26, 0x3F);
+ _screen->modifyScreenDim(12, 0x01, 0x04, 0x14, 0xA0);
+
+ _scriptTimersCount = 1;
+
+ if (_configRenderMode == Common::kRenderEGA) {
+ Palette pal(16);
+ _screen->loadPalette(_egaDefaultPalette, pal, 16);
+ _screen->setScreenPalette(pal);
+ } else {
+ _screen->loadPalette("PALETTE.COL", _screen->getPalette(0));
+ }
+
+ return Common::kNoError;
+}
+
+void EoBEngine::startupNew() {
+ _currentLevel = 1;
+ _currentSub = 0;
+ loadLevel(1, 0);
+ _currentBlock = 490;
+ _currentDirection = 0;
+ setHandItem(0);
+
+ EoBCoreEngine::startupNew();
+}
+
+void EoBEngine::startupLoad() {
+ _sound->loadSoundFile("ADLIB");
+}
+
+void EoBEngine::drawNpcScene(int npcIndex) {
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 6, 0, Screen::CR_NO_P_CHECK);
+ switch (npcIndex) {
+ case 0:
+ encodeDrawNpcSeqShape(2, 88, 104);
+ break;
+
+ case 1:
+ if (_npcSequenceSub == -1) {
+ encodeDrawNpcSeqShape(0, 88, 104);
+ } else {
+ encodeDrawNpcSeqShape(0, 60, 104);
+ encodeDrawNpcSeqShape(5, 116, 104);
+ }
+ break;
+
+ case 2:
+ if (_npcSequenceSub == -1) {
+ encodeDrawNpcSeqShape(3, 88, 104);
+ } else {
+ encodeDrawNpcSeqShape(3, 60, 104);
+ encodeDrawNpcSeqShape(_npcSubShpIndex1[_npcSequenceSub], 116, 104);
+ encodeDrawNpcSeqShape(_npcSubShpIndex2[_npcSequenceSub], 116, _npcSubShpY[_npcSequenceSub]);
+ }
+ break;
+
+ case 3:
+ encodeDrawNpcSeqShape(7, 88, 104);
+ break;
+
+ case 4:
+ encodeDrawNpcSeqShape(6, 88, 104);
+ break;
+
+ case 5:
+ encodeDrawNpcSeqShape(18, 88, 88);
+ break;
+
+ case 6:
+ encodeDrawNpcSeqShape(17, 88, 104);
+ break;
+
+ case 7:
+ encodeDrawNpcSeqShape(4, 88, 104);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void EoBEngine::encodeDrawNpcSeqShape(int npcIndex, int drawX, int drawY) {
+ const uint8 *shpDef = &_npcShpData[npcIndex << 2];
+ _screen->_curPage = 2;
+ const uint8 *shp = _screen->encodeShape(shpDef[0], shpDef[1], shpDef[2], shpDef[3], false, _cgaMappingDefault);
+ _screen->_curPage = 0;
+ _screen->drawShape(0, shp, drawX - (shp[2] << 2), drawY - shp[1], 5);
+ delete[] shp;
+}
+
+#define DLG2(txt, buttonstr) (runDialogue(txt, 2, _npcStrings[buttonstr][0], _npcStrings[buttonstr][1]) - 1)
+#define DLG3(txt, buttonstr) (runDialogue(txt, 3, _npcStrings[buttonstr][0], _npcStrings[buttonstr][1], _npcStrings[buttonstr][2]) - 1)
+#define DLG2A3(cond, txt, buttonstr1, buttonstr2) ((cond) ? (DLG2(txt, buttonstr1) ? 2 : 0) : DLG3(txt, buttonstr2))
+#define TXT(txt) _txt->printDialogueText(txt, _moreStrings[0])
+
+void EoBEngine::runNpcDialogue(int npcIndex) {
+ int r = 0;
+ int a = 0;
+ Item itm = 0;
+
+ switch (npcIndex) {
+ case 0:
+ for (r = 1; r == 1;) {
+ gui_drawDialogueBox();
+ r = DLG2A3(checkScriptFlags(0x2000), 8, 2, 1);
+ if (r == 1) {
+ TXT(1);
+ setScriptFlags(0x2000);
+ } else if (r == 0) {
+ npcJoinDialogue(6, 12, 23, 2);
+ setScriptFlags(0x4000);
+ }
+ }
+ break;
+
+ case 1:
+ if (!checkScriptFlags(0x10000)) {
+ if (checkScriptFlags(0x8000)) {
+ a = 1;
+ } else {
+ setScriptFlags(0x8000);
+ r = DLG2(3, 3);
+ }
+ if (!r)
+ r = DLG2(a ? 13 : 4, 4);
+
+ if (!r) {
+ for (a = 0; a < 6; a++)
+ createItemOnCurrentBlock(55);
+ createItemOnCurrentBlock(62);
+ setScriptFlags(0x10000);
+ TXT(6);
+ npcJoinDialogue(7, 7, 29, 30);
+ } else {
+ TXT(5);
+ }
+ r = 1;
+ }
+
+ if (!checkScriptFlags(0x80000)) {
+ for (a = 0; a < 6; a++) {
+ if (testCharacter(a, 1) && _characters[a].portrait == -9)
+ break;
+ }
+ if (a != 6) {
+ TXT(25);
+ TXT(26);
+ setScriptFlags(0x80000);
+ r = 1;
+ }
+ }
+
+ if (!checkScriptFlags(0x100000)) {
+ if (deletePartyItems(6, -1)) {
+ //_npcSequenceSub = 0;
+ //drawNpcScene(npcIndex);
+ TXT(28);
+ createItemOnCurrentBlock(32);
+ setScriptFlags(0x100000);
+ r = 1;
+ }
+ }
+
+ if (!r)
+ _txt->printDialogueText(_npcStrings[0][0], true);
+
+ break;
+
+ case 2:
+ if (checkScriptFlags(0x10000)) {
+ if (checkScriptFlags(0x20000)) {
+ TXT(11);
+ } else {
+ r = DLG2A3(!countResurrectionCandidates(), 9, 5, 6);
+ if (r < 2) {
+ if (r == 0)
+ healParty();
+ else
+ resurrectionSelectDialogue();
+ setScriptFlags(0x20000);
+ }
+ }
+ } else {
+ TXT(24);
+ }
+ break;
+
+ case 3:
+ if (!DLG2(18, 7)) {
+ setScriptFlags(0x8400000);
+ for (a = 0; a < 30; a++) {
+ if (_monsters[a].mode == 8)
+ _monsters[a].mode = 5;
+ }
+ } else if (deletePartyItems(49, -1)) {
+ TXT(20);
+ setScriptFlags(0x400000);
+ } else {
+ TXT(19);
+ }
+ break;
+
+ case 4:
+ r = DLG3(14, 8);
+ if (r == 0)
+ setScriptFlags(0x200000);
+ else if (r == 1)
+ TXT(15);
+ setScriptFlags(0x800000);
+ break;
+
+ case 5:
+ if (!DLG2(16, 9)) {
+ TXT(17);
+ for (a = 0; a < 6; a++) {
+ for (r = 0; r < 2; r++) {
+ itm = _characters[a].inventory[r];
+ if (itm && (_items[itm].type < 51 || _items[itm].type > 56)) {
+ _characters[a].inventory[r] = 0;
+ setItemPosition((Item *)&_levelBlockProperties[_currentBlock].drawObjects, _currentBlock, itm, _dropItemDirIndex[(_currentDirection << 2) + rollDice(1, 2, -1)]);
+ }
+ }
+ }
+ }
+ setScriptFlags(0x2000000);
+ break;
+
+ case 6:
+ TXT(21);
+ setScriptFlags(0x1000000);
+ break;
+
+ case 7:
+ r = DLG3(22, 10);
+ if (r < 2) {
+ if (r == 0)
+ npcJoinDialogue(8, 27, 44, 45);
+ else
+ TXT(31);
+ setScriptFlags(0x4000000);
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+#undef TXT
+#undef DLG2
+#undef DLG3
+#undef DLG2A3
+
+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::updateScriptTimersExtra() {
+ int cnt = 0;
+ for (int i = 1; i < 30; i++) {
+ if (_monsters[i].hitPointsCur <= 0)
+ cnt++;
+ }
+
+ if (!cnt) {
+ for (int i = 1; i < 30; i++) {
+ if (getBlockDistance(_monsters[i].block, _currentBlock) > 3) {
+ killMonster(&_monsters[i], true);
+ break;
+ }
+ }
+ }
+}
+
+void EoBEngine::loadDoorShapes(int doorType1, int shapeId1, int doorType2, int shapeId2) {
+ _screen->loadShapeSetBitmap("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], false, (_flags.gameID == GI_EOB1) ? _cgaMappingLevel[_cgaLevelMappingIndex[_currentLevel - 1]] : 0);
+ enc = &_doorSwitchShapeEncodeDefs[(doorType1 * 3 + i) << 2];
+ _doorSwitches[shapeId1 + i].shp = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3], false, (_flags.gameID == GI_EOB1) ? _cgaMappingLevel[_cgaLevelMappingIndex[_currentLevel - 1]] : 0);
+ _doorSwitches[shapeId1 + i].x = _doorSwitchCoords[doorType1 * 6 + i * 2];
+ _doorSwitches[shapeId1 + i].y = _doorSwitchCoords[doorType1 * 6 + i * 2 + 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], false, (_flags.gameID == GI_EOB1) ? _cgaMappingLevel[_cgaLevelMappingIndex[_currentLevel - 1]] : 0);
+ enc = &_doorSwitchShapeEncodeDefs[(doorType2 * 3 + i) << 2];
+ _doorSwitches[shapeId2 + i].shp = _screen->encodeShape(enc[0], enc[1], enc[2], enc[3], false, (_flags.gameID == GI_EOB1) ? _cgaMappingLevel[_cgaLevelMappingIndex[_currentLevel - 1]] : 0);
+ _doorSwitches[shapeId2 + i].x = _doorSwitchCoords[doorType2 * 6 + i * 2];
+ _doorSwitches[shapeId2 + i].y = _doorSwitchCoords[doorType2 * 6 + i * 2 + 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 = _dscDoorY6[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);
+ setDoorShapeDim(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 = _dscDoorY4[mDim] + v;
+ drawBlockObject(0, 2, shp, x, y + v, 5);
+ v = (v >> 3) + (v >> 2);
+ 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;
+ }
+}
+
+void EoBEngine::turnUndeadAuto() {
+ if (_currentLevel != 2 && _currentLevel != 7)
+ return;
+
+ int oc = _openBookChar;
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 0x0d))
+ continue;
+
+ EoBCharacter *c = &_characters[i];
+
+ if (_itemTypes[_items[c->inventory[0]].type].extraProperties != 6 && _itemTypes[_items[c->inventory[1]].type].extraProperties != 6)
+ continue;
+
+ int l = getCharacterLevelIndex(2, c->cClass);
+ if (l > -1) {
+ if (c->level[l] > _openBookCasterLevel) {
+ _openBookCasterLevel = c->level[l];
+ _openBookChar = i;
+ }
+ } else {
+ l = getCharacterLevelIndex(4, c->cClass);
+ if (l > -1) {
+ if ((c->level[l] - 2) > _openBookCasterLevel) {
+ _openBookCasterLevel = (c->level[l] - 2);
+ _openBookChar = i;
+ }
+ }
+ }
+ }
+
+ if (_openBookCasterLevel)
+ spellCallback_start_turnUndead();
+
+ _openBookChar = oc;
+ _openBookCasterLevel = 0;
+}
+
+void EoBEngine::turnUndeadAutoHit() {
+ _txt->printMessage(_turnUndeadString[0], -1, _characters[_openBookChar].name);
+ sparkEffectOffensive();
+}
+
+bool EoBEngine::checkPartyStatusExtra() {
+ _screen->copyPage(0, 10);
+ int cd = _screen->curDimIndex();
+ gui_drawBox(0, 121, 320, 80, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ _txt->setupField(9, false);
+ _txt->printMessage(_menuStringsDefeat[0]);
+ while (!shouldQuit()) {
+ removeInputTop();
+ if (checkInput(0, false, 0) & 0xff)
+ break;
+ }
+ _screen->copyPage(10, 0);
+ _eventList.clear();
+ _screen->setScreenDim(cd);
+ _txt->removePageBreakFlag();
+ return true;
+}
+
+int EoBEngine::resurrectionSelectDialogue() {
+ gui_drawDialogueBox();
+ _txt->printDialogueText(_npcStrings[0][1]);
+
+ int r = _rrId[runDialogue(-1, 9, _rrNames[0], _rrNames[1], _rrNames[2], _rrNames[3], _rrNames[4], _rrNames[5], _rrNames[6], _rrNames[7], _rrNames[8]) - 1];
+
+ if (r < 0) {
+ r = -r;
+ deletePartyItems(33, r);
+ _npcSequenceSub = r - 1;
+ drawNpcScene(2);
+ npcJoinDialogue(_npcSequenceSub, 32 + (_npcSequenceSub << 1), -1, 33 + (_npcSequenceSub << 1));
+ } else {
+ _characters[r].hitPointsCur = _characters[r].hitPointsMax;
+ }
+
+ return 1;
+}
+
+void EoBEngine::healParty() {
+ int cnt = rollDice(1, 3, 2);
+ for (int i = 0; i < 6 && cnt; i++) {
+ if (testCharacter(i, 3))
+ continue;
+
+ _characters[i].flags &= ~4;
+ neutralizePoison(i);
+
+ if (_characters[i].hitPointsCur >= _characters[i].hitPointsMax)
+ continue;
+
+ cnt--;
+ _characters[i].hitPointsCur += rollDice(1, 8, 9);
+ if (_characters[i].hitPointsCur > _characters[i].hitPointsMax)
+ _characters[i].hitPointsCur = _characters[i].hitPointsMax;
+ }
+}
+
+const KyraRpgGUISettings *EoBEngine::guiSettings() {
+ return (_configRenderMode == Common::kRenderCGA || _configRenderMode == Common::kRenderEGA) ? &_guiSettingsEGA : &_guiSettingsVGA;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/eob.h b/engines/kyra/eob.h
new file mode 100644
index 0000000000..37ce483702
--- /dev/null
+++ b/engines/kyra/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_EOB1_H
+#define KYRA_EOB1_H
+
+#include "kyra/eobcommon.h"
+
+namespace Kyra {
+
+class EoBEngine : public EoBCoreEngine {
+friend class GUI_EoB;
+friend class EoBIntroPlayer;
+public:
+ EoBEngine(OSystem *system, const GameFlags &flags);
+ ~EoBEngine();
+
+private:
+ // Init / Release
+ Common::Error init();
+ void initStaticResource();
+ void initSpells();
+
+ // Main Menu
+ int mainMenu();
+ int mainMenuLoop();
+ int _menuChoiceInit;
+
+ // Main loop
+ void startupNew();
+ void startupLoad();
+
+ // Intro/Outro
+ void seq_playIntro();
+ void seq_playFinale();
+ void seq_xdeath();
+
+ const char *const *_finBonusStrings;
+
+ // characters
+ void drawNpcScene(int npcIndex);
+ void encodeDrawNpcSeqShape(int npcIndex, int drawX, int drawY);
+ void runNpcDialogue(int npcIndex);
+
+ const uint8 *_npcShpData;
+ const uint8 *_npcSubShpIndex1;
+ const uint8 *_npcSubShpIndex2;
+ const uint8 *_npcSubShpY;
+ const char *const *_npcStrings[11];
+
+ // 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);
+ void updateScriptTimersExtra();
+
+ // Level
+ const uint8 *loadDoorShapes(const char *filename, int doorIndex, const uint8 *shapeDefs) { return 0; }
+ 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 *_dscDoorY7;
+
+ const uint8 *_doorShapeEncodeDefs;
+ const uint8 *_doorSwitchShapeEncodeDefs;
+ const uint8 *_doorSwitchCoords;
+
+ // Magic
+ void turnUndeadAuto();
+ void turnUndeadAutoHit();
+
+ const char * const *_turnUndeadString;
+
+ // Misc
+ bool checkPartyStatusExtra();
+ int resurrectionSelectDialogue();
+ void healParty();
+
+ const KyraRpgGUISettings *guiSettings();
+
+ static const KyraRpgGUISettings _guiSettingsVGA;
+ static const KyraRpgGUISettings _guiSettingsEGA;
+ static const uint8 _egaDefaultPalette[];
+};
+
+
+} // 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..a63f123258
--- /dev/null
+++ b/engines/kyra/eobcommon.cpp
@@ -0,0 +1,2420 @@
+/* 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/kyra_rpg.h"
+#include "kyra/resource.h"
+#include "kyra/sound_intern.h"
+#include "kyra/script_eob.h"
+#include "kyra/timer.h"
+#include "kyra/debugger.h"
+
+#include "common/config-manager.h"
+#include "common/translation.h"
+
+#include "audio/mididrv.h"
+#include "audio/mixer.h"
+
+#include "backends/keymapper/keymapper.h"
+
+namespace Kyra {
+
+const char *const EoBCoreEngine::kKeymapName = "eob";
+
+EoBCoreEngine::EoBCoreEngine(OSystem *system, const GameFlags &flags)
+ : KyraRpgEngine(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;
+ _debugger = 0;
+
+ _playFinale = false;
+ _runFlag = true;
+ _configMouse = true;
+ _loading = false;
+
+ _useHiResDithering = false;
+
+ _envAudioTimer = 0;
+ _flashShapeTimer = 0;
+ _drawSceneTimer = 0;
+
+ _largeItemShapes = _smallItemShapes = _thrownItemShapes = _spellShapes = _firebeamShapes = 0;
+ _itemIconShapes = _wallOfForceShapes = _teleporterShapes = _sparkShapes = _compassShapes = 0;
+ _redSplatShape = _greenSplatShape = _deadCharShape = _disabledCharGrid = 0;
+ _blackBoxSmallGrid = _weaponSlotGrid = _blackBoxWideGrid = _lightningColumnShape = 0;
+
+ _monsterDustStrings = 0;
+ _enemyMageSpellList = 0;
+ _enemyMageSfx = 0;
+ _beholderSpellList = 0;
+ _beholderSfx = 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;
+ _monsterFlashOverlay = _monsterStoneOverlay = 0;
+ _monsters = 0;
+ _dstMonsterIndex = 0;
+ _preventMonsterFlash = false;
+
+ _teleporterPulse = 0;
+
+ _dscShapeCoords = 0;
+ _dscItemPosIndex = 0;
+ _dscItemShpX = 0;
+ _dscItemScaleIndex = 0;
+ _dscItemTileIndex = 0;
+ _dscItemShapeMap = 0;
+ _dscDoorScaleOffs = 0;
+ _dscDoorScaleMult1 = 0;
+ _dscDoorScaleMult2 = 0;
+ _dscDoorScaleMult3 = 0;
+ _dscDoorY1 = 0;
+ _dscDoorXE = 0;
+
+ _menuDefs = 0;
+
+ _exchangeCharacterId = -1;
+ _charExchangeSwap = 0;
+ _configHpBarGraphs = true;
+
+ memset(_dialogueLastBitmap, 0, 13);
+ _npcSequenceSub = 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 = _openBookCasterLevel = 0;
+ _openBookType = _openBookTypeBackup = 0;
+ _openBookSpellList = 0;
+ _openBookAvailableSpells = 0;
+ _activeSpellCharId = 0;
+ _activeSpellCharacterPos = 0;
+ _activeSpell = 0;
+ _characterSpellTarget = 0;
+ _returnAfterSpellCallback = false;
+ _spells = 0;
+ _spellAnimBuffer = 0;
+ _clericSpellOffset = 0;
+ _restPartyElapsedTime = 0;
+ _allowSkip = false;
+ _allowImport = false;
+
+ _wallsOfForce = 0;
+
+ _rrCount = 0;
+ memset(_rrNames, 0, 10 * sizeof(const char *));
+ memset(_rrId, 0, 10 * sizeof(int8));
+
+ _mainMenuStrings = _levelGainStrings = _monsterSpecAttStrings = _characterGuiStringsHp = 0;
+ _characterGuiStringsWp = _characterGuiStringsWr = _characterGuiStringsSt = 0;
+ _characterGuiStringsIn = _characterStatusStrings7 = _characterStatusStrings8 = 0;
+ _characterStatusStrings9 = _characterStatusStrings12 = _characterStatusStrings13 = 0;
+ _classModifierFlags = _saveThrowLevelIndex = _saveThrowModDiv = _saveThrowModExt = 0;
+ _wandTypes = _drawObjPosIndex = _flightObjFlipIndex = _expObjectTblIndex = 0;
+ _expObjectShpStart = _expObjectTlMode = _expObjectAnimTbl1 = _expObjectAnimTbl2 = _expObjectAnimTbl3 = 0;
+ _monsterStepTable0 = _monsterStepTable1 = _monsterStepTable2 = _monsterStepTable3 = 0;
+ _projectileWeaponAmmoTypes = _flightObjShpMap = _flightObjSclIndex = 0;
+ _monsterCloseAttPosTable1 = _monsterCloseAttPosTable2 = _monsterCloseAttChkTable1 = 0;
+ _monsterCloseAttChkTable2 = _monsterCloseAttDstTable1 = _monsterCloseAttDstTable2 = 0;
+ _monsterProximityTable = _findBlockMonstersTable = _wallOfForceDsY = _wallOfForceDsNumW = 0;
+ _wallOfForceDsNumH = _wallOfForceShpId = _wllFlagPreset = _teleporterShapeCoords = 0;
+ _monsterCloseAttUnkTable = _monsterFrmOffsTable1 = _monsterFrmOffsTable2 = 0;
+ _monsterDirChangeTable = _portalSeq = 0;
+ _wallOfForceDsX = 0;
+ _expObjectAnimTbl1Size = _expObjectAnimTbl2Size = _expObjectAnimTbl3Size = 0;
+ _wllFlagPresetSize = _scriptTimersCount = _buttonList1Size = _buttonList2Size = 0;
+ _buttonList3Size = _buttonList4Size = _buttonList5Size = _buttonList6Size = 0;
+ _buttonList7Size = _buttonList8Size = 0;
+ _inventorySlotsY = _mnDef = 0;
+ _transferStringsScummVM = 0;
+ _buttonDefs = 0;
+ _npcPreset = 0;
+ _chargenStatStrings = _chargenRaceSexStrings = _chargenClassStrings = 0;
+ _chargenAlignmentStrings = _pryDoorStrings = _warningStrings = _ripItemStrings = 0;
+ _cursedString = _enchantedString = _magicObjectStrings = _magicObjectString5 = 0;
+ _patternSuffix = _patternGrFix1 = _patternGrFix2 = _validateArmorString = 0;
+ _validateCursedString = _validateNoDropString = _potionStrings = _wandStrings = 0;
+ _itemMisuseStrings = _suffixStringsRings = _suffixStringsPotions = 0;
+ _suffixStringsWands = _takenStrings = _potionEffectStrings = _yesNoStrings = 0;
+ _npcMaxStrings = _okStrings = _npcJoinStrings = _cancelStrings = 0;
+ _abortStrings = _saveLoadStrings = _mnWord = _mnPrompt = _bookNumbers = 0;
+ _mageSpellList = _clericSpellList = _spellNames = _magicStrings1 = 0;
+ _magicStrings2 = _magicStrings3 = _magicStrings4 = _magicStrings6 = 0;
+ _magicStrings7 = _magicStrings8 = 0;
+ _spellAnimBuffer = 0;
+ _sparkEffectDefSteps = _sparkEffectDefSubSteps = _sparkEffectDefShift = 0;
+ _sparkEffectDefAdd = _sparkEffectDefX = _sparkEffectDefY = _sparkEffectOfShift = 0;
+ _sparkEffectOfX = _sparkEffectOfY = _magicFlightObjectProperties = 0;
+ _turnUndeadEffect = _burningHandsDest = _coneOfColdGfxTbl = 0;
+ _sparkEffectOfFlags1 = _sparkEffectOfFlags2 = 0;
+ _coneOfColdDest1 = _coneOfColdDest2 = _coneOfColdDest3 = _coneOfColdDest4 = 0;
+ _coneOfColdGfxTblSize = 0;
+ _menuButtonDefs = 0;
+ _updateCharNum = 0;
+ _menuStringsMain = _menuStringsSaveLoad = _menuStringsOnOff = _menuStringsSpells = 0;
+ _menuStringsRest = _menuStringsDrop = _menuStringsExit = _menuStringsStarve = 0;
+ _menuStringsScribe = _menuStringsDrop2 = _menuStringsHead = _menuStringsPoison = 0;
+ _menuStringsMgc = _menuStringsPrefs = _menuStringsRest2 = _menuStringsRest3 = 0;
+ _menuStringsRest4 = _menuStringsDefeat = _menuStringsTransfer = _menuStringsSpec = 0;
+ _menuStringsSpellNo = _menuYesNoStrings = 0;
+ _errorSlotEmptyString = _errorSlotNoNameString = _menuOkString = 0;
+ _spellLevelsMage = _spellLevelsCleric = _numSpellsCleric = _numSpellsWisAdj = _numSpellsPal = _numSpellsMage = 0;
+ _mnNumWord = _numSpells = _mageSpellListSize = _spellLevelsMageSize = _spellLevelsClericSize = 0;
+ _inventorySlotsX = _slotValidationFlags = _encodeMonsterShpTable = 0;
+ _cgaMappingDefault = _cgaMappingAlt = _cgaMappingInv = _cgaLevelMappingIndex = _cgaMappingItemsL = _cgaMappingItemsS = _cgaMappingThrown = _cgaMappingIcons = _cgaMappingDeco = 0;
+ memset(_cgaMappingLevel, 0, sizeof(_cgaMappingLevel));
+ memset(_expRequirementTables, 0, sizeof(_expRequirementTables));
+ memset(_saveThrowTables, 0, sizeof(_saveThrowTables));
+ memset(_doorType, 0, sizeof(_doorType));
+ memset(_noDoorSwitch, 0, sizeof(_noDoorSwitch));
+ memset(_scriptTimers, 0, sizeof(_scriptTimers));
+ memset(_monsterBlockPosArray, 0, sizeof(_monsterBlockPosArray));
+ memset(_foundMonstersArray, 0, sizeof(_foundMonstersArray));
+
+#define DWM0 _dscWallMapping.push_back(0)
+#define DWM(x) _dscWallMapping.push_back(&_sceneDrawVar##x)
+ DWM0; DWM0; DWM(Down); DWM(Right);
+ DWM(Down); DWM(Right); DWM(Down); DWM0;
+ DWM(Down); DWM(Left); DWM(Down); DWM(Left);
+ DWM0; DWM0; DWM(Down); DWM(Right);
+ DWM(Down); DWM(Right); DWM(Down); DWM0;
+ DWM(Down); DWM(Left); DWM(Down); DWM(Left);
+ DWM(Down); DWM(Right); DWM(Down); DWM0;
+ DWM(Down); DWM(Left); DWM0; DWM(Right);
+ DWM(Down); DWM0; DWM0; DWM(Left);
+#undef DWM
+#undef DWM0
+}
+
+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[] _monsterFlashOverlay;
+ delete[] _monsterStoneOverlay;
+ 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;
+ _dscWallMapping.clear();
+
+ delete[] _spells;
+ delete[] _spellAnimBuffer;
+ delete[] _wallsOfForce;
+
+ delete _gui;
+ _gui = 0;
+ delete _screen;
+ _screen = 0;
+
+ delete[] _menuDefs;
+ _menuDefs = 0;
+
+ delete _inf;
+ _inf = 0;
+ delete _timer;
+ _timer = 0;
+ delete _debugger;
+ _debugger = 0;
+ delete _txt;
+ _txt = 0;
+}
+
+void EoBCoreEngine::initKeymap() {
+#ifdef ENABLE_KEYMAPPER
+ Common::Keymapper *const mapper = _eventMan->getKeymapper();
+
+ // Do not try to recreate same keymap over again
+ if (mapper->getKeymap(kKeymapName) != 0)
+ return;
+
+ Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
+
+ const Common::KeyActionEntry keyActionEntries[] = {
+ { Common::KeyState(Common::KEYCODE_UP), "MVF", _("Move Forward") },
+ { Common::KeyState(Common::KEYCODE_DOWN), "MVB", _("Move Back") },
+ { Common::KeyState(Common::KEYCODE_LEFT), "MVL", _("Move Left") },
+ { Common::KeyState(Common::KEYCODE_RIGHT), "MVR", _("Move Right") },
+ { Common::KeyState(Common::KEYCODE_HOME), "TL", _("Turn Left") },
+ { Common::KeyState(Common::KEYCODE_PAGEUP), "TR", _("Turn Right") },
+ { Common::KeyState(Common::KEYCODE_i), "INV", _("Open/Close Inventory") },
+ { Common::KeyState(Common::KEYCODE_p), "SCE", _("Switch Inventory/Character screen") },
+ { Common::KeyState(Common::KEYCODE_c), "CMP", _("Camp") },
+ { Common::KeyState(Common::KEYCODE_SPACE), "CSP", _("Cast Spell") },
+ // TODO: Spell cursor, but this needs more thought, since different
+ // game versions use different keycodes.
+ { Common::KeyState(Common::KEYCODE_1), "SL1", _("Spell Level 1") },
+ { Common::KeyState(Common::KEYCODE_2), "SL2", _("Spell Level 2") },
+ { Common::KeyState(Common::KEYCODE_3), "SL3", _("Spell Level 3") },
+ { Common::KeyState(Common::KEYCODE_4), "SL4", _("Spell Level 4") },
+ { Common::KeyState(Common::KEYCODE_5), "SL5", _("Spell Level 5") }
+ };
+
+ for (uint i = 0; i < ARRAYSIZE(keyActionEntries); ++i) {
+ Common::Action *const act = new Common::Action(engineKeyMap, keyActionEntries[i].id, keyActionEntries[i].description);
+ act->addKeyEvent(keyActionEntries[i].ks);
+ }
+
+ if (_flags.gameID == GI_EOB2) {
+ Common::Action *const act = new Common::Action(engineKeyMap, "SL6", _("Spell Level 6"));
+ act->addKeyEvent(Common::KeyState(Common::KEYCODE_6));
+ }
+
+ mapper->addGameKeymap(engineKeyMap);
+#endif
+}
+
+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;
+
+ if (ConfMan.hasKey("render_mode"))
+ _configRenderMode = Common::parseRenderMode(ConfMan.get("render_mode"));
+
+ _useHiResDithering = (_configRenderMode == Common::kRenderEGA && _flags.useHiRes);
+
+ _screen = new Screen_EoB(this, _system);
+ assert(_screen);
+ _screen->setResolution();
+
+ //MidiDriverType midiDriver = MidiDriver::detectDevice(MDT_PCSPK | MDT_ADLIB);
+ _sound = new SoundAdLibPC(this, _mixer);
+ assert(_sound);
+ _sound->init();
+
+ // Setup volume settings (and read in all ConfigManager settings)
+ syncSoundSettings();
+
+ _res = new Resource(this);
+ assert(_res);
+ _res->reset();
+
+ _staticres = new StaticResource(this);
+ assert(_staticres);
+ if (!_staticres->init())
+ error("_staticres->init() failed");
+
+ 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);
+ assert(_gui);
+ _txt = new TextDisplayer_rpg(this, _screen);
+ assert(_txt);
+ _inf = new EoBInfProcessor(this, _screen);
+ assert(_inf);
+ _debugger = new Debugger_EoB(this);
+ assert(_debugger);
+
+ _screen->loadFont(Screen::FID_6_FNT, "FONT6.FNT");
+ _screen->loadFont(Screen::FID_8_FNT, "FONT8.FNT");
+
+ if (_useHiResDithering) {
+ _vcnBlockWidth <<= 1;
+ _vcnBlockHeight <<= 1;
+ SWAP(_vcnFlip0, _vcnFlip1);
+ }
+
+ Common::Error err = KyraRpgEngine::init();
+ if (err.getCode() != Common::kNoError)
+ return err;
+
+ initButtonData();
+ initMenus();
+ 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[_numFlyingObjects];
+ _flyingObjectsPtr = _flyingObjects;
+ memset(_flyingObjects, 0, _numFlyingObjects * sizeof(EoBFlyingObject));
+
+ _spellAnimBuffer = new uint8[4096];
+ memset(_spellAnimBuffer, 0, 4096);
+
+ _wallsOfForce = new WallOfForce[5];
+ memset(_wallsOfForce, 0, 5 * sizeof(WallOfForce));
+
+ 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));
+
+ _monsterFlashOverlay = new uint8[16];
+ _monsterStoneOverlay = new uint8[16];
+ memset(_monsterFlashOverlay, (_configRenderMode == Common::kRenderCGA) ? 0xff : 0x0f, 16 * sizeof(uint8));
+ memset(_monsterStoneOverlay, 0x0d, 16 * sizeof(uint8));
+ _monsterFlashOverlay[0] = _monsterStoneOverlay[0] = 0;
+
+ // Prevent autosave on game startup
+ _lastAutosave = _system->getMillis();
+
+#ifdef ENABLE_KEYMAPPER
+ _eventMan->getKeymapper()->pushKeymap(kKeymapName, true);
+#endif
+
+ return Common::kNoError;
+}
+
+Common::Error EoBCoreEngine::go() {
+ _debugger->initialize();
+
+ _txt->removePageBreakFlag();
+
+ _screen->setFont(Screen::FID_8_FNT);
+
+ loadItemsAndDecorationsShapes();
+ _screen->setMouseCursor(0, 0, _itemIconShapes[0]);
+
+ // Import original save game files (especially the "Quick Start Party")
+ if (ConfMan.getBool("importOrigSaves")) {
+ importOriginalSaveFile(-1);
+ ConfMan.setBool("importOrigSaves", false);
+ ConfMan.flushToDisk();
+ }
+
+ loadItemDefs();
+ int action = 0;
+
+ for (bool repeatLoop = true; repeatLoop; repeatLoop ^= true) {
+ action = 0;
+
+ if (_gameToLoad != -1) {
+ if (loadGameState(_gameToLoad).getCode() != Common::kNoError)
+ error("Couldn't load game slot %d on startup", _gameToLoad);
+ startupLoad();
+ _gameToLoad = -1;
+ } else {
+ _screen->showMouse();
+ action = mainMenu();
+ }
+
+ if (action == -1) {
+ // load game
+ repeatLoop = _gui->runLoadMenu(72, 14);
+ if (repeatLoop && !shouldQuit())
+ startupLoad();
+ } else if (action == -2) {
+ // new game
+ repeatLoop = startCharacterGeneration();
+ if (repeatLoop && !shouldQuit())
+ startupNew();
+ } else if (action == -3) {
+ // transfer party
+ repeatLoop = startPartyTransfer();
+ if (repeatLoop && !shouldQuit())
+ startupNew();
+ }
+ }
+
+ if (!shouldQuit() && action >= -3) {
+ runLoop();
+
+ if (_playFinale) {
+ // make final save for party transfer
+ saveGameStateIntern(-1, 0, 0);
+ seq_playFinale();
+ }
+ }
+
+ return Common::kNoError;
+}
+
+void EoBCoreEngine::registerDefaultSettings() {
+ KyraEngine_v1::registerDefaultSettings();
+ ConfMan.registerDefault("hpbargraphs", true);
+ ConfMan.registerDefault("importOrigSaves", true);
+}
+
+void EoBCoreEngine::readSettings() {
+ _configHpBarGraphs = ConfMan.getBool("hpbargraphs");
+ _configSounds = ConfMan.getBool("sfx_mute") ? 0 : 1;
+ _configMusic = _configSounds ? 1 : 0;
+
+ if (_sound)
+ _sound->enableSFX(_configSounds);
+}
+
+void EoBCoreEngine::writeSettings() {
+ ConfMan.setBool("hpbargraphs", _configHpBarGraphs);
+ ConfMan.setBool("sfx_mute", _configSounds == 0);
+
+ if (_sound) {
+ if (!_configSounds)
+ _sound->beginFadeOut();
+ _sound->enableMusic(_configSounds ? 1 : 0);
+ _sound->enableSFX(_configSounds);
+ }
+
+ ConfMan.flushToDisk();
+}
+
+void EoBCoreEngine::startupNew() {
+ gui_setPlayFieldButtons();
+ _screen->_curPage = 0;
+ gui_drawPlayField(false);
+ _screen->_curPage = 0;
+ gui_drawAllCharPortraitsWithStats();
+ drawScene(1);
+ _updateFlags = 0;
+ _updateCharNum = 0;
+}
+
+void EoBCoreEngine::runLoop() {
+ _envAudioTimer = _system->getMillis() + (rollDice(1, 10, 3) * 18 * _tickLength);
+ _flashShapeTimer = 0;
+ _drawSceneTimer = _system->getMillis();
+
+ _screen->setFont(Screen::FID_6_FNT);
+ _screen->setScreenDim(7);
+
+ _runFlag = true;
+
+ while (!shouldQuit() && _runFlag) {
+ checkPartyStatus(true);
+ checkInput(_activeButtons, true, 0);
+ removeInputTop();
+
+ if (!_runFlag)
+ break;
+
+ _timer->update();
+ updateScriptTimers();
+ updateWallOfForceTimers();
+
+ if (_sceneUpdateRequired)
+ drawScene(1);
+
+ if (_envAudioTimer >= _system->getMillis() || (_flags.gameID == GI_EOB1 && (_currentLevel == 0 || _currentLevel > 3)))
+ continue;
+
+ _envAudioTimer = _system->getMillis() + (rollDice(1, 10, 3) * 18 * _tickLength);
+ snd_processEnvironmentalSoundEffect(_flags.gameID == GI_EOB1 ? 30 : (rollDice(1, 2, -1) ? 27 : 28), _currentBlock + rollDice(1, 12, -1));
+ updateEnvironmentalSfx(0);
+ turnUndeadAuto();
+ }
+}
+
+bool EoBCoreEngine::checkPartyStatus(bool handleDeath) {
+ int numChars = 0;
+ for (int i = 0; i < 6; i++)
+ numChars += testCharacter(i, 13);
+
+ if (numChars)
+ return false;
+
+ if (!handleDeath)
+ return true;
+
+ gui_drawAllCharPortraitsWithStats();
+
+ if (checkPartyStatusExtra()) {
+ _screen->setFont(Screen::FID_8_FNT);
+ gui_updateControls();
+ if (_gui->runLoadMenu(0, 0)) {
+ _screen->setFont(Screen::FID_6_FNT);
+ return true;
+ }
+ }
+
+ quitGame();
+ return false;
+}
+
+void EoBCoreEngine::loadItemsAndDecorationsShapes() {
+ releaseItemsAndDecorationsShapes();
+
+ _screen->loadShapeSetBitmap("ITEML1", 5, 3);
+ _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, false, _cgaMappingItemsL);
+
+ _screen->loadShapeSetBitmap("ITEMS1", 5, 3);
+ _smallItemShapes = new const uint8*[_numSmallItemShapes];
+ for (int i = 0; i < _numSmallItemShapes; i++)
+ _smallItemShapes[i] = _screen->encodeShape((i / div) << 2, (i % div) * mul, 4, 24, false, _cgaMappingItemsS);
+
+ _screen->loadShapeSetBitmap("THROWN", 5, 3);
+ _thrownItemShapes = new const uint8*[_numThrownItemShapes];
+ for (int i = 0; i < _numThrownItemShapes; i++)
+ _thrownItemShapes[i] = _screen->encodeShape((i / div) << 2, (i % div) * mul, 4, 24, false, _cgaMappingThrown);
+
+ _spellShapes = new const uint8*[4];
+ for (int i = 0; i < 4; i++)
+ _spellShapes[i] = _screen->encodeShape(8, i << 5, 6, 32, false, _cgaMappingThrown);
+
+ _firebeamShapes = new const uint8*[3];
+ _firebeamShapes[0] = _screen->encodeShape(16, 0, 4, 24, false, _cgaMappingThrown);
+ _firebeamShapes[1] = _screen->encodeShape(16, 24, 4, 24, false, _cgaMappingThrown);
+ _firebeamShapes[2] = _screen->encodeShape(16, 48, 3, 24, false, _cgaMappingThrown);
+ _redSplatShape = _screen->encodeShape(16, _flags.gameID == GI_EOB1 ? 144 : 72, 5, 24, false, _cgaMappingThrown);
+ _greenSplatShape = _screen->encodeShape(16, _flags.gameID == GI_EOB1 ? 168 : 96, 5, 16, false, _cgaMappingThrown);
+
+ _screen->loadShapeSetBitmap("ITEMICN", 5, 3);
+ _itemIconShapes = new const uint8*[_numItemIconShapes];
+ for (int i = 0; i < _numItemIconShapes; i++)
+ _itemIconShapes[i] = _screen->encodeShape((i % 0x14) << 1, (i / 0x14) << 4, 2, 0x10, false, _cgaMappingIcons);
+
+ _screen->loadShapeSetBitmap("DECORATE", 5, 3);
+
+ 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], false, _cgaMappingDefault);
+ _sparkShapes = new const uint8*[3];
+ _sparkShapes[0] = _screen->encodeShape(29, 0, 2, 16, false, _cgaMappingDeco);
+ _sparkShapes[1] = _screen->encodeShape(31, 0, 2, 16, false, _cgaMappingDeco);
+ _sparkShapes[2] = _screen->encodeShape(33, 0, 2, 16, false, _cgaMappingDeco);
+ _deadCharShape = _screen->encodeShape(0, 88, 4, 32, false, _cgaMappingDeco);
+ _disabledCharGrid = _screen->encodeShape(4, 88, 4, 32, false, _cgaMappingDeco);
+ _blackBoxSmallGrid = _screen->encodeShape(9, 88, 2, 8, false, _cgaMappingDeco);
+ _weaponSlotGrid = _screen->encodeShape(8, 88, 4, 16, false, _cgaMappingDeco);
+ _blackBoxWideGrid = _screen->encodeShape(8, 104, 4, 8, false, _cgaMappingDeco);
+
+ 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], false, _cgaMappingDeco);
+ }
+}
+
+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;
+ }
+
+ 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[] _redSplatShape;
+ delete[] _greenSplatShape;
+ 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];
+ const uint8 *ovl = 0;
+
+ if (icon && (_items[_itemInHand].flags & 0x80) && (_partyEffectFlags & 2))
+ ovl = _flags.gameID == GI_EOB1 ? ((_configRenderMode == Common::kRenderCGA) ? _itemsOverlayCGA : &_itemsOverlay[icon << 4]) : _screen->generateShapeOverlay(shp, 3);
+
+ int mouseOffs = itemIndex ? 8 : 0;
+ _screen->setMouseCursor(mouseOffs, mouseOffs, shp, ovl);
+}
+
+int EoBCoreEngine::getDexterityArmorClassModifier(int dexterity) {
+ static const int8 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 = getCharacterClassType(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];
+ // This also applies to EOB1 despite being coded differently there
+ if (res <= 2 || (_classModifierFlags[cclass] & 0x31))
+ return res;
+
+ return 2;
+}
+
+int EoBCoreEngine::getCharacterClassType(int cclass, int levelIndex) {
+ return _characterClassType[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;
+}
+
+Common::String EoBCoreEngine::getCharStrength(int str, int strExt) {
+ if (strExt) {
+ if (strExt == 100)
+ strExt = 0;
+ _strenghtStr = Common::String::format("%d/%02d", str, strExt);
+ } else {
+ _strenghtStr = Common::String::format("%d", str);
+ }
+
+ return _strenghtStr;
+}
+
+int EoBCoreEngine::testCharacter(int16 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 (getClericPaladinLevel(index) > 5)
+ m1 += ((getClericPaladinLevel(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::getClericPaladinLevel(int index) {
+ if (_castScrollSlot)
+ return 9;
+
+ if (index == -1)
+ return (_currentLevel < 7) ? 5 : 9;
+
+ int l = getCharacterLevelIndex(2, _characters[index].cClass);
+ if (l > -1)
+ return _characters[index].level[l];
+
+ l = getCharacterLevelIndex(4, _characters[index].cClass);
+ if (l > -1) {
+ if (_characters[index].level[l] > 8)
+ return _characters[index].level[l] - 8;
+ }
+
+ return 1;
+}
+
+int EoBCoreEngine::getMageLevel(int index) {
+ if (_castScrollSlot)
+ return 9;
+
+ if (index == -1)
+ return (_currentLevel < 7) ? 5 : 9;
+
+ int l = getCharacterLevelIndex(1, _characters[index].cClass);
+ return (l > -1) ? _characters[index].level[l] : 1;
+}
+
+int EoBCoreEngine::getCharacterLevelIndex(int type, int cClass) {
+ if (getCharacterClassType(cClass, 0) == type)
+ return 0;
+
+ if (getCharacterClassType(cClass, 1) == type)
+ return 1;
+
+ if (getCharacterClassType(cClass, 2) == type)
+ 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 (checkInventoryForItem(i, itemType, itemValue) != -1)
+ res++;
+ }
+ return res;
+}
+
+int EoBCoreEngine::checkInventoryForItem(int character, int16 itemType, int16 itemValue) {
+ if (character < 0)
+ return -1;
+
+ 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::npcSequence(int npcIndex) {
+ _screen->loadShapeSetBitmap("OUTTAKE", 5, 3);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 0, 6, Screen::CR_NO_P_CHECK);
+
+ drawNpcScene(npcIndex);
+
+ Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT");
+ _screen->loadFileDataToPage(s, 5, 32000);
+ delete s;
+
+ gui_drawBox(0, 121, 320, 79, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ _txt->setupField(9, true);
+ _txt->resetPageBreakString();
+
+ runNpcDialogue(npcIndex);
+
+ _txt->removePageBreakFlag();
+ gui_restorePlayField();
+}
+
+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->loadShapeSetBitmap(_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, _cgaMappingDefault);
+ _screen->_curPage = 0;
+}
+
+int EoBCoreEngine::npcJoinDialogue(int npcIndex, int queryJoinTextId, int confirmJoinTextId, int noJoinTextId) {
+ gui_drawDialogueBox();
+ _txt->printDialogueText(queryJoinTextId, 0);
+
+ int r = runDialogue(-1, 2, _yesNoStrings[0], _yesNoStrings[1]) - 1;
+ if (r == 0) {
+ if (confirmJoinTextId == -1) {
+ Common::String tmp = Common::String::format(_npcJoinStrings[0], _npcPreset[npcIndex].name);
+ _txt->printDialogueText(tmp.c_str(), 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) {
+ deletePartyItems(itemType, itemValue);
+ } else {
+ gui_drawDialogueBox();
+ _txt->printDialogueText(_npcMaxStrings[0]);
+ int r = runDialogue(-1, 7, _characters[0].name, _characters[1].name, _characters[2].name, _characters[3].name,
+ _characters[4].name, _characters[5].name, _abortStrings[0]) - 1;
+
+ if (r == 6)
+ return 0;
+
+ deletePartyItems(itemType, itemValue);
+ removeCharacterFromParty(r);
+ }
+
+ return 1;
+}
+
+void EoBCoreEngine::dropCharacter(int charIndex) {
+ if (!testCharacter(charIndex, 1))
+ return;
+
+ removeCharacterFromParty(charIndex);
+
+ if (charIndex < 5)
+ exchangeCharacters(charIndex, testCharacter(5, 1) ? 5 : 4);
+
+ gui_processCharPortraitClick(0);
+ gui_setPlayFieldButtons();
+ setupCharacterTimers();
+}
+
+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::exchangeCharacters(int charIndex1, int charIndex2) {
+ EoBCharacter temp;
+ memcpy(&temp, &_characters[charIndex1], sizeof(EoBCharacter));
+ memcpy(&_characters[charIndex1], &_characters[charIndex2], sizeof(EoBCharacter));
+ memcpy(&_characters[charIndex2], &temp, sizeof(EoBCharacter));
+}
+
+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 (getCharacterClassType(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 = getCharacterClassType(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, 1 << 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, va_list &args) {
+ _dialogueNumButtons = numStr;
+ _dialogueHighlightedButton = 0;
+
+ for (int i = 0; i < numStr; i++) {
+ const char *s = va_arg(args, const char *);
+ if (s)
+ _dialogueButtonString[i] = s;
+ 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() {
+ _npcSequenceSub = -1;
+ _txt->setWaitButtonMode(0);
+ _dialogueField = true;
+
+ _dialogueLastBitmap[0] = 0;
+
+ _txt->resetPageBreakString();
+ gui_updateControls();
+ //_allowSkip = true;
+
+ snd_stopSound();
+ 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();
+ //_allowSkip = false;
+ _screen->setScreenDim(7);
+
+ if (_flags.gameID == GI_EOB2)
+ snd_playSoundEffect(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->loadEoBBitmap("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->loadEoBBitmap(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 numStr, ...) {
+ if (dialogueTextId != -1)
+ txt()->printDialogueText(dialogueTextId, 0);
+
+ va_list args;
+ va_start(args, numStr);
+ if (numStr > 2)
+ setupDialogueButtons(2, numStr, args);
+ else
+ setupDialogueButtons(0, numStr, args);
+ va_end(args);
+
+ int res = 0;
+ while (res == 0 && !shouldQuit())
+ res = processDialogue();
+
+ gui_drawDialogueBox();
+
+ return res;
+}
+
+void EoBCoreEngine::restParty_displayWarning(const char *str) {
+ int od = _screen->curDimIndex();
+ _screen->setScreenDim(7);
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+ _screen->setCurPage(0);
+
+ _txt->printMessage(Common::String::format("\r%s\r", str).c_str());
+
+ _screen->setFont(of);
+ _screen->setScreenDim(od);
+}
+
+bool EoBCoreEngine::restParty_updateMonsters() {
+ bool sfxEnabled = _sound->sfxEnabled();
+ bool musicEnabled = _sound->musicEnabled();
+ _sound->enableSFX(false);
+ _sound->enableMusic(false);
+
+ for (int i = 0; i < 5; i++) {
+ _partyResting = true;
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+ int od = _screen->curDimIndex();
+ _screen->setScreenDim(7);
+ updateMonsters(0);
+ updateMonsters(1);
+ timerProcessFlyingObjects(0);
+ _screen->setScreenDim(od);
+ _screen->setFont(of);
+ _partyResting = false;
+
+ for (int ii = 0; ii < 30; ii++) {
+ if (_monsters[ii].mode == 8)
+ continue;
+ if (getBlockDistance(_currentBlock, _monsters[ii].block) >= 2)
+ continue;
+
+ restParty_displayWarning(_menuStringsRest4[0]);
+ _sound->enableSFX(sfxEnabled);
+ _sound->enableMusic(musicEnabled);
+ return true;
+ }
+ }
+
+ _sound->enableSFX(sfxEnabled);
+ _sound->enableMusic(musicEnabled);
+ return false;
+}
+
+int EoBCoreEngine::restParty_getCharacterWithLowestHp() {
+ int lhp = 900;
+ int res = -1;
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 3))
+ continue;
+ if (_characters[i].hitPointsCur >= _characters[i].hitPointsMax)
+ continue;
+ if (_characters[i].hitPointsCur < lhp) {
+ lhp = _characters[i].hitPointsCur;
+ res = i;
+ }
+ }
+
+ return res + 1;
+}
+
+bool EoBCoreEngine::restParty_checkHealSpells(int charIndex) {
+ static const uint8 eob1healSpells[] = { 2, 15, 20 };
+ static const uint8 eob2healSpells[] = { 3, 16, 20 };
+ const uint8 *spells = _flags.gameID == GI_EOB1 ? eob1healSpells : eob2healSpells;
+ const int8 *list = _characters[charIndex].clericSpells;
+
+ for (int i = 0; i < 80; i++) {
+ int s = list[i] < 0 ? -list[i] : list[i];
+ if (s == spells[0] || s == spells[1] || s == spells[2])
+ return true;
+ }
+
+ return false;
+}
+
+bool EoBCoreEngine::restParty_checkSpellsToLearn() {
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 0x43))
+ continue;
+
+ if ((getCharacterLevelIndex(2, _characters[i].cClass) != -1 || getCharacterLevelIndex(4, _characters[i].cClass) != -1) && (checkInventoryForItem(i, 30, -1) != -1)) {
+ for (int ii = 0; ii < 80; ii++) {
+ if (_characters[i].clericSpells[ii] < 0)
+ return true;
+ }
+ }
+
+ if ((getCharacterLevelIndex(1, _characters[i].cClass) != -1) && (checkInventoryForItem(i, 29, -1) != -1)) {
+ for (int ii = 0; ii < 80; ii++) {
+ if (_characters[i].mageSpells[ii] < 0)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool EoBCoreEngine::restParty_extraAbortCondition() {
+ return false;
+}
+
+void EoBCoreEngine::delay(uint32 millis, bool, bool) {
+ while (millis && !shouldQuit() && !(_allowSkip && 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, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ _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, false, 0) & 0xff)
+ break;
+ removeInputTop();
+ }
+ removeInputTop();
+ }
+
+ restoreAfterDialogueSequence();
+}
+
+int EoBCoreEngine::countResurrectionCandidates() {
+ _rrCount = 0;
+ memset(_rrNames, 0, 10 * sizeof(const char *));
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ if (_characters[i].hitPointsCur != -10)
+ continue;
+
+ _rrNames[_rrCount] = _characters[i].name;
+ _rrId[_rrCount++] = 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 ((_flags.gameID == GI_EOB1 && ((_itemTypes[_items[inv].type].extraProperties & 0x7f) != 8)) || (_flags.gameID == GI_EOB2 && _items[inv].type != 33))
+ continue;
+
+ _rrNames[_rrCount] = _npcPreset[_items[inv].value - 1].name;
+ _rrId[_rrCount++] = -_items[inv].value;
+ }
+ }
+
+ if (_itemInHand > 0) {
+ if ((_flags.gameID == GI_EOB1 && ((_itemTypes[_items[_itemInHand].type].extraProperties & 0x7f) == 8)) || (_flags.gameID == GI_EOB2 && _items[_itemInHand].type == 33)) {
+ _rrNames[_rrCount] = _npcPreset[_items[_itemInHand].value - 1].name;
+ _rrId[_rrCount++] = -_items[_itemInHand].value;
+ }
+ }
+
+ return _rrCount;
+}
+
+void EoBCoreEngine::seq_portal() {
+ uint8 *shapes1[5];
+ uint8 *shapes2[5];
+ uint8 *shapes3[5];
+ uint8 *shape0;
+
+ _screen->loadShapeSetBitmap("PORTALA", 5, 3);
+
+ for (int i = 0; i < 5; i++) {
+ shapes1[i] = _screen->encodeShape(i * 3, 0, 3, 75, false, _cgaMappingDefault);
+ shapes2[i] = _screen->encodeShape(i * 3, 80, 3, 75, false, _cgaMappingDefault);
+ shapes3[i] = _screen->encodeShape(15, i * 18, 15, 18, false, _cgaMappingDefault);
+ }
+
+ shape0 = _screen->encodeShape(30, 0, 8, 77, false, _cgaMappingDefault);
+ _screen->loadEoBBitmap("PORTALB", _cgaMappingDefault, 5, 3, 2);
+
+ snd_playSoundEffect(33);
+ snd_playSoundEffect(19);
+ _screen->copyRegion(24, 0, 24, 0, 144, 104, 2, 5, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(24, 0, 24, 0, 144, 104, 0, 2, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(2, shapes3[0], 28, 9, 0);
+ _screen->drawShape(2, shapes1[0], 34, 28, 0);
+ _screen->drawShape(2, shapes2[0], 120, 28, 0);
+ _screen->drawShape(2, shape0, 56, 27, 0);
+ _screen->crossFadeRegion(24, 0, 24, 0, 144, 104, 2, 0);
+ _screen->copyRegion(24, 0, 24, 0, 144, 104, 5, 2, Screen::CR_NO_P_CHECK);
+ delay(30 * _tickLength);
+
+ for (const int8 *pos = _portalSeq; *pos > -1 && !shouldQuit();) {
+ int s = *pos++;
+ _screen->drawShape(0, shapes3[s], 28, 9, 0);
+ _screen->drawShape(0, shapes1[s], 34, 28, 0);
+ _screen->drawShape(0, shapes2[s], 120, 28, 0);
+
+ if ((s == 1) && (pos >= _portalSeq + 3)) {
+ if (*(pos - 3) == 0) {
+ snd_playSoundEffect(24);
+ snd_playSoundEffect(86);
+ }
+ }
+
+ s = *pos++;
+ if (s == 0) {
+ _screen->drawShape(0, shape0, 56, 27, 0);
+ } else {
+ s--;
+ _screen->copyRegion((s % 5) << 6, s / 5 * 77, 56, 27, 64, 77, 2, 0, Screen::CR_NO_P_CHECK);
+ }
+
+ if (s == 1)
+ snd_playSoundEffect(31);
+ else if (s == 3) {
+ if (*(pos - 2) == 3)
+ snd_playSoundEffect(90);
+ }
+
+ _screen->updateScreen();
+ delay(2 * _tickLength);
+ }
+
+ delete[] shape0;
+ for (int i = 0; i < 5; i++) {
+ delete[] shapes1[i];
+ delete[] shapes2[i];
+ delete[] shapes3[i];
+ }
+}
+
+bool EoBCoreEngine::checkPassword() {
+ char answ[20];
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+ _screen->copyPage(0, _useHiResDithering ? 4 : 10);
+
+ _screen->setScreenDim(13);
+ gui_drawBox(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, guiSettings()->colors.frame1, guiSettings()->colors.frame2, -1);
+ gui_drawBox((_screen->_curDim->sx << 3) + 1, _screen->_curDim->sy + 1, (_screen->_curDim->w << 3) - 2, _screen->_curDim->h - 2, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ _screen->modifyScreenDim(13, _screen->_curDim->sx + 1, _screen->_curDim->sy + 2, _screen->_curDim->w - 2, _screen->_curDim->h - 16);
+
+ for (int i = 0; i < 3; i++) {
+ _screen->fillRect(_screen->_curDim->sx << 3, _screen->_curDim->sy, ((_screen->_curDim->sx + _screen->_curDim->w) << 3) - 1, (_screen->_curDim->sy + _screen->_curDim->h) - 1, guiSettings()->colors.fill);
+ int c = rollDice(1, _mnNumWord - 1, -1);
+ const uint8 *shp = (_mnDef[c << 2] < _numLargeItemShapes) ? _largeItemShapes[_mnDef[c << 2]] : (_mnDef[c << 2] < 15 ? 0 : _smallItemShapes[_mnDef[c << 2] - 15]);
+ assert(shp);
+ _screen->drawShape(0, shp, 100, 2, 13);
+ _screen->printShadedText(Common::String::format(_mnPrompt[0], _mnDef[(c << 2) + 1], _mnDef[(c << 2) + 2]).c_str(), (_screen->_curDim->sx + 1) << 3, _screen->_curDim->sy, _screen->_curDim->unk8, guiSettings()->colors.fill);
+ memset(answ, 0, 20);
+ gui_drawBox(76, 100, 133, 14, guiSettings()->colors.frame2, guiSettings()->colors.frame1, -1);
+ gui_drawBox(77, 101, 131, 12, guiSettings()->colors.frame2, guiSettings()->colors.frame1, -1);
+ if (_gui->getTextInput(answ, 10, 103, 15, _screen->_curDim->unk8, guiSettings()->colors.fill, 8) < 0)
+ i = 3;
+ if (!scumm_stricmp(_mnWord[c], answ))
+ break;
+ else if (i == 2)
+ return false;
+ }
+
+ _screen->modifyScreenDim(13, _screen->_curDim->sx - 1, _screen->_curDim->sy - 2, _screen->_curDim->w + 2, _screen->_curDim->h + 16);
+ _screen->setFont(of);
+ _screen->copyPage(_useHiResDithering ? 4 : 10, 0);
+ return true;
+}
+
+void EoBCoreEngine::useSlotWeapon(int charIndex, int slotIndex, Item 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 = projectileWeaponAttack(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, Item item) {
+ if (charIndex > 1)
+ return -3;
+
+ uint16 d = calcNewBlockPosition(_currentBlock, _currentDirection);
+ int r = getClosestMonster(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 (isMagicEffectItem(item))
+ flg |= 1;
+
+ _dstMonsterIndex = r;
+ return calcMonsterDamage(&_monsters[r], charIndex, item, 1, flg, 5, 3);
+ }
+
+ return 0;
+}
+
+int EoBCoreEngine::thrownAttack(int charIndex, int slotIndex, Item 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::projectileWeaponAttack(int charIndex, Item item) {
+ int tp = _items[item].type;
+
+ if (_flags.gameID == GI_EOB1)
+ assert(tp >= 7);
+
+ int t = _projectileWeaponAmmoTypes[_flags.gameID == GI_EOB1 ? tp - 7 : tp];
+ Item ammoItem = 0;
+
+ if (t == 16) {
+ if (_characters[charIndex].inventory[0] && _items[_characters[charIndex].inventory[0]].type == 16)
+ SWAP(ammoItem, _characters[charIndex].inventory[0]);
+ else if (_characters[charIndex].inventory[1] && _items[_characters[charIndex].inventory[1]].type == 16)
+ SWAP(ammoItem, _characters[charIndex].inventory[1]);
+ else if (_characters[charIndex].inventory[16])
+ ammoItem = getQueuedItem(&_characters[charIndex].inventory[16], 0, -1);
+
+ } else {
+ for (int i = 0; i < 27; i++) {
+ if (_items[_characters[charIndex].inventory[i]].type == t) {
+ SWAP(ammoItem, _characters[charIndex].inventory[i]);
+ if (i < 2)
+ gui_drawCharPortraitWithStats(charIndex);
+ break;
+ }
+ }
+ }
+
+ if (!ammoItem)
+ return -4;
+
+ int c = charIndex;
+ if (c > 3)
+ c -= 2;
+
+ if (launchObject(charIndex, ammoItem, _currentBlock, _dropItemDirIndex[(_currentDirection << 2) + c], _currentDirection, tp)) {
+ snd_playSoundEffect(tp == 7 ? 26 : 11);
+ _sceneUpdateRequired = true;
+ }
+
+ return 0;
+}
+
+void EoBCoreEngine::inflictMonsterDamage(EoBMonsterInPlay *m, int damage, bool giveExperience) {
+ m->hitPointsCur -= damage;
+ m->flags = (m->flags & 0xf7) | 1;
+
+ if (_monsterProps[m->type].capsFlags & 0x2000) {
+ explodeMonster(m);
+ checkSceneUpdateNeed(m->block);
+ m->hitPointsCur = 0;
+ } else {
+ if (checkSceneUpdateNeed(m->block)) {
+ m->flags |= 2;
+ if (_preventMonsterFlash)
+ 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 savingThrowType, int savingThrowEffect) {
+ int dmg = calcMonsterDamage(m, times, pips, offs, flags, savingThrowType, savingThrowEffect);
+ if (dmg > 0)
+ inflictMonsterDamage(m, dmg, flags & 0x800 ? true : false);
+}
+
+void EoBCoreEngine::calcAndInflictCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flags, int savingThrowType, int savingThrowEffect) {
+ int dmg = calcCharacterDamage(charIndex, times, itemOrPips, useStrModifierOrBase, flags, savingThrowType, savingThrowEffect);
+ if (dmg)
+ inflictCharacterDamage(charIndex, dmg);
+}
+
+int EoBCoreEngine::calcCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flags, int savingThrowType, int savingThrowEffect) {
+ int s = (flags & 0x100) ? calcDamageModifers(times, 0, itemOrPips, _items[itemOrPips].type, useStrModifierOrBase) : rollDice(times, itemOrPips, useStrModifierOrBase);
+ EoBCharacter *c = &_characters[charIndex];
+
+ if (savingThrowType != 5) {
+ if (trySavingThrow(c, _charClassModifier[c->cClass], c->level[0], savingThrowType, c->raceSex >> 1 /*fix bug in original code by adding a right shift*/))
+ s = savingThrowReduceDamage(savingThrowEffect, s);
+ }
+
+ if ((flags & 0x110) == 0x110) {
+ if (!calcDamageCheckItemType(_items[itemOrPips].type))
+ s = 1;
+ }
+
+ if (flags & 4) {
+ if (checkInventoryForRings(charIndex, 3))
+ s = 0;
+ }
+
+ if (flags & 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].immunityFlags & 0x200) && (d <= 0)) || ((_monsterProps[t].immunityFlags & 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;
+}
+
+bool EoBCoreEngine::monsterAttackHitTest(EoBMonsterInPlay *m, int charIndex) {
+ int tp = m->type;
+ EoBMonsterProperty *p = &_monsterProps[tp];
+
+ int r = rollDice(1, 20);
+ if (r != 20) {
+ // Prot from evil
+ if (_characters[charIndex].effectFlags & 0x800)
+ r -= 2;
+ // blur
+ if (_characters[charIndex].effectFlags & 0x10)
+ r -= 2;
+ // prayer
+ 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 (_characters[c].effectsRemainder[1]) {
+ if (--_characters[c].effectsRemainder[1])
+ dmg = 0;
+ }
+ }
+
+ if (dmg > 0) {
+ if ((_monsterProps[m->type].capsFlags & 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(_ripItemStrings[(_characters[c].raceSex & 1) ^ 1], -1, _characters[c].name);
+ printFullItemName(itm);
+ _txt->printMessage(_ripItemStrings[2]);
+ break;
+ }
+ gui_drawCharPortraitWithStats(c);
+ }
+
+ inflictCharacterDamage(c, dmg);
+
+ if (_monsterProps[m->type].capsFlags & 0x10) {
+ statusAttack(c, 2, _monsterSpecAttStrings[_flags.gameID == GI_EOB1 ? 3 : 2], 0, 1, 8, 1);
+ _characters[c].effectFlags &= ~0x2000;
+ }
+
+ if (_monsterProps[m->type].capsFlags & 0x20)
+ statusAttack(c, 4, _monsterSpecAttStrings[_flags.gameID == GI_EOB1 ? 4 : 3], 2, 5, 9, 1);
+
+ if (_monsterProps[m->type].capsFlags & 0x8000)
+ statusAttack(c, 8, _monsterSpecAttStrings[4], 2, 0, 0, 1);
+
+ }
+
+ if (!(_monsterProps[m->type].capsFlags & 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 savingThrowType, uint32 effectDuration, int restoreEvent, int noRefresh) {
+ EoBCharacter *c = &_characters[charIndex];
+ if ((c->flags & attackStatusFlags) && noRefresh)
+ return;
+ if (!testCharacter(charIndex, 3))
+ return;
+
+ if (savingThrowType != 5 && specialAttackSavingThrow(charIndex, savingThrowType))
+ 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::calcMonsterDamage(EoBMonsterInPlay *m, int times, int pips, int offs, int flags, int savingThrowType, int savingThrowEffect) {
+ int s = flags & 0x100 ? calcDamageModifers(times, m, pips, _items[pips].type, offs) : rollDice(times, pips, offs);
+ EoBMonsterProperty *p = &_monsterProps[m->type];
+
+ if (savingThrowType != 5) {
+ if (trySavingThrow(m, 0, p->level, savingThrowType, 6))
+ s = savingThrowReduceDamage(savingThrowEffect, s);
+ }
+
+ if ((flags & 0x110) == 0x110) {
+ if (!calcDamageCheckItemType(_items[pips].type))
+ s = 1;
+ }
+
+ if ((flags & 0x100) && (!(_itemTypes[_items[pips].type].allowedClasses & 4 /* bug in original code ??*/))
+ && ((_flags.gameID == GI_EOB2 && (p->immunityFlags & 0x100)) || (_flags.gameID == GI_EOB1 && (p->capsFlags & 4))))
+ s >>= 1;
+
+ if (p->immunityFlags & 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 (tryMonsterAttackEvasion(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->immunityFlags & 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].capsFlags & 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::trySavingThrow(void *target, int hpModifier, int level, int type, 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 (type == 5)
+ return false;
+
+ int s = getSaveThrowModifier(hpModifier, level, type);
+ if (((race == 3 || race == 5) && (type == 4 || type == 1 || type == 0)) || (race == 4 && (type == 4 || type == 1))) {
+ EoBCharacter *c = (EoBCharacter *)target;
+ s -= constMod[c->constitutionCur];
+ }
+
+ return rollDice(1, 20) >= s;
+}
+
+bool EoBCoreEngine::specialAttackSavingThrow(int charIndex, int type) {
+ return trySavingThrow(&_characters[charIndex], _charClassModifier[_characters[charIndex].cClass], _characters[charIndex].level[0], type, _characters[charIndex].raceSex >> 1);
+}
+
+int EoBCoreEngine::getSaveThrowModifier(int hpModifier, int level, int type) {
+ const uint8 *tbl = _saveThrowTables[hpModifier];
+ if (_saveThrowLevelIndex[hpModifier] < level)
+ level = _saveThrowLevelIndex[hpModifier];
+ level /= _saveThrowModDiv[hpModifier];
+ level += (_saveThrowModExt[hpModifier] * type);
+
+ return tbl[level];
+}
+
+bool EoBCoreEngine::calcDamageCheckItemType(int itemType) {
+ itemType = _itemTypes[itemType].extraProperties & 0x7f;
+ return (itemType == 2 || itemType == 3) ? true : false;
+}
+
+int EoBCoreEngine::savingThrowReduceDamage(int savingThrowEffect, int damage) {
+ if (savingThrowEffect == 3)
+ return 0;
+
+ if (savingThrowEffect == 0 || savingThrowEffect == 1)
+ return damage >> 1;
+
+ return damage;
+}
+
+bool EoBCoreEngine::tryMonsterAttackEvasion(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 = _charClassModifier[_characters[charIndex].cClass];
+
+ return (20 - ((l / mod1[cm]) * mod2[cm])) - monsterAc;
+}
+
+void EoBCoreEngine::explodeMonster(EoBMonsterInPlay *m) {
+ m->flags |= 2;
+ if (getBlockDistance(m->block, _currentBlock) < 2) {
+ explodeObject(0, _currentBlock, 2);
+ for (int i = 0; i < 6; i++)
+ calcAndInflictCharacterDamage(i, 6, 6, 0, 8, 1, 0);
+ } else {
+ explodeObject(0, m->block, 2);
+ }
+ m->flags &= ~2;
+}
+
+void EoBCoreEngine::snd_playSong(int track) {
+ _sound->playTrack(track);
+}
+
+void EoBCoreEngine::snd_playSoundEffect(int track, int volume) {
+ if ((track < 1) || (_flags.gameID == GI_EOB2 && track > 119) || shouldQuit())
+ return;
+
+ _sound->playSoundEffect(track, volume);
+}
+
+void EoBCoreEngine::snd_stopSound() {
+ _sound->haltTrack();
+ _sound->stopAllSoundEffects();
+}
+
+void EoBCoreEngine::snd_fadeOut() {
+ _sound->beginFadeOut();
+}
+
+} // 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..050fe2b794
--- /dev/null
+++ b/engines/kyra/eobcommon.h
@@ -0,0 +1,1164 @@
+/* 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/kyra_rpg.h"
+#endif // (ENABLE_EOB || ENABLE_LOL)
+
+#ifdef ENABLE_EOB
+
+namespace Kyra {
+
+struct DarkMoonShapeDef {
+ 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 EoBChargenButtonDef {
+ uint8 x;
+ uint8 y;
+ uint8 w;
+ uint8 h;
+ uint8 keyCode;
+};
+
+struct EoBGuiButtonDef {
+ uint16 keyCode;
+ uint16 keyCode2;
+ uint16 flags;
+ uint16 x;
+ uint8 y;
+ uint16 w;
+ uint8 h;
+ 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 mageSpellsAvailableFlags;
+
+ 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;
+ int16 x;
+ int16 y;
+};
+
+struct EoBMonsterProperty {
+ int8 armorClass;
+ int8 hitChance;
+ int8 level;
+ uint8 hpDcTimes;
+ uint8 hpDcPips;
+ uint8 hpDcBase;
+ uint8 attacksPerRound;
+ struct DmgDc {
+ uint8 times;
+ uint8 pips;
+ int8 base;
+ } dmgDc[3];
+ uint16 immunityFlags;
+ uint32 capsFlags;
+ uint32 typeFlags;
+ int32 experience;
+
+ uint8 u30;
+ int8 sound1;
+ int8 sound2;
+ uint8 numRemoteAttacks;
+ uint8 remoteWeaponChangeMode;
+ uint8 numRemoteWeapons;
+
+ int8 remoteWeapons[5];
+
+ int8 tuResist;
+ 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;
+ int8 spellStatusLeft;
+ 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 EoBMenuDef {
+ int8 titleStrId;
+ uint8 dim;
+ uint8 firstButtonStrId;
+ int8 numButtons;
+ int8 titleCol;
+};
+struct EoBMenuButtonDef {
+ int8 labelId;
+ int16 x;
+ int8 y;
+ uint8 width;
+ uint8 height;
+ int16 keyCode;
+ int16 flags;
+};
+
+class EoBInfProcessor;
+
+class EoBCoreEngine : public KyraRpgEngine {
+friend class TextDisplayer_rpg;
+friend class GUI_EoB;
+friend class Debugger_EoB;
+friend class EoBInfProcessor;
+friend class DarkmoonSequenceHelper;
+friend class CharacterGenerator;
+friend class TransferPartyWiz;
+public:
+ EoBCoreEngine(OSystem *system, const GameFlags &flags);
+ virtual ~EoBCoreEngine();
+
+ virtual void initKeymap();
+
+ 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_xdeath() {};
+ virtual void seq_playFinale() = 0;
+ bool _playFinale;
+
+ //Init, config
+ void loadItemsAndDecorationsShapes();
+ void releaseItemsAndDecorationsShapes();
+
+ void initButtonData();
+ void initMenus();
+ void initStaticResource();
+ virtual void initSpells();
+
+ void registerDefaultSettings();
+ void readSettings();
+ void writeSettings();
+
+ 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 *_itemsOverlay;
+ static const uint8 _itemsOverlayCGA[];
+
+ static const uint8 _teleporterShapeDefs[];
+ static const uint8 _wallOfForceShapeDefs[];
+
+ const char *const *_mainMenuStrings;
+
+ // Main loop
+ virtual void startupNew();
+ virtual void startupLoad() = 0;
+ void runLoop();
+ void update() { screen()->updateScreen(); }
+ bool checkPartyStatus(bool handleDeath);
+
+ bool _runFlag;
+
+ // Character generation / party transfer
+ bool startCharacterGeneration();
+ bool startPartyTransfer();
+
+ uint8 **_faceShapes;
+
+ static const int8 _characterClassType[];
+ static const uint8 _hpIncrPerLevel[];
+ static const uint8 _numLevelsPerClass[];
+ static const int16 _hpConstModifiers[];
+ static const uint8 _charClassModifier[];
+
+ 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 advanceTimers(uint32 millis);
+
+ 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;
+
+ int32 _restPartyElapsedTime;
+
+ // Mouse
+ void setHandItem(Item itemIndex);
+
+ // Characters
+ int getDexterityArmorClassModifier(int dexterity);
+ int generateCharacterHitpointsByLevel(int charIndex, int levelIndex);
+ int getClassAndConstHitpointsModifier(int cclass, int constitution);
+ int getCharacterClassType(int cclass, int levelIndex);
+ int getModifiedHpLimits(int hpModifier, int constModifier, int level, bool mode);
+ Common::String getCharStrength(int str, int strExt);
+ int testCharacter(int16 index, int flags);
+ int getNextValidCharIndex(int curCharIndex, int searchStep);
+
+ void recalcArmorClass(int index);
+ int validateWeaponSlotItem(int index, int slot);
+
+ int getClericPaladinLevel(int index);
+ int getMageLevel(int index);
+ int getCharacterLevelIndex(int type, int cClass);
+
+ int countCharactersWithSpecificItems(int16 itemType, int16 itemValue);
+ int checkInventoryForItem(int character, int16 itemType, int16 itemValue);
+ void modifyCharacterHitpoints(int character, int16 points);
+ void neutralizePoison(int character);
+
+ void npcSequence(int npcIndex);
+ virtual void drawNpcScene(int npcIndex) = 0;
+ virtual void runNpcDialogue(int npcIndex) = 0;
+ void initNpc(int npcIndex);
+ int npcJoinDialogue(int npcIndex, int queryJoinTextId, int confirmJoinTextId, int noJoinTextId);
+ int prepareForNewPartyMember(int16 itemType, int16 itemValue);
+ void dropCharacter(int charIndex);
+ void removeCharacterFromParty(int charIndex);
+ void exchangeCharacters(int charIndex1, int charIndex2);
+
+ 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;
+ Common::String _strenghtStr;
+ int _castScrollSlot;
+ int _exchangeCharacterId;
+
+ const char *const *_levelGainStrings;
+ const uint32 *_expRequirementTables[6];
+
+ const uint8 *_saveThrowTables[6];
+ const uint8 *_saveThrowLevelIndex;
+ const uint8 *_saveThrowModDiv;
+ const uint8 *_saveThrowModExt;
+
+ const EoBCharacter *_npcPreset;
+ int _npcSequenceSub;
+ bool _partyResting;
+ bool _loading;
+
+ // Items
+ void loadItemDefs();
+ Item duplicateItem(Item itemIndex);
+ void setItemPosition(Item *itemQueue, int block, Item item, int pos);
+ Item createItemOnCurrentBlock(Item itemIndex);
+ void createInventoryItem(EoBCharacter *c, Item itemIndex, int16 itemValue, int preferedInventorySlot);
+ int deleteInventoryItem(int charIndex, int slot);
+ void deleteBlockItem(uint16 block, int type);
+ int validateInventorySlotForItem(Item item, int charIndex, int slot);
+ int stripPartyItems(int16 itemType, int16 itemValue, int handleValueMode, int numItems);
+ bool deletePartyItems(int16 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 isMagicEffectItem(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 explodeObject(EoBFlyingObject *fo, int block, Item item);
+ 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;
+ const int8 *_projectileWeaponAmmoTypes;
+ const uint8 *_wandTypes;
+
+ EoBFlyingObject *_flyingObjects;
+ const uint8 *_drawObjPosIndex;
+ const uint8 *_flightObjFlipIndex;
+ const int8 *_flightObjShpMap;
+ const int8 *_flightObjSclIndex;
+
+ const uint8 *_expObjectTlMode;
+ const uint8 *_expObjectTblIndex;
+ const uint8 *_expObjectShpStart;
+ const uint8 *_expObjectAnimTbl1;
+ int _expObjectAnimTbl1Size;
+ const uint8 *_expObjectAnimTbl2;
+ int _expObjectAnimTbl2Size;
+ const uint8 *_expObjectAnimTbl3;
+ int _expObjectAnimTbl3Size;
+
+ // 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);
+ virtual bool killMonsterExtra(EoBMonsterInPlay *m);
+ int countSpecificMonsters(int type);
+ void updateAttackingMonsterFlags();
+
+ const int8 *getMonstersOnBlockPositions(uint16 block);
+ int getClosestMonster(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 updateMonsterAttackMode(EoBMonsterInPlay *m);
+ void updateAllMonsterDests();
+ 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 updateMonstersSpellStatus(EoBMonsterInPlay *m);
+ void setBlockMonsterDirection(int block, int dir);
+
+ uint8 *_monsterFlashOverlay;
+ uint8 *_monsterStoneOverlay;
+
+ 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 *_enemyMageSpellList;
+ const uint8 *_enemyMageSfx;
+ const uint8 *_beholderSpellList;
+ const uint8 *_beholderSfx;
+ const char *const *_monsterSpecAttStrings;
+
+ const int8 *_monsterFrmOffsTable1;
+ const int8 *_monsterFrmOffsTable2;
+
+ const uint16 *_encodeMonsterShpTable;
+ const uint8 _teleporterWallId;
+
+ const int16 *_wallOfForceDsX;
+ const uint8 *_wallOfForceDsY;
+ const uint8 *_wallOfForceDsNumW;
+ const uint8 *_wallOfForceDsNumH;
+ const uint8 *_wallOfForceShpId;
+
+ const int8 *_monsterDirChangeTable;
+
+ // Level
+ void loadLevel(int level, int sub);
+ void readLevelFileData(int level);
+ Common::String initLevelData(int sub);
+ void addLevelItems();
+ void loadVcnData(const char *file, const uint8 *cgaMapping);
+ void loadBlockProperties(const char *mazFile);
+ const uint8 *getBlockFileData(int levelIndex = 0);
+ Common::String getBlockFileName(int levelIndex, int sub);
+ const uint8 *getBlockFileData(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) = 0;
+ virtual const uint8 *loadDoorShapes(const char *filename, int doorIndex, const uint8 *shapeDefs) = 0;
+
+ void drawScene(int refresh);
+ void drawSceneShapes(int start = 0);
+ 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;
+ Common::String _curGfxFile;
+ Common::String _curBlockFile;
+
+ uint32 _drawSceneTimer;
+ uint32 _flashShapeTimer;
+ uint32 _envAudioTimer;
+ uint16 _teleporterPulse;
+
+ Common::Array<const int16 *> _dscWallMapping;
+ 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 *_dscDoorXE;
+
+ const uint8 *_wllFlagPreset;
+ int _wllFlagPresetSize;
+ const uint8 *_teleporterShapeCoords;
+ const int8 *_portalSeq;
+
+ // Script
+ void runLevelScript(int block, int flags);
+ void setScriptFlags(uint32 flags);
+ void clearScriptFlags(uint32 flags);
+ bool checkScriptFlags(uint32 flags);
+
+ const uint8 *initScriptTimers(const uint8 *pos);
+ void updateScriptTimers();
+ virtual void updateScriptTimersExtra() {}
+
+ EoBInfProcessor *_inf;
+ int _stepCounter;
+ int _stepsUntilScriptCall;
+ ScriptTimer _scriptTimers[5];
+ int _scriptTimersCount;
+ uint8 _scriptTimersMode;
+
+ // Gui
+ void gui_drawPlayField(bool refresh);
+ 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 _configHpBarGraphs;
+
+ // text
+ void setupDialogueButtons(int presetfirst, int numStr, va_list &args);
+ void initDialogueSequence();
+ void restoreAfterDialogueSequence();
+ void drawSequenceBitmap(const char *file, int destRect, int x1, int y1, int flags);
+ int runDialogue(int dialogueTextId, int numStr, ...);
+
+ char _dialogueLastBitmap[13];
+ int _moveCounter;
+
+ 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 *_ripItemStrings;
+ const char *const *_cursedString;
+ const char *const *_enchantedString;
+ const char *const *_magicObjectStrings;
+ const char *const *_magicObjectString5;
+ const char *const *_patternSuffix;
+ const char *const *_patternGrFix1;
+ const char *const *_patternGrFix2;
+ const char *const *_validateArmorString;
+ const char *const *_validateCursedString;
+ const char *const *_validateNoDropString;
+ const char *const *_potionStrings;
+ const char *const *_wandStrings;
+ const char *const *_itemMisuseStrings;
+
+ const char *const *_suffixStringsRings;
+ const char *const *_suffixStringsPotions;
+ const char *const *_suffixStringsWands;
+
+ 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;
+
+ // Rest party
+ void restParty_displayWarning(const char *str);
+ bool restParty_updateMonsters();
+ int restParty_getCharacterWithLowestHp();
+ bool restParty_checkHealSpells(int charIndex);
+ bool restParty_checkSpellsToLearn();
+ virtual void restParty_npc() {}
+ virtual bool restParty_extraAbortCondition();
+
+ // misc
+ void delay(uint32 millis, bool doUpdate = false, bool isMainLoop = false);
+
+ void displayParchment(int id);
+ int countResurrectionCandidates();
+
+ void seq_portal();
+ bool checkPassword();
+
+ virtual int resurrectionSelectDialogue() = 0;
+ virtual void useHorn(int charIndex, int weaponSlot) {}
+ virtual bool checkPartyStatusExtra() = 0;
+ virtual void drawLightningColumn() {}
+ 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);
+
+ const uint8 *_cgaMappingDefault;
+ const uint8 *_cgaMappingAlt;
+ const uint8 *_cgaMappingInv;
+ const uint8 *_cgaMappingItemsL;
+ const uint8 *_cgaMappingItemsS;
+ const uint8 *_cgaMappingThrown;
+ const uint8 *_cgaMappingIcons;
+ const uint8 *_cgaMappingDeco;
+ const uint8 *_cgaMappingLevel[5];
+ const uint8 *_cgaLevelMappingIndex;
+
+ bool _useHiResDithering;
+
+ // Default parameters will import all present original save files and push them to the top of the save dialog.
+ bool importOriginalSaveFile(int destSlot, const char *sourceFile = 0);
+ Common::String readOriginalSaveFile(Common::String &file);
+
+ void *generateMonsterTempData(LevelTempData *tmp);
+ void restoreMonsterTempData(LevelTempData *tmp);
+ void releaseMonsterTempData(LevelTempData *tmp);
+ void *generateWallOfForceTempData(LevelTempData *tmp);
+ void restoreWallOfForceTempData(LevelTempData *tmp);
+ void releaseWallOfForceTempData(LevelTempData *tmp);
+
+ const char * const *_saveLoadStrings;
+
+ const uint8 *_mnDef;
+ const char * const *_mnWord;
+ const char * const *_mnPrompt;
+ int _mnNumWord;
+
+ int _rrCount;
+ const char *_rrNames[10];
+ int8 _rrId[10];
+
+ bool _allowSkip;
+ bool _allowImport;
+
+ Screen_EoB *_screen;
+ GUI_EoB *_gui;
+
+ // fight
+ void useSlotWeapon(int charIndex, int slotIndex, Item item);
+ int closeDistanceAttack(int charIndex, Item item);
+ int thrownAttack(int charIndex, int slotIndex, Item item);
+ int projectileWeaponAttack(int charIndex, Item item);
+
+ void inflictMonsterDamage(EoBMonsterInPlay *m, int damage, bool giveExperience);
+ void calcAndInflictMonsterDamage(EoBMonsterInPlay *m, int times, int pips, int offs, int flags, int savingThrowType, int savingThrowEffect);
+ void calcAndInflictCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flags, int savingThrowType, int savingThrowEffect);
+ int calcCharacterDamage(int charIndex, int times, int itemOrPips, int useStrModifierOrBase, int flags, int savingThrowType, 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 savingThrowType, uint32 effectDuration, int restoreEvent, int noRefresh);
+
+ int calcMonsterDamage(EoBMonsterInPlay *m, int times, int pips, int offs, int flags, int savingThrowType, int savingThrowEffect);
+ int calcDamageModifers(int charIndex, EoBMonsterInPlay *m, int item, int itemType, int useStrModifier);
+ bool trySavingThrow(void *target, int hpModifier, int level, int type, int race);
+ bool specialAttackSavingThrow(int charIndex, int type);
+ int getSaveThrowModifier(int hpModifier, int level, int type);
+ bool calcDamageCheckItemType(int itemType);
+ int savingThrowReduceDamage(int savingThrowEffect, int damage);
+ bool tryMonsterAttackEvasion(EoBMonsterInPlay *m);
+ int getStrHitChanceModifier(int charIndex);
+ int getStrDamageModifier(int charIndex);
+ int getDexHitChanceModifier(int charIndex);
+ int getMonsterAcHitChanceModifier(int charIndex, int monsterAc);
+ void explodeMonster(EoBMonsterInPlay *m);
+
+ int _dstMonsterIndex;
+ bool _preventMonsterFlash;
+ int16 _foundMonstersArray[5];
+ int8 _monsterBlockPosArray[6];
+
+ // magic
+ void useMagicBookOrSymbol(int charIndex, int type);
+ void useMagicScroll(int charIndex, int type, int weaponSlot);
+ void usePotion(int charIndex, int weaponSlot);
+ void useWand(int charIndex, int weaponSlot);
+
+ virtual void turnUndeadAuto() {};
+ virtual void turnUndeadAutoHit() {};
+
+ 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);
+ void sortCharacterSpellList(int charIndex);
+
+ bool magicObjectDamageHit(EoBFlyingObject *fo, int dcTimes, int dcPips, int dcOffs, int level);
+ bool magicObjectStatusHit(EoBMonsterInPlay *m, int type, bool tryEvade, int mod);
+ bool turnUndeadHit(EoBMonsterInPlay *m, int hitChance, int casterLevel);
+ void causeWounds(int dcTimes, int dcPips, int dcOffs);
+
+ int getMagicWeaponSlot(int charIndex);
+ int createMagicWeaponType(int invFlags, int handFlags, int armorClass, int allowedClasses, int dmgNum, int dmgPips, int dmgInc, int extraProps);
+ Item createMagicWeaponItem(int flags, int icon, int value, int type);
+ void removeMagicWeaponItem(Item item);
+
+ void updateWallOfForceTimers();
+ void destroyWallOfForce(int index);
+
+ int findSingleSpellTarget(int dist);
+
+ int findFirstCharacterSpellTarget();
+ int findNextCharacterSpellTarget(int curCharIndex);
+ int charDeathSavingThrow(int charIndex, int div);
+
+ void printWarning(const char *str);
+ void printNoEffectWarning();
+
+ void spellCallback_start_empty() {}
+ bool spellCallback_end_empty(void *) { return true; }
+ void spellCallback_start_armor();
+ void spellCallback_start_burningHands();
+ void spellCallback_start_detectMagic();
+ bool spellCallback_end_detectMagic(void *);
+ void spellCallback_start_magicMissile();
+ bool spellCallback_end_magicMissile(void *obj);
+ void spellCallback_start_shockingGrasp();
+ bool spellCallback_end_shockingGraspFlameBlade(void *obj);
+ void spellCallback_start_improvedIdentify();
+ void spellCallback_start_melfsAcidArrow();
+ bool spellCallback_end_melfsAcidArrow(void *obj);
+ void spellCallback_start_dispelMagic();
+ void spellCallback_start_fireball();
+ bool spellCallback_end_fireball(void *obj);
+ void spellCallback_start_flameArrow();
+ bool spellCallback_end_flameArrow(void *obj);
+ void spellCallback_start_holdPerson();
+ bool spellCallback_end_holdPerson(void *obj);
+ void spellCallback_start_lightningBolt();
+ bool spellCallback_end_lightningBolt(void *obj);
+ void spellCallback_start_vampiricTouch();
+ bool spellCallback_end_vampiricTouch(void *obj);
+ void spellCallback_start_fear();
+ void spellCallback_start_iceStorm();
+ bool spellCallback_end_iceStorm(void *obj);
+ void spellCallback_start_stoneSkin();
+ void spellCallback_start_removeCurse();
+ void spellCallback_start_coneOfCold();
+ void spellCallback_start_holdMonster();
+ bool spellCallback_end_holdMonster(void *obj);
+ void spellCallback_start_wallOfForce();
+ void spellCallback_start_disintegrate();
+ void spellCallback_start_fleshToStone();
+ void spellCallback_start_stoneToFlesh();
+ void spellCallback_start_trueSeeing();
+ bool spellCallback_end_trueSeeing(void *);
+ void spellCallback_start_slayLiving();
+ void spellCallback_start_powerWordStun();
+ void spellCallback_start_causeLightWounds();
+ void spellCallback_start_cureLightWounds();
+ void spellCallback_start_aid();
+ bool spellCallback_end_aid(void *obj);
+ void spellCallback_start_flameBlade();
+ void spellCallback_start_slowPoison();
+ bool spellCallback_end_slowPoison(void *obj);
+ 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(void *obj);
+ void spellCallback_start_raiseDead();
+ void spellCallback_start_harm();
+ void spellCallback_start_heal();
+ void spellCallback_start_layOnHands();
+ void spellCallback_start_turnUndead();
+ bool spellCallback_end_monster_lightningBolt(void *obj);
+ bool spellCallback_end_monster_fireball1(void *obj);
+ bool spellCallback_end_monster_fireball2(void *obj);
+ bool spellCallback_end_monster_deathSpell(void *obj);
+ bool spellCallback_end_monster_disintegrate(void *obj);
+ bool spellCallback_end_monster_causeCriticalWounds(void *obj);
+ bool spellCallback_end_monster_fleshToStone(void *obj);
+
+ int8 _openBookSpellLevel;
+ int8 _openBookSpellSelectedItem;
+ int8 _openBookSpellListOffset;
+ uint8 _openBookChar;
+ uint8 _openBookType;
+ uint8 _openBookCharBackup;
+ uint8 _openBookTypeBackup;
+ uint8 _openBookCasterLevel;
+ const char *const *_openBookSpellList;
+ int8 *_openBookAvailableSpells;
+ uint8 _activeSpellCharId;
+ uint8 _activeSpellCharacterPos;
+ int _activeSpell;
+ int _characterSpellTarget;
+ bool _returnAfterSpellCallback;
+
+ typedef void (EoBCoreEngine::*SpellStartCallback)();
+ typedef bool (EoBCoreEngine::*SpellEndCallback)(void *obj);
+
+ struct EoBSpell {
+ const char *name;
+ SpellStartCallback startCallback;
+ uint16 flags;
+ const uint16 *timingPara;
+ SpellEndCallback endCallback;
+ uint8 sound;
+ uint32 effectFlags;
+ uint16 damageFlags;
+ };
+
+ EoBSpell *_spells;
+ int _numSpells;
+
+ struct WallOfForce {
+ uint16 block;
+ uint32 duration;
+ };
+
+ WallOfForce *_wallsOfForce;
+
+ 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 *_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;
+ const uint8 *_turnUndeadEffect;
+ const uint8 *_burningHandsDest;
+ const int8 *_coneOfColdDest1;
+ const int8 *_coneOfColdDest2;
+ const int8 *_coneOfColdDest3;
+ const int8 *_coneOfColdDest4;
+ const uint8 *_coneOfColdGfxTbl;
+ int _coneOfColdGfxTblSize;
+
+ // Menu
+ EoBMenuDef *_menuDefs;
+ const EoBMenuButtonDef *_menuButtonDefs;
+
+ bool _configMouse;
+
+ const char *const *_menuStringsMain;
+ const char *const *_menuStringsSaveLoad;
+ const char *const *_menuStringsOnOff;
+ const char *const *_menuStringsSpells;
+ const char *const *_menuStringsRest;
+ const char *const *_menuStringsDrop;
+ const char *const *_menuStringsExit;
+ const char *const *_menuStringsStarve;
+ const char *const *_menuStringsScribe;
+ const char *const *_menuStringsDrop2;
+ const char *const *_menuStringsHead;
+ const char *const *_menuStringsPoison;
+ const char *const *_menuStringsMgc;
+ const char *const *_menuStringsPrefs;
+ const char *const *_menuStringsRest2;
+ const char *const *_menuStringsRest3;
+ const char *const *_menuStringsRest4;
+ const char *const *_menuStringsDefeat;
+ const char *_errorSlotEmptyString;
+ const char *_errorSlotNoNameString;
+ const char *_menuOkString;
+
+ const char *const *_menuStringsTransfer;
+ const char *const *_transferStringsScummVM;
+ const char *const *_menuStringsSpec;
+ const char *const *_menuStringsSpellNo;
+ const char *const *_menuYesNoStrings;
+
+ const uint8 *_spellLevelsMage;
+ int _spellLevelsMageSize;
+ const uint8 *_spellLevelsCleric;
+ int _spellLevelsClericSize;
+ const uint8 *_numSpellsCleric;
+ const uint8 *_numSpellsWisAdj;
+ const uint8 *_numSpellsPal;
+ const uint8 *_numSpellsMage;
+
+ // sound
+ void snd_playSong(int id);
+ void snd_playSoundEffect(int id, int volume=0xFF);
+ void snd_stopSound();
+ void snd_fadeOut();
+
+ // keymap
+ static const char *const kKeymapName;
+};
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
+
+#endif
diff --git a/engines/kyra/gui.cpp b/engines/kyra/gui.cpp
index 27f09b645e..1156b17957 100644
--- a/engines/kyra/gui.cpp
+++ b/engines/kyra/gui.cpp
@@ -20,369 +20,50 @@
*
*/
-#include "kyra/gui.h"
-#include "kyra/text.h"
-#include "kyra/wsamovie.h"
+#include "kyra/gui.h"
+#include "kyra/kyra_v1.h"
+#include "kyra/util.h"
#include "common/savefile.h"
#include "common/system.h"
-namespace Kyra {
-
-GUI::GUI(KyraEngine_v1 *kyra)
- : _vm(kyra), _screen(kyra->screen()), _text(kyra->text()) {
- _menuButtonList = 0;
-
- _redrawButtonFunctor = BUTTON_FUNCTOR(GUI, this, &GUI::redrawButtonCallback);
- _redrawShadedButtonFunctor = BUTTON_FUNCTOR(GUI, this, &GUI::redrawShadedButtonCallback);
-}
-
-Button *GUI::addButtonToList(Button *list, Button *newButton) {
- if (!newButton)
- return list;
-
- newButton->nextButton = 0;
-
- if (list) {
- Button *cur = list;
- while (cur->nextButton)
- cur = cur->nextButton;
- cur->nextButton = newButton;
- } else {
- list = newButton;
- }
-
- return list;
-}
-
-void GUI::initMenuLayout(Menu &menu) {
- if (menu.x == -1)
- menu.x = (320 - menu.width) >> 1;
- if (menu.y == -1)
- menu.y = (200 - menu.height) >> 1;
-
- for (int i = 0; i < menu.numberOfItems; ++i) {
- if (menu.item[i].x == -1)
- menu.item[i].x = (menu.width - menu.item[i].width) >> 1;
- }
-}
-
-void GUI::initMenu(Menu &menu) {
- _menuButtonList = 0;
-
- _screen->hideMouse();
-
- int textX;
- int textY;
-
- int menu_x2 = menu.width + menu.x - 1;
- int menu_y2 = menu.height + menu.y - 1;
-
- _screen->fillRect(menu.x + 2, menu.y + 2, menu_x2 - 2, menu_y2 - 2, menu.bkgdColor);
- _screen->drawShadedBox(menu.x, menu.y, menu_x2, menu_y2, menu.color1, menu.color2);
-
- if (menu.titleX != -1)
- textX = menu.titleX;
- else
- textX = getMenuCenterStringX(getMenuTitle(menu), menu.x, menu_x2);
- textY = menu.y + menu.titleY;
-
- if (_vm->game() == GI_LOL) {
- printMenuText(getMenuTitle(menu), textX, textY, menu.textColor, 0, 9);
- } else {
- if (_vm->gameFlags().platform != Common::kPlatformAmiga)
- printMenuText(getMenuTitle(menu), textX - 1, textY + 1, defaultColor1(), defaultColor2(), 0);
- printMenuText(getMenuTitle(menu), textX, textY, menu.textColor, 0, 0);
- }
-
- int x1, y1, x2, y2;
- for (int i = 0; i < menu.numberOfItems; ++i) {
- if (!menu.item[i].enabled)
- continue;
-
- x1 = menu.x + menu.item[i].x;
- y1 = menu.y + menu.item[i].y;
-
- x2 = x1 + menu.item[i].width - 1;
- y2 = y1 + menu.item[i].height - 1;
-
- if (i < 7) {
- Button *menuButtonData = getButtonListData() + i;
- menuButtonData->nextButton = 0;
- menuButtonData->x = x1;
- menuButtonData->y = y1;
- menuButtonData->width = menu.item[i].width - 1;
- menuButtonData->height = menu.item[i].height - 1;
- menuButtonData->buttonCallback = menu.item[i].callback;
- menuButtonData->keyCode = menu.item[i].keyCode;
- menuButtonData->keyCode2 = 0;
- menuButtonData->arg = menu.item[i].itemId;
-
- _menuButtonList = addButtonToList(_menuButtonList, menuButtonData);
- }
-
- _screen->fillRect(x1, y1, x2, y2, menu.item[i].bkgdColor);
- _screen->drawShadedBox(x1, y1, x2, y2, menu.item[i].color1, menu.item[i].color2);
-
- if (getMenuItemTitle(menu.item[i])) {
- if (menu.item[i].titleX != -1)
- textX = x1 + menu.item[i].titleX + 3;
- else
- textX = getMenuCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2);
-
- textY = y1 + 2;
- if (_vm->game() == GI_LOL) {
- textY++;
- if (i == menu.highlightedItem)
- printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 8);
- else
- printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 8);
- } else {
- Screen::FontId of = _screen->_currentFont;
- if (menu.item[i].saveSlot > 0)
- _screen->setFont(Screen::FID_8_FNT);
-
- if (_vm->gameFlags().platform != Common::kPlatformAmiga)
- printMenuText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0);
-
- if (i == menu.highlightedItem)
- printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 0);
- else
- printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 0);
-
- _screen->setFont(of);
- }
- }
- }
-
- for (int i = 0; i < menu.numberOfItems; ++i) {
- if (getMenuItemLabel(menu.item[i])) {
- if (_vm->game() == GI_LOL) {
- menu.item[i].labelX = menu.item[i].x - 1;
- menu.item[i].labelY = menu.item[i].y + 3;
- printMenuText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX, menu.y + menu.item[i].labelY, menu.item[i].textColor, 0, 10);
- } else {
- if (_vm->gameFlags().platform != Common::kPlatformAmiga)
- printMenuText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX - 1, menu.y + menu.item[i].labelY + 1, defaultColor1(), 0, 0);
- printMenuText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX, menu.y + menu.item[i].labelY, menu.item[i].textColor, 0, 0);
- }
- }
- }
-
- if (menu.scrollUpButtonX != -1) {
- Button *scrollUpButton = getScrollUpButton();
- scrollUpButton->x = menu.scrollUpButtonX + menu.x;
- scrollUpButton->y = menu.scrollUpButtonY + menu.y;
- scrollUpButton->buttonCallback = getScrollUpButtonHandler();
- scrollUpButton->nextButton = 0;
- scrollUpButton->mouseWheel = -1;
-
- _menuButtonList = addButtonToList(_menuButtonList, scrollUpButton);
- updateMenuButton(scrollUpButton);
-
- Button *scrollDownButton = getScrollDownButton();
- scrollDownButton->x = menu.scrollDownButtonX + menu.x;
- scrollDownButton->y = menu.scrollDownButtonY + menu.y;
- scrollDownButton->buttonCallback = getScrollDownButtonHandler();
- scrollDownButton->nextButton = 0;
- scrollDownButton->mouseWheel = 1;
-
- _menuButtonList = addButtonToList(_menuButtonList, scrollDownButton);
- updateMenuButton(scrollDownButton);
- }
-
- _screen->showMouse();
- _screen->updateScreen();
-}
-
-void GUI::processHighlights(Menu &menu) {
- int x1, y1, x2, y2;
- Common::Point p = _vm->getMousePos();
- int mouseX = p.x;
- int mouseY = p.y;
-
- if (_vm->game() == GI_LOL && menu.highlightedItem != 255) {
- // LoL doesnt't have default highlighted items.
- // We use a highlightedItem value of 255 for this.
-
- // With LoL no highlighting should take place unless the
- // mouse cursor moves over a button. The highlighting should end
- // when the mouse cursor leaves the button.
- if (menu.item[menu.highlightedItem].enabled)
- redrawText(menu);
- }
-
- for (int i = 0; i < menu.numberOfItems; ++i) {
- if (!menu.item[i].enabled)
- continue;
-
- x1 = menu.x + menu.item[i].x;
- y1 = menu.y + menu.item[i].y;
-
- x2 = x1 + menu.item[i].width;
- y2 = y1 + menu.item[i].height;
-
- if (mouseX > x1 && mouseX < x2 &&
- mouseY > y1 && mouseY < y2) {
-
- if (menu.highlightedItem != i || _vm->game() == GI_LOL) {
- if (_vm->game() != GI_LOL) {
- if (menu.item[menu.highlightedItem].enabled)
- redrawText(menu);
- }
-
- menu.highlightedItem = i;
- redrawHighlight(menu);
- }
- }
- }
-
- _screen->updateScreen();
-}
-
-void GUI::redrawText(const Menu &menu) {
- int textX;
- int i = menu.highlightedItem;
-
- int x1 = menu.x + menu.item[i].x;
- int y1 = menu.y + menu.item[i].y;
-
- int x2 = x1 + menu.item[i].width - 1;
-
- if (menu.item[i].titleX >= 0)
- textX = x1 + menu.item[i].titleX + 3;
- else
- textX = getMenuCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2);
+namespace Kyra {
- int textY = y1 + 2;
- if (_vm->game() == GI_LOL) {
- textY++;
- printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 8);
- } else {
- Screen::FontId of = _screen->_currentFont;
- if (menu.item[i].saveSlot > 0)
- _screen->setFont(Screen::FID_8_FNT);
- if (_vm->gameFlags().platform != Common::kPlatformAmiga)
- printMenuText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0);
- printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 0);
- _screen->setFont(of);
- }
+GUI::GUI(KyraEngine_v1 *kyra) : _vm(kyra), _screen(kyra->screen()) {
+ _saveSlotsListUpdateNeeded = true;
+ _savegameListSize = 0;
+ _savegameList = 0;
}
-void GUI::redrawHighlight(const Menu &menu) {
- int textX;
- int i = menu.highlightedItem;
-
- int x1 = menu.x + menu.item[i].x;
- int y1 = menu.y + menu.item[i].y;
-
- int x2 = x1 + menu.item[i].width - 1;
-
- if (menu.item[i].titleX != -1)
- textX = x1 + menu.item[i].titleX + 3;
- else
- textX = getMenuCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2);
-
- int textY = y1 + 2;
-
- if (_vm->game() == GI_LOL) {
- textY++;
- printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 8);
- } else {
- Screen::FontId of = _screen->_currentFont;
- if (menu.item[i].saveSlot > 0)
- _screen->setFont(Screen::FID_8_FNT);
- if (_vm->gameFlags().platform != Common::kPlatformAmiga)
- printMenuText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0);
- printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 0);
- _screen->setFont(of);
+GUI::~GUI() {
+ if (_savegameList) {
+ for (int i = 0; i < _savegameListSize; i++)
+ delete[] _savegameList[i];
+ delete[] _savegameList;
+ _savegameList = 0;
}
}
-void GUI::updateAllMenuButtons() {
- for (Button *cur = _menuButtonList; cur; cur = cur->nextButton)
- updateMenuButton(cur);
-}
-
-void GUI::updateMenuButton(Button *button) {
- if (!_displayMenu)
- return;
-
- _screen->hideMouse();
- updateButton(button);
- _screen->updateScreen();
- _screen->showMouse();
-}
-
-void GUI::updateButton(Button *button) {
- if (!button || (button->flags & 8))
- return;
-
- if (button->flags2 & 1)
- button->flags2 &= 0xFFF7;
- else
- button->flags2 |= 8;
-
- button->flags2 &= 0xFFFC;
-
- if (button->flags2 & 4)
- button->flags2 |= 0x10;
- else
- button->flags2 &= 0xEEEF;
-
- button->flags2 &= 0xFFFB;
-
- processButton(button);
-}
-
-int GUI::redrawButtonCallback(Button *button) {
- if (!_displayMenu)
- return 0;
-
- _screen->hideMouse();
- if (_vm->gameFlags().platform == Common::kPlatformAmiga)
- _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 17);
- else
- _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 0xF8);
- _screen->showMouse();
-
- return 0;
-}
-
-int GUI::redrawShadedButtonCallback(Button *button) {
- if (!_displayMenu)
- return 0;
-
- _screen->hideMouse();
- if (_vm->gameFlags().platform == Common::kPlatformAmiga)
- _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 31, 18);
- else
- _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 0xF9, 0xFA);
- _screen->showMouse();
-
- return 0;
-}
-
-void GUI::updateSaveList(bool excludeQuickSaves) {
- Common::String pattern = _vm->_targetName + ".???";
+void GUI::updateSaveFileList(Common::String targetName, bool excludeQuickSaves) {
+ Common::String pattern = targetName + ".???";
Common::StringArray saveFileList = _vm->_saveFileMan->listSavefiles(pattern);
_saveSlots.clear();
for (Common::StringArray::const_iterator i = saveFileList.begin(); i != saveFileList.end(); ++i) {
char s1 = 0, s2 = 0, s3 = 0;
- s1 = (*i)[i->size()-3];
- s2 = (*i)[i->size()-2];
- s3 = (*i)[i->size()-1];
- if (!isdigit(static_cast<unsigned char>(s1)) || !isdigit(static_cast<unsigned char>(s2)) || !isdigit(static_cast<unsigned char>(s3)))
+ s1 = (*i)[i->size() - 3];
+ s2 = (*i)[i->size() - 2];
+ s3 = (*i)[i->size() - 1];
+ if (!Common::isDigit(s1) || !Common::isDigit(s2) || !Common::isDigit(s3))
continue;
s1 -= '0';
s2 -= '0';
s3 -= '0';
if (excludeQuickSaves && s1 == 9 && s2 == 9)
continue;
- _saveSlots.push_back(s1*100+s2*10+s3);
+ _saveSlots.push_back(s1 * 100 + s2 * 10 + s3);
}
if (_saveSlots.begin() == _saveSlots.end())
@@ -394,7 +75,7 @@ void GUI::updateSaveList(bool excludeQuickSaves) {
void GUI::sortSaveSlots() {
Common::sort(_saveSlots.begin(), _saveSlots.end(), Common::Less<int>());
if (_saveSlots.size() > 2)
- Common::sort(_saveSlots.begin()+1, _saveSlots.end(), Common::Greater<int>());
+ Common::sort(_saveSlots.begin() + 1, _saveSlots.end(), Common::Greater<int>());
}
int GUI::getNextSavegameSlot() {
@@ -412,266 +93,49 @@ int GUI::getNextSavegameSlot() {
return 0;
}
-void GUI::checkTextfieldInput() {
- Common::Event event;
-
- uint32 now = _vm->_system->getMillis();
-
- bool running = true;
- int keys = 0;
- while (running && _vm->_eventMan->pollEvent(event)) {
- switch (event.type) {
- case Common::EVENT_KEYDOWN:
- if (event.kbd.keycode == Common::KEYCODE_q && event.kbd.hasFlags(Common::KBD_CTRL))
- _vm->quitGame();
- else
- _keyPressed = event.kbd;
- running = false;
- break;
-
- case Common::EVENT_LBUTTONDOWN:
- case Common::EVENT_LBUTTONUP: {
- Common::Point pos = _vm->getMousePos();
- _vm->_mouseX = pos.x;
- _vm->_mouseY = pos.y;
- keys = event.type == Common::EVENT_LBUTTONDOWN ? 199 : (200 | 0x800);
- running = false;
- } break;
-
- case Common::EVENT_MOUSEMOVE: {
- Common::Point pos = _vm->getMousePos();
- _vm->_mouseX = pos.x;
- _vm->_mouseY = pos.y;
-
- _vm->_system->updateScreen();
- _lastScreenUpdate = now;
- } break;
-
- default:
- break;
- }
- }
-
- if (now - _lastScreenUpdate > 50) {
- _vm->_system->updateScreen();
- _lastScreenUpdate = now;
- }
-
- processButtonList(_menuButtonList, keys | 0x8000, 0);
- _vm->_system->delayMillis(3);
-}
-
-void GUI::printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2) {
- _text->printText(str, x, y, c0, c1, c2);
-}
-
-int GUI::getMenuCenterStringX(const char *str, int x1, int x2) {
- return _text->getCenterStringX(str, x1, x2);
-}
-
-#pragma mark -
-
-MainMenu::MainMenu(KyraEngine_v1 *vm) : _vm(vm), _screen(0) {
- _screen = _vm->screen();
- _nextUpdate = 0;
- _system = g_system;
-}
-
-void MainMenu::init(StaticData data, Animation anim) {
- _static = data;
- _anim = anim;
- _animIntern.curFrame = _anim.startFrame;
- _animIntern.direction = 1;
-}
-
-void MainMenu::updateAnimation() {
- if (_anim.anim) {
- uint32 now = _system->getMillis();
- if (now > _nextUpdate) {
- _nextUpdate = now + _anim.delay * _vm->tickLength();
-
- _anim.anim->displayFrame(_animIntern.curFrame, 0, 0, 0, 0, 0, 0);
- _animIntern.curFrame += _animIntern.direction;
- if (_animIntern.curFrame < _anim.startFrame) {
- _animIntern.curFrame = _anim.startFrame;
- _animIntern.direction = 1;
- } else if (_animIntern.curFrame > _anim.endFrame) {
- _animIntern.curFrame = _anim.endFrame;
- _animIntern.direction = -1;
- }
- }
- }
-
- _screen->updateScreen();
-}
-
-bool MainMenu::getInput() {
- Common::Event event;
- Common::EventManager *eventMan = _vm->getEventManager();
-
- bool updateScreen = false;
-
- while (eventMan->pollEvent(event)) {
- switch (event.type) {
- case Common::EVENT_LBUTTONUP:
- return true;
+void GUI::updateSaveSlotsList(Common::String targetName, bool force) {
+ if (!_saveSlotsListUpdateNeeded && !force)
+ return;
- case Common::EVENT_MOUSEMOVE:
- updateScreen = true;
- break;
+ _saveSlotsListUpdateNeeded = false;
- default:
- break;
- }
+ if (_savegameList) {
+ for (int i = 0; i < _savegameListSize; i++)
+ delete[] _savegameList[i];
+ delete[] _savegameList;
}
- if (updateScreen)
- _system->updateScreen();
- return false;
-}
-
-int MainMenu::handle(int dim) {
- int command = -1;
-
- uint8 colorMap[16];
- memset(colorMap, 0, sizeof(colorMap));
- _screen->setTextColorMap(colorMap);
-
- Screen::FontId oldFont = _screen->setFont(_static.font);
- int charWidthBackUp = _screen->_charWidth;
-
- if (_vm->game() != GI_LOL)
- _screen->_charWidth = -2;
- _screen->setScreenDim(dim);
-
- int backUpX = _screen->_curDim->sx;
- int backUpY = _screen->_curDim->sy;
- int backUpWidth = _screen->_curDim->w;
- int backUpHeight = _screen->_curDim->h;
- _screen->copyRegion(backUpX, backUpY, backUpX, backUpY, backUpWidth, backUpHeight, 0, 3);
-
- int x = _screen->_curDim->sx << 3;
- int y = _screen->_curDim->sy;
- int width = _screen->_curDim->w << 3;
- int height = _screen->_curDim->h;
-
- drawBox(x, y, width, height, 1);
- drawBox(x + 1, y + 1, width - 2, height - 2, 0);
+ updateSaveFileList(targetName, true);
+ int numSaves = _savegameListSize = _saveSlots.size();
+ bool allowEmptySlots = (_vm->game() == GI_EOB1 || _vm->game() == GI_EOB2);
- int selected = 0;
+ if (_savegameListSize) {
+ if (allowEmptySlots)
+ _savegameListSize = 990;
- draw(selected);
+ KyraEngine_v1::SaveHeader header;
+ Common::InSaveFile *in;
- while (!_screen->isMouseVisible())
- _screen->showMouse();
+ _savegameList = new char*[_savegameListSize];
+ memset(_savegameList, 0, _savegameListSize * sizeof(char *));
- int fh = _screen->getFontHeight();
- if (_vm->gameFlags().lang == Common::JA_JPN)
- fh++;
-
- int textPos = ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3;
-
- Common::Rect menuRect(x + 16, y + 4, x + width - 16, y + 4 + fh * _static.menuTable[3]);
-
- while (!_vm->shouldQuit()) {
- updateAnimation();
- bool mousePressed = getInput();
-
- Common::Point mouse = _vm->getMousePos();
- if (menuRect.contains(mouse)) {
- int item = (mouse.y - menuRect.top) / fh;
-
- if (item != selected) {
- printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5, _static.strings[selected]);
- printString("%s", textPos, menuRect.top + item * fh, _static.menuTable[6], 0, 5, _static.strings[item]);
-
- selected = item;
- }
-
- if (mousePressed) {
- for (int i = 0; i < 3; i++) {
- printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5, _static.strings[selected]);
- _screen->updateScreen();
- _system->delayMillis(50);
- printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[6], 0, 5, _static.strings[selected]);
- _screen->updateScreen();
- _system->delayMillis(50);
- }
- command = item;
- break;
+ for (int i = 0; i < numSaves; i++) {
+ in = _vm->openSaveForReading(_vm->getSavegameFilename(targetName, _saveSlots[i]).c_str(), header, targetName == _vm->_targetName);
+ char **listEntry = &_savegameList[allowEmptySlots ? _saveSlots[i] : i];
+ if (in) {
+ *listEntry = new char[header.description.size() + 1];
+ Common::strlcpy(*listEntry, header.description.c_str(), header.description.size() + 1);
+ Util::convertISOToDOS(*listEntry);
+ delete in;
+ } else {
+ *listEntry = 0;
+ error("GUI::updateSavegameList(): Unexpected missing save file for slot: %d.", _saveSlots[i]);
}
}
- _system->delayMillis(10);
- }
-
- if (_vm->shouldQuit())
- command = -1;
- _screen->copyRegion(backUpX, backUpY, backUpX, backUpY, backUpWidth, backUpHeight, 3, 0);
- _screen->_charWidth = charWidthBackUp;
- _screen->setFont(oldFont);
-
- return command;
-}
-
-void MainMenu::draw(int select) {
- int top = _screen->_curDim->sy;
- top += _static.menuTable[1];
- int fh = _screen->getFontHeight();
- if (_vm->gameFlags().lang == Common::JA_JPN)
- fh++;
-
- for (int i = 0; i < _static.menuTable[3]; ++i) {
- int curY = top + i * fh;
- int color = (i == select) ? _static.menuTable[6] : _static.menuTable[5];
- printString("%s", ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3, curY, color, 0, 5, _static.strings[i]);
- }
-}
-
-void MainMenu::drawBox(int x, int y, int w, int h, int fill) {
- --w; --h;
-
- if (fill)
- _screen->fillRect(x, y, x+w, y+h, _static.colorTable[0]);
-
- _screen->drawClippedLine(x, y+h, x+w, y+h, _static.colorTable[1]);
- _screen->drawClippedLine(x+w, y, x+w, y+h, _static.colorTable[1]);
- _screen->drawClippedLine(x, y, x+w, y, _static.colorTable[2]);
- _screen->drawClippedLine(x, y, x, y+h, _static.colorTable[2]);
-
- _screen->setPagePixel(_screen->_curPage, x, y+h, _static.colorTable[3]);
- _screen->setPagePixel(_screen->_curPage, x+w, y, _static.colorTable[3]);
-}
-
-void MainMenu::printString(const char *format, int x, int y, int col1, int col2, int flags, ...) {
- if (!format)
- return;
-
- va_list vaList;
- va_start(vaList, flags);
- Common::String string = Common::String::vformat(format, vaList);
- va_end(vaList);
-
- if (flags & 1)
- x -= _screen->getTextWidth(string.c_str()) >> 1;
-
- if (flags & 2)
- x -= _screen->getTextWidth(string.c_str());
-
- if (_vm->gameFlags().use16ColorMode)
- flags &= 3;
-
- if (flags & 4) {
- _screen->printText(string.c_str(), x - 1, y, _static.altColor, col2);
- _screen->printText(string.c_str(), x, y + 1, _static.altColor, col2);
- }
-
- if (flags & 8) {
- _screen->printText(string.c_str(), x - 1, y, 227, col2);
- _screen->printText(string.c_str(), x, y + 1, 227, col2);
+ } else {
+ _savegameList = 0;
}
-
- _screen->printText(string.c_str(), x, y, col1, col2);
}
} // End of namespace Kyra
diff --git a/engines/kyra/gui.h b/engines/kyra/gui.h
index 6e9606f1de..854f10e85d 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(), extButtonDef(0), arg(0) {}
Button *nextButton;
uint16 index;
@@ -54,6 +54,7 @@ struct Button {
byte data0Val1;
byte data1Val1;
byte data2Val1;
+ byte data3Val1;
uint16 flags;
@@ -78,63 +79,18 @@ struct Button {
uint8 data2Val2;
uint8 data2Val3;
+ uint8 data3Val2;
+ uint8 data3Val3;
+
uint16 flags2;
int8 mouseWheel;
Callback buttonCallback;
- uint16 arg;
-};
-
-struct MenuItem {
- bool enabled;
-
- const char *itemString;
- uint16 itemId;
-
- int16 x, y;
- uint16 width, height;
+ const void *extButtonDef;
- uint8 textColor, highlightColor;
-
- int16 titleX;
-
- uint8 color1, color2;
- uint8 bkgdColor;
-
- Button::Callback callback;
-
- int16 saveSlot;
-
- const char *labelString;
- uint16 labelId;
- int16 labelX, labelY;
-
- uint16 keyCode;
-};
-
-struct Menu {
- int16 x, y;
- uint16 width, height;
-
- uint8 bkgdColor;
- uint8 color1, color2;
-
- const char *menuNameString;
- uint16 menuNameId;
-
- uint8 textColor;
- int16 titleX, titleY;
-
- uint8 highlightedItem;
-
- uint8 numberOfItems;
-
- int16 scrollUpButtonX, scrollUpButtonY;
- int16 scrollDownButtonX, scrollDownButtonY;
-
- MenuItem item[7];
+ uint16 arg;
};
class Screen;
@@ -143,128 +99,39 @@ class TextDisplayer;
class GUI {
public:
GUI(KyraEngine_v1 *vm);
- virtual ~GUI() {}
+ virtual ~GUI();
// button specific
- virtual Button *addButtonToList(Button *list, Button *newButton);
-
virtual void processButton(Button *button) = 0;
virtual int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel) = 0;
- virtual int redrawShadedButtonCallback(Button *button);
- virtual int redrawButtonCallback(Button *button);
-
- // menu specific
- virtual void initMenuLayout(Menu &menu);
- void initMenu(Menu &menu);
-
- void processHighlights(Menu &menu);
-
// utilities for thumbnail creation
virtual void createScreenThumbnail(Graphics::Surface &dst) = 0;
+ void notifyUpdateSaveSlotsList() { _saveSlotsListUpdateNeeded = true; }
+
protected:
KyraEngine_v1 *_vm;
Screen *_screen;
- TextDisplayer *_text;
-
- Button *_menuButtonList;
- bool _displayMenu;
- bool _displaySubMenu;
- bool _cancelSubMenu;
-
- virtual void printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2);
- virtual int getMenuCenterStringX(const char *str, int x1, int x2);
-
- Button::Callback _redrawShadedButtonFunctor;
- Button::Callback _redrawButtonFunctor;
-
- virtual Button *getButtonListData() = 0;
- virtual Button *getScrollUpButton() = 0;
- virtual Button *getScrollDownButton() = 0;
-
- virtual Button::Callback getScrollUpButtonHandler() const = 0;
- virtual Button::Callback getScrollDownButtonHandler() const = 0;
-
- virtual uint8 defaultColor1() const = 0;
- virtual uint8 defaultColor2() const = 0;
-
- virtual const char *getMenuTitle(const Menu &menu) = 0;
- virtual const char *getMenuItemTitle(const MenuItem &menuItem) = 0;
- virtual const char *getMenuItemLabel(const MenuItem &menuItem) = 0;
-
- void updateAllMenuButtons();
- void updateMenuButton(Button *button);
- virtual void updateButton(Button *button);
-
- void redrawText(const Menu &menu);
- void redrawHighlight(const Menu &menu);
// The engine expects a list of contiguous savegame indices.
// Since ScummVM's savegame indices aren't, we re-index them.
// The integers stored in _saveSlots are ScummVM savegame indices.
Common::Array<int> _saveSlots;
- void updateSaveList(bool excludeQuickSaves = false);
+ void updateSaveFileList(Common::String targetName, bool excludeQuickSaves = false);
int getNextSavegameSlot();
+ void updateSaveSlotsList(Common::String targetName, bool force = false);
virtual void sortSaveSlots();
uint32 _lastScreenUpdate;
- Common::KeyState _keyPressed;
- void checkTextfieldInput();
-};
-
-class Movie;
+ char **_savegameList;
+ int _savegameListSize;
+ bool _saveSlotsListUpdateNeeded;
-class MainMenu {
-public:
- MainMenu(KyraEngine_v1 *vm);
- virtual ~MainMenu() {}
-
- struct Animation {
- Animation() : anim(0), startFrame(0), endFrame(0), delay(0) {}
-
- Movie *anim;
- int startFrame;
- int endFrame;
- int delay;
- };
-
- struct StaticData {
- const char *strings[5];
-
- uint8 menuTable[7];
- uint8 colorTable[4];
-
- Screen::FontId font;
- uint8 altColor;
- };
-
- void init(StaticData data, Animation anim);
- int handle(int dim);
-private:
- KyraEngine_v1 *_vm;
- Screen *_screen;
- OSystem *_system;
-
- StaticData _static;
- struct AnimIntern {
- int curFrame;
- int direction;
- };
- Animation _anim;
- AnimIntern _animIntern;
-
- uint32 _nextUpdate;
-
- void updateAnimation();
- void draw(int select);
- void drawBox(int x, int y, int w, int h, int fill);
- bool getInput();
-
- void printString(const char *string, int x, int y, int col1, int col2, int flags, ...) GCC_PRINTF(2, 8);
+ Common::KeyState _keyPressed;
};
-} // end of namesapce Kyra
+} // End of namespace Kyra
#endif
diff --git a/engines/kyra/gui_eob.cpp b/engines/kyra/gui_eob.cpp
new file mode 100644
index 0000000000..e3c0743e5c
--- /dev/null
+++ b/engines/kyra/gui_eob.cpp
@@ -0,0 +1,4093 @@
+/* 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/gui_eob.h"
+#include "kyra/script_eob.h"
+#include "kyra/text_rpg.h"
+#include "kyra/timer.h"
+#include "kyra/util.h"
+
+#include "backends/keymapper/keymapper.h"
+#include "common/system.h"
+#include "common/savefile.h"
+#include "graphics/scaler.h"
+
+namespace Kyra {
+
+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(bool refresh) {
+ _screen->loadEoBBitmap("PLAYFLD", _cgaMappingDeco, 5, 3, 2);
+ int cp = _screen->setCurPage(2);
+ gui_drawCompass(true);
+
+ if (refresh && !_sceneDrawPage2)
+ drawScene(0);
+
+ _screen->setCurPage(cp);
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+
+ if (!_loading)
+ _screen->updateScreen();
+
+ _screen->loadEoBBitmap("INVENT", _cgaMappingInv, 5, 3, 2);
+}
+
+void EoBCoreEngine::gui_restorePlayField() {
+ loadVcnData(0, (_flags.gameID == GI_EOB1) ? _cgaMappingLevel[_cgaLevelMappingIndex[_currentLevel - 1]] : 0);
+ _screen->_curPage = 0;
+ gui_drawPlayField(true);
+ 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;
+ }
+
+ 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, guiSettings()->colors.fill);
+ else
+ _screen->printText(c->name, x2 + 2, y2 + 2, txtCol1, guiSettings()->colors.fill);
+
+ 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);
+ Common::String tmpStr = Common::String::format("%d", c->damageTaken);
+ _screen->printText(tmpStr.c_str(), x2 + 34 - tmpStr.size() * 3, y2 + 42, (_configRenderMode == Common::kRenderCGA) ? 12 : 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, guiSettings()->colors.fill);
+ gui_drawHitpoints(index);
+ gui_drawFoodStatusGraph(index);
+
+ if (_currentControlMode == 1) {
+ if (c->hitPointsCur == -10)
+ _screen->printShadedText(_characterGuiStringsSt[1], 247, 158, 6, guiSettings()->colors.extraFill);
+ else if (c->hitPointsCur < 1)
+ _screen->printShadedText(_characterGuiStringsSt[2], 226, 158, 6, guiSettings()->colors.extraFill);
+ else if (c->effectFlags & (_flags.gameID == GI_EOB1 ? 0x80 : 0x2000))
+ _screen->printShadedText(_characterGuiStringsSt[3], 220, 158, 6, guiSettings()->colors.extraFill);
+ else if (c->flags & 2)
+ _screen->printShadedText(_characterGuiStringsSt[4], 235, 158, 6, guiSettings()->colors.extraFill);
+ else if (c->flags & 4)
+ _screen->printShadedText(_characterGuiStringsSt[5], 232, 158, 6, guiSettings()->colors.extraFill);
+ else if (c->flags & 8)
+ _screen->printShadedText(_characterGuiStringsSt[6], 232, 158, 6, guiSettings()->colors.extraFill);
+
+ 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], guiSettings()->colors.extraFill);
+
+ _screen->printShadedText(_characterGuiStringsIn[0], 183, 42, 15, guiSettings()->colors.extraFill);
+ _screen->printText(_chargenClassStrings[c->cClass], 183, 55, 12, guiSettings()->colors.extraFill);
+ _screen->printText(_chargenAlignmentStrings[c->alignment], 183, 62, 12, guiSettings()->colors.extraFill);
+ _screen->printText(_chargenRaceSexStrings[c->raceSex], 183, 69, 12, guiSettings()->colors.extraFill);
+
+ for (int i = 0; i < 6; i++)
+ _screen->printText(_chargenStatStrings[6 + i], 183, 82 + i * 7, 12, guiSettings()->colors.extraFill);
+
+ _screen->printText(_characterGuiStringsIn[1], 183, 124, 12, guiSettings()->colors.extraFill);
+ _screen->printText(_characterGuiStringsIn[2], 239, 138, 12, guiSettings()->colors.extraFill);
+ _screen->printText(_characterGuiStringsIn[3], 278, 138, 12, guiSettings()->colors.extraFill);
+
+ _screen->printText(getCharStrength(c->strengthCur, c->strengthExtCur).c_str(), 275, 82, 15, guiSettings()->colors.extraFill);
+ _screen->printText(Common::String::format("%d", c->intelligenceCur).c_str(), 275, 89, 15, guiSettings()->colors.extraFill);
+ _screen->printText(Common::String::format("%d", c->wisdomCur).c_str(), 275, 96, 15, guiSettings()->colors.extraFill);
+ _screen->printText(Common::String::format("%d", c->dexterityCur).c_str(), 275, 103, 15, guiSettings()->colors.extraFill);
+ _screen->printText(Common::String::format("%d", c->constitutionCur).c_str(), 275, 110, 15, guiSettings()->colors.extraFill);
+ _screen->printText(Common::String::format("%d", c->charismaCur).c_str(), 275, 117, 15, guiSettings()->colors.extraFill);
+ _screen->printText(Common::String::format("%d", c->armorClass).c_str(), 275, 124, 15, guiSettings()->colors.extraFill);
+
+ for (int i = 0; i < 3; i++) {
+ int t = getCharacterClassType(c->cClass, i);
+ if (t == -1)
+ continue;
+
+ _screen->printText(_chargenClassStrings[t + 15], 180, 145 + 7 * i, 12, guiSettings()->colors.extraFill);
+ Common::String tmpStr = Common::String::format("%d", c->experience[i]);
+ _screen->printText(tmpStr.c_str(), 251 - tmpStr.size() * 3, 145 + 7 * i, 15, guiSettings()->colors.extraFill);
+ tmpStr = Common::String::format("%d", c->level[i]);
+ _screen->printText(tmpStr.c_str(), 286 - tmpStr.size() * 3, 145 + 7 * i, 15, guiSettings()->colors.extraFill);
+ }
+ }
+
+ _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);
+
+ _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, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+
+ 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 && _flags.gameID == GI_EOB2 && checkScriptFlags(0x80000000))
+ _screen->drawShape(_screen->_curPage, _itemIconShapes[103], x + 8, y, 0);
+ else
+ _screen->drawShape(_screen->_curPage, _itemIconShapes[85 + slot], 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) {
+ Common::String tmpStr;
+ Common::String tmpStr2;
+
+ if (status > -3 || status == -5)
+ _screen->drawShape(_screen->_curPage, _greenSplatShape, x - 1, y, 0);
+ else
+ gui_drawBox(x, y, 31, 16, guiSettings()->colors.warningFrame1, guiSettings()->colors.warningFrame2, guiSettings()->colors.warningFill);
+
+ switch (status + 5) {
+ case 0:
+ tmpStr = _characterGuiStringsWp[2];
+ break;
+ case 1:
+ tmpStr = _characterGuiStringsWr[2];
+ tmpStr2 = _characterGuiStringsWr[3];
+ break;
+ case 2:
+ tmpStr = _characterGuiStringsWr[0];
+ tmpStr2 = _characterGuiStringsWr[1];
+ break;
+ case 3:
+ tmpStr = _characterGuiStringsWp[1];
+ break;
+ case 4:
+ tmpStr = _characterGuiStringsWp[0];
+ break;
+ default:
+ tmpStr = Common::String::format("%d", status);
+ break;
+ }
+
+ int textColor= (_configRenderMode == Common::kRenderCGA) ? 2 : 15;
+
+ if (!tmpStr2.empty()) {
+ _screen->printText(tmpStr.c_str(), x + (16 - tmpStr.size() * 3), y + 2, textColor, 0);
+ _screen->printText(tmpStr2.c_str(), x + (16 - tmpStr.size() * 3), y + 9, textColor, 0);
+ } else {
+ _screen->printText(tmpStr.c_str(), x + (16 - tmpStr.size() * 3), y + 5, textColor, 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 (_configHpBarGraphs) {
+ 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], guiSettings()->colors.barGraph);
+
+ } else {
+ Common::String tmpString = Common::String::format(_characterGuiStringsHp[1], c->hitPointsCur, c->hitPointsMax);
+
+ if (!_currentControlMode) {
+ x -= 13;
+ y -= 1;
+ }
+
+ _screen->printText(tmpString.c_str(), x, y, 12, guiSettings()->colors.fill);
+ }
+}
+
+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, guiSettings()->colors.barGraph);
+}
+
+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, guiSettings()->colors.frame2, guiSettings()->colors.frame1, -1);
+ KyraRpgEngine::gui_drawHorizontalBarGraph(x, y, w + 2, h, curVal, maxVal, col1, col2);
+}
+
+void EoBCoreEngine::gui_drawCharPortraitStatusFrame(int index) {
+ uint8 redGreenColor = (_partyEffectFlags & 0x20000) ? 4 : ((_configRenderMode == Common::kRenderCGA) ? 3 : 6);
+
+ static const uint8 xCoords[] = { 8, 80 };
+ static const uint8 yCoords[] = { 2, 54, 106 };
+ int x = xCoords[index & 1];
+ int y = yCoords[index >> 1];
+ int xOffset = (_configRenderMode == Common::kRenderCGA) ? 0 : 1;
+
+ if (!_screen->_curPage)
+ x += 176;
+
+ EoBCharacter *c = &_characters[index];
+
+ bool redGreen = ((c->effectFlags & 0x4818) || (_partyEffectFlags & 0x20000) || c->effectsRemainder[0] || c->effectsRemainder[1]) ? true : false;
+ bool yellow = ((c->effectFlags & 0x13000) || (_partyEffectFlags & 0x8420)) ? true : false;
+
+ if (redGreen || yellow) {
+ if (redGreen && !yellow) {
+ _screen->drawBox(x, y, x + 63, y + 49, redGreenColor);
+ return;
+ }
+
+ if (yellow && !redGreen) {
+ _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 (redGreen) {
+ _screen->drawClippedLine(x, y, x + 7, y, redGreenColor);
+ _screen->drawClippedLine(x + 8, y + 49, x + 15, y + 49, redGreenColor);
+ }
+ if (yellow) {
+ _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 (yellow) {
+ _screen->drawClippedLine(x, y + 1, x, y + 6, 5);
+ _screen->drawClippedLine(x + 63, y + 7, x + 63, y + 12, 5);
+ }
+ if (redGreen) {
+ _screen->drawClippedLine(x, y + 7, x, y + 12, redGreenColor);
+ _screen->drawClippedLine(x + 63, y + 1, x + 63, y + 6, redGreenColor);
+ }
+ }
+
+ } else {
+ _screen->drawClippedLine(x, y, x + 62, y, guiSettings()->colors.frame2);
+ _screen->drawClippedLine(x, y + 49, x + 62, y + 49, guiSettings()->colors.frame1);
+ _screen->drawClippedLine(x - xOffset, y, x - xOffset, 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;
+
+ uint8 col1 = guiSettings()->colors.frame1;
+ uint8 col2 = guiSettings()->colors.frame2;
+ if (_configRenderMode == Common::kRenderCGA ) {
+ col1 = 1;
+ col2 = 3;
+ }
+
+ gui_drawBox(x - 1, y - 1, wh, wh, col1, col2, slot == 16 ? -1 : guiSettings()->colors.fill);
+
+ 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;
+ Common::String str = Common::String::format("%d", cnt);
+ _screen->printText(str.c_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, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ 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 = 0;
+ int col2 = 1;
+ int col3 = 2;
+
+ if (_configRenderMode == Common::kRenderCGA) {
+ if (i == _openBookSpellLevel) {
+ col1 = 1;
+ col2 = 2;
+ col3 = 3;
+ }
+ } else {
+ col1 = guiSettings()->colors.inactiveTabFrame1;
+ col2 = guiSettings()->colors.inactiveTabFrame2;
+ col3 = guiSettings()->colors.inactiveTabFill;
+
+ if (i == _openBookSpellLevel) {
+ col1 = guiSettings()->colors.frame1;
+ col2 = guiSettings()->colors.frame2;
+ col3 = guiSettings()->colors.fill;
+ }
+ }
+
+ 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);
+ _screen->printText(Common::String::format("%d", i + 1).c_str(), i * 18 + 75, 123, 12, 0);
+ }
+ }
+
+ if (_flags.gameID == GI_EOB1)
+ gui_drawBox(71, 131, 105, 44, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ else {
+ gui_drawBox(68, 130, 108, 47, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ gui_drawBox(68, 168, 78, 9, guiSettings()->colors.extraFrame1, guiSettings()->colors.extraFrame2, guiSettings()->colors.extraFill);
+ gui_drawBox(146, 168, 14, 9, guiSettings()->colors.extraFrame1, guiSettings()->colors.extraFrame2, guiSettings()->colors.extraFill);
+ gui_drawBox(160, 168, 16, 9, guiSettings()->colors.extraFrame1, guiSettings()->colors.extraFrame2, guiSettings()->colors.extraFill);
+ gui_drawSpellbookScrollArrow(150, 169, 0);
+ gui_drawSpellbookScrollArrow(165, 169, 1);
+ }
+
+ int textCol1 = (_configRenderMode == Common::kRenderCGA) ? 3 : 15;
+ int textCol2 = 8;
+ int textXa = 74;
+ int textXs = 71;
+ int textY = 170;
+ int col3 = (_configRenderMode == Common::kRenderCGA) ? 2 : guiSettings()->colors.fill;
+ int col4 = guiSettings()->colors.extraFill;
+ int col5 = 12;
+
+ if (_flags.gameID == GI_EOB1) {
+ textCol2 = (_configRenderMode == Common::kRenderCGA) ? 12 : 11;
+ textXa = textXs = 73;
+ textY = 168;
+ col4 = col3;
+ col5 = textCol1;
+ }
+
+ 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, col5, col4);
+ }
+ }
+
+ 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);
+ if (!_loading)
+ _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];
+ b->buttonCallback = _buttonCallbacks[index];
+
+ if (_flags.gameID == GI_EOB1) {
+ // EOB1 spellbook modifications
+ if (index > 60 && index < 66) {
+ d = &_buttonDefs[index + 34];
+ b->buttonCallback = _buttonCallbacks[index + 34];
+ } else if (index == 88) {
+ d = &_buttonDefs[index + 12];
+ b->buttonCallback = _buttonCallbacks[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;
+}
+
+int EoBCoreEngine::clickedCharPortraitDefault(Button *button) {
+ if (!testCharacter(button->arg, 1))
+ return 1;
+
+ gui_processCharPortraitClick(button->arg);
+ return 0;
+}
+
+int EoBCoreEngine::clickedCamp(Button *button) {
+ gui_updateControls();
+ disableSysTimer(2);
+ int cd = _screen->curDimIndex();
+
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+ _characters[i].damageTaken = 0;
+ _characters[i].slotStatus[0] = _characters[i].slotStatus[1] = 0;
+ gui_drawCharPortraitWithStats(i);
+ }
+
+ _screen->copyPage(0, 7);
+ _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, _useHiResDithering ? 1 : 12, Screen::CR_NO_P_CHECK);
+
+ _gui->runCampMenu();
+
+ _screen->copyRegion(0, 0, 0, 120, 176, 24, _useHiResDithering ? 1 : 12, 2, Screen::CR_NO_P_CHECK);
+ _screen->setScreenDim(cd);
+ drawScene(0);
+
+ for (int i = 0; i < 6; i++)
+ sortCharacterSpellList(i);
+
+ _screen->setCurPage(0);
+ const ScreenDim *dm = _screen->getScreenDim(10);
+ _screen->copyRegion(dm->sx << 3, dm->sy, dm->sx << 3, dm->sy, dm->w << 3, dm->h, 2, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->updateScreen();
+
+ enableSysTimer(2);
+ advanceTimers(_restPartyElapsedTime);
+ _restPartyElapsedTime = 0;
+
+ checkPartyStatus(true);
+
+ 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;
+
+ // Fix this using the coordinates from gui_drawWeaponSlot().
+ // The coordinates used in the original are slightly wrong
+ // (most noticeable for characters 5 and 6).
+ static const uint8 sY[] = { 27, 27, 79, 79, 131, 131 };
+ 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;
+ exchangeCharacters(d, button->arg);
+
+ _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 += _clericSpellOffset;
+
+ 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) {
+ _activeSpellCharId = button->arg & 0xff;
+
+ if (_activeSpellCharId == 0xff) {
+ printWarning(_magicStrings3[_flags.gameID == GI_EOB1 ? 2 : 1]);
+ if (_castScrollSlot) {
+ gui_updateSlotAfterScrollUse();
+ } else {
+ gui_toggleButtons();
+ gui_drawSpellbook();
+ }
+ } else {
+ if (_characters[_activeSpellCharId].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, _useHiResDithering ? 4 : 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) {
+ if (!testCharacter(charIndex, 0x0d))
+ return;
+
+ Item 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(_itemMisuseStrings[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(_itemMisuseStrings[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(_itemMisuseStrings[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 (we don't support anything else)
+ // eatItemInHand(charIndex);
+ break;
+
+ case 10:
+ if (_flags.gameID == GI_EOB1)
+ vl += _clericSpellOffset;
+ // drop through
+ 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:
+ useWand(charIndex, wslot);
+ break;
+
+ case 19:
+ // eob2 horn
+ useHorn(charIndex, wslot);
+ break;
+
+ case 20:
+ if (vl == 1)
+ inflictCharacterDamage(charIndex, 200);
+ else
+ useMagicScroll(charIndex, 55, wslot);
+ deleteInventoryItem(charIndex, wslot);
+ break;
+
+ default:
+ break;
+ }
+
+ if (_flags.gameID == GI_EOB1 || (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) {
+ _menuStringsPrefsTemp = new char*[4];
+ memset(_menuStringsPrefsTemp, 0, 4 * sizeof(char *));
+
+ _saveSlotStringsTemp = new char*[6];
+ for (int i = 0; i < 6; i++) {
+ _saveSlotStringsTemp[i] = new char[20];
+ memset(_saveSlotStringsTemp[i], 0, 20);
+ }
+ _saveSlotIdTemp = new int16[6];
+ _savegameOffset = 0;
+ _saveSlotX = _saveSlotY = 0;
+
+ _specialProcessButton = _backupButtonList = 0;
+ _flagsMouseLeft = _flagsMouseRight = _flagsModifier = 0;
+ _backupButtonList = 0;
+ _progress = 0;
+ _prcButtonUnk3 = 1;
+ _cflag = 0xffff;
+
+ _menuLineSpacing = 0;
+ _menuLastInFlags = 0;
+ _menuCur = 0;
+ _menuNumItems = 0;
+
+ _numPages = (_vm->game() == GI_EOB2) ? 8 : 5;
+ _numVisPages = (_vm->game() == GI_EOB2) ? 6 : 5;
+ _clericSpellAvltyFlags = (_vm->game() == GI_EOB2) ? 0xf7ffffff : 0x7bffff;
+ _paladinSpellAvltyFlags = (_vm->game() == GI_EOB2) ? 0xa9bbd1d : 0x800ff2;
+ _numAssignedSpellsOfType = new int8[72];
+ memset(_numAssignedSpellsOfType, 0, 72);
+
+ _charSelectRedraw = false;
+
+ _highLightColorTable = (_vm->game() == GI_EOB1 && (_vm->_configRenderMode == Common::kRenderCGA || _vm->_configRenderMode == Common::kRenderEGA)) ? _highlightColorTableEGA : _highlightColorTableVGA;
+ _updateBoxIndex = -1;
+ _highLightBoxTimer = 0;
+ _updateBoxColorIndex = 0;
+
+ _needRest = false;
+}
+
+GUI_EoB::~GUI_EoB() {
+ if (_menuStringsPrefsTemp) {
+ for (int i = 0; i < 4; i++)
+ delete[] _menuStringsPrefsTemp[i];
+ delete[] _menuStringsPrefsTemp;
+ }
+
+ if (_saveSlotStringsTemp) {
+ for (int i = 0; i < 6; i++)
+ delete[] _saveSlotStringsTemp[i];
+ delete[] _saveSlotStringsTemp;
+ }
+
+ delete[] _saveSlotIdTemp;
+
+ delete[] _numAssignedSpellsOfType;
+}
+
+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)(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)(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)(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)(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)(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;
+ //_vm->_processingButtons = true;
+ _flagsMouseLeft = (_vm->_mouseClick == 1) ? 2 : 4;
+ _flagsMouseRight = (_vm->_mouseClick == 2) ? 2 : 4;
+ _vm->_mouseClick = 0;
+
+ if (mouseWheel) {
+ return 204 + mouseWheel;
+ } else 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 if (inputFlags & 0x8000) {
+ 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 == inputFlags) {
+ _progress = 1;
+ _flagsMouseLeft = 1;
+ flgs2 ^= 1;
+ result = iFlag;
+ v6 = 1;
+ } else if (buttonList->keyCode2 == inputFlags) {
+ _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)(buttonList);
+
+ 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::simpleMenu_setup(int sd, int maxItem, const char *const *strings, int32 menuItemsMask, int itemOffset, int lineSpacing) {
+ simpleMenu_initMenuItemsMask(sd, maxItem, menuItemsMask, itemOffset);
+
+ const ScreenDim *dm = _screen->getScreenDim(19 + sd);
+ int x = (_screen->_curDim->sx + dm->sx) << 3;
+ int y = _screen->_curDim->sy + dm->sy;
+
+ int v = simpleMenu_getMenuItem(_menuCur, menuItemsMask, itemOffset);
+
+ for (int i = 0; i < _menuNumItems; i++) {
+ int item = simpleMenu_getMenuItem(i, menuItemsMask, itemOffset);
+ int ty = y + i * (lineSpacing + _screen->getFontHeight());
+ _screen->printShadedText(strings[item], x, ty, (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : dm->unkA, 0);
+ if (item == v)
+ _screen->printText(strings[item], x, ty, dm->unkC, 0);
+ }
+
+ _screen->updateScreen();
+ _menuLineSpacing = lineSpacing;
+ _menuLastInFlags = 0;
+ _vm->removeInputTop();
+}
+
+int GUI_EoB::simpleMenu_process(int sd, const char *const *strings, void *b, int32 menuItemsMask, int itemOffset) {
+ 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[simpleMenu_getMenuItem(currentItem, menuItemsMask, itemOffset)], x, y + currentItem * lineH, (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : dm->unkA, 0);
+ _screen->printText(strings[simpleMenu_getMenuItem(newItem, menuItemsMask, itemOffset)], x, y + newItem * lineH , dm->unkC, 0);
+ _screen->updateScreen();
+ }
+
+ if (result != -1) {
+ result = simpleMenu_getMenuItem(result, menuItemsMask, itemOffset);
+ simpleMenu_flashSelection(strings[result], x, y + newItem * lineH, dm->unkA, dm->unkC, 0);
+ }
+
+ _menuCur = newItem;
+
+ return result;
+}
+
+int GUI_EoB::simpleMenu_getMenuItem(int index, int32 menuItemsMask, int itemOffset) {
+ if (menuItemsMask == -1)
+ return index;
+
+ int res = 0;
+ int i = index;
+
+ for (; i; res++) {
+ if (menuItemsMask & (1 << (res + itemOffset)))
+ i--;
+ }
+
+ while (!(menuItemsMask & (1 << (res + itemOffset))))
+ res++;
+
+ return res;
+}
+
+void GUI_EoB::simpleMenu_flashSelection(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);
+ }
+}
+
+void GUI_EoB::runCampMenu() {
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+
+ Button *highlightButton = 0;
+ Button *prevHighlightButton = 0;
+
+ int newMenu = 0;
+ int lastMenu = -1;
+ bool redrawPortraits = false;
+
+ _charSelectRedraw = false;
+ _needRest = false;
+ Button *buttonList = 0;
+
+ for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
+ if (newMenu == 2)
+ updateOptionsStrings();
+
+ if (newMenu != -1) {
+ releaseButtons(buttonList);
+
+ _vm->_menuDefs[0].titleStrId = newMenu ? 1 : 56;
+ if (newMenu == 2)
+ _vm->_menuDefs[2].titleStrId = 57;
+ else if (newMenu == 1)
+ _vm->_menuDefs[1].titleStrId = 58;
+
+ buttonList = initMenu(newMenu);
+
+ if (newMenu != lastMenu) {
+ highlightButton = buttonList;
+ prevHighlightButton = 0;
+ }
+
+ lastMenu = newMenu;
+ newMenu = -1;
+ }
+
+ int inputFlag = _vm->checkInput(buttonList, false, 0) & 0x80ff;
+ _vm->removeInputTop();
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE])
+ inputFlag = 0x8007;
+ else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP5] || inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN]) {
+ inputFlag = 0x8000 + prevHighlightButton->index;
+ }
+
+ Button *clickedButton = _vm->gui_getButton(buttonList, inputFlag & 0x7fff);
+
+ if (clickedButton) {
+ drawMenuButton(prevHighlightButton, false, false, true);
+ drawMenuButton(clickedButton, true, true, true);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(80);
+ drawMenuButton(clickedButton, false, true, true);
+ _screen->updateScreen();
+ highlightButton = clickedButton;
+ prevHighlightButton = 0;
+ }
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP3] || inputFlag == _vm->_keyMap[Common::KEYCODE_PAGEDOWN] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP1] || inputFlag == _vm->_keyMap[Common::KEYCODE_END]) {
+ highlightButton = _vm->gui_getButton(buttonList, _vm->_menuDefs[lastMenu].firstButtonStrId + _vm->_menuDefs[lastMenu].numButtons);
+ inputFlag = _vm->_keyMap[Common::KEYCODE_UP];
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP7] || inputFlag == _vm->_keyMap[Common::KEYCODE_HOME] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP9] || inputFlag == _vm->_keyMap[Common::KEYCODE_PAGEUP]) {
+ highlightButton = _vm->gui_getButton(buttonList, _vm->_menuDefs[lastMenu].firstButtonStrId + 1);
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP8] || inputFlag == _vm->_keyMap[Common::KEYCODE_UP] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP2] || inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN]) {
+ if (prevHighlightButton) {
+ int dir = (inputFlag == _vm->_keyMap[Common::KEYCODE_UP]) ? -1 : 1;
+ int s = prevHighlightButton->index + dir;
+ int a = _vm->_menuDefs[lastMenu].firstButtonStrId + 1;
+ int b = a + _vm->_menuDefs[lastMenu].numButtons - 1;
+
+ do {
+ if (s < a)
+ s = b;
+ if (s > b)
+ s = a;
+ if (_vm->_menuButtonDefs[s - 1].flags & 2)
+ break;
+ s += dir;
+ } while (!_vm->shouldQuit());
+
+ highlightButton = _vm->gui_getButton(buttonList, s);
+ }
+
+ } else if (inputFlag > 0x8000 && inputFlag < 0x8010) {
+ int i = 0;
+ int cnt = 0;
+
+ switch (inputFlag) {
+ case 0x8001:
+ if (restParty())
+ runLoop = false;
+ else
+ _needRest = false;
+ redrawPortraits = true;
+ newMenu = 0;
+ break;
+
+ case 0x8002:
+ runMemorizePrayMenu(selectCharacterDialogue(23), 0);
+ newMenu = 0;
+ break;
+
+ case 0x8003:
+ runMemorizePrayMenu(selectCharacterDialogue(26), 1);
+ newMenu = 0;
+ break;
+
+ case 0x8004:
+ scribeScrollDialogue();
+ newMenu = 0;
+ break;
+
+ case 0x8005:
+ newMenu = 2;
+ break;
+
+ case 0x8006:
+ newMenu = 1;
+ break;
+
+ case 0x8007:
+ if (_needRest)
+ displayTextBox(44);
+ // fall through
+
+ case 0x800c:
+ case 0x800f:
+ if (lastMenu == 1 || lastMenu == 2)
+ newMenu = 0;
+ else if (inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE])
+ newMenu = 0;
+ else
+ runLoop = false;
+ break;
+
+ case 0x8008:
+ if (runLoadMenu(0, 0))
+ runLoop = false;
+ else
+ newMenu = 1;
+ break;
+
+ case 0x8009:
+ if (runSaveMenu(0, 0))
+ displayTextBox(14);
+ newMenu = 1;
+ break;
+
+ case 0x800a:
+ for (; i < 6; i++) {
+ if (_vm->testCharacter(i, 1))
+ cnt++;
+ }
+
+ if (cnt > 4) {
+ _vm->dropCharacter(selectCharacterDialogue(53));
+ _vm->gui_drawPlayField(false);
+ _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, _vm->_useHiResDithering ? 1 : 12, Screen::CR_NO_P_CHECK);
+ _screen->setFont(Screen::FID_6_FNT);
+ _vm->gui_drawAllCharPortraitsWithStats();
+ _screen->setFont(Screen::FID_8_FNT);
+ } else {
+ displayTextBox(45);
+ }
+
+ newMenu = 0;
+ break;
+
+ case 0x800b:
+ if (confirmDialogue(46))
+ _vm->quitGame();
+ newMenu = 0;
+ break;
+
+ case 0x800d:
+ _vm->_configSounds ^= true;
+ _vm->_configMusic = _vm->_configSounds ? 1 : 0;
+ newMenu = 2;
+ break;
+
+ case 0x800e:
+ _vm->_configHpBarGraphs ^= true;
+ newMenu = 2;
+ redrawPortraits = true;
+ break;
+
+ default:
+ break;
+ }
+
+ lastMenu = -1;
+
+ } else {
+ Common::Point p = _vm->getMousePos();
+ for (Button *b = buttonList; b; b = b->nextButton) {
+ if ((b->arg & 2) && _vm->posWithinRect(p.x, p.y, b->x, b->y, b->x + b->width, b->y + b->height))
+ highlightButton = b;
+ }
+ }
+
+ if (_charSelectRedraw || redrawPortraits) {
+ for (int i = 0; i < 6; i++) {
+ _vm->gui_drawCharPortraitWithStats(i);
+ _vm->sortCharacterSpellList(i);
+ }
+ }
+
+ _charSelectRedraw = redrawPortraits = false;
+
+ if (prevHighlightButton != highlightButton && newMenu == -1 && runLoop) {
+ drawMenuButton(prevHighlightButton, false, false, true);
+ drawMenuButton(highlightButton, false, true, true);
+ _screen->updateScreen();
+ prevHighlightButton = highlightButton;
+ }
+ }
+
+ _screen->setFont(of);
+ releaseButtons(buttonList);
+ _vm->writeSettings();
+}
+
+bool GUI_EoB::runLoadMenu(int x, int y) {
+ const ScreenDim *dm = _screen->getScreenDim(11);
+ int xo = dm->sx;
+ int yo = dm->sy;
+ bool result = false;
+
+ _screen->modifyScreenDim(11, dm->sx + (x >> 3), dm->sy + y, dm->w, dm->h);
+
+ for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
+ updateSaveSlotsList(_vm->_targetName);
+ int slot = selectSaveSlotDialogue(x, y, 1);
+ if (slot > 5) {
+ runLoop = result = false;
+ } else if (slot >= 0) {
+ if (_saveSlotIdTemp[slot] == -1) {
+ messageDialogue(11, 65, 6);
+ } else {
+ if (_vm->loadGameState(_saveSlotIdTemp[slot]).getCode() != Common::kNoError)
+ messageDialogue(11, 16, 6);
+ runLoop = false;
+ result = true;
+ }
+ }
+ }
+
+ _screen->modifyScreenDim(11, xo, yo, dm->w, dm->h);
+ return result;
+}
+
+bool GUI_EoB::confirmDialogue2(int dim, int id, int deflt) {
+ int od = _screen->curDimIndex();
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+ _screen->setScreenDim(dim);
+
+ drawTextBox(dim, id);
+
+ int16 x[2];
+ x[0] = (_screen->_curDim->sx << 3) + 8;
+ x[1] = (_screen->_curDim->sx + _screen->_curDim->w - 5) << 3;
+ int16 y = _screen->_curDim->sy + _screen->_curDim->h - 21;
+ int newHighlight = deflt ^ 1;
+ int lastHighlight = -1;
+
+ for (int i = 0; i < 2; i++)
+ drawMenuButtonBox(x[i], y, 32, 14, false, false);
+
+ for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
+ Common::Point p = _vm->getMousePos();
+ if (_vm->posWithinRect(p.x, p.y, x[0], y, x[0] + 32, y + 14))
+ newHighlight = 0;
+ else if (_vm->posWithinRect(p.x, p.y, x[1], y, x[1] + 32, y + 14))
+ newHighlight = 1;
+
+ int inputFlag = _vm->checkInput(0, false, 0) & 0x8ff;
+ _vm->removeInputTop();
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN]) {
+ runLoop = false;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_LEFT] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP4] || inputFlag == _vm->_keyMap[Common::KEYCODE_RIGHT] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP6]) {
+ newHighlight ^= 1;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_n]) {
+ newHighlight = 1;
+ runLoop = false;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_y]) {
+ newHighlight = 0;
+ runLoop = false;
+ } else if (inputFlag == 199 || inputFlag == 201) {
+ if (_vm->posWithinRect(p.x, p.y, x[0], y, x[0] + 32, y + 14)) {
+ newHighlight = 0;
+ runLoop = false;
+ } else if (_vm->posWithinRect(p.x, p.y, x[1], y, x[1] + 32, y + 14)) {
+ newHighlight = 1;
+ runLoop = false;
+ }
+ }
+
+ if (newHighlight != lastHighlight) {
+ for (int i = 0; i < 2; i++)
+ _screen->printShadedText(_vm->_menuYesNoStrings[i], x[i] + 16 - (strlen(_vm->_menuYesNoStrings[i]) << 2) + 1, y + 3, i == newHighlight ? 6 : 15, 0);
+ _screen->updateScreen();
+ lastHighlight = newHighlight;
+ }
+ }
+
+ drawMenuButtonBox(x[newHighlight], y, 32, 14, true, true);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(80);
+ drawMenuButtonBox(x[newHighlight], y, 32, 14, false, true);
+ _screen->updateScreen();
+
+ _screen->copyRegion(0, _screen->_curDim->h, _screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->setFont(of);
+ _screen->setScreenDim(od);
+
+ return newHighlight == 0;
+}
+
+void GUI_EoB::messageDialogue(int dim, int id, int buttonTextCol) {
+ int od = _screen->curDimIndex();
+ _screen->setScreenDim(dim);
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+
+ drawTextBox(dim, id);
+ const ScreenDim *dm = _screen->getScreenDim(dim);
+
+ int bx = ((dm->sx + dm->w) << 3) - ((strlen(_vm->_menuOkString) << 3) + 16);
+ int by = dm->sy + dm->h - 19;
+ int bw = (strlen(_vm->_menuOkString) << 3) + 7;
+
+ drawMenuButtonBox(bx, by, bw, 14, false, false);
+ _screen->printShadedText(_vm->_menuOkString, bx + 4, by + 3, buttonTextCol, 0);
+ _screen->updateScreen();
+
+ for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
+ int inputFlag = _vm->checkInput(0, false, 0) & 0x8ff;
+ _vm->removeInputTop();
+
+ if (inputFlag == 199 || inputFlag == 201) {
+ if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, bx, by, bx + bw, by + 14))
+ runLoop = false;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN] || inputFlag == _vm->_keyMap[Common::KEYCODE_o]) {
+ runLoop = false;
+ }
+ }
+
+ drawMenuButtonBox(bx, by, bw, 14, true, true);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(80);
+ drawMenuButtonBox(bx, by, bw, 14, false, true);
+ _screen->updateScreen();
+
+ _screen->copyRegion(0, dm->h, dm->sx << 3, dm->sy, dm->w << 3, dm->h, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->setScreenDim(od);
+ _screen->setFont(of);
+ dm = _screen->getScreenDim(dim);
+}
+
+void GUI_EoB::messageDialogue2(int dim, int id, int buttonTextCol) {
+ drawMenuButtonBox(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, false, false);
+
+ _screen->_curPage = 2;
+ _screen->setClearScreenDim(dim);
+ drawMenuButtonBox(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, false, false);
+ _screen->printShadedText(getMenuString(id), (_screen->_curDim->sx << 3) + 5, _screen->_curDim->sy + 5, 15, 0);
+ _screen->_curPage = 0;
+ _screen->copyRegion(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, 2, 0, Screen::CR_NO_P_CHECK);
+
+ int x = (_screen->_curDim->sx << 3) + (_screen->_curDim->w << 2) - (strlen(_vm->_menuOkString) << 2);
+ int y = _screen->_curDim->sy + _screen->_curDim->h - 21;
+ int w = (strlen(_vm->_menuOkString) << 3) + 8;
+ drawMenuButtonBox(x, y, w, 14, false, false);
+ _screen->printShadedText(_vm->_menuOkString, x + 4, y + 3, buttonTextCol, 0);
+ _screen->updateScreen();
+
+ for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
+ int inputFlag = _vm->checkInput(0, false, 0) & 0x8ff;
+ _vm->removeInputTop();
+
+ if (inputFlag == 199 || inputFlag == 201) {
+ if (_vm->posWithinRect(_vm->_mouseX, _vm->_mouseY, x, y, x + w, y + 14))
+ runLoop = false;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN] || inputFlag == _vm->_keyMap[Common::KEYCODE_o]) {
+ runLoop = false;
+ }
+ }
+
+ _vm->gui_drawBox(x, y, w, 14, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill, -1);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(80);
+ drawMenuButtonBox(x, y, w, 14, false, false);
+ _screen->printShadedText(_vm->_menuOkString, x + 4, y + 3, buttonTextCol, 0);
+ _screen->updateScreen();
+
+}
+
+void GUI_EoB::updateBoxFrameHighLight(int box) {
+ if (_updateBoxIndex == box) {
+ if (_updateBoxIndex == -1)
+ return;
+
+ if (_vm->_system->getMillis() <= _highLightBoxTimer)
+ return;
+
+ if (!_highLightColorTable[_updateBoxColorIndex])
+ _updateBoxColorIndex = 0;
+
+ const EoBRect16 *r = &_highlightFrames[_updateBoxIndex];
+ _screen->drawBox(r->x1, r->y1, r->x2, r->y2, _highLightColorTable[_updateBoxColorIndex++]);
+ _screen->updateScreen();
+
+ _highLightBoxTimer = _vm->_system->getMillis() + _vm->_tickLength;
+
+ } else {
+ if (_updateBoxIndex != -1) {
+ const EoBRect16 *r = &_highlightFrames[_updateBoxIndex];
+ _screen->drawBox(r->x1, r->y1, r->x2, r->y2, 12);
+ _screen->updateScreen();
+ }
+
+ _updateBoxColorIndex = 0;
+ _updateBoxIndex = box;
+ _highLightBoxTimer = _vm->_system->getMillis();
+ }
+}
+
+int GUI_EoB::getTextInput(char *dest, int x, int y, int destMaxLen, int textColor1, int textColor2, int cursorColor) {
+#ifdef ENABLE_KEYMAPPER
+ Common::Keymapper *const keymapper = _vm->getEventManager()->getKeymapper();
+ keymapper->pushKeymap(Common::kGlobalKeymapName);
+#endif
+
+ 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 && !_vm->shouldQuit()) {
+ 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 && !_vm->shouldQuit());
+
+#ifdef ENABLE_KEYMAPPER
+ keymapper->popKeymap(Common::kGlobalKeymapName);
+#endif
+
+ return _keyPressed.keycode == Common::KEYCODE_ESCAPE ? -1 : len;
+}
+
+void GUI_EoB::transferWaitBox() {
+ const ScreenDim *dm = _screen->getScreenDim(11);
+ int xo = dm->sx;
+ int yo = dm->sy;
+ _screen->modifyScreenDim(11, dm->sx + 9, dm->sy + 24, dm->w, dm->h);
+ displayTextBox(-4);
+ _screen->modifyScreenDim(11, xo, yo, dm->w, dm->h);
+}
+
+Common::String GUI_EoB::transferTargetMenu(Common::Array<Common::String> &targets) {
+ if (_savegameList) {
+ for (int i = 0; i < _savegameListSize; i++)
+ delete[] _savegameList[i];
+ delete[] _savegameList;
+ }
+
+ _savegameListSize = targets.size();
+ _savegameList = new char*[_savegameListSize];
+ memset(_savegameList, 0, _savegameListSize * sizeof(char *));
+
+ Common::StringArray::iterator ii = targets.begin();
+ for (int i = 0; i < _savegameListSize; ++i) {
+ _savegameList[i] = new char[(*ii).size() + 1];
+ strcpy(_savegameList[i], (*ii++).c_str());
+ }
+
+ const ScreenDim *dm = _screen->getScreenDim(11);
+ int xo = dm->sx;
+ int yo = dm->sy;
+ _screen->modifyScreenDim(11, dm->sx + 9, dm->sy + 14, dm->w, dm->h);
+
+ int slot = 0;
+ do {
+ slot = selectSaveSlotDialogue(72, 14, 2);
+ if (slot == 6)
+ break;
+ } while (_saveSlotIdTemp[slot] == -1);
+
+ _screen->copyRegion(72, 14, 72, 14, 176, 144, _vm->_useHiResDithering ? 7 : 12, 0, Screen::CR_NO_P_CHECK);
+ _screen->modifyScreenDim(11, xo, yo, dm->w, dm->h);
+
+ return (slot < 6) ? _savegameList[_savegameOffset + slot] : Common::String();
+}
+
+bool GUI_EoB::transferFileMenu(Common::String &targetName, Common::String &selection) {
+ updateSaveSlotsList(targetName, true);
+ _saveSlotsListUpdateNeeded = true;
+ selection.clear();
+
+ if (!_savegameListSize)
+ return false;
+
+ const ScreenDim *dm = _screen->getScreenDim(11);
+ int xo = dm->sx;
+ int yo = dm->sy;
+ _screen->modifyScreenDim(11, dm->sx + 9, dm->sy + 14, dm->w, dm->h);
+
+ int slot = 0;
+ do {
+ slot = selectSaveSlotDialogue(72, 14, 4);
+ if (slot == 6)
+ break;
+
+ if (_saveSlotIdTemp[slot] == -1)
+ messageDialogue(11, 65, 6);
+ else {
+ _screen->modifyScreenDim(11, xo, yo, dm->w, dm->h);
+ selection = _vm->getSavegameFilename(targetName, _saveSlotIdTemp[slot]);
+ return true;
+ }
+ } while (_saveSlotIdTemp[slot] == -1);
+
+ _screen->modifyScreenDim(11, xo, yo, dm->w, dm->h);
+ return true;
+}
+
+void GUI_EoB::createScreenThumbnail(Graphics::Surface &dst) {
+ uint8 *screenPal = new uint8[768];
+ _screen->getRealPalette(0, screenPal);
+ uint16 width = Screen::SCREEN_W;
+ uint16 height = Screen::SCREEN_H;
+ if (_vm->_useHiResDithering) {
+ width <<= 1;
+ height <<= 1;
+ }
+
+ ::createThumbnail(&dst, _screen->getCPagePtr(7), width, height, screenPal);
+ delete[] screenPal;
+}
+
+void GUI_EoB::simpleMenu_initMenuItemsMask(int menuId, int maxItem, int32 menuItemsMask, int itemOffset) {
+ 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 + itemOffset)))
+ _menuNumItems++;
+ }
+
+ _menuCur = 0;
+}
+
+bool GUI_EoB::runSaveMenu(int x, int y) {
+ const ScreenDim *dm = _screen->getScreenDim(11);
+ int xo = dm->sx;
+ int yo = dm->sy;
+ bool result = false;
+
+ _screen->modifyScreenDim(11, dm->sx + (x >> 3), dm->sy + y, dm->w, dm->h);
+
+ for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
+ updateSaveSlotsList(_vm->_targetName);
+ int slot = selectSaveSlotDialogue(x, y, 0);
+ if (slot > 5) {
+ runLoop = result = false;
+ } else if (slot >= 0) {
+ bool useSlot = (_saveSlotIdTemp[slot] == -1);
+ if (useSlot)
+ _saveSlotStringsTemp[slot][0] = 0;
+ else
+ useSlot = confirmDialogue2(11, 55, 1);
+
+ if (!useSlot)
+ continue;
+
+ int fx = (x + 1) << 3;
+ int fy = y + slot * 17 + 23;
+
+ for (int in = -1; in == -1 && !_vm->shouldQuit();) {
+ _screen->fillRect(fx - 2, fy, fx + 160, fy + 8, _vm->guiSettings()->colors.fill);
+ in = getTextInput(_saveSlotStringsTemp[slot], x + 1, fy, 19, 2, 0, 8);
+ if (!strlen(_saveSlotStringsTemp[slot])) {
+ messageDialogue(11, 54, 6);
+ in = -1;
+ }
+ };
+
+ _screen->fillRect(fx - 2, fy, fx + 160, fy + 8, _vm->guiSettings()->colors.fill);
+ _screen->printShadedText(_saveSlotStringsTemp[slot], (x + 1) << 3, fy, 15, 0);
+
+ Graphics::Surface thumb;
+ createScreenThumbnail(thumb);
+ Common::Error err = _vm->saveGameStateIntern(_savegameOffset + slot, _saveSlotStringsTemp[slot], &thumb);
+ thumb.free();
+
+ if (err.getCode() == Common::kNoError)
+ result = true;
+ else
+ messageDialogue(11, 15, 6);
+
+ runLoop = false;
+ }
+ }
+
+ _screen->modifyScreenDim(11, xo, yo, dm->w, dm->h);
+ return result;
+}
+
+int GUI_EoB::selectSaveSlotDialogue(int x, int y, int id) {
+ _saveSlotX = _saveSlotY = 0;
+ int col1 = (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : 15;
+ _screen->setCurPage(2);
+
+ _savegameOffset = 0;
+
+ drawMenuButtonBox(0, 0, 176, 144, false, false);
+ const char *title = (id < 2) ? _vm->_saveLoadStrings[2 + id] : _vm->_transferStringsScummVM[id - 1];
+ _screen->printShadedText(title, 52, 5, col1, 0);
+
+ _screen->copyRegion(0, 0, x, y, 176, 144, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->setCurPage(0);
+ _screen->updateScreen();
+
+ _saveSlotX = x;
+ _saveSlotY = y;
+ int lastHighlight = -1;
+ int lastOffset = -1;
+ int newHighlight = 0;
+ int slot = -1;
+
+ for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
+ int inputFlag = _vm->checkInput(0, false, 0) & 0x8ff;
+ _vm->removeInputTop();
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN]) {
+ runLoop = false;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE]) {
+ newHighlight = 6;
+ runLoop = false;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP2]) {
+ if (++newHighlight > 5) {
+ newHighlight = 5;
+ if (++_savegameOffset > 984)
+ _savegameOffset = 984;
+ else
+ lastOffset = -1;
+ }
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_UP] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP8]) {
+ if (--newHighlight < 0) {
+ newHighlight = 0;
+ if (--_savegameOffset < 0)
+ _savegameOffset = 0;
+ else
+ lastOffset = -1;
+ }
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_PAGEDOWN] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP1]) {
+ _savegameOffset += 6;
+ if (_savegameOffset > 984)
+ _savegameOffset = 984;
+ else
+ lastOffset = -1;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_PAGEUP] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP7]) {
+ _savegameOffset -= 6;
+ if (_savegameOffset < 0)
+ _savegameOffset = 0;
+ else
+ lastOffset = -1;
+ } else if (inputFlag == 205) {
+ if (++_savegameOffset > 984)
+ _savegameOffset = 984;
+ else
+ lastOffset = -1;
+ } else if (inputFlag == 203) {
+ if (--_savegameOffset < 0)
+ _savegameOffset = 0;
+ else
+ lastOffset = -1;
+ } else {
+ slot = getHighlightSlot();
+ if (slot != -1) {
+ newHighlight = slot;
+ if (inputFlag == 199)
+ runLoop = false;
+ }
+ }
+
+ if (lastOffset != _savegameOffset) {
+ lastHighlight = -1;
+ setupSaveMenuSlots();
+ for (int i = 0; i < 7; i++)
+ drawSaveSlotButton(i, 1, col1);
+ lastOffset = _savegameOffset;
+ }
+
+ if (lastHighlight != newHighlight) {
+ drawSaveSlotButton(lastHighlight, 0, col1);
+ drawSaveSlotButton(newHighlight, 0, 6);
+
+ // Display highlighted slot index in the bottom left corner to avoid people getting lost with the 990 save slots
+ _screen->setFont(Screen::FID_6_FNT);
+ int sli = (newHighlight == 6) ? _savegameOffset : (_savegameOffset + newHighlight);
+ _screen->printText(Common::String::format("%03d/989", sli).c_str(), _saveSlotX + 5, _saveSlotY + 135, _vm->guiSettings()->colors.frame2, _vm->guiSettings()->colors.fill);
+ _screen->setFont(Screen::FID_8_FNT);
+
+ _screen->updateScreen();
+ lastHighlight = newHighlight;
+ }
+ }
+
+ drawSaveSlotButton(newHighlight, 2, 6);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(80);
+ drawSaveSlotButton(newHighlight, 1, 6);
+ _screen->updateScreen();
+
+ return newHighlight;
+}
+
+void GUI_EoB::runMemorizePrayMenu(int charIndex, int spellType) {
+ if (charIndex == -1)
+ return;
+
+ uint8 np[8];
+ memset(np, 0, sizeof(np));
+ uint32 avltyFlags = 0;
+ int li = 0;
+ int lv = 0;
+
+ EoBCharacter *c = &_vm->_characters[charIndex];
+ int8 wm = c->wisdomCur - 12;
+ if (wm < 0)
+ wm = 0;
+
+ if (spellType) {
+ li = _vm->getCharacterLevelIndex(2, c->cClass);
+
+ if (li == -1) {
+ li = _vm->getCharacterLevelIndex(4, c->cClass);
+
+ if (li != -1) {
+ lv = c->level[li] - 1;
+ if (lv < 0)
+ lv = 0;
+
+ for (int i = 0; i < _numPages; i++)
+ np[i] = _vm->_numSpellsPal[lv * _numPages + i];
+
+ avltyFlags = _paladinSpellAvltyFlags;
+ }
+
+ } else {
+ lv = c->level[li] - 1;
+ for (int i = 0; i < _numPages; i++) {
+ np[i] = _vm->_numSpellsCleric[lv * _numPages + i];
+ if (np[i])
+ np[i] += _vm->_numSpellsWisAdj[wm * _numPages + i];
+ }
+ avltyFlags = _clericSpellAvltyFlags;
+ }
+
+ } else {
+ li = _vm->getCharacterLevelIndex(1, c->cClass);
+
+ if (li == -1) {
+ if (_vm->checkInventoryForRings(charIndex, 1)) {
+ np[3] <<= 1;
+ np[4] <<= 1;
+ }
+
+ } else {
+ lv = c->level[li] - 1;
+ for (int i = 0; i < _numPages; i++)
+ np[i] = _vm->_numSpellsMage[lv * _numPages + i];
+
+ avltyFlags = c->mageSpellsAvailableFlags;
+ }
+ }
+
+ int8 *menuSpellMap = new int8[88];
+ memset(menuSpellMap, 0, 88);
+ int8 *numAssignedSpellsPerBookPage = new int8[8];
+ memset(numAssignedSpellsPerBookPage, 0, 8);
+ memset(_numAssignedSpellsOfType, 0, 72);
+ int8 *lh = new int8[40];
+ memset(lh, 0, 40);
+
+ memcpy(lh, spellType ? _vm->_spellLevelsCleric : _vm->_spellLevelsMage, spellType ? _vm->_spellLevelsClericSize : _vm->_spellLevelsMageSize);
+ int8 *charSpellList = spellType ? c->clericSpells : c->mageSpells;
+
+ for (int i = 0; i < 80; i++) {
+ int8 s = charSpellList[i];
+ if (s == 0 || (_vm->game() == GI_EOB2 && s == 29))
+ continue;
+
+ if (s < 0)
+ s = -s;
+ else
+ _numAssignedSpellsOfType[s * 2 - 1]++;
+
+ s--;
+ _numAssignedSpellsOfType[s * 2]++;
+ numAssignedSpellsPerBookPage[lh[s] - 1]++;
+ }
+
+ for (int i = 0; i < 32; i++) {
+ if (!(avltyFlags & (1 << i)))
+ continue;
+
+ int d = lh[i] - 1;
+ if (d < 0)
+ continue;
+
+ if (!spellType || (spellType && np[d])) {
+ menuSpellMap[d * 11]++;
+ menuSpellMap[d * 11 + menuSpellMap[d * 11]] = i + 1;
+ }
+ }
+
+ Button *buttonList = initMenu(4);
+
+ int lastHighLightText = -1;
+ int lastHighLightButton = -1;
+ int newHighLightButton = 0;
+ int newHighLightText = 0;
+ bool updateDesc = true;
+ bool updateList = true;
+
+ for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
+ updateBoxFrameHighLight(charIndex);
+
+ if (newHighLightButton < 0)
+ newHighLightButton = 7;
+ if (newHighLightButton > 7)
+ newHighLightButton = 0;
+
+ Button *b = 0;
+
+ if (lastHighLightButton != newHighLightButton) {
+ if (lastHighLightButton >= 0)
+ drawMenuButton(_vm->gui_getButton(buttonList, lastHighLightButton + 26), false, false, true);
+ drawMenuButton(_vm->gui_getButton(buttonList, newHighLightButton + 26), false, true, true);
+ newHighLightText = 0;
+ lastHighLightText = -1;
+ lastHighLightButton = newHighLightButton;
+ updateDesc = updateList = true;
+ }
+
+ if (updateList) {
+ updateList = false;
+ _screen->setCurPage(2);
+ for (int ii = 1; ii < 9; ii++)
+ memorizePrayMenuPrintString(menuSpellMap[lastHighLightButton * 11 + ii], ii - 1, spellType, false, false);
+
+ _screen->setCurPage(0);
+ _screen->copyRegion(0, 50, 0, 50, 176, 72, 2, 0, Screen::CR_NO_P_CHECK);
+ lastHighLightText = -1;
+ }
+
+ if (updateDesc) {
+ updateDesc = false;
+ _screen->printShadedText(Common::String::format(_vm->_menuStringsMgc[1], np[lastHighLightButton] - numAssignedSpellsPerBookPage[lastHighLightButton], np[lastHighLightButton]).c_str(), 8, 38, 9, _vm->guiSettings()->colors.fill);
+ }
+
+ if (newHighLightText < 0)
+ newHighLightText = menuSpellMap[lastHighLightButton * 11] - 1;
+
+ if (menuSpellMap[lastHighLightButton * 11] <= newHighLightText)
+ newHighLightText = 0;
+
+ if (newHighLightText != lastHighLightText) {
+ memorizePrayMenuPrintString(menuSpellMap[lastHighLightButton * 11 + lastHighLightText + 1], lastHighLightText, spellType, true, false);
+ memorizePrayMenuPrintString(menuSpellMap[lastHighLightButton * 11 + newHighLightText + 1], newHighLightText, spellType, true, true);
+ lastHighLightText = newHighLightText;
+ }
+
+ int inputFlag = _vm->checkInput(buttonList, false, 0) & 0x80ff;
+ _vm->removeInputTop();
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP6] || inputFlag == _vm->_keyMap[Common::KEYCODE_RIGHT]) {
+ inputFlag = 0x801a + ((lastHighLightButton + 1) % _numVisPages);
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP4] || inputFlag == _vm->_keyMap[Common::KEYCODE_LEFT]) {
+ inputFlag = lastHighLightButton ? 0x8019 + lastHighLightButton : 0x8019 + _numVisPages;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE]) {
+ inputFlag = 0x8018;
+ } else {
+ Common::Point p = _vm->getMousePos();
+ if (_vm->posWithinRect(p.x, p.y, 8, 50, 168, 122)) {
+ newHighLightText = (p.y - 50) / 9;
+ if (menuSpellMap[lastHighLightButton * 11] - 1 < newHighLightText)
+ newHighLightText = menuSpellMap[lastHighLightButton * 11] - 1;
+ }
+ }
+
+ if (inputFlag & 0x8000) {
+ b = _vm->gui_getButton(buttonList, inputFlag & 0x7fff);
+ drawMenuButton(b, true, true, true);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(80);
+ drawMenuButton(b, false, false, true);
+ _screen->updateScreen();
+ }
+
+ if (inputFlag == 0x8019 || inputFlag == _vm->_keyMap[Common::KEYCODE_KP_PLUS] || inputFlag == _vm->_keyMap[Common::KEYCODE_PLUS] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP5] || inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN]) {
+ if (np[lastHighLightButton] > numAssignedSpellsPerBookPage[lastHighLightButton] && lastHighLightText != -1) {
+ _numAssignedSpellsOfType[menuSpellMap[lastHighLightButton * 11 + lastHighLightText + 1] * 2 - 2]++;
+ numAssignedSpellsPerBookPage[lastHighLightButton]++;
+ memorizePrayMenuPrintString(menuSpellMap[lastHighLightButton * 11 + lastHighLightText + 1], lastHighLightText, spellType, false, true);
+ updateDesc = true;
+ }
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP_MINUS] || inputFlag == _vm->_keyMap[Common::KEYCODE_MINUS]) {
+ if (np[lastHighLightButton] && _numAssignedSpellsOfType[menuSpellMap[lastHighLightButton * 11 + lastHighLightText + 1] * 2 - 2]) {
+ _numAssignedSpellsOfType[menuSpellMap[lastHighLightButton * 11 + lastHighLightText + 1] * 2 - 2]--;
+ numAssignedSpellsPerBookPage[lastHighLightButton]--;
+ memorizePrayMenuPrintString(menuSpellMap[lastHighLightButton * 11 + lastHighLightText + 1], lastHighLightText, spellType, false, true);
+ updateDesc = true;
+ }
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_UP] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP8]) {
+ newHighLightText = lastHighLightText - 1;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP2]) {
+ newHighLightText = lastHighLightText + 1;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_END] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP1]) {
+ newHighLightText = menuSpellMap[lastHighLightButton * 11] - 1;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_HOME] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP7]) {
+ newHighLightText = 0;
+ } else if (inputFlag == 0x8017) {
+ if (numAssignedSpellsPerBookPage[lastHighLightButton]) {
+ for (int i = 1; i <= menuSpellMap[lastHighLightButton * 11]; i++) {
+ numAssignedSpellsPerBookPage[lastHighLightButton] -= _numAssignedSpellsOfType[menuSpellMap[lastHighLightButton * 11 + i] * 2 - 2];
+ _numAssignedSpellsOfType[menuSpellMap[lastHighLightButton * 11 + i] * 2 - 2] = 0;
+ }
+
+ updateDesc = updateList = true;
+ }
+
+ } else if (inputFlag == 0x8018) {
+ _vm->gui_drawAllCharPortraitsWithStats();
+ runLoop = false;
+
+ } else if (inputFlag & 0x8000) {
+ newHighLightButton = inputFlag - 0x801a;
+ if (newHighLightButton == lastHighLightButton)
+ drawMenuButton(_vm->gui_getButton(buttonList, inputFlag & 0x7fff), false, true, true);
+ }
+ }
+
+ releaseButtons(buttonList);
+ updateBoxFrameHighLight(-1);
+
+ _screen->setFont(Screen::FID_6_FNT);
+ _vm->gui_drawCharPortraitWithStats(charIndex);
+ _screen->setFont(Screen::FID_8_FNT);
+
+ memset(charSpellList, 0, 80);
+ if (spellType && _vm->game() == GI_EOB2)
+ charSpellList[0] = 29;
+
+ for (int i = 0; i < 32; i++) {
+ if (_numAssignedSpellsOfType[i * 2] < _numAssignedSpellsOfType[i * 2 + 1])
+ _numAssignedSpellsOfType[i * 2 + 1] = _numAssignedSpellsOfType[i * 2];
+
+ if (_numAssignedSpellsOfType[i * 2 + 1]) {
+ _numAssignedSpellsOfType[i * 2]--;
+ _numAssignedSpellsOfType[i * 2 + 1]--;
+
+ int pg = lh[i] - 1;
+ for (int ii = 0; ii < 10; ii++) {
+ if (!charSpellList[pg * 10 + ii]) {
+ charSpellList[pg * 10 + ii] = i + 1;
+ break;
+ }
+ }
+ i--;
+
+ } else if (_numAssignedSpellsOfType[i * 2]) {
+ _numAssignedSpellsOfType[i * 2]--;
+
+ _needRest = true;
+ int pg = lh[i] - 1;
+ for (int ii = 0; ii < 10; ii++) {
+ if (!charSpellList[pg * 10 + ii]) {
+ charSpellList[pg * 10 + ii] = -(i + 1);
+ break;
+ }
+ }
+ i--;
+ }
+ }
+
+ delete[] menuSpellMap;
+ delete[] numAssignedSpellsPerBookPage;
+ delete[] lh;
+}
+
+
+void GUI_EoB::scribeScrollDialogue() {
+ int16 *scrollInvSlot = new int16[32];
+ int16 *scrollCharacter = new int16[32];
+ int16 *menuItems = new int16[6];
+ int numScrolls = 0;
+
+ for (int i = 0; i < 32; i++) {
+ for (int ii = 0; ii < 6; ii++) {
+ scrollInvSlot[i] = _vm->checkInventoryForItem(ii, 34, i + 1) + 1;
+ if (scrollInvSlot[i] > 0) {
+ numScrolls++;
+ scrollCharacter[i] = ii;
+ break;
+ }
+ }
+ }
+
+ if (numScrolls) {
+ int csel = selectCharacterDialogue(49);
+ if (csel != -1) {
+
+ EoBCharacter *c = &_vm->_characters[csel];
+ int s = 0;
+
+ for (int i = 0; i < 32 && s < 6; i++) {
+ if (!scrollInvSlot[i])
+ continue;
+
+ if (c->mageSpellsAvailableFlags & (1 << i))
+ scrollInvSlot[i] = 0;
+ else
+ menuItems[s++] = i + 1;
+ }
+
+ if (s) {
+ Button *buttonList = 0;
+ bool redraw = true;
+ int lastHighLight = -1;
+ int newHighLight = 0;
+
+ while (s && !_vm->shouldQuit()) {
+ if (redraw) {
+ s = 0;
+ for (int i = 0; i < 32 && s < 6; i++) {
+ if (!scrollInvSlot[i])
+ continue;
+ menuItems[s++] = i + 1;
+ }
+
+ if (!s)
+ break;
+
+ releaseButtons(buttonList);
+ buttonList = initMenu(6);
+
+ for (int i = 0; i < s; i++)
+ _screen->printShadedText(_vm->_mageSpellList[menuItems[i]], 8, 9 * i + 50, 15, 0);
+
+ redraw = false;
+ lastHighLight = -1;
+ newHighLight = 0;
+ }
+
+ if (lastHighLight != newHighLight) {
+ if (lastHighLight >= 0)
+ _screen->printText(_vm->_mageSpellList[menuItems[lastHighLight]], 8, 9 * lastHighLight + 50, 15, 0);
+ lastHighLight = newHighLight;
+ _screen->printText(_vm->_mageSpellList[menuItems[lastHighLight]], 8, 9 * lastHighLight + 50, 6, 0);
+ _screen->updateScreen();
+ }
+
+ int inputFlag = _vm->checkInput(buttonList, false, 0);
+ _vm->removeInputTop();
+
+ if (inputFlag == 0) {
+ Common::Point p = _vm->getMousePos();
+ if (_vm->posWithinRect(p.x, p.y, 8, 50, 176, s * 9 + 49))
+ newHighLight = (p.y - 50) / 9;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP2] || inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN]) {
+ newHighLight = (newHighLight + 1) % s;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP8] || inputFlag == _vm->_keyMap[Common::KEYCODE_UP]) {
+ newHighLight = (newHighLight + s - 1) % s;
+ } else if (inputFlag == 0x8023 || inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE]) {
+ s = 0;
+ } else if (inputFlag == 0x8024) {
+ newHighLight = (_vm->_mouseY - 50) / 9;
+ if (newHighLight >= 0 && newHighLight < s) {
+ inputFlag = _vm->_keyMap[Common::KEYCODE_SPACE];
+ } else {
+ inputFlag = 0;
+ newHighLight = lastHighLight;
+ }
+ }
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP5]) {
+ int t = menuItems[newHighLight] - 1;
+ Item scItem = _vm->_characters[scrollCharacter[t]].inventory[scrollInvSlot[t] - 1];
+ c->mageSpellsAvailableFlags |= (1 << t);
+ _vm->_characters[scrollCharacter[t]].inventory[scrollInvSlot[t] - 1] = 0;
+ _vm->gui_drawCharPortraitWithStats(_vm->_characters[scrollCharacter[t]].id);
+ scrollInvSlot[t] = 0;
+ _vm->_items[scItem].block = -1;
+ redraw = true;
+ s--;
+ }
+ }
+
+ releaseButtons(buttonList);
+
+ } else {
+ displayTextBox(51);
+ }
+ }
+ } else {
+ displayTextBox(50);
+ }
+
+ delete[] menuItems;
+ delete[] scrollCharacter;
+ delete[] scrollInvSlot;
+}
+
+bool GUI_EoB::restParty() {
+ static const int8 eob1healSpells[] = { 2, 15, 20, 24 };
+ static const int8 eob2healSpells[] = { 3, 16, 20, 28 };
+ const int8 *spells = _vm->game() == GI_EOB1 ? eob1healSpells : eob2healSpells;
+
+ uint8 crs[6];
+ memset(crs, 0, 6);
+ int hours = 0;
+
+ if (_vm->_inf->preventRest()) {
+ assert(_vm->_menuStringsRest3[0]);
+ _vm->restParty_displayWarning(_vm->_menuStringsRest3[0]);
+ return true;
+ }
+
+ if (_vm->restParty_updateMonsters())
+ return true;
+
+ if (_vm->restParty_extraAbortCondition())
+ return true;
+
+ drawMenuButtonBox(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, false, false);
+
+ int nonPoisoned = 0;
+ for (int i = 0; i < 6; i++) {
+ if (!_vm->testCharacter(i, 1))
+ continue;
+ nonPoisoned |= _vm->testCharacter(i, 0x10);
+ }
+
+ if (!nonPoisoned) {
+ if (!confirmDialogue(59))
+ return false;
+ }
+
+ int8 *list = 0;
+ bool useHealers = false;
+ bool res = false;
+ bool restLoop = true;
+ bool restContinue = false;
+ int injured = _vm->restParty_getCharacterWithLowestHp();
+
+ if (injured > 0) {
+ for (int i = 0; i < 6; i++) {
+ if (!_vm->testCharacter(i, 13))
+ continue;
+ if (_vm->getCharacterLevelIndex(2, _vm->_characters[i].cClass) == -1 && _vm->getCharacterLevelIndex(4, _vm->_characters[i].cClass) == -1)
+ continue;
+ if (_vm->checkInventoryForItem(i, 30, -1) == -1)
+ continue;
+ if (_vm->restParty_checkHealSpells(i)) {
+ useHealers = confirmDialogue(40);
+ break;
+ }
+ }
+ }
+
+ _screen->setClearScreenDim(7);
+ _screen->setFont(Screen::FID_6_FNT);
+
+ restParty_updateRestTime(hours, true);
+
+ for (int l = 0; !res && restLoop && !_vm->shouldQuit();) {
+ l++;
+
+ // Regenerate spells
+ for (int i = 0; i < 6; i++) {
+ crs[i]++;
+
+ if (!_vm->_characters[i].food)
+ continue;
+ if (!_vm->testCharacter(i, 5))
+ continue;
+
+ if (_vm->checkInventoryForItem(i, 30, -1) != -1) {
+ list = _vm->_characters[i].clericSpells;
+
+ for (int ii = 0; ii < 80; ii++) {
+ if ((ii / 10 + 48) >= crs[i])
+ break;
+
+ if (*list >= 0) {
+ list++;
+ continue;
+ }
+
+ *list *= -1;
+ crs[i] = 48;
+ _vm->_txt->printMessage(Common::String::format(_vm->_menuStringsRest2[0], _vm->_characters[i].name, _vm->_spells[_vm->_clericSpellOffset + *list].name).c_str());
+ _vm->delay(80);
+ break;
+ }
+ }
+
+ if (_vm->checkInventoryForItem(i, 29, -1) != -1) {
+ list = _vm->_characters[i].mageSpells;
+
+ for (int ii = 0; ii < 80; ii++) {
+ if ((ii / 6 + 48) >= crs[i])
+ break;
+
+ if (*list >= 0) {
+ list++;
+ continue;
+ }
+
+ *list *= -1;
+ crs[i] = 48;
+ _vm->_txt->printMessage(Common::String::format(_vm->_menuStringsRest2[1], _vm->_characters[i].name, _vm->_spells[*list].name).c_str());
+ _vm->delay(80);
+ break;
+ }
+ }
+ }
+
+ // Heal party members
+ if (useHealers) {
+ for (int i = 0; i < 6 && injured; i++) {
+ if (_vm->getCharacterLevelIndex(2, _vm->_characters[i].cClass) == -1 && _vm->getCharacterLevelIndex(4, _vm->_characters[i].cClass) == -1)
+ continue;
+ if (_vm->checkInventoryForItem(i, 30, -1) == -1)
+ continue;
+
+ list = 0;
+ if (crs[i] >= 48) {
+ for (int ii = 0; !list && ii < 3; ii++)
+ list = (int8 *)memchr(_vm->_characters[i].clericSpells, -spells[ii], 80);
+ }
+
+ if (list)
+ break;
+
+ list = _vm->_characters[i].clericSpells;
+ for (int ii = 0; ii < 80 && injured; ii++) {
+ int healHp = 0;
+ if (*list == spells[0])
+ healHp = _vm->rollDice(1, 8, 0);
+ else if (*list == spells[1])
+ healHp = _vm->rollDice(2, 8, 1);
+ else if (*list == spells[2])
+ healHp = _vm->rollDice(3, 8, 3);
+
+ if (!healHp) {
+ list++;
+ continue;
+ }
+
+ *list *= -1;
+ list++;
+
+ crs[i] = 0;
+ injured--;
+
+ _vm->_txt->printMessage(Common::String::format(_vm->_menuStringsRest2[2], _vm->_characters[i].name, _vm->_characters[injured].name).c_str());
+ _vm->delay(80);
+
+ _vm->_characters[injured].hitPointsCur += healHp;
+ if (_vm->_characters[injured].hitPointsCur > _vm->_characters[injured].hitPointsMax)
+ _vm->_characters[injured].hitPointsCur = _vm->_characters[injured].hitPointsMax;
+
+ _vm->gui_drawCharPortraitWithStats(injured++);
+ }
+ }
+ }
+
+ if (l == 6) {
+ l = 0;
+ restParty_updateRestTime(++hours, false);
+ _vm->_restPartyElapsedTime += (32760 * _vm->_tickLength);
+
+ // Update poisoning
+ for (int i = 0; i < 6; i++) {
+ if (!_vm->testCharacter(i, 1))
+ continue;
+ if (_vm->testCharacter(i, 16))
+ continue;
+ _vm->inflictCharacterDamage(i, 10);
+ _vm->delayWithTicks(5);
+ }
+
+ if (!(hours % 8)) {
+ bool starving = false;
+ for (int i = 0; i < 6; i++) {
+ // Add Lay On Hands spell
+ if (_vm->_characters[i].cClass == 2) {
+ list = (int8 *)memchr(_vm->_characters[i].clericSpells, spells[3], 10);
+ if (list) {
+ *list = spells[3];
+ } else {
+ list = (int8 *)memchr(_vm->_characters[i].clericSpells, -spells[3], 10);
+ if (list) {
+ *list = spells[3];
+ } else if (!memchr(_vm->_characters[i].clericSpells, spells[3], 10)) {
+ list = (int8 *)memchr(_vm->_characters[i].clericSpells, 0, 10);
+ *list = spells[3];
+ }
+ }
+ }
+
+ if (!_vm->testCharacter(i, 3))
+ continue;
+
+ // Update hitpoints and food status
+ if (_vm->_characters[i].food) {
+ if (_vm->_characters[i].hitPointsCur < _vm->_characters[i].hitPointsMax) {
+ _vm->_characters[i].hitPointsCur++;
+ _screen->setFont(Screen::FID_6_FNT);
+ _vm->gui_drawCharPortraitWithStats(i);
+ }
+
+ if (!_vm->checkInventoryForRings(i, 2)) {
+ if (_vm->_characters[i].food <= 5) {
+ _vm->_characters[i].food = 0;
+ starving = true;
+ } else {
+ _vm->_characters[i].food -= 5;
+ }
+ }
+ } else {
+ if ((hours % 24) || (_vm->_characters[i].hitPointsCur <= -10))
+ continue;
+ _vm->inflictCharacterDamage(i, 1);
+ starving = true;
+ _screen->setFont(Screen::FID_6_FNT);
+ _vm->gui_drawCharPortraitWithStats(i);
+ }
+ }
+
+ if (starving) {
+ if (!confirmDialogue(47)) {
+ restContinue = false;
+ restLoop = false;
+ }
+ restParty_updateRestTime(hours, true);
+ }
+ injured = restLoop ? _vm->restParty_getCharacterWithLowestHp() : 0;
+ }
+ }
+
+ if (!_vm->restParty_checkSpellsToLearn() && restLoop && !restContinue && injured) {
+ restContinue = confirmDialogue(41);
+ restParty_updateRestTime(hours, true);
+ if (!restContinue)
+ restLoop = false;
+ }
+
+ int in = _vm->checkInput(0, false, 0);
+ _vm->removeInputTop();
+ if (in)
+ restLoop = false;
+
+ if (restLoop) {
+ res = _vm->restParty_updateMonsters();
+ if (!res)
+ res = _vm->checkPartyStatus(false);
+ }
+
+ if (!_vm->restParty_checkSpellsToLearn()) {
+ if (!restContinue) {
+ if (!useHealers)
+ restLoop = false;
+ }
+ if (!injured)
+ restLoop = false;
+ }
+ }
+
+ _vm->removeInputTop();
+ _screen->setScreenDim(4);
+ _screen->setFont(Screen::FID_8_FNT);
+
+ if (!res) {
+ if (!injured)
+ displayTextBox(43);
+ if (hours > 4)
+ _vm->restParty_npc();
+ }
+
+ return res;
+}
+
+bool GUI_EoB::confirmDialogue(int id) {
+ int od = _screen->curDimIndex();
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+
+ Button *buttonList = initMenu(5);
+
+ _screen->printShadedText(getMenuString(id), (_screen->_curDim->sx + 1) << 3, _screen->_curDim->sy + 4, 15, 0);
+
+ int newHighlight = 0;
+ int lastHighlight = -1;
+ bool result = false;
+
+ for (bool runLoop = true; runLoop && !_vm->shouldQuit();) {
+ if (newHighlight != lastHighlight) {
+ if (lastHighlight != -1)
+ drawMenuButton(_vm->gui_getButton(buttonList, lastHighlight + 33), false, false, true);
+ drawMenuButton(_vm->gui_getButton(buttonList, newHighlight + 33), false, true, true);
+ _screen->updateScreen();
+ lastHighlight = newHighlight;
+ }
+
+ int inputFlag = _vm->checkInput(buttonList, false, 0) & 0x80ff;
+ _vm->removeInputTop();
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP5] || inputFlag == _vm->_keyMap[Common::KEYCODE_SPACE] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN]) {
+ result = lastHighlight == 0;
+ inputFlag = 0x8021 + lastHighlight;
+ runLoop = false;
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP4] || inputFlag == _vm->_keyMap[Common::KEYCODE_LEFT] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP6] || inputFlag == _vm->_keyMap[Common::KEYCODE_RIGHT]) {
+ newHighlight ^= 1;
+ } else if (inputFlag == 0x8021) {
+ result = true;
+ runLoop = false;
+ } else if (inputFlag == 0x8022) {
+ result = false;
+ runLoop = false;
+ } else {
+ Common::Point p = _vm->getMousePos();
+ for (Button *b = buttonList; b; b = b->nextButton) {
+ if ((b->arg & 2) && _vm->posWithinRect(p.x, p.y, b->x, b->y, b->x + b->width, b->y + b->height))
+ newHighlight = b->index - 33;
+ }
+ }
+
+ if (!runLoop) {
+ Button *b = _vm->gui_getButton(buttonList, lastHighlight + 33);
+ drawMenuButton(b, true, true, true);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(80);
+ drawMenuButton(b, false, true, true);
+ _screen->updateScreen();
+ }
+ }
+
+ releaseButtons(buttonList);
+
+ _screen->setFont(of);
+ _screen->setScreenDim(od);
+
+ return result;
+}
+
+int GUI_EoB::selectCharacterDialogue(int id) {
+ uint8 flags = (id == 26) ? (_vm->game() == GI_EOB1 ? 0x04 : 0x14) : 0x02;
+ _vm->removeInputTop();
+
+ _charSelectRedraw = false;
+ bool starvedUnconscious = false;
+ int count = 0;
+ int result = -1;
+ int found[6];
+
+ for (int i = 0; i < 6; i++) {
+ found[i] = -1;
+
+ if (!_vm->testCharacter(i, 1))
+ continue;
+
+ if (!(_vm->_classModifierFlags[_vm->_characters[i].cClass] & flags) && (id != 53))
+ continue;
+
+ if (id != 53 && (!_vm->_characters[i].food || !_vm->testCharacter(i, 4))) {
+ starvedUnconscious = true;
+ } else {
+ found[i] = 0;
+ result = i;
+ count++;
+ }
+ }
+
+ if (!count) {
+ int eid = 0;
+ if (id == 23)
+ eid = (starvedUnconscious || _vm->game() == GI_EOB1) ? 28 : 72;
+ else if (id == 26)
+ eid = (starvedUnconscious || _vm->game() == GI_EOB1) ? 27 : 73;
+ else if (id == 49)
+ eid = 52;
+
+ displayTextBox(eid);
+ return -1;
+ }
+
+ static const uint16 selX[] = { 184, 256, 184, 256, 184, 256 };
+ static const uint8 selY[] = { 2, 2, 54, 54, 106, 106};
+
+ for (int i = 0; i < 6; i++) {
+ if (found[i] != -1 || !_vm->testCharacter(i, 1))
+ continue;
+
+ _screen->drawShape(0, _vm->_blackBoxSmallGrid, selX[i], selY[i], 0);
+ _screen->drawShape(0, _vm->_blackBoxSmallGrid, selX[i] + 16, selY[i], 0);
+ _screen->drawShape(0, _vm->_blackBoxSmallGrid, selX[i] + 32, selY[i], 0);
+ _screen->drawShape(0, _vm->_blackBoxSmallGrid, selX[i] + 48, selY[i], 0);
+ _charSelectRedraw = true;
+ }
+
+ if (count == 1) {
+ int l = _vm->getCharacterLevelIndex(4, _vm->_characters[result].cClass);
+
+ if (l == -1)
+ return result;
+
+ if (_vm->_characters[result].level[l] > 8)
+ return result;
+
+ displayTextBox(24);
+ return -1;
+ }
+
+ _vm->_menuDefs[3].titleStrId = id;
+ Button *buttonList = initMenu(3);
+
+ result = -2;
+ int hlCur = -1;
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+
+ while (result == -2 && !_vm->shouldQuit()) {
+ int inputFlag = _vm->checkInput(buttonList, false, 0);
+ _vm->removeInputTop();
+
+ updateBoxFrameHighLight(hlCur);
+
+ if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP4] || inputFlag == _vm->_keyMap[Common::KEYCODE_LEFT] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP8] || inputFlag == _vm->_keyMap[Common::KEYCODE_UP] || inputFlag == _vm->_keyMap[Common::KEYCODE_a] || inputFlag == _vm->_keyMap[Common::KEYCODE_w]) {
+ updateBoxFrameHighLight(-1);
+ _vm->gui_drawCharPortraitWithStats(hlCur--);
+ if (hlCur < 0)
+ hlCur = 5;
+ while (found[hlCur]) {
+ if (--hlCur < 0)
+ hlCur = 5;
+ }
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP6] || inputFlag == _vm->_keyMap[Common::KEYCODE_RIGHT] || inputFlag == _vm->_keyMap[Common::KEYCODE_KP2] || inputFlag == _vm->_keyMap[Common::KEYCODE_DOWN] || inputFlag == _vm->_keyMap[Common::KEYCODE_z] || inputFlag == _vm->_keyMap[Common::KEYCODE_s]) {
+ updateBoxFrameHighLight(-1);
+ _vm->gui_drawCharPortraitWithStats(hlCur++);
+ if (hlCur == 6)
+ hlCur = 0;
+ while (found[hlCur]) {
+ if (++hlCur == 6)
+ hlCur = 0;
+ }
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_KP5] || inputFlag == _vm->_keyMap[Common::KEYCODE_RETURN]) {
+ if (hlCur >= 0)
+ result = hlCur;
+
+ } else if (inputFlag == _vm->_keyMap[Common::KEYCODE_ESCAPE] || inputFlag == 0x8010) {
+ _screen->setFont(Screen::FID_8_FNT);
+ drawMenuButton(buttonList, true, true, true);
+ _screen->updateScreen();
+ _vm->_system->delayMillis(80);
+ drawMenuButton(buttonList, false, false, true);
+ _screen->updateScreen();
+ _screen->setFont(Screen::FID_6_FNT);
+ result = -1;
+
+ } else if (inputFlag > 0x8010 && inputFlag < 0x8017) {
+ result = inputFlag - 0x8011;
+ if (found[result])
+ result = -2;
+ }
+ }
+
+ updateBoxFrameHighLight(-1);
+ if (hlCur >= 0)
+ _vm->gui_drawCharPortraitWithStats(hlCur);
+
+ _screen->setFont(Screen::FID_8_FNT);
+
+ if (result != -1 && id != 53) {
+ if (flags & 4) {
+ int lv = _vm->getCharacterLevelIndex(4, _vm->_characters[result].cClass);
+ if (lv != -1) {
+ if (_vm->_characters[result].level[lv] < 9) {
+ displayTextBox(24);
+ result = -1;
+ }
+ }
+ } else {
+ if (_vm->checkInventoryForItem(result, 29, -1) == -1) {
+ displayTextBox(25);
+ result = -1;
+ }
+ }
+ }
+
+ releaseButtons(buttonList);
+ _screen->setFont(of);
+
+ return result;
+}
+
+void GUI_EoB::displayTextBox(int id) {
+ int op = _screen->setCurPage(2);
+ int od = _screen->curDimIndex();
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+ _screen->setClearScreenDim(11);
+ const ScreenDim *dm = _screen->getScreenDim(11);
+
+ drawMenuButtonBox(dm->sx << 3, dm->sy, dm->w << 3, dm->h, false, false);
+ _screen->printShadedText(getMenuString(id), (dm->sx << 3) + 5, dm->sy + 5, 15, 0);
+ _screen->copyRegion(dm->sx << 3, dm->sy, dm->sx << 3, dm->sy, dm->w << 3, dm->h, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ for (uint32 timeOut = _vm->_system->getMillis() + 1440; _vm->_system->getMillis() < timeOut && !_vm->shouldQuit();) {
+ int in = _vm->checkInput(0, false, 0);
+ _vm->removeInputTop();
+ if (in && !(in & 0x800))
+ break;
+ _vm->_system->delayMillis(4);
+ }
+
+ _screen->setCurPage(op);
+ _screen->setFont(of);
+ _screen->setScreenDim(od);
+}
+
+Button *GUI_EoB::initMenu(int id) {
+ _screen->setCurPage(2);
+
+ EoBMenuDef *m = &_vm->_menuDefs[id];
+
+ if (m->dim) {
+ const ScreenDim *dm = _screen->getScreenDim(m->dim);
+ _screen->fillRect(dm->sx << 3, dm->sy, ((dm->sx + dm->w) << 3) - 1, (dm->sy + dm->h) - 1, _vm->guiSettings()->colors.fill);
+ _screen->setScreenDim(m->dim);
+ drawMenuButtonBox(dm->sx << 3, dm->sy, dm->w << 3, dm->h, false, false);
+ }
+
+ _screen->printShadedText(getMenuString(m->titleStrId), 5, 5, m->titleCol, 0);
+
+ Button *buttons = 0;
+ for (int i = 0; i < m->numButtons; i++) {
+ const EoBMenuButtonDef *df = &_vm->_menuButtonDefs[m->firstButtonStrId + i];
+ Button *b = new Button;
+ b->index = m->firstButtonStrId + i + 1;
+ if (id == 4 && _vm->game() == GI_EOB1)
+ b->index -= 14;
+
+ b->data0Val2 = 12;
+ b->data1Val2 = b->data2Val2 = 15;
+ b->data3Val2 = 8;
+ b->flags = 0x1100;
+ b->keyCode = df->keyCode;
+ b->keyCode2 = df->keyCode | 0x100;
+ b->x = df->x;
+ b->y = df->y;
+ b->width = df->width;
+ b->height = df->height;
+ b->extButtonDef = df;
+ b->arg = df->flags;
+
+ drawMenuButton(b, false, false, false);
+ buttons = linkButton(buttons, b);
+ }
+
+ _screen->copyRegion(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, 2, 0, Screen::CR_NO_P_CHECK);
+ _vm->gui_notifyButtonListChanged();
+ _screen->setCurPage(0);
+ _screen->updateScreen();
+
+ return buttons;
+}
+
+void GUI_EoB::drawMenuButton(Button *b, bool clicked, bool highlight, bool noFill) {
+ if (!b)
+ return;
+
+ const EoBMenuButtonDef *d = (const EoBMenuButtonDef *)b->extButtonDef;
+
+ if (d->flags & 1)
+ drawMenuButtonBox(b->x, b->y, b->width, b->height, clicked, noFill);
+
+ if (d->labelId) {
+ const char *s = getMenuString(d->labelId);
+
+ int xOffs = 4;
+ int yOffs = 3;
+
+ if (d->flags & 4) {
+ xOffs = ((b->width - (strlen(s) << 3)) >> 1) + 1;
+ yOffs = (b->height - 7) >> 1;
+ }
+
+ int col1 = (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : 15;
+
+ if (noFill || clicked)
+ _screen->printText(s, b->x + xOffs, b->y + yOffs, highlight ? 6 : col1, 0);
+ else
+ _screen->printShadedText(s, b->x + xOffs, b->y + yOffs, highlight ? 6 : col1, 0);
+ }
+}
+
+void GUI_EoB::drawMenuButtonBox(int x, int y, int w, int h, bool clicked, bool noFill) {
+ uint8 col1 = _vm->guiSettings()->colors.frame1;
+ uint8 col2 = _vm->guiSettings()->colors.frame2;
+
+ if (clicked)
+ col1 = col2 = _vm->guiSettings()->colors.fill;
+
+ _vm->gui_drawBox(x, y, w, h, col1, col2, -1);
+ _vm->gui_drawBox(x + 1, y + 1, w - 2, h - 2, _vm->guiSettings()->colors.frame1, _vm->guiSettings()->colors.frame2, noFill ? -1 : _vm->guiSettings()->colors.fill);
+}
+
+void GUI_EoB::drawTextBox(int dim, int id) {
+ int od = _screen->curDimIndex();
+ _screen->setScreenDim(dim);
+ const ScreenDim *dm = _screen->getScreenDim(dim);
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+
+ if (dm->w <= 22 && dm->h <= 84)
+ _screen->copyRegion(dm->sx << 3, dm->sy, 0, dm->h, dm->w << 3, dm->h, 0, 2, Screen::CR_NO_P_CHECK);
+
+ _screen->setCurPage(2);
+
+ drawMenuButtonBox(0, 0, dm->w << 3, dm->h, false, false);
+ _screen->printShadedText(getMenuString(id), 5, 5, 15, 0);
+
+ _screen->setCurPage(0);
+ _screen->copyRegion(0, 0, dm->sx << 3, dm->sy, dm->w << 3, dm->h, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _screen->setScreenDim(od);
+ _screen->setFont(of);
+}
+
+void GUI_EoB::drawSaveSlotButton(int slot, int redrawBox, int textCol) {
+ if (slot < 0)
+ return;
+
+ int x = _saveSlotX + 4;
+ int y = _saveSlotY + slot * 17 + 20;
+ int w = 167;
+ const char *s = (slot < 6) ? _saveSlotStringsTemp[slot] : _vm->_saveLoadStrings[0];
+
+ if (slot >= 6) {
+ x = _saveSlotX + 118;
+ y = _saveSlotY + 126;
+ w = 53;
+ }
+
+ if (redrawBox)
+ drawMenuButtonBox(x, y, w, 14, (redrawBox - 1) ? true : false, false);
+
+ _screen->printShadedText(s, x + 4, y + 3, textCol, 0);
+}
+
+void GUI_EoB::memorizePrayMenuPrintString(int spellId, int bookPageIndex, int spellType, bool noFill, bool highLight) {
+ if (bookPageIndex < 0)
+ return;
+
+ int y = bookPageIndex * 9 + 50;
+ int col1 = (_vm->_configRenderMode == Common::kRenderCGA) ? 1 : 15;
+
+ if (spellId) {
+ Common::String s(Common::String::format(_vm->_menuStringsMgc[0], spellType ? _vm->_clericSpellList[spellId] : _vm->_mageSpellList[spellId], _numAssignedSpellsOfType[spellId * 2 - 2]));
+ if (noFill)
+ _screen->printText(s.c_str(), 8, y, highLight ? 6 : col1, 0);
+ else
+ _screen->printShadedText(s.c_str(), 8, y, highLight ? 6 : col1, _vm->guiSettings()->colors.fill);
+
+ } else {
+ _screen->fillRect(6, y, 168, y + 8, _vm->guiSettings()->colors.fill);
+ }
+}
+
+void GUI_EoB::updateOptionsStrings() {
+ for (int i = 0; i < 4; i++) {
+ delete[] _menuStringsPrefsTemp[i];
+ _menuStringsPrefsTemp[i] = new char[strlen(_vm->_menuStringsPrefs[i]) + 8];
+ }
+
+ Common::strlcpy(_menuStringsPrefsTemp[0], Common::String::format(_vm->_menuStringsPrefs[0], _vm->_menuStringsOnOff[_vm->_configMusic ? 0 : 1]).c_str(), strlen(_vm->_menuStringsPrefs[0]) + 8);
+ Common::strlcpy(_menuStringsPrefsTemp[1], Common::String::format(_vm->_menuStringsPrefs[1], _vm->_menuStringsOnOff[_vm->_configSounds ? 0 : 1]).c_str(), strlen(_vm->_menuStringsPrefs[1]) + 8);
+ Common::strlcpy(_menuStringsPrefsTemp[2], Common::String::format(_vm->_menuStringsPrefs[2], _vm->_menuStringsOnOff[_vm->_configHpBarGraphs ? 0 : 1]).c_str(), strlen(_vm->_menuStringsPrefs[2]) + 8);
+ Common::strlcpy(_menuStringsPrefsTemp[3], Common::String::format(_vm->_menuStringsPrefs[3], _vm->_menuStringsOnOff[_vm->_configMouse ? 0 : 1]).c_str(), strlen(_vm->_menuStringsPrefs[3]) + 8);
+}
+
+const char *GUI_EoB::getMenuString(int id) {
+ static const char empty[] = "";
+
+ if (id >= 69)
+ return _vm->_menuStringsTransfer[id - 69];
+ else if (id == 68)
+ return _vm->_transferStringsScummVM[0];
+ else if (id == 67)
+ return _vm->_menuStringsDefeat[0];
+ else if (id == 66)
+ return _vm->_errorSlotEmptyString;
+ else if (id == 65)
+ return _vm->_errorSlotEmptyString;
+ else if (id >= 63)
+ return _vm->_menuStringsSpec[id - 63];
+ else if (id >= 60)
+ return _vm->_menuStringsSpellNo[id - 60];
+ else if (id == 59)
+ return _vm->_menuStringsPoison[0];
+ else if (id >= 56)
+ return _vm->_menuStringsHead[id - 56];
+ else if (id == 55)
+ return _vm->_menuStringsDrop2[_vm->game() == GI_EOB1 ? 1 : 2];
+ else if (id == 54)
+ return _vm->_errorSlotNoNameString;
+ else if (id == 53)
+ return _vm->_menuStringsDrop2[0];
+ else if (id >= 48)
+ return _vm->_menuStringsScribe[id - 48];
+ else if (id == 47)
+ return _vm->_menuStringsStarve[0];
+ else if (id == 46)
+ return _vm->_menuStringsExit[0];
+ else if (id == 45)
+ return _vm->_menuStringsDrop[0];
+ else if (id >= 40)
+ return _vm->_menuStringsRest[id - 40];
+ else if (id >= 23)
+ return _vm->_menuStringsSpells[id - 23];
+ else if (id >= 21)
+ return _vm->_menuStringsOnOff[id - 21];
+ else if (id >= 17)
+ return _menuStringsPrefsTemp[id - 17];
+ else if (id >= 9)
+ return _vm->_menuStringsSaveLoad[id - 9];
+ else if (id >= 1)
+ return _vm->_menuStringsMain[id - 1];
+ else if (id < 0)
+ return _vm->_transferStringsScummVM[-id];
+ return empty;
+}
+
+Button *GUI_EoB::linkButton(Button *list, Button *newbt) {
+ if (!list) {
+ list = newbt;
+ return list;
+ }
+
+ if (!newbt)
+ return list;
+
+ Button *resList = list;
+ while (list->nextButton)
+ list = list->nextButton;
+ list->nextButton = newbt;
+ newbt->nextButton = 0;
+
+ return resList;
+}
+
+void GUI_EoB::releaseButtons(Button *list) {
+ while (list) {
+ Button *n = list->nextButton;
+ delete list;
+ list = n;
+ }
+ _vm->gui_notifyButtonListChanged();
+}
+
+void GUI_EoB::setupSaveMenuSlots() {
+ for (int i = 0; i < 6; ++i) {
+ if (_savegameOffset + i < _savegameListSize) {
+ if (_savegameList[i + _savegameOffset]) {
+ Common::strlcpy(_saveSlotStringsTemp[i], _savegameList[i + _savegameOffset], 20);
+ _saveSlotIdTemp[i] = i + _savegameOffset;
+ continue;
+ }
+ }
+ Common::strlcpy(_saveSlotStringsTemp[i], _vm->_saveLoadStrings[1], 20);
+ _saveSlotIdTemp[i] = -1;
+ }
+}
+
+int GUI_EoB::getHighlightSlot() {
+ int res = -1;
+ Common::Point p = _vm->getMousePos();
+
+ for (int i = 0; i < 6; i++) {
+ int y = _saveSlotY + i * 17 + 20;
+ if (_vm->posWithinRect(p.x, p.y, _saveSlotX + 4, y, _saveSlotX + 167, y + 14)) {
+ res = i;
+ break;
+ }
+ }
+
+ if (_vm->posWithinRect(p.x, p.y, _saveSlotX + 118, _saveSlotY + 126, _saveSlotX + 171, _saveSlotY + 140))
+ res = 6;
+
+ return res;
+}
+
+void GUI_EoB::sortSaveSlots() {
+ Common::sort(_saveSlots.begin(), _saveSlots.end(), Common::Less<int>());
+}
+
+void GUI_EoB::restParty_updateRestTime(int hours, bool init) {
+ Screen::FontId of = _screen->setFont(Screen::FID_8_FNT);
+ int od = _screen->curDimIndex();
+ _screen->setScreenDim(10);
+
+ if (init) {
+ _screen->setCurPage(0);
+ _vm->_txt->clearCurDim();
+ drawMenuButtonBox(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, false, false);
+ _screen->copyRegion(_screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->sx << 3, _screen->_curDim->sy, _screen->_curDim->w << 3, _screen->_curDim->h, 0, 2, Screen::CR_NO_P_CHECK);
+ _screen->printShadedText(getMenuString(42), (_screen->_curDim->sx + 1) << 3, _screen->_curDim->sy + 5, 9, 0);
+ }
+
+ _screen->setCurPage(2);
+ _screen->printShadedText(Common::String::format(_vm->_menuStringsRest2[3], hours).c_str(), (_screen->_curDim->sx + 1) << 3, _screen->_curDim->sy + 20, 15, _vm->guiSettings()->colors.fill);
+ _screen->setCurPage(0);
+ _screen->copyRegion(((_screen->_curDim->sx + 1) << 3) - 1, _screen->_curDim->sy + 20, ((_screen->_curDim->sx + 1) << 3) - 1, _screen->_curDim->sy + 20, 144, 8, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+
+ _vm->delay(160);
+
+ _screen->setScreenDim(od);
+ _screen->setFont(of);
+}
+
+const EoBRect16 GUI_EoB::_highlightFrames[] = {
+ { 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 uint8 GUI_EoB::_highlightColorTableVGA[] = { 0x0F, 0xB0, 0xB2, 0xB4, 0xB6, 0xB8, 0xBA, 0xBC, 0x0C, 0xBC, 0xBA, 0xB8, 0xB6, 0xB4, 0xB2, 0xB0, 0x00 };
+
+const uint8 GUI_EoB::_highlightColorTableEGA[] = { 0x0C, 0x0D, 0x0E, 0x0F, 0x0E, 0x0D, 0x00 };
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/gui_eob.h b/engines/kyra/gui_eob.h
new file mode 100644
index 0000000000..f6be18ffbb
--- /dev/null
+++ b/engines/kyra/gui_eob.h
@@ -0,0 +1,165 @@
+/* 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 {
+
+struct EoBRect16 {
+ int16 x1;
+ int16 y1;
+ uint16 x2;
+ uint16 y2;
+};
+
+class DarkMoonEngine;
+class Screen_EoB;
+
+class GUI_EoB : public GUI {
+ friend class EoBCoreEngine;
+ friend class CharacterGenerator;
+public:
+ GUI_EoB(EoBCoreEngine *vm);
+ virtual ~GUI_EoB();
+
+ void initStaticData() {}
+
+ // button specific
+ void processButton(Button *button);
+ int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel);
+
+ // Non button based menu handling (main menu, character generation)
+ void simpleMenu_setup(int sd, int maxItem, const char *const *strings, int32 menuItemsMask, int unk, int lineSpacing);
+ int simpleMenu_process(int sd, const char *const *strings, void *b, int32 menuItemsMask, int unk);
+
+ // Button based menus (camp menu, load menu)
+ void runCampMenu();
+ bool runLoadMenu(int x, int y);
+
+ bool confirmDialogue2(int dim, int id, int deflt);
+ void messageDialogue(int dim, int id, int buttonTextCol);
+ void messageDialogue2(int dim, int id, int buttonTextCol);
+
+ void updateBoxFrameHighLight(int box);
+
+ int getTextInput(char *dest, int x, int y, int destMaxLen, int textColor1, int textColor2, int cursorColor);
+
+ // Transfer party
+ void transferWaitBox();
+ Common::String transferTargetMenu(Common::Array<Common::String> &targets);
+ bool transferFileMenu(Common::String &targetName, Common::String &selection);
+
+ // utilities for thumbnail creation
+ void createScreenThumbnail(Graphics::Surface &dst);
+
+private:
+ int simpleMenu_getMenuItem(int index, int32 menuItemsMask, int itemOffset);
+ void simpleMenu_flashSelection(const char *str, int x, int y, int color1, int color2, int color3);
+ void simpleMenu_initMenuItemsMask(int menuId, int maxItem, int32 menuItemsMask, int unk);
+
+ bool runSaveMenu(int x, int y);
+ int selectSaveSlotDialogue(int x, int y, int id);
+ void runMemorizePrayMenu(int charIndex, int spellType);
+ void scribeScrollDialogue();
+ bool restParty();
+
+ bool confirmDialogue(int id);
+ int selectCharacterDialogue(int id);
+ void displayTextBox(int id);
+
+ Button *initMenu(int id);
+ void drawMenuButton(Button *b, bool clicked, bool highlight, bool noFill);
+ void drawMenuButtonBox(int x, int y, int w, int h, bool clicked, bool noFill);
+ void drawTextBox(int dim, int id);
+ void drawSaveSlotButton(int slot, int redrawBox, int textCol);
+ void memorizePrayMenuPrintString(int spellId, int bookPageIndex, int spellType, bool noFill, bool highLight);
+ void updateOptionsStrings();
+ const char *getMenuString(int id);
+
+ Button *linkButton(Button *list, Button *newbt);
+ void releaseButtons(Button *list);
+
+ void setupSaveMenuSlots();
+ int getHighlightSlot();
+ void sortSaveSlots();
+
+ void restParty_updateRestTime(int hours, bool init);
+
+ char **_menuStringsPrefsTemp;
+ char **_saveSlotStringsTemp;
+ int16 *_saveSlotIdTemp;
+ int _savegameOffset;
+ int16 _saveSlotX;
+ int16 _saveSlotY;
+
+ EoBCoreEngine *_vm;
+ Screen_EoB *_screen;
+
+ bool _pressFlag;
+
+ Button *_specialProcessButton;
+ Button *_backupButtonList;
+ uint16 _flagsMouseLeft;
+ uint16 _flagsMouseRight;
+ uint16 _flagsModifier;
+ uint16 _progress;
+ uint16 _prcButtonUnk3;
+ uint16 _cflag;
+
+ int _menuLineSpacing;
+ int _menuLastInFlags;
+
+ uint8 _numPages;
+ uint8 _numVisPages;
+ int8 *_numAssignedSpellsOfType;
+ uint32 _clericSpellAvltyFlags;
+ uint32 _paladinSpellAvltyFlags;
+ bool _needRest;
+
+ int _menuCur;
+ int _menuNumItems;
+ bool _charSelectRedraw;
+
+ int _updateBoxIndex;
+ int _updateBoxColorIndex;
+ const uint8 *_highLightColorTable;
+ uint32 _highLightBoxTimer;
+
+ static const EoBRect16 _highlightFrames[];
+ static const uint8 _highlightColorTableVGA[];
+ static const uint8 _highlightColorTableEGA[];
+};
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
+
+#endif
+
+#endif // ENABLE_EOB || ENABLE_LOL
diff --git a/engines/kyra/gui_hof.cpp b/engines/kyra/gui_hof.cpp
index a1e0ce66bf..c1bfee066f 100644
--- a/engines/kyra/gui_hof.cpp
+++ b/engines/kyra/gui_hof.cpp
@@ -1148,7 +1148,7 @@ int GUI_HoF::sliderHandler(Button *caller) {
}
int GUI_HoF::loadMenu(Button *caller) {
- updateSaveList();
+ updateSaveFileList(_vm->_targetName);
if (!_vm->_menuDirectlyToLoad) {
updateMenuButton(caller);
diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp
index 4a2d51faa3..b4e5148b64 100644
--- a/engines/kyra/gui_lok.cpp
+++ b/engines/kyra/gui_lok.cpp
@@ -62,7 +62,7 @@ int KyraEngine_LoK::buttonInventoryCallback(Button *caller) {
snd_playSoundEffect(0x35);
_screen->hideMouse();
_screen->fillRect(_itemPosX[itemOffset], _itemPosY[itemOffset], _itemPosX[itemOffset] + 15, _itemPosY[itemOffset] + 15, _flags.platform == Common::kPlatformAmiga ? 19 : 12);
- _screen->drawShape(0, _shapes[216+_itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0);
+ _screen->drawShape(0, _shapes[216 + _itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0);
setMouseItem(inventoryItem);
// TODO: Proper support for both taken strings in Amiga version
if (_flags.platform == Common::kPlatformAmiga)
@@ -75,7 +75,7 @@ int KyraEngine_LoK::buttonInventoryCallback(Button *caller) {
} else {
snd_playSoundEffect(0x32);
_screen->hideMouse();
- _screen->drawShape(0, _shapes[216+_itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0);
+ _screen->drawShape(0, _shapes[216 + _itemInHand], _itemPosX[itemOffset], _itemPosY[itemOffset], 0, 0);
_screen->setMouseCursor(1, 1, _shapes[0]);
updateSentenceCommand(_itemList[getItemListIndex(_itemInHand)], _placedList[0], 179);
_screen->showMouse();
@@ -107,7 +107,7 @@ int KyraEngine_LoK::buttonAmuletCallback(Button *caller) {
characterSays(2001, _waitForAmulet[0], 0, -2);
return 1;
}
- if (!queryGameFlag(0x55+jewel)) {
+ if (!queryGameFlag(0x55 + jewel)) {
assert(_blackJewel);
_animator->makeBrandonFaceMouse();
drawJewelPress(jewel, 1);
@@ -130,7 +130,7 @@ int KyraEngine_LoK::buttonAmuletCallback(Button *caller) {
return 1;
_unkAmuletVar = 1;
- switch (jewel-1) {
+ switch (jewel - 1) {
case 0:
if (_brandonStatusBit & 1) {
seq_brandonHealing2();
@@ -184,7 +184,7 @@ int KyraEngine_LoK::buttonAmuletCallback(Button *caller) {
#pragma mark -
-GUI_LoK::GUI_LoK(KyraEngine_LoK *vm, Screen_LoK *screen) : GUI(vm), _vm(vm), _screen(screen) {
+GUI_LoK::GUI_LoK(KyraEngine_LoK *vm, Screen_LoK *screen) : GUI_v1(vm), _vm(vm), _screen(screen) {
_lastScreenUpdate = 0;
_menu = 0;
_pressFlag = false;
@@ -198,7 +198,7 @@ GUI_LoK::~GUI_LoK() {
}
void GUI_LoK::createScreenThumbnail(Graphics::Surface &dst) {
- uint8 *screen = new uint8[Screen::SCREEN_W*Screen::SCREEN_H];
+ uint8 *screen = new uint8[Screen::SCREEN_W * Screen::SCREEN_H];
if (screen) {
_screen->queryPageFromDisk("SEENPAGE.TMP", 0, screen);
uint8 screenPal[768];
@@ -243,7 +243,7 @@ int GUI_LoK::processButtonList(Button *list, uint16 inputFlag, int8 mouseWheel)
}
if (mouseWheel && list->mouseWheel == mouseWheel && list->buttonCallback) {
- if ((*list->buttonCallback.get())(list))
+ if ((*list->buttonCallback)(list))
break;
}
@@ -282,7 +282,7 @@ int GUI_LoK::processButtonList(Button *list, uint16 inputFlag, int8 mouseWheel)
if (processMouseClick) {
if (list->buttonCallback) {
- if ((*list->buttonCallback.get())(list))
+ if ((*list->buttonCallback)(list))
break;
}
}
@@ -349,7 +349,7 @@ void GUI_LoK::processButton(Button *button) {
if (processType == 1 && shape)
_screen->drawShape(_screen->_curPage, shape, x, y, button->dimTableIndex, 0x10);
else if (processType == 4 && callback)
- (*callback.get())(button);
+ (*callback)(button);
}
void GUI_LoK::setGUILabels() {
@@ -579,7 +579,7 @@ void GUI_LoK::setupSavegames(Menu &menu, int num) {
// Trim long GMM save descriptions to fit our save slots
_screen->_charWidth = -2;
int fC = _screen->getTextWidth(_savegameNames[i]);
- while (_savegameNames[i][0] && (fC > 240 )) {
+ while (_savegameNames[i][0] && (fC > 240)) {
_savegameNames[i][strlen(_savegameNames[i]) - 1] = 0;
fC = _screen->getTextWidth(_savegameNames[i]);
}
@@ -596,7 +596,7 @@ void GUI_LoK::setupSavegames(Menu &menu, int num) {
}
int GUI_LoK::saveGameMenu(Button *button) {
- updateSaveList();
+ updateSaveFileList(_vm->_targetName);
updateMenuButton(button);
_menu[2].item[5].enabled = true;
@@ -605,7 +605,7 @@ int GUI_LoK::saveGameMenu(Button *button) {
_screen->savePageToDisk("SEENPAGE.TMP", 0);
_menu[2].menuNameString = _vm->_guiStrings[8]; // Select a position to save to:
- _specialSavegameString = _vm->_guiStrings[_vm->gameFlags().platform == Common::kPlatformPC98 ? 10: 9]; // [ EMPTY SLOT ]
+ _specialSavegameString = _vm->_guiStrings[_vm->gameFlags().platform == Common::kPlatformPC98 ? 10 : 9]; // [ EMPTY SLOT ]
for (int i = 0; i < 5; i++)
_menu[2].item[i].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::saveGame);
@@ -636,7 +636,7 @@ int GUI_LoK::saveGameMenu(Button *button) {
}
int GUI_LoK::loadGameMenu(Button *button) {
- updateSaveList();
+ updateSaveFileList(_vm->_targetName);
if (_vm->_menuDirectlyToLoad) {
_menu[2].item[5].enabled = false;
@@ -710,15 +710,15 @@ void GUI_LoK::updateSavegameString() {
Util::convertISOToDOS(inputKey);
if ((uint8)inputKey > 31 && (uint8)inputKey < (_vm->gameFlags().lang == Common::JA_JPN ? 128 : 226)) {
- if ((length < ARRAYSIZE(_savegameName)-1) && (width <= 240)) {
+ if ((length < ARRAYSIZE(_savegameName) - 1) && (width <= 240)) {
_savegameName[length] = inputKey;
- _savegameName[length+1] = 0;
+ _savegameName[length + 1] = 0;
redrawTextfield();
}
} else if (_keyPressed.keycode == Common::KEYCODE_BACKSPACE ||
_keyPressed.keycode == Common::KEYCODE_DELETE) {
if (length > 0) {
- _savegameName[length-1] = 0;
+ _savegameName[length - 1] = 0;
redrawTextfield();
}
} else if (_keyPressed.keycode == Common::KEYCODE_RETURN ||
@@ -733,7 +733,7 @@ void GUI_LoK::updateSavegameString() {
int GUI_LoK::saveGame(Button *button) {
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
updateMenuButton(button);
- _vm->_gameToLoad = _menu[2].item[button->index-0xC].saveSlot;
+ _vm->_gameToLoad = _menu[2].item[button->index - 0xC].saveSlot;
_screen->loadPageFromDisk("SEENPAGE.TMP", 0);
_screen->savePageToDisk("SEENPAGE.TMP", 0);
@@ -800,7 +800,7 @@ int GUI_LoK::savegameConfirm(Button *button) {
int GUI_LoK::loadGame(Button *button) {
updateMenuButton(button);
_displaySubMenu = false;
- _vm->_gameToLoad = _menu[2].item[button->index-0xC].saveSlot;
+ _vm->_gameToLoad = _menu[2].item[button->index - 0xC].saveSlot;
return 0;
}
@@ -914,15 +914,15 @@ int GUI_LoK::gameControlsMenu(Button *button) {
void GUI_LoK::setupControls(Menu &menu) {
switch (_vm->_configMusic) {
- case 0:
- menu.item[0].itemString = _offString; //"Off"
- break;
- case 1:
- menu.item[0].itemString = _onString; //"On"
- break;
- case 2:
- menu.item[0].itemString = _onCDString; //"On + CD"
- break;
+ case 0:
+ menu.item[0].itemString = _offString; //"Off"
+ break;
+ case 1:
+ menu.item[0].itemString = _onString; //"On"
+ break;
+ case 2:
+ menu.item[0].itemString = _onCDString; //"On + CD"
+ break;
}
if (_vm->_configSounds)
diff --git a/engines/kyra/gui_lok.h b/engines/kyra/gui_lok.h
index 5a8d6ab532..d3e0beaa9e 100644
--- a/engines/kyra/gui_lok.h
+++ b/engines/kyra/gui_lok.h
@@ -23,7 +23,7 @@
#ifndef KYRA_GUI_LOK_H
#define KYRA_GUI_LOK_H
-#include "kyra/gui.h"
+#include "kyra/gui_v1.h"
#include "kyra/screen_lok.h"
namespace Kyra {
@@ -92,7 +92,7 @@ namespace Kyra {
class KyraEngine_LoK;
-class GUI_LoK : public GUI {
+class GUI_LoK : public GUI_v1 {
friend class KyraEngine_LoK;
public:
GUI_LoK(KyraEngine_LoK *vm, Screen_LoK *screen);
diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp
index 5bef3cd5b5..a79da0681e 100644
--- a/engines/kyra/gui_lol.cpp
+++ b/engines/kyra/gui_lol.cpp
@@ -32,8 +32,11 @@
#include "common/savefile.h"
#include "common/system.h"
#include "common/config-manager.h"
+
#include "graphics/scaler.h"
+#include "backends/keymapper/keymapper.h"
+
#include "base/version.h"
namespace Kyra {
@@ -213,9 +216,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 +346,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)
@@ -402,9 +380,9 @@ void LoLEngine::gui_drawCharPortraitWithStats(int charNum) {
int spellLevels = 0;
if (_availableSpells[_selectedSpell] != -1) {
for (int i = 0; i < 4; i++) {
- if (_spellProperties[_availableSpells[_selectedSpell]].mpRequired[i] <= _characters[charNum].magicPointsCur &&
- _spellProperties[_availableSpells[_selectedSpell]].hpRequired[i] <= _characters[charNum].hitPointsCur)
- spellLevels++;
+ if (_spellProperties[_availableSpells[_selectedSpell]].mpRequired[i] <= _characters[charNum].magicPointsCur
+ && _spellProperties[_availableSpells[_selectedSpell]].hpRequired[i] <= _characters[charNum].hitPointsCur)
+ spellLevels++;
}
}
@@ -460,17 +438,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 +820,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 +865,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 +950,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;
@@ -1229,7 +1162,7 @@ int LoLEngine::clickedPortraitLeft(Button *button) {
int LoLEngine::clickedLiveMagicBarsLeft(Button *button) {
gui_highlightPortraitFrame(button->arg);
_txt->printMessage(0, getLangString(0x4047), _characters[button->arg].name, _characters[button->arg].hitPointsCur,
- _characters[button->arg].hitPointsMax, _characters[button->arg].magicPointsCur, _characters[button->arg].magicPointsMax);
+ _characters[button->arg].hitPointsMax, _characters[button->arg].magicPointsCur, _characters[button->arg].magicPointsMax);
return 1;
}
@@ -1333,7 +1266,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 +1280,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);
@@ -1404,7 +1336,7 @@ int LoLEngine::clickedInventorySlot(Button *button) {
int hItem = _itemInHand;
if ((_itemsInPlay[hItem].itemPropertyIndex == 281 || _itemsInPlay[slotItem].itemPropertyIndex == 281) &&
- (_itemsInPlay[hItem].itemPropertyIndex == 220 || _itemsInPlay[slotItem].itemPropertyIndex == 220)) {
+ (_itemsInPlay[hItem].itemPropertyIndex == 220 || _itemsInPlay[slotItem].itemPropertyIndex == 220)) {
// merge ruby of truth
WSAMovie_v2 *wsa = new WSAMovie_v2(this);
@@ -1908,20 +1840,16 @@ int LoLEngine::clickedStatusIcon(Button *button) {
return 1;
}
-GUI_LoL::GUI_LoL(LoLEngine *vm) : GUI(vm), _vm(vm), _screen(vm->_screen) {
+GUI_LoL::GUI_LoL(LoLEngine *vm) : GUI_v1(vm), _vm(vm), _screen(vm->_screen) {
_scrollUpFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::scrollUp);
_scrollDownFunctor = BUTTON_FUNCTOR(GUI_LoL, this, &GUI_LoL::scrollDown);
- _redrawButtonFunctor = BUTTON_FUNCTOR(GUI, this, &GUI::redrawButtonCallback);
- _redrawShadedButtonFunctor = BUTTON_FUNCTOR(GUI, this, &GUI::redrawShadedButtonCallback);
+ _redrawButtonFunctor = BUTTON_FUNCTOR(GUI_v1, this, &GUI_v1::redrawButtonCallback);
+ _redrawShadedButtonFunctor = BUTTON_FUNCTOR(GUI_v1, this, &GUI_v1::redrawShadedButtonCallback);
_specialProcessButton = _backUpButtonList = 0;
_flagsModifier = 0;
- _mouseClick = 0;
_sliderSfx = 11;
- _buttonListChanged = false;
- _savegameList = 0;
- _savegameListSize = 0;
}
void GUI_LoL::processButton(Button *button) {
@@ -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);
@@ -2088,7 +2016,7 @@ int GUI_LoL::processButtonList(Button *buttonList, uint16 inputFlag, int8 mouseW
bool progress = false;
- if (mouseX >= x && mouseY >= y && mouseX <= x+buttonList->width && mouseY <= y+buttonList->height)
+ if (mouseX >= x && mouseY >= y && mouseX <= x + buttonList->width && mouseY <= y + buttonList->height)
progress = true;
buttonList->flags2 &= ~0x80;
@@ -2237,7 +2165,7 @@ int GUI_LoL::processButtonList(Button *buttonList, uint16 inputFlag, int8 mouseW
if (buttonList->buttonCallback) {
//_vm->removeInputTop();
- if ((*buttonList->buttonCallback.get())(buttonList))
+ if ((*buttonList->buttonCallback)(buttonList))
break;
}
@@ -2296,13 +2224,13 @@ int GUI_LoL::runMenu(Menu &menu) {
// Instead, the respevtive struct entry is used to determine whether
// a menu has scroll buttons or slider bars.
uint8 hasSpecialButtons = 0;
- _savegameListUpdateNeeded = true;
+ _saveSlotsListUpdateNeeded = true;
while (_displayMenu) {
_vm->_mouseX = _vm->_mouseY = 0;
if (_currentMenu == &_loadMenu || _currentMenu == &_saveMenu || _currentMenu == &_deleteMenu) {
- updateSavegameList();
+ updateSaveSlotsList(_vm->_targetName);
setupSaveMenuSlots(*_currentMenu, 4);
}
@@ -2602,44 +2530,6 @@ void GUI_LoL::setupSaveMenuSlots(Menu &menu, int num) {
}
}
-void GUI_LoL::updateSavegameList() {
- if (!_savegameListUpdateNeeded)
- return;
-
- _savegameListUpdateNeeded = false;
-
- if (_savegameList) {
- for (int i = 0; i < _savegameListSize; i++)
- delete[] _savegameList[i];
- delete[] _savegameList;
- }
-
- updateSaveList(true);
- _savegameListSize = _saveSlots.size();
-
- if (_savegameListSize) {
- LoLEngine::SaveHeader header;
- Common::InSaveFile *in;
-
- _savegameList = new char *[_savegameListSize];
-
- for (int i = 0; i < _savegameListSize; i++) {
- in = _vm->openSaveForReading(_vm->getSavegameFilename(_saveSlots[i]), header);
- if (in) {
- _savegameList[i] = new char[header.description.size() + 1];
- Common::strlcpy(_savegameList[i], header.description.c_str(), header.description.size() + 1);
- Util::convertISOToDOS(_savegameList[i]);
- delete in;
- } else {
- _savegameList[i] = 0;
- warning("GUI_LoL::updateSavegameList(): Unexpected missing save file for slot: %d.", _saveSlots[i]);
- }
- }
- } else {
- _savegameList = 0;
- }
-}
-
void GUI_LoL::sortSaveSlots() {
Common::sort(_saveSlots.begin(), _saveSlots.end(), Common::Greater<int>());
}
@@ -2661,6 +2551,11 @@ int GUI_LoL::getInput() {
if (!_displayMenu)
return 0;
+#ifdef ENABLE_KEYMAPPER
+ Common::Keymapper *const keymapper = _vm->getEventManager()->getKeymapper();
+ keymapper->pushKeymap(Common::kGlobalKeymapName);
+#endif
+
Common::Point p = _vm->getMousePos();
_vm->_mouseX = p.x;
_vm->_mouseY = p.y;
@@ -2676,7 +2571,7 @@ int GUI_LoL::getInput() {
int inputFlag = _vm->checkInput(_menuButtonList);
- if (_currentMenu == &_savenameMenu && _keyPressed.ascii){
+ if (_currentMenu == &_savenameMenu && _keyPressed.ascii) {
char inputKey = _keyPressed.ascii;
Util::convertISOToDOS(inputKey);
@@ -2697,6 +2592,11 @@ int GUI_LoL::getInput() {
_displayMenu = false;
_vm->delay(8);
+
+#ifdef ENABLE_KEYMAPPER
+ keymapper->popKeymap(Common::kGlobalKeymapName);
+#endif
+
return inputFlag & 0x8000 ? 1 : 0;
}
@@ -2826,7 +2726,7 @@ int GUI_LoL::clickedOptionsMenu(Button *button) {
delete[] _vm->_landsFile;
_vm->_landsFile = _vm->resource()->fileData(filename.c_str(), 0);
_newMenu = _lastMenu;
- } break;
+ } break;
default:
// TODO: Is there anything we should do if we hit this case?
break;
@@ -2945,11 +2845,11 @@ int GUI_LoL::clickedChoiceMenu(Button *button) {
if (*i >= 990)
break;
Common::String oldName = _vm->getSavegameFilename(*i);
- Common::String newName = _vm->getSavegameFilename(*i-1);
+ Common::String newName = _vm->getSavegameFilename(*i - 1);
_vm->_saveFileMan->renameSavefile(oldName, newName);
}
_newMenu = &_mainMenu;
- _savegameListUpdateNeeded = true;
+ _saveSlotsListUpdateNeeded = true;
}
} else if (button->arg == _choiceMenu.item[1].itemId) {
_newMenu = &_mainMenu;
diff --git a/engines/kyra/gui_lol.h b/engines/kyra/gui_lol.h
index af487402f6..dbf54e41f0 100644
--- a/engines/kyra/gui_lol.h
+++ b/engines/kyra/gui_lol.h
@@ -25,7 +25,7 @@
#ifndef KYRA_GUI_LOL_H
#define KYRA_GUI_LOL_H
-#include "kyra/gui.h"
+#include "kyra/gui_v1.h"
namespace Kyra {
#define GUI_LOL_MENU(menu, a, b, c, d, e, f, g, i) \
@@ -88,7 +88,7 @@ namespace Kyra {
class LoLEngine;
class Screen_LoL;
-class GUI_LoL : public GUI {
+class GUI_LoL : public GUI_v1 {
friend class LoLEngine;
public:
GUI_LoL(LoLEngine *vm);
@@ -112,7 +112,6 @@ private:
void restorePage0();
void setupSaveMenuSlots(Menu &menu, int num);
- void updateSavegameList();
void printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 flags);
int getMenuCenterStringX(const char *str, int x1, int x2);
@@ -162,9 +161,7 @@ private:
Button *_specialProcessButton;
Button *_backUpButtonList;
- bool _buttonListChanged;
uint16 _flagsModifier;
- uint8 _mouseClick;
int _savegameOffset;
int _sliderSfx;
@@ -172,10 +169,6 @@ private:
Button::Callback _scrollUpFunctor;
Button::Callback _scrollDownFunctor;
- char **_savegameList;
- int _savegameListSize;
- bool _savegameListUpdateNeeded;
-
virtual void sortSaveSlots();
};
diff --git a/engines/kyra/gui_mr.cpp b/engines/kyra/gui_mr.cpp
index 82082961e9..e88b7fdffb 100644
--- a/engines/kyra/gui_mr.cpp
+++ b/engines/kyra/gui_mr.cpp
@@ -1277,7 +1277,7 @@ int GUI_MR::optionsButton(Button *button) {
}
int GUI_MR::loadMenu(Button *caller) {
- updateSaveList();
+ updateSaveFileList(_vm->_targetName);
if (!_vm->_menuDirectlyToLoad) {
updateMenuButton(caller);
diff --git a/engines/kyra/gui_rpg.cpp b/engines/kyra/gui_rpg.cpp
new file mode 100644
index 0000000000..be40050bb1
--- /dev/null
+++ b/engines/kyra/gui_rpg.cpp
@@ -0,0 +1,134 @@
+/* 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/kyra_rpg.h"
+
+namespace Kyra {
+
+void KyraRpgEngine::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 KyraRpgEngine::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 KyraRpgEngine::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 - 1, y + h, col2);
+}
+
+void KyraRpgEngine::gui_initButtonsFromList(const int16 *list) {
+ while (*list != -1)
+ gui_initButton(*list++);
+}
+
+void KyraRpgEngine::gui_resetButtonList() {
+ for (uint i = 0; i < ARRAYSIZE(_activeButtonData); ++i)
+ _activeButtonData[i].nextButton = 0;
+
+ gui_notifyButtonListChanged();
+ _activeButtons = 0;
+}
+
+void KyraRpgEngine::gui_notifyButtonListChanged() {
+ if (gui()) {
+ if (!_buttonListChanged && !_preserveEvents)
+ removeInputTop();
+ _buttonListChanged = true;
+ }
+}
+
+bool KyraRpgEngine::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;
+}
+
+} // End of namespace Kyra
+
+#endif // defined(ENABLE_EOB) || defined(ENABLE_LOL)
diff --git a/engines/kyra/gui_v1.cpp b/engines/kyra/gui_v1.cpp
new file mode 100644
index 0000000000..f3459ddfe3
--- /dev/null
+++ b/engines/kyra/gui_v1.cpp
@@ -0,0 +1,629 @@
+/* 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/gui_v1.h"
+
+#include "kyra/text.h"
+#include "kyra/wsamovie.h"
+
+#include "common/savefile.h"
+#include "common/system.h"
+
+namespace Kyra {
+
+GUI_v1::GUI_v1(KyraEngine_v1 *kyra) : GUI(kyra), _text(kyra->text()) {
+ _menuButtonList = 0;
+
+ _redrawButtonFunctor = BUTTON_FUNCTOR(GUI_v1, this, &GUI_v1::redrawButtonCallback);
+ _redrawShadedButtonFunctor = BUTTON_FUNCTOR(GUI_v1, this, &GUI_v1::redrawShadedButtonCallback);
+}
+
+Button *GUI_v1::addButtonToList(Button *list, Button *newButton) {
+ if (!newButton)
+ return list;
+
+ newButton->nextButton = 0;
+
+ if (list) {
+ Button *cur = list;
+ while (cur->nextButton)
+ cur = cur->nextButton;
+ cur->nextButton = newButton;
+ } else {
+ list = newButton;
+ }
+
+ return list;
+}
+
+void GUI_v1::initMenuLayout(Menu &menu) {
+ if (menu.x == -1)
+ menu.x = (320 - menu.width) >> 1;
+ if (menu.y == -1)
+ menu.y = (200 - menu.height) >> 1;
+
+ for (int i = 0; i < menu.numberOfItems; ++i) {
+ if (menu.item[i].x == -1)
+ menu.item[i].x = (menu.width - menu.item[i].width) >> 1;
+ }
+}
+
+void GUI_v1::initMenu(Menu &menu) {
+ _menuButtonList = 0;
+
+ _screen->hideMouse();
+
+ int textX;
+ int textY;
+
+ int menu_x2 = menu.width + menu.x - 1;
+ int menu_y2 = menu.height + menu.y - 1;
+
+ _screen->fillRect(menu.x + 2, menu.y + 2, menu_x2 - 2, menu_y2 - 2, menu.bkgdColor);
+ _screen->drawShadedBox(menu.x, menu.y, menu_x2, menu_y2, menu.color1, menu.color2);
+
+ if (menu.titleX != -1)
+ textX = menu.titleX;
+ else
+ textX = getMenuCenterStringX(getMenuTitle(menu), menu.x, menu_x2);
+
+ textY = menu.y + menu.titleY;
+
+ if (_vm->game() == GI_LOL) {
+ printMenuText(getMenuTitle(menu), textX, textY, menu.textColor, 0, 9);
+ } else {
+ if (_vm->gameFlags().platform != Common::kPlatformAmiga)
+ printMenuText(getMenuTitle(menu), textX - 1, textY + 1, defaultColor1(), defaultColor2(), 0);
+ printMenuText(getMenuTitle(menu), textX, textY, menu.textColor, 0, 0);
+ }
+
+ int x1, y1, x2, y2;
+ for (int i = 0; i < menu.numberOfItems; ++i) {
+ if (!menu.item[i].enabled)
+ continue;
+
+ x1 = menu.x + menu.item[i].x;
+ y1 = menu.y + menu.item[i].y;
+
+ x2 = x1 + menu.item[i].width - 1;
+ y2 = y1 + menu.item[i].height - 1;
+
+ if (i < 7) {
+ Button *menuButtonData = getButtonListData() + i;
+ menuButtonData->nextButton = 0;
+ menuButtonData->x = x1;
+ menuButtonData->y = y1;
+ menuButtonData->width = menu.item[i].width - 1;
+ menuButtonData->height = menu.item[i].height - 1;
+ menuButtonData->buttonCallback = menu.item[i].callback;
+ menuButtonData->keyCode = menu.item[i].keyCode;
+ menuButtonData->keyCode2 = 0;
+ menuButtonData->arg = menu.item[i].itemId;
+
+ _menuButtonList = addButtonToList(_menuButtonList, menuButtonData);
+ }
+
+ _screen->fillRect(x1, y1, x2, y2, menu.item[i].bkgdColor);
+ _screen->drawShadedBox(x1, y1, x2, y2, menu.item[i].color1, menu.item[i].color2);
+
+ if (getMenuItemTitle(menu.item[i])) {
+ if (menu.item[i].titleX != -1)
+ textX = x1 + menu.item[i].titleX + 3;
+ else
+ textX = getMenuCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2);
+
+ textY = y1 + 2;
+ if (_vm->game() == GI_LOL) {
+ textY++;
+ if (i == menu.highlightedItem)
+ printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 8);
+ else
+ printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 8);
+ } else {
+ Screen::FontId of = _screen->_currentFont;
+ if (menu.item[i].saveSlot > 0)
+ _screen->setFont(Screen::FID_8_FNT);
+
+ if (_vm->gameFlags().platform != Common::kPlatformAmiga)
+ printMenuText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0);
+
+ if (i == menu.highlightedItem)
+ printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 0);
+ else
+ printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 0);
+
+ _screen->setFont(of);
+ }
+ }
+ }
+
+ for (int i = 0; i < menu.numberOfItems; ++i) {
+ if (getMenuItemLabel(menu.item[i])) {
+ if (_vm->game() == GI_LOL) {
+ menu.item[i].labelX = menu.item[i].x - 1;
+ menu.item[i].labelY = menu.item[i].y + 3;
+ printMenuText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX, menu.y + menu.item[i].labelY, menu.item[i].textColor, 0, 10);
+ } else {
+ if (_vm->gameFlags().platform != Common::kPlatformAmiga)
+ printMenuText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX - 1, menu.y + menu.item[i].labelY + 1, defaultColor1(), 0, 0);
+ printMenuText(getMenuItemLabel(menu.item[i]), menu.x + menu.item[i].labelX, menu.y + menu.item[i].labelY, menu.item[i].textColor, 0, 0);
+ }
+ }
+ }
+
+ if (menu.scrollUpButtonX != -1) {
+ Button *scrollUpButton = getScrollUpButton();
+ scrollUpButton->x = menu.scrollUpButtonX + menu.x;
+ scrollUpButton->y = menu.scrollUpButtonY + menu.y;
+ scrollUpButton->buttonCallback = getScrollUpButtonHandler();
+ scrollUpButton->nextButton = 0;
+ scrollUpButton->mouseWheel = -1;
+
+ _menuButtonList = addButtonToList(_menuButtonList, scrollUpButton);
+ updateMenuButton(scrollUpButton);
+
+ Button *scrollDownButton = getScrollDownButton();
+ scrollDownButton->x = menu.scrollDownButtonX + menu.x;
+ scrollDownButton->y = menu.scrollDownButtonY + menu.y;
+ scrollDownButton->buttonCallback = getScrollDownButtonHandler();
+ scrollDownButton->nextButton = 0;
+ scrollDownButton->mouseWheel = 1;
+
+ _menuButtonList = addButtonToList(_menuButtonList, scrollDownButton);
+ updateMenuButton(scrollDownButton);
+ }
+
+ _screen->showMouse();
+ _screen->updateScreen();
+}
+
+void GUI_v1::processHighlights(Menu &menu) {
+ int x1, y1, x2, y2;
+ Common::Point p = _vm->getMousePos();
+ int mouseX = p.x;
+ int mouseY = p.y;
+
+ if (_vm->game() == GI_LOL && menu.highlightedItem != 255) {
+ // LoL doesnt't have default highlighted items.
+ // We use a highlightedItem value of 255 for this.
+
+ // With LoL no highlighting should take place unless the
+ // mouse cursor moves over a button. The highlighting should end
+ // when the mouse cursor leaves the button.
+ if (menu.item[menu.highlightedItem].enabled)
+ redrawText(menu);
+ }
+
+ for (int i = 0; i < menu.numberOfItems; ++i) {
+ if (!menu.item[i].enabled)
+ continue;
+
+ x1 = menu.x + menu.item[i].x;
+ y1 = menu.y + menu.item[i].y;
+
+ x2 = x1 + menu.item[i].width;
+ y2 = y1 + menu.item[i].height;
+
+ if (mouseX > x1 && mouseX < x2 &&
+ mouseY > y1 && mouseY < y2) {
+
+ if (menu.highlightedItem != i || _vm->game() == GI_LOL) {
+ if (_vm->game() != GI_LOL) {
+ if (menu.item[menu.highlightedItem].enabled)
+ redrawText(menu);
+ }
+
+ menu.highlightedItem = i;
+ redrawHighlight(menu);
+ }
+ }
+ }
+
+ _screen->updateScreen();
+}
+
+void GUI_v1::redrawText(const Menu &menu) {
+ int textX;
+ int i = menu.highlightedItem;
+
+ int x1 = menu.x + menu.item[i].x;
+ int y1 = menu.y + menu.item[i].y;
+
+ int x2 = x1 + menu.item[i].width - 1;
+
+ if (menu.item[i].titleX >= 0)
+ textX = x1 + menu.item[i].titleX + 3;
+ else
+ textX = getMenuCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2);
+
+ int textY = y1 + 2;
+ if (_vm->game() == GI_LOL) {
+ textY++;
+ printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 8);
+ } else {
+ Screen::FontId of = _screen->_currentFont;
+ if (menu.item[i].saveSlot > 0)
+ _screen->setFont(Screen::FID_8_FNT);
+ if (_vm->gameFlags().platform != Common::kPlatformAmiga)
+ printMenuText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0);
+ printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].textColor, 0, 0);
+ _screen->setFont(of);
+ }
+}
+
+void GUI_v1::redrawHighlight(const Menu &menu) {
+ int textX;
+ int i = menu.highlightedItem;
+
+ int x1 = menu.x + menu.item[i].x;
+ int y1 = menu.y + menu.item[i].y;
+
+ int x2 = x1 + menu.item[i].width - 1;
+
+ if (menu.item[i].titleX != -1)
+ textX = x1 + menu.item[i].titleX + 3;
+ else
+ textX = getMenuCenterStringX(getMenuItemTitle(menu.item[i]), x1, x2);
+
+ int textY = y1 + 2;
+
+ if (_vm->game() == GI_LOL) {
+ textY++;
+ printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 8);
+ } else {
+ Screen::FontId of = _screen->_currentFont;
+ if (menu.item[i].saveSlot > 0)
+ _screen->setFont(Screen::FID_8_FNT);
+ if (_vm->gameFlags().platform != Common::kPlatformAmiga)
+ printMenuText(getMenuItemTitle(menu.item[i]), textX - 1, textY + 1, defaultColor1(), 0, 0);
+ printMenuText(getMenuItemTitle(menu.item[i]), textX, textY, menu.item[i].highlightColor, 0, 0);
+ _screen->setFont(of);
+ }
+}
+
+void GUI_v1::updateAllMenuButtons() {
+ for (Button *cur = _menuButtonList; cur; cur = cur->nextButton)
+ updateMenuButton(cur);
+}
+
+void GUI_v1::updateMenuButton(Button *button) {
+ if (!_displayMenu)
+ return;
+
+ _screen->hideMouse();
+ updateButton(button);
+ _screen->updateScreen();
+ _screen->showMouse();
+}
+
+void GUI_v1::updateButton(Button *button) {
+ if (!button || (button->flags & 8))
+ return;
+
+ if (button->flags2 & 1)
+ button->flags2 &= 0xFFF7;
+ else
+ button->flags2 |= 8;
+
+ button->flags2 &= 0xFFFC;
+
+ if (button->flags2 & 4)
+ button->flags2 |= 0x10;
+ else
+ button->flags2 &= 0xEEEF;
+
+ button->flags2 &= 0xFFFB;
+
+ processButton(button);
+}
+
+int GUI_v1::redrawButtonCallback(Button *button) {
+ if (!_displayMenu)
+ return 0;
+
+ _screen->hideMouse();
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga)
+ _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 17);
+ else
+ _screen->drawBox(button->x + 1, button->y + 1, button->x + button->width - 1, button->y + button->height - 1, 0xF8);
+ _screen->showMouse();
+
+ return 0;
+}
+
+int GUI_v1::redrawShadedButtonCallback(Button *button) {
+ if (!_displayMenu)
+ return 0;
+
+ _screen->hideMouse();
+ if (_vm->gameFlags().platform == Common::kPlatformAmiga)
+ _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 31, 18);
+ else
+ _screen->drawShadedBox(button->x, button->y, button->x + button->width, button->y + button->height, 0xF9, 0xFA);
+ _screen->showMouse();
+
+ return 0;
+}
+
+void GUI_v1::checkTextfieldInput() {
+ Common::Event event;
+
+ uint32 now = _vm->_system->getMillis();
+
+ bool running = true;
+ int keys = 0;
+ while (_vm->_eventMan->pollEvent(event) && running) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ if (event.kbd.keycode == Common::KEYCODE_q && event.kbd.hasFlags(Common::KBD_CTRL))
+ _vm->quitGame();
+ else
+ _keyPressed = event.kbd;
+ running = false;
+ break;
+
+ case Common::EVENT_LBUTTONDOWN:
+ case Common::EVENT_LBUTTONUP: {
+ Common::Point pos = _vm->getMousePos();
+ _vm->_mouseX = pos.x;
+ _vm->_mouseY = pos.y;
+ keys = event.type == Common::EVENT_LBUTTONDOWN ? 199 : (200 | 0x800);
+ running = false;
+ } break;
+
+ case Common::EVENT_MOUSEMOVE: {
+ Common::Point pos = _vm->getMousePos();
+ _vm->_mouseX = pos.x;
+ _vm->_mouseY = pos.y;
+
+ _vm->_system->updateScreen();
+ _lastScreenUpdate = now;
+ } break;
+
+ default:
+ break;
+ }
+ }
+
+ if (now - _lastScreenUpdate > 50) {
+ _vm->_system->updateScreen();
+ _lastScreenUpdate = now;
+ }
+
+ processButtonList(_menuButtonList, keys | 0x8000, 0);
+ _vm->_system->delayMillis(3);
+}
+
+void GUI_v1::printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2) {
+ _text->printText(str, x, y, c0, c1, c2);
+}
+
+int GUI_v1::getMenuCenterStringX(const char *str, int x1, int x2) {
+ return _text->getCenterStringX(str, x1, x2);
+}
+
+#pragma mark -
+
+MainMenu::MainMenu(KyraEngine_v1 *vm) : _vm(vm), _screen(0) {
+ _screen = _vm->screen();
+ _nextUpdate = 0;
+ _system = g_system;
+}
+
+void MainMenu::init(StaticData data, Animation anim) {
+ _static = data;
+ _anim = anim;
+ _animIntern.curFrame = _anim.startFrame;
+ _animIntern.direction = 1;
+}
+
+void MainMenu::updateAnimation() {
+ if (_anim.anim) {
+ uint32 now = _system->getMillis();
+ if (now > _nextUpdate) {
+ _nextUpdate = now + _anim.delay * _vm->tickLength();
+
+ _anim.anim->displayFrame(_animIntern.curFrame, 0, 0, 0, 0, 0, 0);
+ _animIntern.curFrame += _animIntern.direction;
+ if (_animIntern.curFrame < _anim.startFrame) {
+ _animIntern.curFrame = _anim.startFrame;
+ _animIntern.direction = 1;
+ } else if (_animIntern.curFrame > _anim.endFrame) {
+ _animIntern.curFrame = _anim.endFrame;
+ _animIntern.direction = -1;
+ }
+ }
+ }
+
+ _screen->updateScreen();
+}
+
+bool MainMenu::getInput() {
+ Common::Event event;
+ Common::EventManager *eventMan = _vm->getEventManager();
+
+ bool updateScreen = false;
+
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_LBUTTONUP:
+ return true;
+
+ case Common::EVENT_MOUSEMOVE:
+ updateScreen = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (updateScreen)
+ _system->updateScreen();
+ return false;
+}
+
+int MainMenu::handle(int dim) {
+ int command = -1;
+
+ uint8 colorMap[16];
+ memset(colorMap, 0, sizeof(colorMap));
+ _screen->setTextColorMap(colorMap);
+
+ Screen::FontId oldFont = _screen->setFont(_static.font);
+ int charWidthBackUp = _screen->_charWidth;
+
+ if (_vm->game() != GI_LOL)
+ _screen->_charWidth = -2;
+ _screen->setScreenDim(dim);
+
+ int backUpX = _screen->_curDim->sx;
+ int backUpY = _screen->_curDim->sy;
+ int backUpWidth = _screen->_curDim->w;
+ int backUpHeight = _screen->_curDim->h;
+ _screen->copyRegion(backUpX, backUpY, backUpX, backUpY, backUpWidth, backUpHeight, 0, 3);
+
+ int x = _screen->_curDim->sx << 3;
+ int y = _screen->_curDim->sy;
+ int width = _screen->_curDim->w << 3;
+ int height = _screen->_curDim->h;
+
+ drawBox(x, y, width, height, 1);
+ drawBox(x + 1, y + 1, width - 2, height - 2, 0);
+
+ int selected = 0;
+
+ draw(selected);
+
+ while (!_screen->isMouseVisible())
+ _screen->showMouse();
+
+ int fh = _screen->getFontHeight();
+ if (_vm->gameFlags().lang == Common::JA_JPN)
+ fh++;
+
+ int textPos = ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3;
+
+ Common::Rect menuRect(x + 16, y + 4, x + width - 16, y + 4 + fh * _static.menuTable[3]);
+
+ while (!_vm->shouldQuit()) {
+ updateAnimation();
+ bool mousePressed = getInput();
+
+ Common::Point mouse = _vm->getMousePos();
+ if (menuRect.contains(mouse)) {
+ int item = (mouse.y - menuRect.top) / fh;
+
+ if (item != selected) {
+ printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5, _static.strings[selected]);
+ printString("%s", textPos, menuRect.top + item * fh, _static.menuTable[6], 0, 5, _static.strings[item]);
+
+ selected = item;
+ }
+
+ if (mousePressed) {
+ for (int i = 0; i < 3; i++) {
+ printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[5], 0, 5, _static.strings[selected]);
+ _screen->updateScreen();
+ _system->delayMillis(50);
+ printString("%s", textPos, menuRect.top + selected * fh, _static.menuTable[6], 0, 5, _static.strings[selected]);
+ _screen->updateScreen();
+ _system->delayMillis(50);
+ }
+ command = item;
+ break;
+ }
+ }
+ _system->delayMillis(10);
+ }
+
+ if (_vm->shouldQuit())
+ command = -1;
+
+ _screen->copyRegion(backUpX, backUpY, backUpX, backUpY, backUpWidth, backUpHeight, 3, 0);
+ _screen->_charWidth = charWidthBackUp;
+ _screen->setFont(oldFont);
+
+ return command;
+}
+
+void MainMenu::draw(int select) {
+ int top = _screen->_curDim->sy;
+ top += _static.menuTable[1];
+ int fh = _screen->getFontHeight();
+ if (_vm->gameFlags().lang == Common::JA_JPN)
+ fh++;
+
+ for (int i = 0; i < _static.menuTable[3]; ++i) {
+ int curY = top + i * fh;
+ int color = (i == select) ? _static.menuTable[6] : _static.menuTable[5];
+ printString("%s", ((_screen->_curDim->w >> 1) + _screen->_curDim->sx) << 3, curY, color, 0, 5, _static.strings[i]);
+ }
+}
+
+void MainMenu::drawBox(int x, int y, int w, int h, int fill) {
+ --w; --h;
+
+ if (fill)
+ _screen->fillRect(x, y, x + w, y + h, _static.colorTable[0]);
+
+ _screen->drawClippedLine(x, y + h, x + w, y + h, _static.colorTable[1]);
+ _screen->drawClippedLine(x + w, y, x + w, y + h, _static.colorTable[1]);
+ _screen->drawClippedLine(x, y, x + w, y, _static.colorTable[2]);
+ _screen->drawClippedLine(x, y, x, y + h, _static.colorTable[2]);
+
+ _screen->setPagePixel(_screen->_curPage, x, y + h, _static.colorTable[3]);
+ _screen->setPagePixel(_screen->_curPage, x + w, y, _static.colorTable[3]);
+}
+
+void MainMenu::printString(const char *format, int x, int y, int col1, int col2, int flags, ...) {
+ if (!format)
+ return;
+
+ va_list vaList;
+ va_start(vaList, flags);
+ Common::String string = Common::String::vformat(format, vaList);
+ va_end(vaList);
+
+ if (flags & 1)
+ x -= _screen->getTextWidth(string.c_str()) >> 1;
+
+ if (flags & 2)
+ x -= _screen->getTextWidth(string.c_str());
+
+ if (_vm->gameFlags().use16ColorMode)
+ flags &= 3;
+
+ if (flags & 4) {
+ _screen->printText(string.c_str(), x - 1, y, _static.altColor, col2);
+ _screen->printText(string.c_str(), x, y + 1, _static.altColor, col2);
+ }
+
+ if (flags & 8) {
+ _screen->printText(string.c_str(), x - 1, y, 227, col2);
+ _screen->printText(string.c_str(), x, y + 1, 227, col2);
+ }
+
+ _screen->printText(string.c_str(), x, y, col1, col2);
+}
+
+} // End of namespace Kyra
diff --git a/engines/kyra/gui_v1.h b/engines/kyra/gui_v1.h
new file mode 100644
index 0000000000..260edae8e5
--- /dev/null
+++ b/engines/kyra/gui_v1.h
@@ -0,0 +1,197 @@
+/* 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_GUI_V1_H
+#define KYRA_GUI_V1_H
+
+#include "kyra/gui.h"
+
+namespace Kyra {
+
+struct MenuItem {
+ bool enabled;
+
+ const char *itemString;
+ uint16 itemId;
+
+ int16 x, y;
+ uint16 width, height;
+
+ uint8 textColor, highlightColor;
+
+ int16 titleX;
+
+ uint8 color1, color2;
+ uint8 bkgdColor;
+
+ Button::Callback callback;
+
+ int16 saveSlot;
+
+ const char *labelString;
+ uint16 labelId;
+ int16 labelX, labelY;
+
+ uint16 keyCode;
+};
+
+struct Menu {
+ int16 x, y;
+ uint16 width, height;
+
+ uint8 bkgdColor;
+ uint8 color1, color2;
+
+ const char *menuNameString;
+ uint16 menuNameId;
+
+ uint8 textColor;
+ int16 titleX, titleY;
+
+ uint8 highlightedItem;
+
+ uint8 numberOfItems;
+
+ int16 scrollUpButtonX, scrollUpButtonY;
+ int16 scrollDownButtonX, scrollDownButtonY;
+
+ MenuItem item[7];
+};
+
+class TextDisplayer;
+
+class GUI_v1 : public GUI {
+public:
+ GUI_v1(KyraEngine_v1 *vm);
+ virtual ~GUI_v1() {}
+
+ // button specific
+ virtual Button *addButtonToList(Button *list, Button *newButton);
+
+ virtual void processButton(Button *button) = 0;
+ virtual int processButtonList(Button *buttonList, uint16 inputFlags, int8 mouseWheel) = 0;
+
+ virtual int redrawShadedButtonCallback(Button *button);
+ virtual int redrawButtonCallback(Button *button);
+
+ // menu specific
+ virtual void initMenuLayout(Menu &menu);
+ void initMenu(Menu &menu);
+
+ void processHighlights(Menu &menu);
+
+ // utilities for thumbnail creation
+ virtual void createScreenThumbnail(Graphics::Surface &dst) = 0;
+
+protected:
+ TextDisplayer *_text;
+
+ Button *_menuButtonList;
+ bool _displayMenu;
+ bool _displaySubMenu;
+ bool _cancelSubMenu;
+
+ virtual void printMenuText(const char *str, int x, int y, uint8 c0, uint8 c1, uint8 c2);
+ virtual int getMenuCenterStringX(const char *str, int x1, int x2);
+
+ Button::Callback _redrawShadedButtonFunctor;
+ Button::Callback _redrawButtonFunctor;
+
+ virtual Button *getButtonListData() = 0;
+ virtual Button *getScrollUpButton() = 0;
+ virtual Button *getScrollDownButton() = 0;
+
+ virtual Button::Callback getScrollUpButtonHandler() const = 0;
+ virtual Button::Callback getScrollDownButtonHandler() const = 0;
+
+ virtual uint8 defaultColor1() const = 0;
+ virtual uint8 defaultColor2() const = 0;
+
+ virtual const char *getMenuTitle(const Menu &menu) = 0;
+ virtual const char *getMenuItemTitle(const MenuItem &menuItem) = 0;
+ virtual const char *getMenuItemLabel(const MenuItem &menuItem) = 0;
+
+ void updateAllMenuButtons();
+ void updateMenuButton(Button *button);
+ virtual void updateButton(Button *button);
+
+ void redrawText(const Menu &menu);
+ void redrawHighlight(const Menu &menu);
+
+ uint32 _lastScreenUpdate;
+ void checkTextfieldInput();
+};
+
+class Movie;
+
+class MainMenu {
+public:
+ MainMenu(KyraEngine_v1 *vm);
+ virtual ~MainMenu() {}
+
+ struct Animation {
+ Animation() : anim(0), startFrame(0), endFrame(0), delay(0) {}
+
+ Movie *anim;
+ int startFrame;
+ int endFrame;
+ int delay;
+ };
+
+ struct StaticData {
+ const char *strings[5];
+
+ uint8 menuTable[7];
+ uint8 colorTable[4];
+
+ Screen::FontId font;
+ uint8 altColor;
+ };
+
+ void init(StaticData data, Animation anim);
+ int handle(int dim);
+private:
+ KyraEngine_v1 *_vm;
+ Screen *_screen;
+ OSystem *_system;
+
+ StaticData _static;
+ struct AnimIntern {
+ int curFrame;
+ int direction;
+ };
+ Animation _anim;
+ AnimIntern _animIntern;
+
+ uint32 _nextUpdate;
+
+ void updateAnimation();
+ void draw(int select);
+ void drawBox(int x, int y, int w, int h, int fill);
+ bool getInput();
+
+ void printString(const char *string, int x, int y, int col1, int col2, int flags, ...) GCC_PRINTF(2, 8);
+};
+
+} // end of namesapce Kyra
+
+#endif
diff --git a/engines/kyra/gui_v2.cpp b/engines/kyra/gui_v2.cpp
index c0477f29f1..65f8bd45e5 100644
--- a/engines/kyra/gui_v2.cpp
+++ b/engines/kyra/gui_v2.cpp
@@ -30,7 +30,7 @@
namespace Kyra {
-GUI_v2::GUI_v2(KyraEngine_v2 *vm) : GUI(vm), _vm(vm), _screen(vm->screen_v2()) {
+GUI_v2::GUI_v2(KyraEngine_v2 *vm) : GUI_v1(vm), _vm(vm), _screen(vm->screen_v2()) {
_backUpButtonList = _specialProcessButton = 0;
_buttonListChanged = false;
_lastScreenUpdate = 0;
@@ -48,7 +48,7 @@ GUI_v2::GUI_v2(KyraEngine_v2 *vm) : GUI(vm), _vm(vm), _screen(vm->screen_v2()) {
}
Button *GUI_v2::addButtonToList(Button *list, Button *newButton) {
- list = GUI::addButtonToList(list, newButton);
+ list = GUI_v1::addButtonToList(list, newButton);
_buttonListChanged = true;
return list;
}
@@ -211,7 +211,7 @@ int GUI_v2::processButtonList(Button *buttonList, uint16 inputFlag, int8 mouseWh
bool progress = false;
- if (mouseX >= x && mouseY >= y && mouseX <= x+buttonList->width && mouseY <= y+buttonList->height)
+ if (mouseX >= x && mouseY >= y && mouseX <= x + buttonList->width && mouseY <= y + buttonList->height)
progress = true;
buttonList->flags2 &= ~0x80;
@@ -360,7 +360,7 @@ int GUI_v2::processButtonList(Button *buttonList, uint16 inputFlag, int8 mouseWh
if (buttonList->buttonCallback) {
_vm->removeInputTop();
- if ((*buttonList->buttonCallback.get())(buttonList))
+ if ((*buttonList->buttonCallback)(buttonList))
break;
}
@@ -425,7 +425,7 @@ void GUI_v2::renewHighlight(Menu &menu) {
int x = item.x + menu.x; int y = item.y + menu.y;
int x2 = x + item.width - 1; int y2 = y + item.height - 1;
redrawText(menu);
- _screen->fillRect(x+2, y+2, x2-2, y2-2, item.bkgdColor);
+ _screen->fillRect(x + 2, y + 2, x2 - 2, y2 - 2, item.bkgdColor);
redrawHighlight(menu);
_screen->updateScreen();
}
@@ -594,7 +594,7 @@ int GUI_v2::cancelLoadMenu(Button *caller) {
}
int GUI_v2::saveMenu(Button *caller) {
- updateSaveList();
+ updateSaveFileList(_vm->_targetName);
updateMenuButton(caller);
@@ -690,7 +690,7 @@ int GUI_v2::cancelSaveMenu(Button *caller) {
}
int GUI_v2::deleteMenu(Button *caller) {
- updateSaveList();
+ updateSaveFileList(_vm->_targetName);
updateMenuButton(caller);
if (_saveSlots.size() < 2) {
@@ -736,10 +736,10 @@ int GUI_v2::deleteMenu(Button *caller) {
break;
// We are only renaming all savefiles until we get some slots missing
// Also not rename quicksave slot filenames
- if (*(i-1) != *i || *i >= 990)
+ if (*(i - 1) != *i || *i >= 990)
break;
Common::String oldName = _vm->getSavegameFilename(*i);
- Common::String newName = _vm->getSavegameFilename(*i-1);
+ Common::String newName = _vm->getSavegameFilename(*i - 1);
_vm->_saveFileMan->renameSavefile(oldName, newName);
}
_saveMenu.menuNameId = _vm->gameFlags().isTalkie ? 9 : 17;
@@ -845,7 +845,7 @@ int GUI_v2::getCharWidth(uint8 c) {
}
void GUI_v2::drawTextfieldBlock(int x, int y, uint8 c) {
- _screen->fillRect(x+1, y+1, x+7, y+8, c);
+ _screen->fillRect(x + 1, y + 1, x + 7, y + 8, c);
}
bool GUI_v2::choiceDialog(int name, bool type) {
diff --git a/engines/kyra/gui_v2.h b/engines/kyra/gui_v2.h
index ef95c0301a..bdbcce1c4f 100644
--- a/engines/kyra/gui_v2.h
+++ b/engines/kyra/gui_v2.h
@@ -23,7 +23,7 @@
#ifndef KYRA_GUI_V2_H
#define KYRA_GUI_V2_H
-#include "kyra/gui.h"
+#include "kyra/gui_v1.h"
namespace Kyra {
@@ -99,7 +99,7 @@ namespace Kyra {
class KyraEngine_v2;
class Screen_v2;
-class GUI_v2 : public GUI {
+class GUI_v2 : public GUI_v1 {
public:
GUI_v2(KyraEngine_v2 *vm);
diff --git a/engines/kyra/items_eob.cpp b/engines/kyra/items_eob.cpp
new file mode 100644
index 0000000000..0994e12e4f
--- /dev/null
+++ b/engines/kyra/items_eob.cpp
@@ -0,0 +1,731 @@
+/* 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");
+ memset(_items, 0, sizeof(EoBItem) * 600);
+ _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();
+
+ delete[] _itemTypes;
+ _itemTypes = new EoBItemType[65];
+ memset(_itemTypes, 0, sizeof(EoBItemType) * 65);
+
+ 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], itm, sizeof(EoBItem));
+ return i;
+}
+
+Item EoBCoreEngine::createItemOnCurrentBlock(Item itemIndex) {
+ Item itm = duplicateItem(itemIndex);
+ setItemPosition((Item *)&_levelBlockProperties[_currentBlock].drawObjects, _currentBlock, itm, _dropItemDirIndex[(_currentDirection << 2) + rollDice(1, 2, -1)]);
+ return itm;
+}
+
+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, int16 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;
+
+ _levelBlockProperties[block].drawObjects = 0;
+
+ 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;
+
+ if (slot == 17 && item && !itemUsableByCharacter(charIndex, item)) {
+ _txt->printMessage(_validateArmorString[0], -1, _characters[charIndex].name);
+ return 0;
+ }
+
+ int itm = _characters[charIndex].inventory[slot];
+ int ex = _itemTypes[_items[itm].type].extraProperties & 0x7f;
+
+ if (_items[itm].flags & 0x20 && (_flags.gameID == GI_EOB1 || slot < 2)) {
+ if (_flags.gameID == GI_EOB2 && ex > 0 && ex < 4)
+ _txt->printMessage(_validateCursedString[0], -1, _characters[charIndex].name);
+ return 0;
+ }
+
+ uint16 v = item ? _itemTypes[_items[item].type].invFlags : 0xffff;
+ if (v & _slotValidationFlags[slot])
+ return 1;
+
+ _txt->printMessage(_validateNoDropString[0]);
+ return 0;
+}
+
+int EoBCoreEngine::stripPartyItems(int16 itemType, int16 itemValue, int handleValueMode, int numItems) {
+ int itemsLeft = numItems;
+
+ for (bool runloop = true; runloop && itemsLeft;) {
+ runloop = false;
+ for (int i = 0; i < 6 && itemsLeft; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+
+ for (int ii = 0; ii < 27 && itemsLeft; ii++) {
+ if (ii == 16)
+ continue;
+
+ Item itm = _characters[i].inventory[ii];
+ if ((_items[itm].type == itemType) && ((handleValueMode == -1 && _items[itm].value <= itemValue) || (handleValueMode == 0 && _items[itm].value == itemValue) || (handleValueMode == 1 && _items[itm].value >= itemValue))) {
+ _characters[i].inventory[ii] = 0;
+ _items[itm].block = -1;
+ itemsLeft--;
+ runloop = true;
+ }
+ }
+ }
+ }
+
+ return numItems - itemsLeft;
+}
+
+bool EoBCoreEngine::deletePartyItems(int16 itemType, int16 itemValue) {
+ bool res = false;
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 1))
+ continue;
+
+ EoBCharacter *c = &_characters[i];
+ for (int slot = checkInventoryForItem(i, itemType, itemValue); slot != -1; slot = checkInventoryForItem(i, itemType, itemValue)) {
+ int itm = c->inventory[slot];
+ _items[itm].block = -1;
+ c->inventory[slot] = 0;
+ res = true;
+
+ if (!_dialogueField) {
+ if (_currentControlMode == 0 && slot < 2 && i < 5)
+ gui_drawWeaponSlot(i, slot);
+
+ if (_currentControlMode == 1 && i == _updateCharNum)
+ gui_drawInventoryItem(slot, 1, 0);
+ }
+ }
+ }
+
+ if (_itemInHand > 0) {
+ if ((itemType == -1 || itemType == _items[_itemInHand].type) && (itemValue == -1 || itemValue == _items[_itemInHand].value)) {
+ _items[_itemInHand].block = -1;
+ setHandItem(0);
+ res = true;
+ }
+ }
+
+ return res;
+}
+
+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) || (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;
+
+ bool correctSuffixCase = false;
+
+ Common::String tmpString;
+
+ if ((itm->flags & 0x40) && !strlen(nameId)) {
+ switch (f) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ if (v == 0)
+ tmpString = nameUnid;
+ else if (v < 0)
+ tmpString = _flags.gameID == GI_EOB1 ? Common::String::format(_cursedString[0], nameUnid, v) : Common::String::format(_cursedString[0], v, nameUnid);
+ else
+ tmpString = _flags.gameID == GI_EOB1 ? Common::String::format(_enchantedString[0], nameUnid, v) : Common::String::format(_enchantedString[0], v, nameUnid);
+ break;
+
+ case 9:
+ tstr2 = _magicObjectStrings[0];
+ tstr3 = _spells[v].name;
+ correctSuffixCase = true;
+ break;
+
+ case 10:
+ tstr2 = _magicObjectStrings[1];
+ tstr3 = _spells[_flags.gameID == GI_EOB1 ? (_clericSpellOffset + v) : v].name;
+ correctSuffixCase = true;
+ break;
+
+ case 14:
+ tstr2 = _magicObjectStrings[3];
+ if (_flags.gameID == GI_EOB1)
+ v--;
+ tstr3 = _suffixStringsPotions[v];
+ break;
+
+ case 16:
+ tstr2 = _magicObjectStrings[2];
+ tstr3 = _suffixStringsRings[v];
+ break;
+
+ case 18:
+ if (_flags.gameID == GI_EOB2 && v == 5) {
+ if (_flags.lang == Common::DE_DEU)
+ tstr2 = _magicObjectString5[0];
+ else
+ tstr3 = _magicObjectString5[0];
+ correctSuffixCase = true;
+ } else {
+ tstr2 = _magicObjectStrings[4];
+ }
+ tstr3 = _suffixStringsWands[v];
+ break;
+
+ default:
+ tmpString = nameUnid;
+ break;
+ }
+
+
+ if (tstr3) {
+ if (!tstr2) {
+ tmpString = tstr3;
+ } else {
+ if (correctSuffixCase) {
+ if (tstr2 == _magicObjectString5[0])
+ tmpString = Common::String::format(_patternGrFix2[0], tstr2, tstr3);
+ else
+ tmpString = Common::String::format(_patternGrFix1[0], tstr2, tstr3);
+ } else {
+ tmpString = Common::String::format(_patternSuffix[0], tstr2, tstr3);
+ }
+ }
+ }
+ } else {
+ tmpString = (itm->flags & 0x40) ? nameId : nameUnid;
+ }
+
+ _txt->printMessage(tmpString.c_str());
+}
+
+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;
+ const uint8 *ovl = 0;
+
+ if (applyBluePal) {
+ if (_flags.gameID == GI_EOB1) {
+ ovl = (_configRenderMode == Common::kRenderCGA) ? _itemsOverlayCGA : &_itemsOverlay[icn << 4];
+ } else {
+ _screen->setFadeTableIndex(3);
+ _screen->setShapeFadeMode(1, true);
+ }
+ }
+
+ _screen->drawShape(pageNum, _itemIconShapes[icn], x, y, 0, ovl ? 2 : 0, ovl);
+
+ if (applyBluePal) {
+ _screen->setFadeTableIndex(4);
+ _screen->setShapeFadeMode(1, false);
+ }
+}
+
+bool EoBCoreEngine::isMagicEffectItem(Item itemIndex) {
+ return (itemIndex > 10 && itemIndex < 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 && !(_flags.gameID == GI_EOB1 && _items[_itemInHand].type == 49)) {
+ _txt->printMessage(_warningStrings[_flags.gameID == GI_EOB1 ? 2 : 3]);
+ } else if (_items[_itemInHand].value == -1) {
+ printWarning(_warningStrings[2]);
+ } 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->starting = 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->starting = 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->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->starting) || ((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->starting && (fo->curBlock != _currentBlock || fo->attackerId >= 0) && (!blockHasMonsters(fo->curBlock) || 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::explodeObject(EoBFlyingObject *fo, int block, Item item) {
+ if (_partyResting) {
+ snd_processEnvironmentalSoundEffect(35, _currentBlock);
+ return;
+ }
+
+ const uint8 *table = (_expObjectTblIndex[item] == 0) ? _expObjectAnimTbl1 : ((_expObjectTblIndex[item] == 1) ? _expObjectAnimTbl2 : _expObjectAnimTbl3);
+ int tableSize = (_expObjectTblIndex[item] == 0) ? _expObjectAnimTbl1Size : ((_expObjectTblIndex[item] == 1) ? _expObjectAnimTbl2Size : _expObjectAnimTbl3Size);
+
+ int tl = 0;
+ for (; tl < 18; tl++) {
+ if (_visibleBlockIndex[tl] == block)
+ break;
+ }
+
+ if (tl == 18)
+ return;
+
+ int b = _expObjectTlMode ? _expObjectTlMode[tl] : 2;
+
+ if (b == 0 || (b == 1 && (fo->direction & 1) == (_currentDirection & 1))) {
+ snd_processEnvironmentalSoundEffect(35, _currentBlock);
+ return;
+ }
+
+ uint8 dm = _dscDimMap[tl];
+ int16 x1 = 0;
+ int16 x2 = 0;
+
+ setLevelShapesDim(tl, x1, x2, 5);
+
+ if (x2 < x1)
+ return;
+
+ if (fo)
+ fo->enable = 0;
+
+ drawScene(1);
+
+ if (fo)
+ fo->enable = 2;
+
+ _screen->fillRect(0, 0, 176, 120, 0, 2);
+ uint8 col = _screen->getPagePixel(2, 0, 0);
+ drawSceneShapes(_expObjectShpStart[dm]);
+
+ setLevelShapesDim(tl, x1, x2, 5);
+ _screen->updateScreen();
+
+ _screen->setGfxParameters(_dscShapeCoords[(tl * 5 + 4) << 1] + 88, 48, col);
+ snd_processEnvironmentalSoundEffect(35, _currentBlock);
+
+ disableSysTimer(2);
+ if (dm == 0) {
+ _screen->drawExplosion(3, 147, 35, 20, 7, table, tableSize);
+ } else if (dm == 1) {
+ _screen->drawExplosion(2, 147, 35, 20, 7, table, tableSize);
+ } else if (dm == 2) {
+ _screen->drawExplosion(1, 147, 35, 20, 7, table, tableSize);
+ } else if (dm == 3) {
+ _screen->drawExplosion(0, 460, 50, 20, 4, table, tableSize);
+ }
+ enableSysTimer(2);
+}
+
+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() {
+ if (!_runFlag)
+ return;
+
+ 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/items_lok.cpp b/engines/kyra/items_lok.cpp
index d598a17cf1..2937038463 100644
--- a/engines/kyra/items_lok.cpp
+++ b/engines/kyra/items_lok.cpp
@@ -38,7 +38,7 @@ int KyraEngine_LoK::findDuplicateItemShape(int shape) {
while (dupTable[i] != 0xFF) {
if (dupTable[i] == shape)
- return dupTable[i+1];
+ return dupTable[i + 1];
i += 2;
}
return -1;
@@ -180,7 +180,7 @@ void KyraEngine_LoK::setMouseItem(Item item) {
if (item == kItemNone)
_screen->setMouseCursor(1, 1, _shapes[6]);
else
- _screen->setMouseCursor(8, 15, _shapes[216+item]);
+ _screen->setMouseCursor(8, 15, _shapes[216 + item]);
}
void KyraEngine_LoK::wipeDownMouseItem(int xpos, int ypos) {
@@ -196,16 +196,16 @@ void KyraEngine_LoK::wipeDownMouseItem(int xpos, int ypos) {
while (height >= 0) {
restoreItemRect1(xpos, ypos);
- _screen->setNewShapeHeight(_shapes[216+_itemInHand], height);
+ _screen->setNewShapeHeight(_shapes[216 + _itemInHand], height);
uint32 nextTime = _system->getMillis() + 1 * _tickLength;
- _screen->drawShape(0, _shapes[216+_itemInHand], xpos, y, 0, 0);
+ _screen->drawShape(0, _shapes[216 + _itemInHand], xpos, y, 0, 0);
_screen->updateScreen();
y += 2;
height -= 2;
delayUntil(nextTime);
}
restoreItemRect1(xpos, ypos);
- _screen->resetShapeHeight(_shapes[216+_itemInHand]);
+ _screen->resetShapeHeight(_shapes[216 + _itemInHand]);
removeHandItem();
_screen->showMouse();
}
@@ -517,7 +517,7 @@ void KyraEngine_LoK::itemDropDown(int x, int y, int destX, int destY, byte freeI
drawY = tempY - 16;
backUpItemRect0(drawX, drawY);
uint32 nextTime = _system->getMillis() + 1 * _tickLength;
- _screen->drawShape(0, _shapes[216+item], drawX, drawY, 0, 0);
+ _screen->drawShape(0, _shapes[216 + item], drawX, drawY, 0, 0);
_screen->updateScreen();
delayUntil(nextTime);
}
@@ -554,7 +554,7 @@ void KyraEngine_LoK::itemDropDown(int x, int y, int destX, int destY, byte freeI
drawY = tempY - 16;
backUpItemRect0(drawX, drawY);
uint32 nextTime = _system->getMillis() + 1 * _tickLength;
- _screen->drawShape(0, _shapes[216+item], drawX, drawY, 0, 0);
+ _screen->drawShape(0, _shapes[216 + item], drawX, drawY, 0, 0);
_screen->updateScreen();
delayUntil(nextTime);
}
@@ -575,7 +575,7 @@ void KyraEngine_LoK::dropItem(int unk1, int item, int x, int y, int unk2) {
if (processItemDrop(_currentCharacter->sceneId, item, x, y, unk1, unk2))
return;
snd_playSoundEffect(54);
-
+
// Old floppy versions don't print warning messages and don't have the necessary string resources.
// These versions will only play the warning sound effect.
if (_flags.isOldFloppy && !_noDropList)
@@ -597,7 +597,7 @@ void KyraEngine_LoK::itemSpecialFX(int x, int y, int item) {
}
void KyraEngine_LoK::itemSpecialFX1(int x, int y, int item) {
- uint8 *shape = _shapes[216+item];
+ uint8 *shape = _shapes[216 + item];
x -= 8;
int startY = y;
y -= 15;
@@ -635,7 +635,7 @@ void KyraEngine_LoK::itemSpecialFX2(int x, int y, int item) {
for (int i = 204; i >= 201; --i) {
restoreItemRect0(x, y);
uint32 nextTime = _system->getMillis() + 3 * _tickLength;
- _screen->drawShape(0, _shapes[216+item], x, y, 0, 0);
+ _screen->drawShape(0, _shapes[216 + item], x, y, 0, 0);
_screen->drawShape(0, _shapes[i], x, y + yAdd, 0, 0);
_screen->updateScreen();
delayUntil(nextTime);
@@ -687,7 +687,7 @@ void KyraEngine_LoK::magicOutMouseItem(int animIndex, int itemPos) {
for (int shape = _magicMouseItemStartFrame[animIndex]; shape <= _magicMouseItemEndFrame[animIndex]; ++shape) {
restoreItemRect1(x, y);
uint32 nextTime = _system->getMillis() + 4 * _tickLength;
- _screen->drawShape(0, _shapes[216+_itemInHand], x + 4, y + 3, 0, 0);
+ _screen->drawShape(0, _shapes[216 + _itemInHand], x + 4, y + 3, 0, 0);
if (tableIndex == -1)
_screen->drawShape(0, _shapes[shape], x, y, 0, 0);
else
@@ -705,7 +705,7 @@ void KyraEngine_LoK::magicOutMouseItem(int animIndex, int itemPos) {
for (int shape = _magicMouseItemStartFrame2[animIndex]; shape <= _magicMouseItemEndFrame2[animIndex]; ++shape) {
restoreItemRect1(x, y);
uint32 nextTime = _system->getMillis() + 4 * _tickLength;
- _screen->drawShape(0, _shapes[216+_itemInHand], x + 4, y + 3, 0, 0);
+ _screen->drawShape(0, _shapes[216 + _itemInHand], x + 4, y + 3, 0, 0);
if (tableIndex == -1)
_screen->drawShape(0, _shapes[shape], x, y, 0, 0);
else
@@ -789,12 +789,12 @@ void KyraEngine_LoK::magicInMouseItem(int animIndex, int item, int itemPos) {
}
restoreItemRect1(x, y);
if (itemPos == -1) {
- _screen->setMouseCursor(8, 15, _shapes[216+item]);
+ _screen->setMouseCursor(8, 15, _shapes[216 + item]);
_itemInHand = item;
} else {
_characterList[0].inventoryItems[itemPos] = item;
_screen->hideMouse();
- _screen->drawShape(0, _shapes[216+item], _itemPosX[itemPos], _itemPosY[itemPos], 0, 0);
+ _screen->drawShape(0, _shapes[216 + item], _itemPosX[itemPos], _itemPosY[itemPos], 0, 0);
_screen->showMouse();
}
_screen->showMouse();
@@ -847,7 +847,7 @@ void KyraEngine_LoK::updatePlayerItemsForScene() {
if (_itemInHand > 33)
_itemInHand = 33;
_screen->hideMouse();
- _screen->setMouseCursor(8, 15, _shapes[216+_itemInHand]);
+ _screen->setMouseCursor(8, 15, _shapes[216 + _itemInHand]);
_screen->showMouse();
}
@@ -890,7 +890,7 @@ void KyraEngine_LoK::redrawInventory(int page) {
if (_currentCharacter->inventoryItems[i] != kItemNone) {
uint8 item = _currentCharacter->inventoryItems[i];
- _screen->drawShape(page, _shapes[216+item], _itemPosX[i], _itemPosY[i], 0, 0);
+ _screen->drawShape(page, _shapes[216 + item], _itemPosX[i], _itemPosY[i], 0, 0);
}
}
_screen->showMouse();
@@ -899,23 +899,23 @@ void KyraEngine_LoK::redrawInventory(int page) {
}
void KyraEngine_LoK::backUpItemRect0(int xpos, int ypos) {
- _screen->rectClip(xpos, ypos, 3<<3, 24);
- _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 3<<3, 24, _itemBkgBackUp[0]);
+ _screen->rectClip(xpos, ypos, 3 << 3, 24);
+ _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 3 << 3, 24, _itemBkgBackUp[0]);
}
void KyraEngine_LoK::restoreItemRect0(int xpos, int ypos) {
- _screen->rectClip(xpos, ypos, 3<<3, 24);
- _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 3<<3, 24, _itemBkgBackUp[0]);
+ _screen->rectClip(xpos, ypos, 3 << 3, 24);
+ _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 3 << 3, 24, _itemBkgBackUp[0]);
}
void KyraEngine_LoK::backUpItemRect1(int xpos, int ypos) {
- _screen->rectClip(xpos, ypos, 4<<3, 32);
- _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 4<<3, 32, _itemBkgBackUp[1]);
+ _screen->rectClip(xpos, ypos, 4 << 3, 32);
+ _screen->copyRegionToBuffer(_screen->_curPage, xpos, ypos, 4 << 3, 32, _itemBkgBackUp[1]);
}
void KyraEngine_LoK::restoreItemRect1(int xpos, int ypos) {
- _screen->rectClip(xpos, ypos, 4<<3, 32);
- _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 4<<3, 32, _itemBkgBackUp[1]);
+ _screen->rectClip(xpos, ypos, 4 << 3, 32);
+ _screen->copyBlockToPage(_screen->_curPage, xpos, ypos, 4 << 3, 32, _itemBkgBackUp[1]);
}
int KyraEngine_LoK::getItemListIndex(Item item) {
diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp
index 0d6e99a696..ea2acaf64d 100644
--- a/engines/kyra/items_lol.cpp
+++ b/engines/kyra/items_lol.cpp
@@ -27,6 +27,68 @@
namespace Kyra {
+LoLObject *LoLEngine::findObject(uint16 index) {
+ if (index & 0x8000)
+ return &_monsters[index & 0x7fff];
+ else
+ return &_itemsInPlay[index];
+}
+
+int LoLEngine::calcObjectPosition(LoLObject *i, uint16 direction) {
+ int x = i->x;
+ int y = i->y;
+
+ calcSpriteRelPosition(_partyPosX, _partyPosY, x, y, direction);
+
+ if (y < 0)
+ y = 0;
+
+ int res = (i->flyingHeight << 12);
+ res |= (4095 - y);
+
+ return res;
+}
+
+void LoLEngine::removeAssignedObjectFromBlock(LevelBlockProperty *l, uint16 id) {
+ uint16 *blockItemIndex = &l->assignedObjects;
+ LoLObject *i = 0;
+
+ while (*blockItemIndex) {
+ if (*blockItemIndex == id) {
+ i = findObject(id);
+ *blockItemIndex = i->nextAssignedObject;
+ i->nextAssignedObject = 0;
+ return;
+ }
+
+ i = findObject(*blockItemIndex);
+ blockItemIndex = &i->nextAssignedObject;
+ }
+}
+
+void LoLEngine::removeDrawObjectFromBlock(LevelBlockProperty *l, uint16 id) {
+ uint16 *blockItemIndex = &l->drawObjects;
+ LoLObject *i = 0;
+
+ while (*blockItemIndex) {
+ if (*blockItemIndex == id) {
+ i = findObject(id);
+ *blockItemIndex = i->nextDrawObject;
+ i->nextDrawObject = 0;
+ return;
+ }
+
+ i = findObject(*blockItemIndex);
+ blockItemIndex = &i->nextDrawObject;
+ }
+}
+
+void LoLEngine::assignObjectToBlock(uint16 *assignedBlockObjects, uint16 id) {
+ LoLObject *t = findObject(id);
+ t->nextAssignedObject = *assignedBlockObjects;
+ *assignedBlockObjects = id;
+}
+
void LoLEngine::giveCredits(int credits, int redraw) {
if (redraw)
snd_playSoundEffect(101, -1);
@@ -156,7 +218,7 @@ Item LoLEngine::makeItem(int itemType, int curFrame, int flags) {
}
}
- memset(&_itemsInPlay[slot], 0, sizeof(ItemInPlay));
+ memset(&_itemsInPlay[slot], 0, sizeof(LoLItem));
_itemsInPlay[slot].itemPropertyIndex = itemType;
_itemsInPlay[slot].shpCurFrame_flg = (curFrame & 0x1fff) | flags;
@@ -221,17 +283,10 @@ bool LoLEngine::isItemMoveable(Item itemIndex) {
}
void LoLEngine::deleteItem(Item itemIndex) {
- memset(&_itemsInPlay[itemIndex], 0, sizeof(ItemInPlay));
+ memset(&_itemsInPlay[itemIndex], 0, sizeof(LoLItem));
_itemsInPlay[itemIndex].shpCurFrame_flg |= 0x8000;
}
-ItemInPlay *LoLEngine::findObject(uint16 index) {
- if (index & 0x8000)
- return (ItemInPlay *)&_monsters[index & 0x7fff];
- else
- return &_itemsInPlay[index];
-}
-
void LoLEngine::runItemScript(int charNum, Item item, int flags, int next, int reg4) {
EMCState scriptState;
memset(&scriptState, 0, sizeof(EMCState));
@@ -342,7 +397,7 @@ bool LoLEngine::launchObject(int objectType, Item item, int startX, int startY,
}
int csp = checkDrawObjectSpace(_partyPosX, _partyPosY, t->x, t->y);
- if (csp > sp){
+ if (csp > sp) {
sp = csp;
slot = i;
}
@@ -443,7 +498,7 @@ void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int objec
if (_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000) {
int o = _levelBlockProperties[_itemsInPlay[t->item].block].assignedObjects;
while (o & 0x8000) {
- ItemInPlay *i = findObject(o);
+ LoLObject *i = findObject(o);
o = i->nextAssignedObject;
runItemScript(t->attackerId, t->item, 0x8000, o, 0);
}
@@ -473,7 +528,7 @@ void LoLEngine::updateFlyingObject(FlyingObject *t) {
getNextStepCoords(t->x, t->y, x, y, t->direction);
/* WORKAROUND:
Large fireballs cast by the "birds" in white tower level 2 and by the "wraith knights" in castle cimmeria
- level 1 (or possible other objects with flag 0x4000) could not fly through corridors in ScummVM and would
+ level 1 (or possible other objects with flag 0x4000) could not fly through corridors in ScummVM and would
be terminated prematurely. The original code (all versions) involuntarily circumvents this via a bug in the
next line of code.
The original checks for _itemProperties[t->item].flags instead of _itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags.
@@ -484,7 +539,7 @@ void LoLEngine::updateFlyingObject(FlyingObject *t) {
at least.
Other methods of working around this issue don't make too much sense. An object with a width of 256
- could never fly through corridors, since 256 is also the width of a block. Aligning the fireballs to the
+ could never fly through corridors, since 256 is also the width of a block. Aligning the fireballs to the
middle of a block (or making the monsters align to the middle before casting them) wouldn't help here
(and wouldn't be faithful to the original either).
*/
@@ -502,13 +557,13 @@ void LoLEngine::updateFlyingObject(FlyingObject *t) {
void LoLEngine::assignItemToBlock(uint16 *assignedBlockObjects, int id) {
while (*assignedBlockObjects & 0x8000) {
- ItemInPlay *tmp = findObject(*assignedBlockObjects);
+ LoLObject *tmp = findObject(*assignedBlockObjects);
assignedBlockObjects = &tmp->nextAssignedObject;
}
- ItemInPlay *newObject = findObject(id);
+ LoLObject *newObject = findObject(id);
newObject->nextAssignedObject = *assignedBlockObjects;
- newObject->level = -1;
+ ((LoLItem *)newObject)->level = -1;
*assignedBlockObjects = id;
}
@@ -531,7 +586,7 @@ int LoLEngine::checkSceneForItems(uint16 *blockDrawObjects, int color) {
return *blockDrawObjects;
}
- ItemInPlay *i = findObject(*blockDrawObjects);
+ LoLObject *i = findObject(*blockDrawObjects);
blockDrawObjects = &i->nextDrawObject;
}
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index 34bde7fe5c..0ba173d9d0 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -88,7 +88,7 @@ KyraEngine_HoF::KyraEngine_HoF(OSystem *system, const GameFlags &flags) : KyraEn
_currentTalkSections.ENDTim = 0;
memset(&_invWsa, 0, sizeof(_invWsa));
- _itemAnimData = 0;
+ _itemAnimDefinition = 0;
_demoAnimData = 0;
_nextAnimItem = 0;
@@ -211,8 +211,8 @@ void KyraEngine_HoF::pauseEngineIntern(bool pause) {
_nextIdleAnim += pausedTime;
- for (int x = 0; x < _itemAnimDataSize; x++)
- _activeItemAnim[x].nextFrame += pausedTime;
+ for (int x = 0; x < _itemAnimDefinitionSize; x++)
+ _activeItemAnim[x].nextFrameTime += pausedTime;
_tim->refreshTimersAfterPause(pausedTime);
}
@@ -286,7 +286,7 @@ Common::Error KyraEngine_HoF::go() {
if (_flags.isDemo && !_flags.isTalkie) {
#ifdef ENABLE_LOL
if (_flags.gameID == GI_LOL)
- seq_playSequences(kSequenceLolDemoScene1, kSequenceLolDemoScene6);
+ seq_playSequences(kSequenceLoLDemoScene1, kSequenceLoLDemoScene6);
else
#endif // ENABLE_LOL
seq_playSequences(kSequenceDemoVirgin, kSequenceDemoFisher);
diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h
index 916cac0c9d..182854cdf1 100644
--- a/engines/kyra/kyra_hof.h
+++ b/engines/kyra/kyra_hof.h
@@ -95,18 +95,18 @@ enum NestedSequencesDemo {
};
#ifdef ENABLE_LOL
-enum SequencesLolDemo {
- kSequenceLolDemoScene1 = 0,
- kSequenceLolDemoText1,
- kSequenceLolDemoScene2,
- kSequenceLolDemoText2,
- kSequenceLolDemoScene3,
- kSequenceLolDemoText3,
- kSequenceLolDemoScene4,
- kSequenceLolDemoText4,
- kSequenceLolDemoScene5,
- kSequenceLolDemoText5,
- kSequenceLolDemoScene6
+enum SequencesLoLDemo {
+ kSequenceLoLDemoScene1 = 0,
+ kSequenceLoLDemoText1,
+ kSequenceLoLDemoScene2,
+ kSequenceLoLDemoText2,
+ kSequenceLoLDemoScene3,
+ kSequenceLoLDemoText3,
+ kSequenceLoLDemoScene4,
+ kSequenceLoLDemoText4,
+ kSequenceLoLDemoScene5,
+ kSequenceLoLDemoText5,
+ kSequenceLoLDemoScene6
};
#endif // ENABLE_LOL
@@ -874,8 +874,8 @@ protected:
const char * const *_ingameTimJpStr;
int _ingameTimJpStrSize;
const HofSeqData *_sequences;
- const ItemAnimData_v2 *_itemAnimData;
- int _itemAnimDataSize;
+ const ItemAnimDefinition *_itemAnimDefinition;
+ int _itemAnimDefinitionSize;
const ItemAnimData_v1 *_demoAnimData;
int _demoAnimSize;
diff --git a/engines/kyra/kyra_lok.cpp b/engines/kyra/kyra_lok.cpp
index 84990bcfb8..ece4a0daba 100644
--- a/engines/kyra/kyra_lok.cpp
+++ b/engines/kyra/kyra_lok.cpp
@@ -40,8 +40,8 @@ namespace Kyra {
KyraEngine_LoK::KyraEngine_LoK(OSystem *system, const GameFlags &flags)
: KyraEngine_v1(system, flags) {
- _seq_Forest = _seq_KallakWriting = _seq_KyrandiaLogo = _seq_KallakMalcolm =
- _seq_MalcolmTree = _seq_WestwoodLogo = _seq_Demo1 = _seq_Demo2 = _seq_Demo3 =
+ _seq_Forest = _seq_KallakWriting = _seq_KyrandiaLogo = _seq_KallakMalcolm = 0;
+ _seq_MalcolmTree = _seq_WestwoodLogo = _seq_Demo1 = _seq_Demo2 = _seq_Demo3 = 0;
_seq_Demo4 = 0;
_seq_WSATable = _seq_CPSTable = _seq_COLTable = _seq_textsTable = 0;
@@ -167,7 +167,7 @@ KyraEngine_LoK::~KyraEngine_LoK() {
}
Common::Error KyraEngine_LoK::init() {
- if (_flags.platform == Common::kPlatformPC98 && _flags.useHiResOverlay && ConfMan.getBool("16_color"))
+ if (Common::parseRenderMode(ConfMan.get("render_mode")) == Common::kRenderPC9801)
_screen = new Screen_LoK_16(this, _system);
else
_screen = new Screen_LoK(this, _system);
@@ -215,7 +215,7 @@ Common::Error KyraEngine_LoK::init() {
_currentCharacter = 0;
_characterList = new Character[11];
assert(_characterList);
- memset(_characterList, 0, sizeof(Character)*11);
+ memset(_characterList, 0, sizeof(Character) * 11);
for (int i = 0; i < 11; ++i)
memset(_characterList[i].inventoryItems, 0xFF, sizeof(_characterList[i].inventoryItems));
@@ -370,7 +370,7 @@ void KyraEngine_LoK::startup() {
// XXX
for (int i = 0; i < 12; ++i) {
int size = _screen->getRectSize(3, 24);
- _shapes[361+i] = new byte[size];
+ _shapes[361 + i] = new byte[size];
}
_itemBkgBackUp[0] = new uint8[_screen->getRectSize(3, 24)];
@@ -510,6 +510,9 @@ void KyraEngine_LoK::delay(uint32 amount, bool update, bool isMainLoop) {
updateTextFade();
updateMousePointer();
} else {
+ // We need to do Screen::updateScreen here, since client code
+ // relies on this method to copy screen changes to the actual
+ // screen since at least 0af418e7ea3a41f93fcc551a45ee5bae822d812a.
_screen->updateScreen();
}
@@ -582,23 +585,23 @@ void KyraEngine_LoK::setupShapes123(const Shape *shapeTable, int endShape, int f
uint8 curImage = 0xFF;
int curPageBackUp = _screen->_curPage;
- _screen->_curPage = 8; // we are using page 8 here in the original page 2 was backuped and then used for this stuff
+ _screen->_curPage = 8; // we are using page 8 here in the original page 2 was backuped and then used for this stuff
int shapeFlags = 2;
if (flags)
shapeFlags = 3;
- for (int i = 123; i < 123+endShape; ++i) {
- uint8 newImage = shapeTable[i-123].imageIndex;
+ for (int i = 123; i < 123 + endShape; ++i) {
+ uint8 newImage = shapeTable[i - 123].imageIndex;
if (newImage != curImage && newImage != 0xFF) {
assert(_characterImageTable);
_screen->loadBitmap(_characterImageTable[newImage], 8, 8, 0);
curImage = newImage;
}
- _shapes[i] = _screen->encodeShape(shapeTable[i-123].x<<3, shapeTable[i-123].y, shapeTable[i-123].w<<3, shapeTable[i-123].h, shapeFlags);
- assert(i-7 < _defaultShapeTableSize);
- _defaultShapeTable[i-7].xOffset = shapeTable[i-123].xOffset;
- _defaultShapeTable[i-7].yOffset = shapeTable[i-123].yOffset;
- _defaultShapeTable[i-7].w = shapeTable[i-123].w;
- _defaultShapeTable[i-7].h = shapeTable[i-123].h;
+ _shapes[i] = _screen->encodeShape(shapeTable[i - 123].x << 3, shapeTable[i - 123].y, shapeTable[i - 123].w << 3, shapeTable[i - 123].h, shapeFlags);
+ assert(i - 7 < _defaultShapeTableSize);
+ _defaultShapeTable[i - 7].xOffset = shapeTable[i - 123].xOffset;
+ _defaultShapeTable[i - 7].yOffset = shapeTable[i - 123].yOffset;
+ _defaultShapeTable[i - 7].w = shapeTable[i - 123].w;
+ _defaultShapeTable[i - 7].h = shapeTable[i - 123].h;
}
_screen->_curPage = curPageBackUp;
}
@@ -788,7 +791,7 @@ void KyraEngine_LoK::updateMousePointer(bool forceUpdate) {
}
if (mouse.x >= _entranceMouseCursorTracks[0] && mouse.y >= _entranceMouseCursorTracks[1]
- && mouse.x <= _entranceMouseCursorTracks[2] && mouse.y <= _entranceMouseCursorTracks[3]) {
+ && mouse.x <= _entranceMouseCursorTracks[2] && mouse.y <= _entranceMouseCursorTracks[3]) {
switch (_entranceMouseCursorTracks[4]) {
case 0:
newMouseState = -6;
@@ -844,7 +847,7 @@ void KyraEngine_LoK::updateMousePointer(bool forceUpdate) {
if (_itemInHand == kItemNone)
_screen->setMouseCursor(1, 1, _shapes[0]);
else
- _screen->setMouseCursor(8, 15, _shapes[216+_itemInHand]);
+ _screen->setMouseCursor(8, 15, _shapes[216 + _itemInHand]);
_screen->showMouse();
}
}
@@ -884,8 +887,8 @@ int KyraEngine_LoK::checkForNPCScriptRun(int xpos, int ypos) {
int charLeft = 0, charRight = 0, charTop = 0, charBottom = 0;
int scaleFactor = _scaleTable[currentChar->y1];
- int addX = (((scaleFactor*8)*3)>>8)>>1;
- int addY = ((scaleFactor*3)<<4)>>8;
+ int addX = (((scaleFactor * 8) * 3) >> 8) >> 1;
+ int addY = ((scaleFactor * 3) << 4) >> 8;
charLeft = currentChar->x1 - addX;
charRight = currentChar->x1 + addX;
@@ -908,7 +911,7 @@ int KyraEngine_LoK::checkForNPCScriptRun(int xpos, int ypos) {
charRight = currentChar->x1 + 11;
charTop = currentChar->y1 - 48;
// if (!i)
- // charBottom = currentChar->y2 - 16;
+ // charBottom = currentChar->y2 - 16;
// else
charBottom = currentChar->y1;
@@ -957,9 +960,6 @@ void KyraEngine_LoK::registerDefaultSettings() {
// Most settings already have sensible defaults. This one, however, is
// specific to the Kyra engine.
ConfMan.registerDefault("walkspeed", 2);
-
- if (_flags.platform == Common::kPlatformPC98 && _flags.useHiResOverlay)
- ConfMan.registerDefault("16_color", false);
}
void KyraEngine_LoK::readSettings() {
@@ -968,13 +968,13 @@ void KyraEngine_LoK::readSettings() {
// The default talk speed is 60. This should be mapped to "Normal".
if (talkspeed == 0)
- _configTextspeed = 3; // Clickable
+ _configTextspeed = 3; // Clickable
if (talkspeed <= 50)
- _configTextspeed = 0; // Slow
+ _configTextspeed = 0; // Slow
else if (talkspeed <= 150)
- _configTextspeed = 1; // Normal
+ _configTextspeed = 1; // Normal
else
- _configTextspeed = 2; // Fast
+ _configTextspeed = 2; // Fast
KyraEngine_v1::readSettings();
}
@@ -983,16 +983,16 @@ void KyraEngine_LoK::writeSettings() {
int talkspeed;
switch (_configTextspeed) {
- case 0: // Slow
+ case 0: // Slow
talkspeed = 1;
break;
- case 1: // Normal
+ case 1: // Normal
talkspeed = 60;
break;
- case 2: // Fast
+ case 2: // Fast
talkspeed = 255;
break;
- default: // Clickable
+ default: // Clickable
talkspeed = 0;
}
diff --git a/engines/kyra/kyra_mr.h b/engines/kyra/kyra_mr.h
index 473c0371dc..004236ca04 100644
--- a/engines/kyra/kyra_mr.h
+++ b/engines/kyra/kyra_mr.h
@@ -219,7 +219,7 @@ private:
bool _nextIdleType;
void showIdleAnim();
- const ItemAnimData_v2 *_itemAnimData;
+ const ItemAnimDefinition *_itemAnimDefinition;
ActiveItemAnim _activeItemAnim[10];
int _nextAnimItem;
diff --git a/engines/kyra/kyra_rpg.cpp b/engines/kyra/kyra_rpg.cpp
new file mode 100644
index 0000000000..f1d9550e8f
--- /dev/null
+++ b/engines/kyra/kyra_rpg.cpp
@@ -0,0 +1,367 @@
+/* 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/kyra_rpg.h"
+#include "kyra/sound.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+KyraRpgEngine::KyraRpgEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(system, flags), _numFlyingObjects(_flags.gameID == GI_LOL ? 8 : 10) {
+ _txt = 0;
+ _mouseClick = 0;
+ _preserveEvents = _buttonListChanged = false;
+
+ _sceneXoffset = 0;
+ _sceneShpDim = 5;
+
+ _activeButtons = 0;
+
+ _currentLevel = 0;
+
+ _vcnBlocks = 0;
+ _vcfBlocks = 0;
+ _vcnTransitionMask = 0;
+ _vcnShift = 0;
+ _vcnColTable = 0;
+ _vcnBlockWidth = 4;
+ _vcnBlockHeight = 8;
+ _vcnFlip0 = 0;
+ _vcnFlip1 = 1;
+ _vmpPtr = 0;
+ _vmpSize = 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;
+
+ _flyingObjectsPtr = 0;
+ _flyingObjectStructSize = sizeof(EoBFlyingObject);
+
+ _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;
+ _dscDoorFrameY1 = 0;
+ _dscDoorFrameY2 = 0;
+ _dscDoorFrameIndex1 = 0;
+ _dscDoorFrameIndex2 = 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;
+ _updateCharNum = -1;
+ _activeVoiceFileTotalTime = 0;
+ _updatePortraitSpeechAnimDuration = _resetPortraitAfterSpeechAnim = _needSceneRestore = 0;
+ _fadeText = false;
+
+ memset(_lvlTempData, 0, sizeof(_lvlTempData));
+
+ _dialogueField = false;
+
+ _environmentSfx = _environmentSfxVol = _envSfxDistThreshold = 0;
+ _monsterStepCounter = _monsterStepMode = 0;
+}
+
+KyraRpgEngine::~KyraRpgEngine() {
+ delete[] _wllVmpMap;
+ delete[] _wllShapeMap;
+ delete[] _specialWallTypes;
+ delete[] _wllWallFlags;
+
+ delete[] _vmpPtr;
+ delete[] _vcnColTable;
+ delete[] _vcnBlocks;
+ delete[] _vcfBlocks;
+ delete[] _vcnTransitionMask;
+ delete[] _vcnShift;
+ delete[] _blockDrawingBuffer;
+ delete[] _sceneWindowBuffer;
+
+ delete[] _lvlShapeTop;
+ delete[] _lvlShapeBottom;
+ delete[] _lvlShapeLeftRight;
+
+ delete[] _doorShapes;
+
+ delete[] _levelDecorationShapes;
+ delete[] _levelDecorationData;
+ delete[] _levelDecorationProperties;
+ delete[] _levelBlockProperties;
+}
+
+Common::Error KyraRpgEngine::init() {
+ gui_resetButtonList();
+
+ _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[256];
+ memset(_wllVmpMap, 0, 256);
+ _wllShapeMap = new int8[256];
+ memset(_wllShapeMap, 0, 256);
+ _specialWallTypes = new uint8[256];
+ memset(_specialWallTypes, 0, 256);
+ _wllWallFlags = new uint8[256];
+ memset(_wllWallFlags, 0, 256);
+
+ _blockDrawingBuffer = new uint16[1320];
+ memset(_blockDrawingBuffer, 0, 1320 * sizeof(uint16));
+ uint32 swbSize = 22 * _vcnBlockWidth * 2 * 15 * _vcnBlockHeight;
+ _sceneWindowBuffer = new uint8[swbSize];
+ memset(_sceneWindowBuffer, 0, swbSize);
+
+ _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));
+
+ _vcnColTable = new uint8[128];
+ for (int i = 0; i < 128; i++)
+ _vcnColTable[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;
+
+ _dialogueButtonLabelColor1 = guiSettings()->buttons.labelColor1;
+ _dialogueButtonLabelColor2 = guiSettings()->buttons.labelColor2;
+ _dialogueButtonWidth = guiSettings()->buttons.width;
+
+ return Common::kNoError;
+}
+
+bool KyraRpgEngine::posWithinRect(int posX, int posY, int x1, int y1, int x2, int y2) {
+ if (posX < x1 || posX > x2 || posY < y1 || posY > y2)
+ return false;
+ return true;
+}
+
+void KyraRpgEngine::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]), _dialogueButtonWidth, guiSettings()->buttons.height, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ screen()->printText(_dialogueButtonString[i], x + (_dialogueButtonWidth >> 1) - (screen()->getTextWidth(_dialogueButtonString[i])) / 2,
+ (_dialogueButtonYoffs + _dialogueButtonPosY[i]) + 2, _dialogueHighlightedButton == i ? _dialogueButtonLabelColor1 : _dialogueButtonLabelColor2, 0);
+ }
+ }
+ screen()->setFont(of);
+ screen()->setCurPage(cp);
+}
+
+uint16 KyraRpgEngine::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 + _dialogueButtonWidth, y + guiSettings()->buttons.height)) {
+ _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, 0) & 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 + _dialogueButtonWidth, y + guiSettings()->buttons.height)) {
+ _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 KyraRpgEngine::delayUntil(uint32 time, bool, bool doUpdate, bool isMainLoop) {
+ uint32 curTime = _system->getMillis();
+ if (time > curTime)
+ delay(time - curTime, doUpdate, isMainLoop);
+}
+
+int KyraRpgEngine::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 KyraRpgEngine::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 KyraRpgEngine::updateEnvironmentalSfx(int soundId) {
+ snd_processEnvironmentalSoundEffect(soundId, _currentBlock);
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB || ENABLE_LOL
diff --git a/engines/kyra/kyra_rpg.h b/engines/kyra/kyra_rpg.h
new file mode 100644
index 0000000000..50a4c9bdc1
--- /dev/null
+++ b/engines/kyra/kyra_rpg.h
@@ -0,0 +1,392 @@
+/* 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_RPG_H
+#define KYRA_RPG_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;
+ void *wallsOfForce;
+ uint8 monsterDifficulty;
+};
+
+struct EoBFlyingObject {
+ uint8 enable;
+ uint8 objectType;
+ int16 attackerId;
+ Item item;
+ uint16 curBlock;
+ uint16 starting;
+ uint8 u1;
+ uint8 direction;
+ uint8 distance;
+ int8 callBackIndex;
+ uint8 curPos;
+ uint8 flags;
+ uint8 unused;
+};
+
+struct KyraRpgGUISettings {
+ struct DialogueButtons {
+ uint8 labelColor1;
+ uint8 labelColor2;
+ uint16 width;
+ uint16 height;
+ int waitReserve;
+ uint16 waitX[2];
+ uint8 waitY[2];
+ uint16 waitWidth[2];
+ } buttons;
+
+ struct Colors {
+ uint8 frame1;
+ uint8 frame2;
+ int fill;
+
+ uint8 unused;
+ uint8 barGraph;
+
+ uint8 warningFrame1;
+ uint8 warningFrame2;
+ int warningFill;
+
+ uint8 extraFrame1;
+ uint8 extraFrame2;
+ int extraFill;
+
+ uint8 inactiveTabFrame1;
+ uint8 inactiveTabFrame2;
+ int inactiveTabFill;
+ } colors;
+};
+
+class KyraRpgEngine : public KyraEngine_v1 {
+friend class TextDisplayer_rpg;
+public:
+ KyraRpgEngine(OSystem *system, const GameFlags &flags);
+ virtual ~KyraRpgEngine();
+
+ 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 posX, int posY, 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(int start) = 0;
+ virtual void drawDecorations(int index) = 0;
+
+ virtual const uint8 *getBlockFileData(int levelIndex) = 0;
+ void setLevelShapesDim(int index, int16 &x1, int16 &x2, int dim);
+ void setDoorShapeDim(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;
+ uint16 _vmpSize;
+ uint8 *_vcnBlocks;
+ uint8 *_vcfBlocks;
+ uint8 *_vcnTransitionMask;
+ uint8 *_vcnShift;
+ uint8 *_vcnColTable;
+ uint16 *_blockDrawingBuffer;
+ uint8 *_sceneWindowBuffer;
+ uint8 _blockBrightness;
+ uint8 _wllVcnOffset;
+ uint8 _vcnBlockWidth;
+ uint8 _vcnBlockHeight;
+ uint8 _vcnFlip0;
+ uint8 _vcnFlip1;
+
+ 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;
+ int _dscDoorShpIndexSize;
+ const uint8 *_dscDoorY2;
+ const uint8 *_dscDoorFrameY1;
+ const uint8 *_dscDoorFrameY2;
+ const uint8 *_dscDoorFrameIndex1;
+ const uint8 *_dscDoorFrameIndex2;
+
+ // 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);
+
+ virtual const KyraRpgGUISettings *guiSettings() = 0;
+
+ int _clickedShapeXOffs;
+ int _clickedShapeYOffs;
+
+ Button *_activeButtons;
+ Button _activeButtonData[70];
+ Common::Array<Button::Callback> _buttonCallbacks;
+ //bool _processingButtons;
+
+ uint8 _mouseClick;
+ bool _preserveEvents;
+ bool _buttonListChanged;
+
+ int _updateFlags;
+ int _clickedSpecialFlag;
+
+ int _compassDirection;
+
+ static const uint8 _dropItemDirIndex[];
+
+ // text
+ void drawDialogueButtons();
+ uint16 processDialogue();
+
+ TextDisplayer_rpg *_txt;
+ virtual TextDisplayer_rpg *txt() { return _txt; }
+
+ bool _dialogueField;
+
+ const char *_dialogueButtonString[9];
+ const uint16 *_dialogueButtonPosX;
+ const uint8 *_dialogueButtonPosY;
+ int16 _dialogueButtonYoffs;
+ uint16 _dialogueButtonWidth;
+ int _dialogueNumButtons;
+ int _dialogueHighlightedButton;
+ int _currentControlMode;
+ int _specialSceneFlag;
+ uint8 _dialogueButtonLabelColor1;
+ uint8 _dialogueButtonLabelColor2;
+
+ const char *const *_moreStrings;
+
+ // misc
+ virtual void delay(uint32 millis, bool doUpdate = false, bool isMainLoop = false) = 0;
+ void delayUntil(uint32 time, bool unused = false, 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();
+ virtual void restoreBlockTempData(int levelIndex);
+ void releaseTempData();
+ virtual void *generateMonsterTempData(LevelTempData *tmp) = 0;
+ virtual void restoreMonsterTempData(LevelTempData *tmp) = 0;
+ virtual void releaseMonsterTempData(LevelTempData *tmp) = 0;
+ void restoreFlyingObjectTempData(LevelTempData *tmp);
+ void *generateFlyingObjectTempData(LevelTempData *tmp);
+ void releaseFlyingObjectTempData(LevelTempData *tmp);
+ virtual void *generateWallOfForceTempData(LevelTempData *tmp) { return 0; }
+ virtual void restoreWallOfForceTempData(LevelTempData *tmp) {}
+ virtual void releaseWallOfForceTempData(LevelTempData *tmp) {}
+
+ LevelTempData *_lvlTempData[29];
+ const int _numFlyingObjects;
+ uint32 _flyingObjectStructSize;
+ void *_flyingObjectsPtr;
+
+ // 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
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index dbdcda22d5..2672618c67 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -42,6 +42,8 @@ KyraEngine_v1::KyraEngine_v1(OSystem *system, const GameFlags &flags)
_emc = 0;
_debugger = 0;
+ _configRenderMode = Common::kRenderDefault;
+
if (_flags.platform == Common::kPlatformAmiga)
_gameSpeed = 50;
else
@@ -163,6 +165,9 @@ Common::Error KyraEngine_v1::init() {
if (_sound)
_sound->updateVolumeSettings();
+ if (ConfMan.hasKey("render_mode"))
+ _configRenderMode = Common::parseRenderMode(ConfMan.get("render_mode"));
+
_res = new Resource(this);
assert(_res);
_res->reset();
@@ -225,10 +230,10 @@ KyraEngine_v1::~KyraEngine_v1() {
delete _debugger;
}
-Common::Point KyraEngine_v1::getMousePos() const {
+Common::Point KyraEngine_v1::getMousePos() {
Common::Point mouse = _eventMan->getMousePos();
- if (_flags.useHiResOverlay) {
+ if (_flags.useHiRes) {
mouse.x >>= 1;
mouse.y >>= 1;
}
@@ -237,7 +242,7 @@ Common::Point KyraEngine_v1::getMousePos() const {
}
void KyraEngine_v1::setMousePos(int x, int y) {
- if (_flags.useHiResOverlay) {
+ if (_flags.useHiRes) {
x <<= 1;
y <<= 1;
}
@@ -262,7 +267,7 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag)
switch (event.type) {
case Common::EVENT_KEYDOWN:
if (event.kbd.keycode >= Common::KEYCODE_1 && event.kbd.keycode <= Common::KEYCODE_9 &&
- (event.kbd.hasFlags(Common::KBD_CTRL) || event.kbd.hasFlags(Common::KBD_ALT)) && mainLoop) {
+ (event.kbd.hasFlags(Common::KBD_CTRL) || event.kbd.hasFlags(Common::KBD_ALT)) && mainLoop) {
int saveLoadSlot = 9 - (event.kbd.keycode - Common::KEYCODE_0) + 990;
if (event.kbd.hasFlags(Common::KBD_CTRL)) {
@@ -285,10 +290,13 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag)
}
} else {
KeyMap::const_iterator keycode = _keyMap.find(event.kbd.keycode);
- if (keycode != _keyMap.end())
+ if (keycode != _keyMap.end()) {
keys = keycode->_value;
- else
+ if (event.kbd.flags & Common::KBD_SHIFT)
+ keys |= 0x100;
+ } else {
keys = 0;
+ }
// When we got an keypress, which we might need to handle,
// break the event loop and pass it to GUI code.
@@ -301,7 +309,7 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag)
case Common::EVENT_LBUTTONUP: {
_mouseX = event.mouse.x;
_mouseY = event.mouse.y;
- if (_flags.useHiResOverlay) {
+ if (_flags.useHiRes) {
_mouseX >>= 1;
_mouseY >>= 1;
}
@@ -313,7 +321,7 @@ int KyraEngine_v1::checkInput(Button *buttonList, bool mainLoop, int eventFlag)
case Common::EVENT_RBUTTONUP: {
_mouseX = event.mouse.x;
_mouseY = event.mouse.y;
- if (_flags.useHiResOverlay) {
+ if (_flags.useHiRes) {
_mouseX >>= 1;
_mouseY >>= 1;
}
@@ -354,14 +362,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 +385,58 @@ 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*/ },
+
+ // Multiple mappings for the keys to the right of the 'M' key,
+ // since these are different for QWERTZ, QWERTY and AZERTY keyboards.
+ // QWERTZ
+ { KC(COMMA), 53, 0/*unknown*/ },
+ { KC(PERIOD), 54, 0/*unknown*/ },
+ // AZERTY
+ { KC(SEMICOLON), 53, 0/*unknown*/ },
+ { KC(COLON), 54, 0/*unknown*/ },
+ // QWERTY
+ { KC(LESS), 53, 0/*unknown*/ },
+ { KC(GREATER), 54, 0/*unknown*/ }
};
#undef KC
@@ -402,10 +455,10 @@ void KyraEngine_v1::updateInput() {
switch (event.type) {
case Common::EVENT_KEYDOWN:
if (event.kbd.keycode == Common::KEYCODE_PERIOD || event.kbd.keycode == Common::KEYCODE_ESCAPE ||
- event.kbd.keycode == Common::KEYCODE_SPACE || event.kbd.keycode == Common::KEYCODE_RETURN ||
- event.kbd.keycode == Common::KEYCODE_UP || event.kbd.keycode == Common::KEYCODE_RIGHT ||
- event.kbd.keycode == Common::KEYCODE_DOWN || event.kbd.keycode == Common::KEYCODE_LEFT)
- _eventList.push_back(Event(event, true));
+ event.kbd.keycode == Common::KEYCODE_SPACE || event.kbd.keycode == Common::KEYCODE_RETURN ||
+ event.kbd.keycode == Common::KEYCODE_UP || event.kbd.keycode == Common::KEYCODE_RIGHT ||
+ event.kbd.keycode == Common::KEYCODE_DOWN || event.kbd.keycode == Common::KEYCODE_LEFT)
+ _eventList.push_back(Event(event, true));
else if (event.kbd.keycode == Common::KEYCODE_q && event.kbd.hasFlags(Common::KBD_CTRL))
quitGame();
else
@@ -536,11 +589,11 @@ void KyraEngine_v1::readSettings() {
bool subtitles = ConfMan.getBool("subtitles");
if (!speechMute && subtitles)
- _configVoice = 2; // Voice & Text
+ _configVoice = 2; // Voice & Text
else if (!speechMute && !subtitles)
- _configVoice = 1; // Voice only
+ _configVoice = 1; // Voice only
else
- _configVoice = 0; // Text only
+ _configVoice = 0; // Text only
setWalkspeed(_configWalkspeed);
}
@@ -555,15 +608,15 @@ void KyraEngine_v1::writeSettings() {
ConfMan.setBool("sfx_mute", _configSounds == 0);
switch (_configVoice) {
- case 0: // Text only
+ case 0: // Text only
speechMute = true;
subtitles = true;
break;
- case 1: // Voice only
+ case 1: // Voice only
speechMute = false;
subtitles = false;
break;
- default: // Voice & Text
+ default: // Voice & Text
speechMute = false;
subtitles = true;
}
diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h
index 5a9feb0054..0033969047 100644
--- a/engines/kyra/kyra_v1.h
+++ b/engines/kyra/kyra_v1.h
@@ -28,8 +28,9 @@
#include "common/array.h"
#include "common/error.h"
#include "common/events.h"
-#include "common/random.h"
#include "common/hashmap.h"
+#include "common/random.h"
+#include "common/rendermode.h"
#include "audio/mixer.h"
@@ -118,7 +119,7 @@ struct GameFlags {
bool useAltShapeHeader : 1; // alternative shape header (uses 2 bytes more, those are unused though)
bool isTalkie : 1;
bool isOldFloppy : 1;
- bool useHiResOverlay : 1;
+ bool useHiRes : 1;
bool use16ColorMode : 1;
bool useDigSound : 1;
bool useInstallerPackage : 1;
@@ -134,7 +135,9 @@ enum {
GI_KYRA1 = 0,
GI_KYRA2 = 1,
GI_KYRA3 = 2,
- GI_LOL = 4
+ GI_LOL = 4,
+ GI_EOB1 = 5,
+ GI_EOB2 = 6
};
struct AudioDataStruct {
@@ -182,7 +185,10 @@ class KyraEngine_v1 : public Engine {
friend class Debugger;
friend class ::KyraMetaEngine;
friend class GUI;
+friend class GUI_v1;
+friend class GUI_EoB;
friend class SoundMidiPC; // For _eventMan
+friend class TransferPartyWiz; // For save state API
public:
KyraEngine_v1(OSystem *system, const GameFlags &flags);
virtual ~KyraEngine_v1();
@@ -205,7 +211,7 @@ public:
// input
void setMousePos(int x, int y);
- Common::Point getMousePos() const;
+ Common::Point getMousePos();
// config specific
bool speechEnabled();
@@ -301,6 +307,8 @@ protected:
bool _configSounds;
uint8 _configVoice;
+ Common::RenderMode _configRenderMode;
+
// game speed
virtual bool skipFlag() const;
virtual void resetSkipFlag(bool removeEvent = true);
@@ -421,7 +429,7 @@ protected:
Common::Error saveGameState(int slot, const Common::String &desc) { return saveGameStateIntern(slot, desc.c_str(), 0); }
virtual Common::Error saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) = 0;
- Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header);
+ Common::SeekableReadStream *openSaveForReading(const char *filename, SaveHeader &header, bool checkID = true);
Common::WriteStream *openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const;
// TODO: Consider moving this to Screen
diff --git a/engines/kyra/kyra_v2.cpp b/engines/kyra/kyra_v2.cpp
index e8cb9b4370..75b568a00a 100644
--- a/engines/kyra/kyra_v2.cpp
+++ b/engines/kyra/kyra_v2.cpp
@@ -121,7 +121,7 @@ KyraEngine_v2::~KyraEngine_v2() {
delete[] _animObjects;
- for (Common::Array<const Opcode*>::iterator i = _opcodesAnimation.begin(); i != _opcodesAnimation.end(); ++i)
+ for (Common::Array<const Opcode *>::iterator i = _opcodesAnimation.begin(); i != _opcodesAnimation.end(); ++i)
delete *i;
_opcodesAnimation.clear();
@@ -162,8 +162,8 @@ void KyraEngine_v2::delay(uint32 amount, bool updateGame, bool isMainLoop) {
}
bool KyraEngine_v2::checkSpecialSceneExit(int num, int x, int y) {
- if (_specialExitTable[0+num] > x || _specialExitTable[5+num] > y ||
- _specialExitTable[10+num] < x || _specialExitTable[15+num] < y)
+ if (_specialExitTable[0 + num] > x || _specialExitTable[5 + num] > y ||
+ _specialExitTable[10 + num] < x || _specialExitTable[15 + num] < y)
return false;
return true;
}
diff --git a/engines/kyra/kyra_v2.h b/engines/kyra/kyra_v2.h
index 56391d151a..563416bf1e 100644
--- a/engines/kyra/kyra_v2.h
+++ b/engines/kyra/kyra_v2.h
@@ -24,7 +24,7 @@
#define KYRA_KYRA_V2_H
#include "kyra/kyra_v1.h"
-#include "kyra/gui.h"
+#include "kyra/gui_v1.h"
#include "kyra/wsamovie.h"
#include "kyra/item.h"
@@ -38,7 +38,7 @@ struct FrameControl {
uint16 delay;
};
-struct ItemAnimData_v2 {
+struct ItemAnimDefinition {
Item itemIndex;
uint8 numFrames;
const FrameControl *frames;
@@ -46,7 +46,7 @@ struct ItemAnimData_v2 {
struct ActiveItemAnim {
uint16 currentFrame;
- uint32 nextFrame;
+ uint32 nextFrameTime;
};
class Screen_v2;
@@ -224,7 +224,7 @@ protected:
// Sequences
EMCData _animationScriptData;
EMCState _animationScriptState;
- Common::Array<const Opcode*> _opcodesAnimation;
+ Common::Array<const Opcode *> _opcodesAnimation;
void runAnimationScript(const char *filename, int allowSkip, int resetChar, int newShapes, int shapeUnload);
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
index 538e88aa90..38e9d33259 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) : KyraRpgEngine(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;
_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,38 +167,29 @@ 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;
- gui_resetButtonList();
_preserveEvents = false;
_buttonList1 = _buttonList2 = _buttonList3 = _buttonList4 = _buttonList5 = _buttonList6 = _buttonList7 = _buttonList8 = 0;
- memset(_lvlTempData, 0, sizeof(_lvlTempData));
-
_mapOverlay = 0;
_automapShapes = 0;
_defaultLegendData = 0;
@@ -250,10 +210,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy
LoLEngine::~LoLEngine() {
setupPrologueData(false);
-
-#ifdef ENABLE_KEYMAPPER
- _eventMan->getKeymapper()->cleanupGameKeymaps();
-#endif
+ releaseTempData();
delete[] _landsFile;
delete[] _levelLangFile;
@@ -322,12 +279,24 @@ 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;
+ _monsterShapes = 0;
+ delete[] _monsterPalettes;
+ _monsterPalettes = 0;
+ delete[] _monsterDecorationShapes;
+ _monsterDecorationShapes = 0;
+ }
+
+ for (int i = 0; i < 6; i++) {
+ delete[] _doorShapes[i];
+ _doorShapes[i] = 0;
+ }
- delete[] _monsterShapes;
- delete[] _monsterPalettes;
- delete[] _monsterShapesEx;
+ releaseDecorations();
delete[] _automapShapes;
@@ -343,43 +312,16 @@ LoLEngine::~LoLEngine() {
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 +330,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];
@@ -440,8 +372,6 @@ Common::Error LoLEngine::init() {
KyraEngine_v1::init();
initStaticResource();
- _envSfxDistThreshold = _sound->getSfxType() == Sound::kAdLib ? 15 : 3;
-
_gui = new GUI_LoL(this);
assert(_gui);
_gui->initStaticData();
@@ -456,8 +386,8 @@ Common::Error LoLEngine::init() {
_pageBuffer2 = new uint8[0xfa00];
memset(_pageBuffer2, 0, 0xfa00);
- _itemsInPlay = new ItemInPlay[400];
- memset(_itemsInPlay, 0, sizeof(ItemInPlay) * 400);
+ _itemsInPlay = new LoLItem[400];
+ memset(_itemsInPlay, 0, sizeof(LoLItem) * 400);
_characters = new LoLCharacter[4];
memset(_characters, 0, sizeof(LoLCharacter) * 4);
@@ -465,69 +395,46 @@ 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;
+ KyraRpgEngine::init();
+
+ _wllAutomapData = new uint8[80];
+ memset(_wllAutomapData, 0, 80);
+
+ _monsters = new LoLMonster[30];
+ memset(_monsters, 0, 30 * sizeof(LoLMonster));
+ _monsterProperties = new LoLMonsterProperty[5];
+ memset(_monsterProperties, 0, 5 * sizeof(LoLMonsterProperty));
_tempBuffer5120 = new uint8[5120];
memset(_tempBuffer5120, 0, 5120);
- _flyingObjects = new FlyingObject[8];
- memset(_flyingObjects, 0, 8 * sizeof(FlyingObject));
+ _flyingObjects = new FlyingObject[_numFlyingObjects];
+ _flyingObjectsPtr = _flyingObjects;
+ _flyingObjectStructSize = sizeof(FlyingObject);
+ memset(_flyingObjects, 0, _numFlyingObjects * sizeof(FlyingObject));
memset(_globalScriptVars, 0, sizeof(_globalScriptVars));
- _levelFileData = 0;
_lvlShpFileHandle = 0;
_sceneDrawPage1 = 2;
_sceneDrawPage2 = 6;
- _monsterShapes = new uint8 *[48];
+ _clickedShapeXOffs = 136;
+ _clickedShapeYOffs = 8;
+ _clickedSpecialFlag = 0x40;
+
+ _monsterShapes = new uint8*[48];
memset(_monsterShapes, 0, 48 * sizeof(uint8 *));
- _monsterPalettes = new uint8 *[48];
+ _monsterPalettes = new uint8*[48];
memset(_monsterPalettes, 0, 48 * sizeof(uint8 *));
-
- _monsterShapesEx = new uint8 *[576];
- memset(_monsterShapesEx, 0, 576 * 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);
@@ -550,64 +457,45 @@ Common::Error LoLEngine::init() {
_spellProcs.push_back(new SpellProc(this, 0));
_spellProcs.push_back(new SpellProc(this, &LoLEngine::castGuardian));
- initKeymap();
+#ifdef ENABLE_KEYMAPPER
+ _eventMan->getKeymapper()->pushKeymap(kKeymapName, true);
+#endif
return Common::kNoError;
}
void LoLEngine::initKeymap() {
#ifdef ENABLE_KEYMAPPER
-
- bool tmp;
- Common::Keymapper *mapper = _eventMan->getKeymapper();
+ Common::Keymapper *const mapper = _eventMan->getKeymapper();
// Do not try to recreate same keymap over again
- if (mapper->getKeymap(kKeymapName, tmp) != 0)
+ if (mapper->getKeymap(kKeymapName) != 0)
return;
- Common::Action *act;
- Common::Keymap *engineKeyMap = new Common::Keymap(kKeymapName);
-
- act = new Common::Action(engineKeyMap, "AT1", _("Attack 1"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_F1, Common::ASCII_F1 , 0));
-
- act = new Common::Action(engineKeyMap, "AT2", _("Attack 2"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_F2, Common::ASCII_F2 , 0));
-
- act = new Common::Action(engineKeyMap, "AT3", _("Attack 3"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_F3, Common::ASCII_F3 , 0));
-
- act = new Common::Action(engineKeyMap, "MVF", _("Move Forward"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_UP));
-
- act = new Common::Action(engineKeyMap, "MVB", _("Move Back"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_DOWN));
-
- act = new Common::Action(engineKeyMap, "SLL", _("Slide Left"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_LEFT));
-
- act = new Common::Action(engineKeyMap, "SLR", _("Slide Right"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_RIGHT));
-
- act = new Common::Action(engineKeyMap, "TL", _("Turn Left"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_HOME));
-
- act = new Common::Action(engineKeyMap, "TR", _("Turn Right"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_PAGEUP));
-
- act = new Common::Action(engineKeyMap, "RST", _("Rest"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_r));
-
- act = new Common::Action(engineKeyMap, "OPT", _("Options"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_o));
+ Common::Keymap *const engineKeyMap = new Common::Keymap(kKeymapName);
+
+ const Common::KeyActionEntry keyActionEntries[] = {
+ {Common::KeyState(Common::KEYCODE_F1, Common::ASCII_F1), "AT1", _("Attack 1")},
+ {Common::KeyState(Common::KEYCODE_F2, Common::ASCII_F2), "AT2", _("Attack 2")},
+ {Common::KeyState(Common::KEYCODE_F3, Common::ASCII_F3), "AT3", _("Attack 3")},
+ {Common::KeyState(Common::KEYCODE_UP), "MVF", _("Move Forward")},
+ {Common::KeyState(Common::KEYCODE_DOWN), "MVB", _("Move Back")},
+ {Common::KeyState(Common::KEYCODE_LEFT), "SLL", _("Slide Left")},
+ {Common::KeyState(Common::KEYCODE_RIGHT), "SLR", _("Slide Right")},
+ {Common::KeyState(Common::KEYCODE_HOME), "TL", _("Turn Left")},
+ {Common::KeyState(Common::KEYCODE_PAGEUP), "TR", _("Turn Right")},
+ {Common::KeyState(Common::KEYCODE_r), "RST", _("Rest")},
+ {Common::KeyState(Common::KEYCODE_o), "OPT", _("Options")},
+ {Common::KeyState(Common::KEYCODE_SLASH), "SPL", _("Choose Spell")},
+ {Common::KeyState(), 0, 0}
+ };
- act = new Common::Action(engineKeyMap, "SPL", _("Choose Spell"), Common::kGenericActionType, Common::kActionKeyType);
- act->addKeyEvent(Common::KeyState(Common::KEYCODE_SLASH));
+ for (const Common::KeyActionEntry *entry = keyActionEntries; entry->id; ++entry) {
+ Common::Action *const act = new Common::Action(engineKeyMap, entry->id, entry->description);
+ act->addKeyEvent(entry->ks);
+ }
mapper->addGameKeymap(engineKeyMap);
-
- mapper->pushKeymap(kKeymapName, true);
-
#endif
}
@@ -701,7 +589,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);
@@ -711,7 +599,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);
}
@@ -731,12 +619,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;
@@ -891,46 +773,46 @@ 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);
- memset(_itemsInPlay, 0, 400 * sizeof(ItemInPlay));
+ memset(_itemsInPlay, 0, 400 * sizeof(LoLItem));
for (int i = 0; i < 400; i++)
_itemsInPlay[i].shpCurFrame_flg |= 0x8000;
@@ -983,10 +865,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.
@@ -1132,7 +1013,7 @@ uint8 *LoLEngine::getTableEntry(uint8 *buffer, uint16 id) {
if (!buffer)
return 0;
- return buffer + READ_LE_UINT16(buffer + (id<<1));
+ return buffer + READ_LE_UINT16(buffer + (id << 1));
}
void LoLEngine::decodeSjis(const char *src, char *dst) {
@@ -1160,7 +1041,7 @@ void LoLEngine::decodeSjis(const char *src, char *dst) {
int LoLEngine::decodeCyrillic(const char *src, char *dst) {
static const uint8 decodeTable1[] = {
- 0x20, 0xAE, 0xA5, 0xA0, 0xE2, 0xAD, 0xA8, 0xE0, 0xE1, 0xAB, 0xA2,
+ 0x20, 0xAE, 0xA5, 0xA0, 0xE2, 0xAD, 0xA8, 0xE0, 0xE1, 0xAB, 0xA2,
0xA4, 0xAC, 0xAA, 0xE3, 0x2E
};
@@ -1191,7 +1072,7 @@ int LoLEngine::decodeCyrillic(const char *src, char *dst) {
assert(cChar < sizeof(decodeTable2));
cChar = decodeTable2[cChar];
} else if (cChar >= 0x70) {
- cChar = *src++;
+ cChar = *src++;
} else if (cChar >= 0x30) {
if (cChar < 0x60)
cChar -= 0x30;
@@ -1207,8 +1088,10 @@ int LoLEngine::decodeCyrillic(const char *src, char *dst) {
}
bool LoLEngine::addCharacter(int id) {
- const uint16 *cdf[] = { _charDefsMan, _charDefsMan, _charDefsMan, _charDefsWoman,
- _charDefsMan, _charDefsMan, _charDefsWoman, _charDefsKieran, _charDefsAkshel };
+ const uint16 *cdf[] = {
+ _charDefsMan, _charDefsMan, _charDefsMan, _charDefsWoman,
+ _charDefsMan, _charDefsMan, _charDefsWoman, _charDefsKieran, _charDefsAkshel
+ };
int numChars = countActiveCharacters();
if (numChars == 4)
@@ -1267,6 +1150,7 @@ void LoLEngine::setCharacterUpdateEvent(int charNum, int updateType, int updateD
l->characterUpdateEvents[i] = updateType;
l->characterUpdateDelay[i] = updateDelay;
_timer->setNextRun(3, _system->getMillis());
+ _timer->resetNextRun();
_timer->enable(3);
break;
}
@@ -1798,44 +1682,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);
@@ -1959,7 +1805,7 @@ int LoLEngine::characterSays(int track, int charId, bool redraw) {
charId = 0;
} else {
int i = 0;
- for (;i < 4; i++) {
+ for (; i < 4; i++) {
if (charId != _characters[i].id || !(_characters[i].flags & 1))
continue;
charId = i;
@@ -2054,7 +1900,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 - (_dialogueButtonWidth + 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(LoLMonster *monster, Item item) {
uint16 *c = &monster->assignedItems;
while (*c)
c = &_itemsInPlay[*c].nextAssignedObject;
@@ -2087,19 +1972,8 @@ 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);
+const KyraRpgGUISettings *LoLEngine::guiSettings() {
+ return &_guiSettings;
}
// spells
@@ -2332,7 +2206,7 @@ int LoLEngine::processMagicHeal(int charNum, int spellLevel) {
int ch = 0;
int n = 4;
- if (charNum != -1){
+ if (charNum != -1) {
ch = charNum;
n = charNum + 1;
}
@@ -2516,7 +2390,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];
+ LoLMonster *m = &_monsters[o & 0x7fff];
if (m->hitPoints <= dmg) {
increaseExperience(charNum, 2, m->hitPoints);
o = m->nextAssignedObject;
@@ -2595,7 +2469,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];
+ LoLMonster *m = &_monsters[o & 0x7fff];
o = m->nextAssignedObject;
_envSfxUseQueue = true;
inflictDamage(m->id | 0x8000, dmg, charNum, 2, 4);
@@ -2760,7 +2634,7 @@ int LoLEngine::processMagicHandOfFate(int spellLevel) {
uint16 o = _levelBlockProperties[b1].assignedObjects;
while (o & 0x8000) {
uint16 o2 = o;
- MonsterInPlay *m = &_monsters[o & 0x7fff];
+ LoLMonster *m = &_monsters[o & 0x7fff];
o = findObject(o)->nextAssignedObject;
int nX = 0;
int nY = 0;
@@ -2993,7 +2867,7 @@ int LoLEngine::processMagicVaelansCube() {
uint16 a = sp1[i * 3 + 1] + 16;
tmpPal2[i * 3 + 1] = (a > 58) ? 58 : a;
tmpPal2[i * 3] = sp1[i * 3];
- a = sp1[i * 3 + 2] + 16;
+ a = sp1[i * 3 + 2] + 16;
tmpPal2[i * 3 + 2] = (a > 63) ? 63 : a;
}
} else {
@@ -3001,7 +2875,7 @@ int LoLEngine::processMagicVaelansCube() {
uint16 a = sp1[i * 3] + 16;
tmpPal2[i * 3] = (a > 60) ? 60 : a;
tmpPal2[i * 3 + 1] = sp1[i * 3 + 1];
- a = sp1[i * 3 + 2] + 19;
+ a = sp1[i * 3 + 2] + 19;
tmpPal2[i * 3 + 2] = (a > 60) ? 60 : a;
}
}
@@ -3029,7 +2903,7 @@ int LoLEngine::processMagicVaelansCube() {
uint16 o = _levelBlockProperties[bl].assignedObjects;
while (o & 0x8000) {
- MonsterInPlay *m = &_monsters[o & 0x7fff];
+ LoLMonster *m = &_monsters[o & 0x7fff];
if (m->properties->flags & 0x1000) {
inflictDamage(o, 100, 0xffff, 0, 0x80);
v = 1;
@@ -3509,7 +3383,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;
+ LoLMonster *m = 0;
LoLCharacter *c = 0;
if (target & 0x8000) {
@@ -3726,7 +3600,7 @@ void LoLEngine::checkForPartyDeath() {
}
}
-void LoLEngine::applyMonsterAttackSkill(MonsterInPlay *monster, int16 target, int16 damage) {
+void LoLEngine::applyMonsterAttackSkill(LoLMonster *monster, int16 target, int16 damage) {
if (rollDice(1, 100) > monster->properties->attackSkillChance)
return;
@@ -3796,7 +3670,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(LoLMonster *monster, int16 attacker, int flags, int skill, int damage) {
if (rollDice(1, 100) > monster->properties->defenseSkillChance)
return;
@@ -4055,7 +3929,7 @@ uint16 LoLEngine::getNearestMonsterFromCharacterForBlock(uint16 block, int charN
int o = _levelBlockProperties[block].assignedObjects;
while (o & 0x8000) {
- MonsterInPlay *m = &_monsters[o & 0x7fff];
+ LoLMonster *m = &_monsters[o & 0x7fff];
if (m->mode >= 13) {
o = m->nextAssignedObject;
continue;
@@ -4121,7 +3995,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);
@@ -4185,7 +4059,7 @@ void LoLEngine::displayAutomap() {
if (f == 0x30) {
for (int i = 0; i < 1024; i++)
- _levelBlockProperties[i].flags |= 7;
+ _levelBlockProperties[i].flags |= 7;
_mapUpdateNeeded = true;
} else if (f == _keyMap[Common::KEYCODE_ESCAPE]) {
exitAutomap = true;
@@ -4202,7 +4076,7 @@ void LoLEngine::displayAutomap() {
_screen->fadeToBlack(10);
loadLevelWallData(_currentLevel, false);
- memcpy(_wllBuffer4, tmpWll, 80);
+ memcpy(_wllAutomapData, tmpWll, 80);
delete[] tmpWll;
restoreBlockTempData(_currentLevel);
addLevelItems();
@@ -4243,7 +4117,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;
}
@@ -4251,13 +4125,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;
@@ -4320,7 +4194,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);
@@ -4337,25 +4211,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);
}
@@ -4522,7 +4396,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;
@@ -4532,7 +4406,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;
@@ -4625,48 +4499,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..dbd461267f 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/kyra_rpg.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,21 +108,24 @@ struct MonsterProperty {
uint8 sounds[3];
};
-struct MonsterInPlay {
+struct LoLObject {
uint16 nextAssignedObject;
uint16 nextDrawObject;
uint8 flyingHeight;
uint16 block;
uint16 x;
uint16 y;
+};
+
+struct LoLMonster : public LoLObject {
+ uint8 destDirection;
int8 shiftStep;
uint16 destX;
uint16 destY;
- uint8 destDirection;
+
int8 hitOffsX;
int8 hitOffsY;
uint8 currentSubFrame;
-
uint8 mode;
int8 fightCurTick;
uint8 id;
@@ -138,11 +133,10 @@ struct MonsterInPlay {
uint8 facing;
uint16 flags;
uint16 damageReceived;
- //uint8 field_1C;
int16 hitPoints;
uint8 speedTick;
uint8 type;
- MonsterProperty *properties;
+ LoLMonsterProperty *properties;
uint8 numDistAttacks;
uint8 curDistWeapon;
int8 distAttackTick;
@@ -150,20 +144,10 @@ struct MonsterInPlay {
uint8 equipmentShapes[4];
};
-struct ItemInPlay {
- uint16 nextAssignedObject;
- uint16 nextDrawObject;
- uint8 flyingHeight;
- uint16 block;
- uint16 x;
- uint16 y;
+struct LoLItem : public LoLObject {
int8 level;
uint16 itemPropertyIndex;
uint16 shpCurFrame_flg;
- uint8 destDirection;
- int8 hitOffsX;
- int8 hitOffsY;
- uint8 currentSubFrame;
};
struct ItemProperty {
@@ -179,15 +163,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 +170,7 @@ struct CompassDef {
uint8 flags;
};
-struct ButtonDef {
+struct LoLButtonDef {
uint16 buttonflags;
uint16 keyCode;
uint16 keyCode2;
@@ -207,12 +182,6 @@ struct ButtonDef {
uint16 screenDim;
};
-struct OpenDoorState {
- uint16 block;
- int8 wall;
- int8 state;
-};
-
struct ActiveSpell {
uint8 spell;
const SpellProperty *p;
@@ -245,14 +214,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 +257,7 @@ struct MistOfDoomAnimData {
uint8 sound;
};
-class LoLEngine : public KyraEngine_v1 {
+class LoLEngine : public KyraRpgEngine {
friend class GUI_LoL;
friend class TextDisplayer_LoL;
friend class TIMInterpreter_LoL;
@@ -305,7 +266,7 @@ friend class Debugger_LoL;
friend class HistoryPlayer;
public:
LoLEngine(OSystem *system, const GameFlags &flags);
- ~LoLEngine();
+ virtual ~LoLEngine();
virtual void initKeymap();
@@ -348,13 +309,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 +402,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 +412,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 +428,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,14 +437,10 @@ 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];
@@ -502,9 +456,7 @@ private:
int _ingameSoundListSize;
const uint8 *_musicTrackMap;
- int _musicTrackMapSize;
const uint16 *_ingameSoundIndex;
- int _ingameSoundIndexSize;
const uint8 *_ingameGMSoundIndex;
int _ingameGMSoundIndexSize;
const uint8 *_ingameMT32SoundIndex;
@@ -519,7 +471,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 +485,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 +498,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 +553,33 @@ private:
int clickedLamp(Button *button);
int clickedStatusIcon(Button *button);
- const ButtonDef *_buttonData;
- int _buttonDataSize;
+ 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_rpg *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 +630,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 +644,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 +720,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 +748,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);
@@ -900,7 +828,6 @@ private:
void createTransparencyTables();
void updateSequenceBackgroundAnimations();
- bool _dialogueField;
uint8 **_itemIconShapes;
int _numItemIconShapes;
uint8 **_itemShapes;
@@ -913,7 +840,6 @@ private:
int _numEffectShapes;
const int8 *_gameShapeMap;
- int _gameShapeMapSize;
uint8 *_characterFaceShapes[40][3];
@@ -942,19 +868,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 +883,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,18 +898,18 @@ private:
int _lampOilStatus;
uint32 _lampStatusTimer;
bool _lampStatusSuspended;
- uint8 _blockBrightness;
// level
void loadLevel(int index);
void addLevelItems();
- void loadLevelWallData(int index, bool mapShapes);
- void assignBlockObject(LevelBlockProperty *l, uint16 item);
- int assignLevelShapes(int index);
- uint8 *getLevelShapes(int index);
- void restoreBlockTempData(int index);
+ void loadLevelWallData(int fileIndex, bool mapShapes);
+ void assignBlockItem(LevelBlockProperty *l, uint16 item);
+ int assignLevelDecorationShapes(int index);
+ uint8 *getLevelDecorationShapes(int index);
+ void releaseDecorations(int first = 0, int num = 400);
void restoreTempDataAdjustMonsterStrength(int index);
void loadBlockProperties(const char *cmzFile);
+ const uint8 *getBlockFileData(int levelIndex);
void loadLevelShpDat(const char *shpFile, const char *datFile, bool flag);
void loadLevelGraphics(const char *file, int specialColor, int weight, int vcnLen, int vmpLen, const char *palFile);
@@ -1006,17 +921,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 drawSceneShapes(int start = 0);
void drawDecorations(int index);
void drawBlockEffects(int index, int type);
void drawSpecialGuiShape(int pageNum);
@@ -1033,27 +938,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 +964,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 +1010,27 @@ 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;
+ // objects (item/monster common)
+ LoLObject *findObject(uint16 index);
+ int calcObjectPosition(LoLObject *obj, uint16 direction);
+ void removeAssignedObjectFromBlock(LevelBlockProperty *l, uint16 id);
+ void removeDrawObjectFromBlock(LevelBlockProperty *l, uint16 id);
+ void assignObjectToBlock(uint16 *assignedBlockObjects, uint16 id);
// items
void giveCredits(int credits, int redraw);
@@ -1212,7 +1040,6 @@ private:
bool addItemToInventory(Item itemIndex);
bool isItemMoveable(Item itemIndex);
void deleteItem(Item itemIndex);
- ItemInPlay *findObject(uint16 index);
void runItemScript(int charNum, Item item, int flags, int next, int reg4);
void setHandItem(Item itemIndex);
bool itemEquipped(int charNum, uint16 itemType);
@@ -1233,14 +1060,13 @@ private:
uint8 _moneyColumnHeight[5];
uint16 _credits;
- ItemInPlay *_itemsInPlay;
+ LoLItem *_itemsInPlay;
ItemProperty *_itemProperties;
Item _itemInHand;
Item _inventory[48];
Item _inventoryCurItem;
- int _currentControlMode;
- int _specialSceneFlag;
+
int _lastCharInventory;
uint16 _charStatusFlags[3];
int _emcLastItem;
@@ -1250,34 +1076,24 @@ 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(LoLMonster *monster, int mode);
+ bool updateMonsterAdjustBlocks(LoLMonster *monster);
+ void placeMonster(LoLMonster *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 removeAssignedObjectFromBlock(LevelBlockProperty *l, uint16 id);
- void removeDrawObjectFromBlock(LevelBlockProperty *l, uint16 id);
- void assignMonsterToBlock(uint16 *assignedBlockObjects, uint16 id);
- void giveItemToMonster(MonsterInPlay *monster, Item item);
+ void setMonsterDirection(LoLMonster *monster, int dir);
+ void monsterDropItems(LoLMonster *monster);
+ void giveItemToMonster(LoLMonster *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,57 +1104,46 @@ private:
void drawBlockObjects(int blockArrayIndex);
void drawMonster(uint16 id);
- int getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags);
+ int getMonsterCurFrame(LoLMonster *m, uint16 dirFlags);
void reassignDrawObjects(uint16 direction, uint16 itemIndex, LevelBlockProperty *l, bool flag);
void redrawSceneItem();
- int calcItemMonsterPosition(ItemInPlay *i, uint16 direction);
void calcSpriteRelPosition(uint16 x1, uint16 y1, int &x2, int &y2, uint16 direction);
void drawDoor(uint8 *shape, uint8 *doorPalette, int index, int unk2, int w, int h, int flags);
void drawDoorOrMonsterEquipment(uint8 *shape, uint8 *objectPalette, int x, int y, int flags, const uint8 *brightnessOverlay);
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(LoLMonster *monster);
+ void moveMonster(LoLMonster *monster);
+ void walkMonster(LoLMonster *monster);
+ bool chasePartyWithDistanceAttacks(LoLMonster *monster);
+ void chasePartyWithCloseAttacks(LoLMonster *monster);
+ int walkMonsterCalcNextStep(LoLMonster *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, LoLMonster *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(LoLMonster *monster);
+ void moveStrayingMonster(LoLMonster *monster);
+ void killMonster(LoLMonster *monster);
+
+ LoLMonster *_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);
+
+ const KyraRpgGUISettings *guiSettings();
uint8 _compassBroken;
uint8 _drainMagic;
@@ -1347,6 +1152,8 @@ private:
uint8 *_pageBuffer1;
uint8 *_pageBuffer2;
+ static const KyraRpgGUISettings _guiSettings;
+
// spells
typedef Common::Functor1Mem<ActiveSpell *, int, LoLEngine> SpellProc;
Common::Array<const SpellProc *> _spellProcs;
@@ -1398,7 +1205,7 @@ private:
int8 _availableSpells[8];
int _selectedSpell;
const SpellProperty *_spellProperties;
- int _spellPropertiesSize;
+ //int _spellPropertiesSize;
int _subMenuIndex;
LightningProperty *_lightningProps;
@@ -1420,13 +1227,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 +1240,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(LoLMonster *monster, int16 target, int16 damage);
+ void applyMonsterDefenseSkill(LoLMonster *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 +1281,6 @@ private:
uint8 *_mapOverlay;
const uint8 **_automapShapes;
const uint16 *_autoMapStrings;
- int _autoMapStringsSize;
MapLegendData *_defaultLegendData;
uint8 *_mapCursorOverlay;
uint8 _automapTopLeftX;
@@ -1495,10 +1297,12 @@ 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 restoreBlockTempData(int levelIndex);
+ void restoreMonsterTempData(LevelTempData *tmp);
+ void releaseMonsterTempData(LevelTempData *tmp);
- void generateTempData();
- LevelTempData *_lvlTempData[29];
+ Graphics::Surface *generateSaveThumbnail() const;
};
class HistoryPlayer {
diff --git a/engines/kyra/magic_eob.cpp b/engines/kyra/magic_eob.cpp
new file mode 100644
index 0000000000..985286854b
--- /dev/null
+++ b/engines/kyra/magic_eob.cpp
@@ -0,0 +1,1382 @@
+/* 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 "common/system.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, _useHiResDithering ? 4 : 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[charIndex];
+
+ int val = deleteInventoryItem(charIndex, weaponSlot);
+ snd_playSoundEffect(10);
+
+ if (_flags.gameID == GI_EOB1)
+ val--;
+
+ 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, _potionStrings[0], 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(_potionStrings[1], -1, c->name, _potionEffectStrings[val]);
+}
+
+void EoBCoreEngine::useWand(int charIndex, int weaponSlot) {
+ int v = _items[_characters[charIndex].inventory[weaponSlot]].value;
+ if (!v) {
+ _txt->printMessage(_wandStrings[0]);
+ return;
+ }
+
+ if (v != 5)
+ useMagicScroll(charIndex, _wandTypes[v], weaponSlot);
+ else if (_flags.gameID == GI_EOB2)
+ useMagicScroll(charIndex, 64, weaponSlot);
+ else {
+ uint16 bl1 = calcNewBlockPosition(_currentBlock, _currentDirection);
+ uint16 bl2 = calcNewBlockPosition(bl1, _currentDirection);
+ snd_playSoundEffect(98);
+ sparkEffectOffensive();
+
+ if ((_wllWallFlags[_levelBlockProperties[bl2].walls[_currentDirection ^ 2]] & 4) && !(_levelBlockProperties[bl2].flags & 7) && (_levelBlockProperties[bl1].flags & 7)) {
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].block != bl1)
+ continue;
+ placeMonster(&_monsters[i], bl2, -1);
+ _sceneUpdateRequired = true;
+ }
+ } else {
+ _txt->printMessage(_wandStrings[1]);
+ }
+ }
+}
+
+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;
+
+ _activeSpellCharacterPos = _dropItemDirIndex[(_currentDirection << 2) + ci];
+
+ if (s->flags & 0x400) {
+ if (c->inventory[0] && c->inventory[1]) {
+ printWarning(_magicStrings1[2]);
+ return;
+ }
+
+ if (isMagicEffectItem(c->inventory[0]) || isMagicEffectItem(c->inventory[1])) {
+ printWarning(_magicStrings1[3]);
+ 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;
+ }
+
+ _activeSpellCharId = _openBookChar;
+ startSpell(spell);
+}
+
+void EoBCoreEngine::removeCharacterEffect(int spell, int charIndex, int showWarning) {
+ assert(spell >= 0);
+ EoBCharacter *c = &_characters[charIndex];
+ EoBSpell *s = &_spells[spell];
+
+ if (showWarning) {
+ int od = _screen->curDimIndex();
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+ _screen->setScreenDim(7);
+ printWarning(Common::String::format(_magicStrings3[_flags.gameID == GI_EOB1 ? 3 : 2], c->name, s->name).c_str());
+ _screen->setScreenDim(od);
+ _screen->setFont(of);
+ }
+
+ if (s->endCallback)
+ (this->*s->endCallback)(c);
+
+ 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(_activeSpellCharId);
+
+ if (showWarning) {
+ if (s->flags & 0x20A0)
+ gui_drawCharPortraitWithStats(charIndex);
+ else if (s->flags & 0x40)
+ gui_drawAllCharPortraitsWithStats();
+ }
+}
+
+void EoBCoreEngine::removeAllCharacterEffects(int charIndex) {
+ EoBCharacter *c = &_characters[charIndex];
+ c->effectFlags = 0;
+ 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() {
+ printWarning(_magicStrings3[0]);
+ gui_setCastOnWhomButtons();
+}
+
+void EoBCoreEngine::startSpell(int spell) {
+ EoBSpell *s = &_spells[spell];
+ EoBCharacter *c = &_characters[_activeSpellCharId];
+ snd_playSoundEffect(s->sound);
+
+ if (s->flags & 0xa0)
+ sparkEffectDefensive(_activeSpellCharId);
+ else if (s->flags & 0x40)
+ sparkEffectDefensive(-1);
+ else if (s->flags & 0x1000)
+ sparkEffectOffensive();
+
+ if (s->flags & 0x20) {
+ _txt->printMessage(c->name);
+ _txt->printMessage(_flags.gameID == GI_EOB1 ? _magicStrings3[1] : _magicStrings1[5]);
+ }
+
+ if ((s->flags & 0x30) && (s->effectFlags & c->effectFlags)) {
+ if (_flags.gameID == GI_EOB2)
+ printWarning(Common::String::format(_magicStrings7[0], c->name, s->name).c_str());
+ } else if ((s->flags & 0x50) && (s->effectFlags & _partyEffectFlags)) {
+ if (_flags.gameID == GI_EOB1 && s->effectFlags == 0x400)
+ // EOB 1 only warns in case of a bless spell
+ printWarning(_magicStrings8[1]);
+ else
+ printWarning(Common::String::format(_magicStrings7[1], s->name).c_str());
+ } 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(_activeSpellCharId);
+
+ if (s->flags & 0x20A0)
+ gui_drawCharPortraitWithStats(_activeSpellCharId);
+ if (s->flags & 0x40)
+ gui_drawAllCharPortraitsWithStats();
+ }
+
+ if (_castScrollSlot) {
+ gui_updateSlotAfterScrollUse();
+ } else {
+ _characters[_openBookChar].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();
+ }
+ }
+ 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);
+ }
+ 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) {
+ assert(spell >= 0);
+ int l = _openBookType == 1 ? getClericPaladinLevel(_openBookChar) : getMageLevel(_openBookChar);
+ uint32 countdown = timerLength * timerBaseFactor + timerLength * l * timerLevelFactor;
+ setCharEventTimer(_activeSpellCharId, countdown, -spell, updateExistingTimer);
+}
+
+void EoBCoreEngine::sortCharacterSpellList(int charIndex) {
+ int8 *list = _characters[charIndex].mageSpells;
+
+ for (int i = 0; i < 16;) {
+ bool p = false;
+ for (int ii = 0; ii < 9; ii++) {
+ int8 *pos = &list[ii];
+
+ int s1 = pos[0];
+ int s2 = pos[1];
+
+ if (s1 == 0)
+ s1 = 80;
+ else if (s1 < 0)
+ s1 = s1 * -1 + 40;
+
+ if (s2 == 0)
+ s2 = 80;
+ else if (s2 < 0)
+ s2 = s2 * -1 + 40;
+
+ if (s1 > s2) {
+ SWAP(pos[0], pos[1]);
+ p = true;
+ }
+ }
+
+ if (p)
+ continue;
+
+ list += 10;
+ if (++i == 8)
+ list = _characters[charIndex].clericSpells;
+ }
+}
+
+bool EoBCoreEngine::magicObjectDamageHit(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 savingThrowType = 5;
+ int savingThrowEffect = 3;
+ if (fo->flags & 8) {
+ savingThrowType = 4;
+ savingThrowEffect = 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)) {
+ _preventMonsterFlash = true;
+
+ 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, savingThrowType, savingThrowEffect);
+ 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, savingThrowType, savingThrowEffect);
+ }
+ } else {
+ int c = _dscItemPosIndex[(_currentDirection << 2) + (fo->curPos & 3)];
+ if ((c > 2) && (testCharacter(4, 1) || testCharacter(5, 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, savingThrowType, savingThrowEffect);
+ }
+ }
+ }
+ }
+
+ if (res && (fo->flags & 0x40))
+ explodeObject(fo, fo->curBlock, fo->item);
+ else if ((_flags.gameID == GI_EOB1 && fo->item == 5) || (_flags.gameID == GI_EOB2 && fo->item == 4))
+ res = false;
+
+ return res;
+}
+
+bool EoBCoreEngine::magicObjectStatusHit(EoBMonsterInPlay *m, int type, bool tryEvade, int mod) {
+ EoBMonsterProperty *p = &_monsterProps[m->type];
+ if (tryEvade) {
+ if (tryMonsterAttackEvasion(m) || (p->immunityFlags & 0x10))
+ return true;
+ }
+
+ if (trySavingThrow(m, 0, p->level, mod, 6))
+ return false;
+
+ int para = 0;
+
+ switch (type) {
+ case 0:
+ case 1:
+ case 2:
+ para = (type == 0) ? ((p->typeFlags & 1) ? 1 : 0) : ((type == 1) ? ((p->typeFlags & 2) ? 1 : 0) : 1);
+ if (para && !(p->immunityFlags & 2)) {
+ m->mode = 10;
+ m->spellStatusLeft = 15;
+ }
+
+ break;
+
+ case 3:
+ if (!(p->immunityFlags & 8))
+ inflictMonsterDamage(m, 1000, true);
+ break;
+
+ case 4:
+ inflictMonsterDamage(m, 1000, true);
+ break;
+
+ case 5:
+ m->flags |= 0x20;
+ _sceneUpdateRequired = true;
+ break;
+
+ case 6:
+ if (!(_flags.gameID == GI_EOB1 && !(p->typeFlags & 3)) && !(p->immunityFlags & 4) && m->mode != 7 && m->mode != 8 && m->mode != 10) {
+ m->mode = 0;
+ m->spellStatusLeft = 20;
+ m->flags |= 8;
+ walkMonsterNextStep(m, -1, (getNextMonsterDirection(m->block, _currentBlock) ^ 4) >> 1);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+bool EoBCoreEngine::turnUndeadHit(EoBMonsterInPlay *m, int hitChance, int casterLevel) {
+ assert(_monsterProps[m->type].tuResist > 0);
+ uint8 e = _turnUndeadEffect[_monsterProps[m->type].tuResist * 14 + MIN(casterLevel, 14)];
+
+ if (e == 0xff) {
+ calcAndInflictMonsterDamage(m, 0, 0, 500, 0x200, 5, 3);
+ } else if (hitChance < e) {
+ return false;
+ } else {
+ m->mode = 0;
+ m->flags |= 8;
+ m->spellStatusLeft = 40;
+ m->dir = (getNextMonsterDirection(m->block, _currentBlock) ^ 4) >> 1;
+ }
+
+ return true;
+}
+
+int EoBCoreEngine::getMagicWeaponSlot(int charIndex) {
+ return _characters[charIndex].inventory[1] ? 0 : 1;
+}
+
+void EoBCoreEngine::causeWounds(int dcTimes, int dcPips, int dcOffs) {
+ if (_openBookChar == 0 || _openBookChar == 1) {
+ int d = getClosestMonster(_openBookChar, calcNewBlockPosition(_currentBlock, _currentDirection));
+ if (d != -1) {
+ if (!characterAttackHitTest(_openBookChar, d, 0, 1))
+ return;
+
+ if (dcTimes == -1) {
+ dcOffs = _monsters[d].hitPointsMax - rollDice(1, 4);
+ dcTimes = dcPips = 0;
+ }
+ calcAndInflictMonsterDamage(&_monsters[d], dcTimes, dcPips, dcOffs, 0x801, 4, 2);
+ } else {
+ printWarning(Common::String::format(_magicStrings3[_flags.gameID == GI_EOB1 ? 4 : 3], _characters[_openBookChar].name).c_str());
+ }
+ } else {
+ printWarning(Common::String::format(_magicStrings3[_flags.gameID == GI_EOB1 ? 5 : 4], _characters[_openBookChar].name).c_str());
+ }
+}
+
+int EoBCoreEngine::createMagicWeaponType(int invFlags, int handFlags, int armorClass, int allowedClasses, int dmgNumDice, int dmgPips, int dmgInc, int extraProps) {
+ int i = 51;
+ for (; i < 57; i++) {
+ if (_itemTypes[i].armorClass == -30)
+ break;
+ }
+
+ if (i == 57)
+ return -1;
+
+ EoBItemType *tp = &_itemTypes[i];
+ tp->invFlags = invFlags;
+ tp->requiredHands = 0;
+ tp->handFlags = handFlags;
+ tp->armorClass = armorClass;
+ tp->allowedClasses = allowedClasses;
+ tp->dmgNumDiceL = tp->dmgNumDiceS = dmgNumDice;
+ tp->dmgNumPipsL = tp->dmgNumPipsS = dmgPips;
+ tp->dmgIncL = tp->dmgIncS = dmgInc;
+ tp->extraProperties = extraProps;
+
+ return i;
+}
+
+Item EoBCoreEngine::createMagicWeaponItem(int flags, int icon, int value, int type) {
+ Item i = 11;
+ for (; i < 17; i++) {
+ if (_items[i].block == -2)
+ break;
+ }
+
+ if (i == 17)
+ return -1;
+
+ EoBItem *itm = &_items[i];
+ itm->flags = 0x20 | flags;
+ itm->icon = icon;
+ itm->value = value;
+ itm->type = type;
+ itm->pos = 0;
+ itm->block = 0;
+ itm->nameId = itm->nameUnid = 0;
+ itm->prev = itm->next = 0;
+
+ return i;
+}
+
+void EoBCoreEngine::removeMagicWeaponItem(Item item) {
+ _itemTypes[_items[item].type].armorClass = -30;
+ _items[item].block = -2;
+ _items[item].level = 0xff;
+}
+
+void EoBCoreEngine::updateWallOfForceTimers() {
+ uint32 ct = _system->getMillis();
+ for (int i = 0; i < 5; i++) {
+ if (!_wallsOfForce[i].block)
+ continue;
+ if (_wallsOfForce[i].duration < ct)
+ destroyWallOfForce(i);
+ }
+}
+
+void EoBCoreEngine::destroyWallOfForce(int index) {
+ memset(_levelBlockProperties[_wallsOfForce[index].block].walls, 0, 4);
+ _wallsOfForce[index].block = 0;
+ _sceneUpdateRequired = true;
+}
+
+int EoBCoreEngine::findSingleSpellTarget(int dist) {
+ uint16 bl = _currentBlock;
+ int res = -1;
+
+ for (int i = 0; i < dist && res == -1; i++) {
+ bl = calcNewBlockPosition(bl, _currentDirection);
+ res = getClosestMonster(_openBookChar, bl);
+ if (!(_wllWallFlags[_levelBlockProperties[bl].walls[_sceneDrawVarDown]] & 1)) {
+ i = dist;
+ res = -1;
+ }
+ }
+
+ return res;
+}
+
+int EoBCoreEngine::findFirstCharacterSpellTarget() {
+ int curCharIndex = rollDice(1, 6, -1);
+ for (_characterSpellTarget = 0; _characterSpellTarget < 6; _characterSpellTarget++) {
+ if (testCharacter(curCharIndex, 3))
+ return curCharIndex;
+ if (++curCharIndex == 6)
+ curCharIndex = 0;
+ }
+ return -1;
+}
+
+int EoBCoreEngine::findNextCharacterSpellTarget(int curCharIndex) {
+ for (_characterSpellTarget++; _characterSpellTarget < 6;) {
+ if (++curCharIndex == 6)
+ curCharIndex = 0;
+ if (testCharacter(curCharIndex, 3))
+ return curCharIndex;
+ }
+ return -1;
+}
+
+int EoBCoreEngine::charDeathSavingThrow(int charIndex, int div) {
+ bool _beholderOrgBhv = true;
+ // Due to a bug in the original code the saving throw result is completely ignored
+ // here. The Beholders' disintegrate spell will alway succeed while their flesh to
+ // stone spell will always fail.
+ if (_beholderOrgBhv)
+ div >>= 1;
+ else
+ div = specialAttackSavingThrow(charIndex, 4) ? 1 : 0;
+ return div;
+}
+
+void EoBCoreEngine::printWarning(const char *str) {
+ _txt->printMessage(str);
+ snd_playSoundEffect(79);
+}
+
+void EoBCoreEngine::printNoEffectWarning() {
+ printWarning(_magicStrings4[0]);
+}
+
+void EoBCoreEngine::spellCallback_start_armor() {
+ _characters[_activeSpellCharId].effectsRemainder[0] = getMageLevel(_openBookChar) + 8;
+ if ((getDexterityArmorClassModifier(_characters[_activeSpellCharId].dexterityCur) + 6) >= _characters[_activeSpellCharId].armorClass)
+ printWarning(Common::String::format(_magicStrings6[0], _characters[_activeSpellCharId].name).c_str());
+}
+
+void EoBCoreEngine::spellCallback_start_burningHands() {
+ static const int16 bX[] = { 0, 152, 24, 120, 56, 88 };
+ static const int8 bY[] = { 64, 64, 56, 56, 56, 56 };
+
+ for (int i = 0; i < 6; i++)
+ drawBlockObject(i & 1, 0, _firebeamShapes[(5 - i) >> 1], bX[i], bY[i], 0);
+ _screen->updateScreen();
+ delay(2 * _tickLength);
+
+ int cl = getMageLevel(_openBookChar);
+ int bl = calcNewBlockPosition(_currentBlock, _currentDirection);
+
+ const int8 *pos = getMonstersOnBlockPositions(bl);
+ _preventMonsterFlash = true;
+
+ int numDest = (_flags.gameID == GI_EOB1) ? 2 : 6;
+ const uint8 *d = &_burningHandsDest[_currentDirection * (_flags.gameID == GI_EOB1 ? 2 : 8)];
+
+ for (int i = 0; i < numDest; i++, d++) {
+ if (pos[*d] == -1)
+ continue;
+ calcAndInflictMonsterDamage(&_monsters[pos[*d]], 1, 3, cl << 1, 0x21, 4, 0);
+ }
+
+ updateAllMonsterShapes();
+ _sceneUpdateRequired = true;
+}
+
+void EoBCoreEngine::spellCallback_start_detectMagic() {
+ setHandItem(_itemInHand);
+}
+
+bool EoBCoreEngine::spellCallback_end_detectMagic(void *) {
+ setHandItem(_itemInHand);
+ return true;
+}
+
+void EoBCoreEngine::spellCallback_start_magicMissile() {
+ launchMagicObject(_openBookChar, 0, _currentBlock, _activeSpellCharacterPos, _currentDirection);
+}
+
+bool EoBCoreEngine::spellCallback_end_magicMissile(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ return magicObjectDamageHit(fo, 1, 4, 1, (getMageLevel(fo->attackerId) - 1) >> 1);
+}
+
+void EoBCoreEngine::spellCallback_start_shockingGrasp() {
+ int t = createMagicWeaponType(0, 0, 0, 0x0f, 1, 8, getMageLevel(_openBookChar), 1);
+ Item i = (t != -1) ? createMagicWeaponItem(0x10, 82, 0, t) : -1;
+ if (t == -1 || i == -1) {
+ if (_flags.gameID == GI_EOB2)
+ printWarning(_magicStrings8[0]);
+ removeCharacterEffect(_activeSpell, _activeSpellCharId, 0);
+ deleteCharEventTimer(_activeSpellCharId, -_activeSpell);
+ _returnAfterSpellCallback = true;
+ } else {
+ _characters[_activeSpellCharId].inventory[getMagicWeaponSlot(_activeSpellCharId)] = i;
+ }
+}
+
+bool EoBCoreEngine::spellCallback_end_shockingGraspFlameBlade(void *obj) {
+ EoBCharacter *c = (EoBCharacter *)obj;
+ for (int i = 0; i < 2; i++) {
+ if (isMagicEffectItem(c->inventory[i])) {
+ removeMagicWeaponItem(c->inventory[i]);
+ c->inventory[i] = 0;
+ }
+ }
+ return true;
+}
+
+void EoBCoreEngine::spellCallback_start_improvedIdentify() {
+ for (int i = 0; i < 2; i++) {
+ Item itm = _characters[_activeSpellCharId].inventory[i];
+ if (itm)
+ _items[itm].flags |= 0x40;
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_melfsAcidArrow() {
+ launchMagicObject(_openBookChar, 1, _currentBlock, _activeSpellCharacterPos, _currentDirection);
+}
+
+bool EoBCoreEngine::spellCallback_end_melfsAcidArrow(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ assert(fo);
+ return magicObjectDamageHit(fo, 2, 4, 0, getMageLevel(fo->attackerId) / 3);
+}
+
+void EoBCoreEngine::spellCallback_start_dispelMagic() {
+ for (int i = 0; i < 6; i++) {
+ if (testCharacter(i, 1))
+ removeAllCharacterEffects(i);
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_fireball() {
+ launchMagicObject(_openBookChar, 2, _currentBlock, _activeSpellCharacterPos, _currentDirection);
+}
+
+bool EoBCoreEngine::spellCallback_end_fireball(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ return magicObjectDamageHit(fo, 1, 6, 0, getMageLevel(fo->attackerId));
+}
+
+void EoBCoreEngine::spellCallback_start_flameArrow() {
+ launchMagicObject(_openBookChar, 3, _currentBlock, _activeSpellCharacterPos, _currentDirection);
+}
+
+bool EoBCoreEngine::spellCallback_end_flameArrow(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ return magicObjectDamageHit(fo, 5, 6, 0, getMageLevel(fo->attackerId));
+}
+
+void EoBCoreEngine::spellCallback_start_holdPerson() {
+ launchMagicObject(_openBookChar, _flags.gameID == GI_EOB1 ? 4 : 3, _currentBlock, _activeSpellCharacterPos, _currentDirection);
+}
+
+bool EoBCoreEngine::spellCallback_end_holdPerson(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ bool res = false;
+
+ if (_flags.gameID == GI_EOB2 && fo->curBlock == _currentBlock) {
+ // party hit
+ int numChar = rollDice(1, 4, 0);
+ int charIndex = rollDice(1, 6, -1);
+ for (int i = 0; i < 6 && numChar; i++) {
+ if (testCharacter(charIndex, 3)) {
+ statusAttack(charIndex, 4, _magicStrings8[1], 4, 5, 9, 1);
+ numChar--;
+ }
+ charIndex = (charIndex + 1) % 6;
+ }
+ res = true;
+
+ } else {
+ // monster hit
+ for (const int16 *m = findBlockMonsters(fo->curBlock, fo->curPos, fo->direction, 1, 1); *m != -1; m++)
+ res |= magicObjectStatusHit(&_monsters[*m], 0, true, 4);
+ }
+
+ return res;
+}
+
+void EoBCoreEngine::spellCallback_start_lightningBolt() {
+ launchMagicObject(_openBookChar, _flags.gameID == GI_EOB1 ? 5 : 4, _currentBlock, _activeSpellCharacterPos, _currentDirection);
+}
+
+bool EoBCoreEngine::spellCallback_end_lightningBolt(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ return magicObjectDamageHit(fo, 1, 6, 0, getMageLevel(fo->attackerId));
+}
+
+void EoBCoreEngine::spellCallback_start_vampiricTouch() {
+ int t = createMagicWeaponType(0, 0, 0, 0x0f, getMageLevel(_openBookChar) >> 1, 6, 0, 1);
+ Item i = (t != -1) ? createMagicWeaponItem(0x18, 83, 0, t) : -1;
+ if (t == -1 || i == -1) {
+ if (_flags.gameID == GI_EOB2)
+ printWarning(_magicStrings8[2]);
+ removeCharacterEffect(_activeSpell, _activeSpellCharId, 0);
+ deleteCharEventTimer(_activeSpellCharId, -_activeSpell);
+ _returnAfterSpellCallback = true;
+ } else {
+ _characters[_activeSpellCharId].inventory[getMagicWeaponSlot(_activeSpellCharId)] = i;
+ }
+}
+
+bool EoBCoreEngine::spellCallback_end_vampiricTouch(void *obj) {
+ EoBCharacter *c = (EoBCharacter *)obj;
+ if (c->hitPointsCur > c->hitPointsMax)
+ c->hitPointsCur = c->hitPointsMax;
+ spellCallback_end_shockingGraspFlameBlade(obj);
+ return true;
+}
+
+void EoBCoreEngine::spellCallback_start_fear() {
+ sparkEffectOffensive();
+ uint16 bl = calcNewBlockPosition(_currentBlock, _currentDirection);
+ for (int i = 0; i < 30; i++) {
+ if (_monsters[i].block == bl)
+ magicObjectStatusHit(&_monsters[i], 6, true, 4);
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_iceStorm() {
+ launchMagicObject(_openBookChar, _flags.gameID == GI_EOB1 ? 6 : 5, _currentBlock, _activeSpellCharacterPos, _currentDirection);
+}
+
+bool EoBCoreEngine::spellCallback_end_iceStorm(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ static int8 blockAdv[] = { -32, 32, 1, -1 };
+ bool res = magicObjectDamageHit(fo, 1, 6, 0, getMageLevel(fo->attackerId));
+ if (res) {
+ for (int i = 0; i < 4; i++) {
+ uint16 bl = fo->curBlock;
+ fo->curBlock = (fo->curBlock + blockAdv[i]) & 0x3ff;
+ magicObjectDamageHit(fo, 1, 6, 0, getMageLevel(fo->attackerId));
+ fo->curBlock = bl;
+ }
+ }
+ return res;
+}
+
+void EoBCoreEngine::spellCallback_start_stoneSkin() {
+ _characters[_activeSpellCharId].effectsRemainder[1] = (getMageLevel(_openBookChar) >> 1) + rollDice(1, 4);
+}
+
+void EoBCoreEngine::spellCallback_start_removeCurse() {
+ for (int i = 0; i < 27; i++) {
+ Item itm = _characters[_activeSpellCharId].inventory[i];
+ if (itm && (_items[itm].flags & 0x20) && !isMagicEffectItem(itm))
+ _items[itm].flags = (_items[itm].flags & ~0x20) | 0x40;
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_coneOfCold() {
+ const int8 *dirTables[] = { _coneOfColdDest1, _coneOfColdDest2, _coneOfColdDest3, _coneOfColdDest4 };
+
+ int cl = getMageLevel(_openBookChar);
+
+ _screen->setCurPage(2);
+ _screen->fillRect(0, 0, 176, 120, 0);
+ _screen->setGfxParameters(0, 0, _screen->getPagePixel(2, 0, 0));
+ drawSceneShapes(7);
+ _screen->setCurPage(0);
+ disableSysTimer(2);
+ _screen->drawVortex(150, 50, 10, 1, 100, _coneOfColdGfxTbl, _coneOfColdGfxTblSize);
+ enableSysTimer(2);
+
+ const int8 *tbl = dirTables[_currentDirection];
+ _preventMonsterFlash = true;
+
+ for (int i = 0; i < 7; i++) {
+ for (const int16 *m = findBlockMonsters((_currentBlock + tbl[i]) & 0x3ff, 4, _currentDirection, 1, 1); *m != -1; m++)
+ calcAndInflictMonsterDamage(&_monsters[*m], cl, 4, cl, 0x41, 5, 0);
+ }
+
+ updateAllMonsterShapes();
+}
+
+void EoBCoreEngine::spellCallback_start_holdMonster() {
+ launchMagicObject(_openBookChar, _flags.gameID == GI_EOB1 ? 7 : 6, _currentBlock, _activeSpellCharacterPos, _currentDirection);
+}
+
+bool EoBCoreEngine::spellCallback_end_holdMonster(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ bool res = false;
+ for (const int16 *m = findBlockMonsters(fo->curBlock, fo->curPos, fo->direction, 1, 1); *m != -1; m++)
+ res |= magicObjectStatusHit(&_monsters[*m], 1, true, 4);
+ return res;
+}
+
+void EoBCoreEngine::spellCallback_start_wallOfForce() {
+ uint16 bl = calcNewBlockPosition(_currentBlock, _currentDirection);
+ LevelBlockProperty *l = &_levelBlockProperties[bl];
+ if (l->walls[0] || l->walls[1] || l->walls[2] || l->walls[3] || (l->flags & 7)) {
+ printWarning(_magicStrings8[3]);
+ return;
+ }
+
+ uint32 dur = 0xffffffff;
+ int s = 0;
+ int i = 0;
+
+ for (; i < 5; i++) {
+ if (!_wallsOfForce[i].block)
+ break;
+ if (_wallsOfForce[i].duration < dur) {
+ dur = _wallsOfForce[i].duration;
+ s = i;
+ }
+ }
+
+ if (i == 5)
+ destroyWallOfForce(s);
+
+ memset(_levelBlockProperties[bl].walls, 74, 4);
+ _wallsOfForce[s].block = bl;
+ _wallsOfForce[s].duration = _system->getMillis() + (((getMageLevel(_openBookChar) * 546) >> 1) + 546) * _tickLength;
+ _sceneUpdateRequired = true;
+}
+
+void EoBCoreEngine::spellCallback_start_disintegrate() {
+ int d = findSingleSpellTarget(1);
+ if (d != -1)
+ magicObjectStatusHit(&_monsters[d], 4, true, 4);
+ memset(_visibleBlocks[13]->walls, 0, 4);
+ _sceneUpdateRequired = true;
+}
+
+void EoBCoreEngine::spellCallback_start_fleshToStone() {
+ sparkEffectOffensive();
+ int t = getClosestMonster(_openBookChar, calcNewBlockPosition(_currentBlock, _currentDirection));
+ if (t != -1)
+ magicObjectStatusHit(&_monsters[t], 5, true, 4);
+ else
+ printWarning(_magicStrings8[4]);
+}
+
+void EoBCoreEngine::spellCallback_start_stoneToFlesh() {
+ if (_characters[_activeSpellCharId].flags & 8)
+ _characters[_activeSpellCharId].flags &= ~8;
+ else
+ printNoEffectWarning();
+}
+
+void EoBCoreEngine::spellCallback_start_trueSeeing() {
+ _wllVmpMap[46] = 0;
+}
+
+bool EoBCoreEngine::spellCallback_end_trueSeeing(void *) {
+ _wllVmpMap[46] = 1;
+ return true;
+}
+
+void EoBCoreEngine::spellCallback_start_slayLiving() {
+ int d = findSingleSpellTarget(2);
+ if (d != -1) {
+ if (!magicObjectStatusHit(&_monsters[d], 3, true, 4))
+ inflictMonsterDamage(&_monsters[d], rollDice(2, 8, 1), true);
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_powerWordStun() {
+ int d = findSingleSpellTarget(2);
+ if (d != -1) {
+ if (_monsters[d].hitPointsCur < 90)
+ magicObjectStatusHit(&_monsters[d], 5, true, 4);
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_causeLightWounds() {
+ causeWounds(1, 8, 0);
+}
+
+void EoBCoreEngine::spellCallback_start_cureLightWounds() {
+ modifyCharacterHitpoints(_activeSpellCharId, rollDice(1, 8));
+}
+
+void EoBCoreEngine::spellCallback_start_aid() {
+ if (!testCharacter(_activeSpellCharId, 3)) {
+ printNoEffectWarning();
+ } else if (_characters[_activeSpellCharId].effectsRemainder[3]) {
+ printWarning(Common::String::format(_magicStrings8[(_flags.gameID == GI_EOB1) ? 2 : 5], _characters[_activeSpellCharId].name).c_str());
+ } else {
+ _characters[_activeSpellCharId].effectsRemainder[3] = rollDice(1, 8);
+ _characters[_activeSpellCharId].hitPointsCur += _characters[_activeSpellCharId].effectsRemainder[3];
+ _characters[_activeSpellCharId].effectFlags |= 0x1000;
+ return;
+ }
+
+ removeCharacterEffect(_activeSpell, _activeSpellCharId, 0);
+ deleteCharEventTimer(_activeSpellCharId, -_activeSpell);
+}
+
+bool EoBCoreEngine::spellCallback_end_aid(void *obj) {
+ EoBCharacter *c = (EoBCharacter *)obj;
+ c->hitPointsCur -= c->effectsRemainder[3];
+ c->effectsRemainder[3] = 0;
+ c->effectFlags &= ~0x1000;
+ return true;
+}
+
+void EoBCoreEngine::spellCallback_start_flameBlade() {
+ int t = createMagicWeaponType(0, 0, 0, 0x0f, 1, 4, 4, 1);
+ Item i = (t != -1) ? createMagicWeaponItem(0, 84, 0, t) : -1;
+ if (t == -1 || i == -1) {
+ if (_flags.gameID == GI_EOB2)
+ printWarning(_magicStrings8[0]);
+ removeCharacterEffect(_activeSpell, _activeSpellCharId, 0);
+ deleteCharEventTimer(_activeSpellCharId, -_activeSpell);
+ _returnAfterSpellCallback = true;
+ } else {
+ _characters[_activeSpellCharId].inventory[getMagicWeaponSlot(_activeSpellCharId)] = i;
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_slowPoison() {
+ if (_characters[_activeSpellCharId].flags & 2) {
+ _characters[_activeSpellCharId].effectFlags |= 0x2000;
+ setSpellEventTimer(_activeSpell, 1, 32760, 1, 1);
+ } else {
+ printNoEffectWarning();
+ }
+}
+
+bool EoBCoreEngine::spellCallback_end_slowPoison(void *obj) {
+ EoBCharacter *c = (EoBCharacter *)obj;
+ c->effectFlags &= ~0x2000;
+ return true;
+}
+
+void EoBCoreEngine::spellCallback_start_createFood() {
+ for (int i = 0; i < 6; i++) {
+ if (!testCharacter(i, 3))
+ continue;
+ _characters[i].food = 100;
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_removeParalysis() {
+ int numChar = 4;
+ for (int i = 0; i < 6; i++) {
+ if (!(_characters[i].flags & 4) || !numChar)
+ continue;
+ _characters[i].flags &= ~4;
+ numChar--;
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_causeSeriousWounds() {
+ causeWounds(2, 8, 1);
+}
+
+void EoBCoreEngine::spellCallback_start_cureSeriousWounds() {
+ modifyCharacterHitpoints(_activeSpellCharId, rollDice(2, 8, 1));
+}
+
+void EoBCoreEngine::spellCallback_start_neutralizePoison() {
+ if (_characters[_activeSpellCharId].flags & 2)
+ neutralizePoison(_activeSpellCharId);
+ else
+ printNoEffectWarning();
+}
+
+void EoBCoreEngine::spellCallback_start_causeCriticalWounds() {
+ causeWounds(3, 8, 3);
+}
+
+void EoBCoreEngine::spellCallback_start_cureCriticalWounds() {
+ modifyCharacterHitpoints(_activeSpellCharId, rollDice(3, 8, 3));
+}
+
+void EoBCoreEngine::spellCallback_start_flameStrike() {
+ launchMagicObject(_openBookChar, _flags.gameID == GI_EOB1 ? 8 : 7, _currentBlock, _activeSpellCharacterPos, _currentDirection);
+}
+
+bool EoBCoreEngine::spellCallback_end_flameStrike(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ return magicObjectDamageHit(fo, 6, 8, 0, 0);
+}
+
+void EoBCoreEngine::spellCallback_start_raiseDead() {
+ if (_characters[_activeSpellCharId].hitPointsCur == -10 && ((_characters[_activeSpellCharId].raceSex >> 1) != 1)) {
+ _characters[_activeSpellCharId].hitPointsCur = 1;
+ gui_drawCharPortraitWithStats(_activeSpellCharId);
+ } else {
+ printNoEffectWarning();
+ }
+}
+
+void EoBCoreEngine::spellCallback_start_harm() {
+ causeWounds(-1, -1, -1);
+}
+
+void EoBCoreEngine::spellCallback_start_heal() {
+ EoBCharacter *c = &_characters[_activeSpellCharId];
+ if (c->hitPointsMax <= c->hitPointsCur)
+ printWarning(_magicStrings4[0]);
+ else
+ modifyCharacterHitpoints(_activeSpellCharId, c->hitPointsMax - c->hitPointsCur);
+}
+
+void EoBCoreEngine::spellCallback_start_layOnHands() {
+ modifyCharacterHitpoints(_activeSpellCharId, _characters[_openBookChar].level[0] << 1);
+}
+
+void EoBCoreEngine::spellCallback_start_turnUndead() {
+ uint16 bl = calcNewBlockPosition(_currentBlock, _currentDirection);
+ if (!(_levelBlockProperties[bl].flags & 7))
+ return;
+
+ int cl = _openBookCasterLevel ? _openBookCasterLevel : getClericPaladinLevel(_openBookChar);
+ int r = rollDice(1, 20);
+ bool hit = false;
+
+ for (const int16 *m = findBlockMonsters(bl, 4, 4, 1, 1); *m != -1; m++) {
+ if ((_monsterProps[_monsters[*m].type].typeFlags & 4) && !(_monsters[*m].flags & 0x10)) {
+ _preventMonsterFlash = true;
+ _monsters[*m].flags |= 0x10;
+ hit |= turnUndeadHit(&_monsters[*m], r, cl);
+ }
+ }
+
+ if (hit) {
+ turnUndeadAutoHit();
+ snd_playSoundEffect(95);
+ updateAllMonsterShapes();
+ }
+
+ _preventMonsterFlash = false;
+}
+
+bool EoBCoreEngine::spellCallback_end_monster_lightningBolt(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ return magicObjectDamageHit(fo, 0, 0, 12, 1);
+}
+
+bool EoBCoreEngine::spellCallback_end_monster_fireball1(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ bool res = false;
+ if (_partyEffectFlags & 0x20000) {
+ res = magicObjectDamageHit(fo, 4, 10, 6, 0);
+ if (res) {
+ gui_drawAllCharPortraitsWithStats();
+ _partyEffectFlags &= ~0x20000;
+ }
+ } else {
+ res = magicObjectDamageHit(fo, 12, 10, 6, 0);
+ }
+ return res;
+}
+
+bool EoBCoreEngine::spellCallback_end_monster_fireball2(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ return magicObjectDamageHit(fo, 0, 0, 18, 0);
+}
+
+bool EoBCoreEngine::spellCallback_end_monster_deathSpell(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ if (fo->curBlock != _currentBlock)
+ return false;
+
+ int numDest = rollDice(1, 4);
+ _txt->printMessage(_magicStrings2[2]);
+ for (int d = findFirstCharacterSpellTarget(); d != -1 && numDest; d = findNextCharacterSpellTarget(d)) {
+ if (_characters[d].level[0] < 8) {
+ inflictCharacterDamage(d, 300);
+ numDest--;
+ }
+ }
+
+ return true;
+}
+
+bool EoBCoreEngine::spellCallback_end_monster_disintegrate(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ if (fo->curBlock != _currentBlock)
+ return false;
+
+ int d = findFirstCharacterSpellTarget();
+ if (d != -1) {
+ if (!charDeathSavingThrow(d, 1)) {
+ inflictCharacterDamage(d, 300);
+ _txt->printMessage(_magicStrings2[1], -1, _characters[d].name);
+ }
+ }
+
+ return true;
+}
+
+bool EoBCoreEngine::spellCallback_end_monster_causeCriticalWounds(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ if (fo->curBlock != _currentBlock)
+ return false;
+
+ int d = findFirstCharacterSpellTarget();
+ if (d != -1) {
+ _txt->printMessage(_magicStrings2[3], -1, _characters[d].name);
+ inflictCharacterDamage(d, rollDice(3, 8, 3));
+ }
+
+ return true;
+}
+
+bool EoBCoreEngine::spellCallback_end_monster_fleshToStone(void *obj) {
+ EoBFlyingObject *fo = (EoBFlyingObject *)obj;
+ if (fo->curBlock != _currentBlock)
+ return false;
+
+ int d = findFirstCharacterSpellTarget();
+ while (d != -1) {
+ if (!charDeathSavingThrow(d, 2)) {
+ statusAttack(d, 8, _magicStrings2[4], 5, 0, 0, 1);
+ d = -1;
+ } else {
+ d = findNextCharacterSpellTarget(d);
+ }
+ }
+
+ return true;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk
index abd535ee29..21e3ba3dff 100644
--- a/engines/kyra/module.mk
+++ b/engines/kyra/module.mk
@@ -9,6 +9,7 @@ MODULE_OBJS := \
debugger.o \
detection.o \
gui.o \
+ gui_v1.o \
gui_lok.o \
gui_v2.o \
gui_hof.o \
@@ -72,8 +73,19 @@ MODULE_OBJS := \
vqa.o \
wsamovie.o
+KYRARPG_COMMON_OBJ = \
+ gui_rpg.o \
+ kyra_rpg.o \
+ saveload_rpg.o \
+ scene_rpg.o \
+ sprites_rpg.o \
+ staticres_rpg.o \
+ text_rpg.o \
+ timer_rpg.o
+
ifdef ENABLE_LOL
MODULE_OBJS += \
+ $(KYRARPG_COMMON_OBJ) \
gui_lol.o \
items_lol.o \
lol.o \
@@ -89,6 +101,30 @@ MODULE_OBJS += \
timer_lol.o
endif
+ifdef ENABLE_EOB
+ifndef ENABLE_LOL
+MODULE_OBJS += \
+ $(KYRARPG_COMMON_OBJ)
+endif
+MODULE_OBJS += \
+ chargen.o \
+ eobcommon.o \
+ eob.o \
+ darkmoon.o \
+ gui_eob.o \
+ items_eob.o \
+ magic_eob.o \
+ saveload_eob.o \
+ scene_eob.o \
+ screen_eob.o \
+ script_eob.o \
+ sequences_eob.o \
+ sequences_darkmoon.o \
+ sprites_eob.o \
+ staticres_eob.o \
+ timer_eob.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..adb3063344 100644
--- a/engines/kyra/resource.cpp
+++ b/engines/kyra/resource.cpp
@@ -59,14 +59,14 @@ 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;
if (!_vm->gameFlags().isDemo && _vm->gameFlags().isTalkie) {
// List of files in the talkie version, which can never be unload.
- static const char * const list[] = {
+ static const char *const list[] = {
"ADL.PAK", "CHAPTER1.VRM", "COL.PAK", "FINALE.PAK", "INTRO1.PAK", "INTRO2.PAK",
"INTRO3.PAK", "INTRO4.PAK", "MISC.PAK", "SND.PAK", "STARTUP.PAK", "XMI.PAK",
"CAVE.APK", "DRAGON1.APK", "DRAGON2.APK", "LAGOON.APK", 0
@@ -84,7 +84,7 @@ bool Resource::reset() {
name.toUppercase();
// No PAK file
- if (name == "TWMUSIC.PAK")
+ if (name == "TWMUSIC.PAK" || name == "EYE.PAK")
continue;
// We need to only load the script archive for the language the user specified
@@ -122,15 +122,15 @@ bool Resource::reset() {
_files.add("installer", loadInstallerArchive("WESTWOOD", "%d", 0), 2, false);
if (!_vm->gameFlags().isTalkie && !_vm->gameFlags().isDemo) {
- static const char * const list[] = {
+ static const char *const list[] = {
"GENERAL.PAK", 0
};
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
+ return false; // for compilers that don't support NORETURN
}
return true;
@@ -173,7 +173,7 @@ bool Resource::loadFileList(const Common::String &filedata) {
f->seek(filenameOffset, SEEK_SET);
uint8 buffer[13];
- f->read(buffer, sizeof(buffer)-1);
+ f->read(buffer, sizeof(buffer) - 1);
buffer[12] = 0;
f->seek(offset + 16, SEEK_SET);
@@ -189,7 +189,7 @@ bool Resource::loadFileList(const Common::String &filedata) {
} else if (!loadPakFile(filename)) {
delete f;
error("couldn't load file '%s'", filename.c_str());
- return false; // for compilers that don't support NORETURN
+ return false; // for compilers that don't support NORETURN
}
}
}
@@ -198,21 +198,21 @@ bool Resource::loadFileList(const Common::String &filedata) {
return true;
}
-bool Resource::loadFileList(const char * const *filelist, uint32 numFiles) {
+bool Resource::loadFileList(const char *const *filelist, uint32 numFiles) {
if (!filelist)
return false;
while (numFiles--) {
if (!loadPakFile(filelist[numFiles])) {
error("couldn't load file '%s'", filelist[numFiles]);
- return false; // for compilers that don't support NORETURN
+ return false; // for compilers that don't support NORETURN
}
}
return true;
}
-bool Resource::loadProtectedFiles(const char * const * list) {
+bool Resource::loadProtectedFiles(const char *const *list) {
for (uint i = 0; list[i]; ++i) {
Common::ArchiveMemberPtr file = _files.getMember(list[i]);
if (!file)
diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h
index c2a697f18d..f2bc4e8146 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/darkmoon.h"
#include "kyra/lol.h"
#include "kyra/kyra_hof.h"
@@ -250,91 +251,490 @@ enum KyraResources {
k3ItemMagicTable,
k3ItemStringMap,
-#ifdef ENABLE_LOL
- kLolIngamePakFiles,
- kLolCharacterDefs,
- kLolIngameSfxFiles,
- kLolIngameSfxIndex,
- kLolMusicTrackMap,
- kLolIngameGMSfxIndex,
- kLolIngameMT32SfxIndex,
- kLolIngamePcSpkSfxIndex,
- kLolSpellProperties,
- kLolGameShapeMap,
- kLolSceneItemOffs,
- kLolCharInvIndex,
- kLolCharInvDefs,
- kLolCharDefsMan,
- kLolCharDefsWoman,
- kLolCharDefsKieran,
- kLolCharDefsAkshel,
- kLolExpRequirements,
- kLolMonsterModifiers,
- kLolMonsterShiftOffsets,
- kLolMonsterDirFlags,
- kLolMonsterScaleY,
- kLolMonsterScaleX,
- kLolMonsterScaleWH,
- kLolFlyingObjectShp,
- kLolInventoryDesc,
-
- kLolLevelShpList,
- kLolLevelDatList,
- kLolCompassDefs,
- kLolItemPrices,
- kLolStashSetup,
-
- kLolDscUnk1,
- kLolDscShapeIndex,
- kLolDscOvlMap,
- kLolDscScaleWidthData,
- kLolDscScaleHeightData,
- kLolDscX,
- kLolDscY,
- kLolDscTileIndex,
- kLolDscUnk2,
- kLolDscDoorShapeIndex,
- kLolDscDimData1,
- kLolDscDimData2,
- kLolDscBlockMap,
- kLolDscDimMap,
- kLolDscDoor1,
- kLolDscDoorScale,
- kLolDscDoor4,
- kLolDscDoorX,
- kLolDscDoorY,
- kLolDscOvlIndex,
- kLolDscBlockIndex,
-
- kLolScrollXTop,
- kLolScrollYTop,
- kLolScrollXBottom,
- kLolScrollYBottom,
-
- kLolButtonDefs,
- kLolButtonList1,
- kLolButtonList2,
- kLolButtonList3,
- kLolButtonList4,
- kLolButtonList5,
- kLolButtonList6,
- kLolButtonList7,
- kLolButtonList8,
-
- kLolLegendData,
- kLolMapCursorOvl,
- kLolMapStringId,
-
- kLolSpellbookAnim,
- kLolSpellbookCoords,
- kLolHealShapeFrames,
- kLolLightningDefs,
- kLolFireballCoords,
-
- kLolCredits,
-
- kLolHistory,
-#endif
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ kRpgCommonMoreStrings,
+ kRpgCommonDscShapeIndex,
+ kRpgCommonDscX,
+ kRpgCommonDscTileIndex,
+ kRpgCommonDscUnk2,
+ kRpgCommonDscDoorShapeIndex,
+ kRpgCommonDscDimData1,
+ kRpgCommonDscDimData2,
+ kRpgCommonDscBlockMap,
+ kRpgCommonDscDimMap,
+ kRpgCommonDscDoorY2,
+ kRpgCommonDscDoorFrameY1,
+ kRpgCommonDscDoorFrameY2,
+ kRpgCommonDscDoorFrameIndex1,
+ kRpgCommonDscDoorFrameIndex2,
+ kRpgCommonDscBlockIndex,
+
+ kEoBBaseChargenStrings1,
+ kEoBBaseChargenStrings2,
+ kEoBBaseChargenStartLevels,
+ kEoBBaseChargenStatStrings,
+ kEoBBaseChargenRaceSexStrings,
+ kEoBBaseChargenClassStrings,
+ kEoBBaseChargenAlignmentStrings,
+ kEoBBaseChargenEnterGameStrings,
+ kEoBBaseChargenClassMinStats,
+ kEoBBaseChargenRaceMinStats,
+ kEoBBaseChargenRaceMaxStats,
+
+ kEoBBaseSaveThrowTable1,
+ kEoBBaseSaveThrowTable2,
+ kEoBBaseSaveThrowTable3,
+ kEoBBaseSaveThrowTable4,
+ kEoBBaseSaveThrwLvlIndex,
+ kEoBBaseSaveThrwModDiv,
+ kEoBBaseSaveThrwModExt,
+
+ kEoBBasePryDoorStrings,
+ kEoBBaseWarningStrings,
+
+ kEoBBaseItemSuffixStringsRings,
+ kEoBBaseItemSuffixStringsPotions,
+ kEoBBaseItemSuffixStringsWands,
+
+ kEoBBaseRipItemStrings,
+ kEoBBaseCursedString,
+ kEoBBaseEnchantedString,
+ kEoBBaseMagicObjectStrings,
+ kEoBBaseMagicObjectString5,
+ kEoBBasePatternSuffix,
+ kEoBBasePatternGrFix1,
+ kEoBBasePatternGrFix2,
+ kEoBBaseValidateArmorString,
+ kEoBBaseValidateCursedString,
+ kEoBBaseValidateNoDropString,
+ kEoBBasePotionStrings,
+ kEoBBaseWandStrings,
+ kEoBBaseItemMisuseStrings,
+
+ kEoBBaseTakenStrings,
+ kEoBBasePotionEffectStrings,
+
+ kEoBBaseYesNoStrings,
+ kEoBBaseNpcMaxStrings,
+ kEoBBaseOkStrings,
+ kEoBBaseNpcJoinStrings,
+ kEoBBaseCancelStrings,
+ kEoBBaseAbortStrings,
+
+ kEoBBaseMenuStringsMain,
+ kEoBBaseMenuStringsSaveLoad,
+ kEoBBaseMenuStringsOnOff,
+ kEoBBaseMenuStringsSpells,
+ kEoBBaseMenuStringsRest,
+ kEoBBaseMenuStringsDrop,
+ kEoBBaseMenuStringsExit,
+ kEoBBaseMenuStringsStarve,
+ kEoBBaseMenuStringsScribe,
+ kEoBBaseMenuStringsDrop2,
+ kEoBBaseMenuStringsHead,
+ kEoBBaseMenuStringsPoison,
+ kEoBBaseMenuStringsMgc,
+ kEoBBaseMenuStringsPrefs,
+ kEoBBaseMenuStringsRest2,
+ kEoBBaseMenuStringsRest3,
+ kEoBBaseMenuStringsRest4,
+ kEoBBaseMenuStringsDefeat,
+ kEoBBaseMenuStringsTransfer,
+ kEoBBaseMenuStringsSpec,
+ kEoBBaseMenuStringsSpellNo,
+ kEoBBaseMenuYesNoStrings,
+
+ kEoBBaseSpellLevelsMage,
+ kEoBBaseSpellLevelsCleric,
+ kEoBBaseNumSpellsCleric,
+ kEoBBaseNumSpellsWisAdj,
+ kEoBBaseNumSpellsPal,
+ kEoBBaseNumSpellsMage,
+
+ 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,
+ kEoBBaseDscDoorXE,
+ kEoBBaseDscDoorY1,
+ kEoBBaseDscDoorY3,
+ kEoBBaseDscDoorY4,
+ kEoBBaseDscDoorY5,
+ kEoBBaseDscDoorY6,
+ kEoBBaseDscDoorY7,
+ kEoBBaseDscDoorCoordsExt,
+
+ kEoBBaseDscItemPosIndex,
+ kEoBBaseDscItemShpX,
+ kEoBBaseDscItemScaleIndex,
+ kEoBBaseDscItemTileIndex,
+ kEoBBaseDscItemShapeMap,
+
+ kEoBBaseDscMonsterFrmOffsTbl1,
+ kEoBBaseDscMonsterFrmOffsTbl2,
+
+ kEoBBaseInvSlotX,
+ kEoBBaseInvSlotY,
+ kEoBBaseSlotValidationFlags,
+
+ kEoBBaseProjectileWeaponTypes,
+ kEoBBaseWandTypes,
+
+ kEoBBaseDrawObjPosIndex,
+ kEoBBaseFlightObjFlipIndex,
+ kEoBBaseFlightObjShpMap,
+ kEoBBaseFlightObjSclIndex,
+
+ kEoBBaseDscTelptrShpCoords,
+
+ kEoBBasePortalSeqData,
+ kEoBBaseManDef,
+ kEoBBaseManWord,
+ kEoBBaseManPrompt,
+
+ kEoBBaseBookNumbers,
+ kEoBBaseMageSpellsList,
+ kEoBBaseClericSpellsList,
+ kEoBBaseSpellNames,
+ kEoBBaseMagicStrings1,
+ kEoBBaseMagicStrings2,
+ kEoBBaseMagicStrings3,
+ kEoBBaseMagicStrings4,
+ kEoBBaseMagicStrings6,
+ kEoBBaseMagicStrings7,
+ kEoBBaseMagicStrings8,
+
+ kEoBBaseExpObjectTlMode,
+ kEoBBaseExpObjectTblIndex,
+ kEoBBaseExpObjectShpStart,
+ kEoBBaseExpObjectTbl1,
+ kEoBBaseExpObjectTbl2,
+ kEoBBaseExpObjectTbl3,
+ kEoBBaseExpObjectY,
+
+ kEoBBaseSparkDefSteps,
+ kEoBBaseSparkDefSubSteps,
+ kEoBBaseSparkDefShift,
+ kEoBBaseSparkDefAdd,
+ kEoBBaseSparkDefX,
+ kEoBBaseSparkDefY,
+ kEoBBaseSparkOfFlags1,
+ kEoBBaseSparkOfFlags2,
+ kEoBBaseSparkOfShift,
+ kEoBBaseSparkOfX,
+ kEoBBaseSparkOfY,
+
+ kEoBBaseSpellProperties,
+ kEoBBaseMagicFlightProps,
+ kEoBBaseTurnUndeadEffect,
+ kEoBBaseBurningHandsDest,
+ kEoBBaseConeOfColdDest1,
+ kEoBBaseConeOfColdDest2,
+ kEoBBaseConeOfColdDest3,
+ kEoBBaseConeOfColdDest4,
+ kEoBBaseConeOfColdGfxTbl,
+
+ kEoB1MainMenuStrings,
+ kEoB1BonusStrings,
+
+ kEoB1IntroFilesOpening,
+ kEoB1IntroFilesTower,
+ kEoB1IntroFilesOrb,
+ kEoB1IntroFilesWdEntry,
+ kEoB1IntroFilesKing,
+ kEoB1IntroFilesHands,
+ kEoB1IntroFilesWdExit,
+ kEoB1IntroFilesTunnel,
+ kEoB1IntroOpeningFrmDelay,
+ kEoB1IntroWdEncodeX,
+ kEoB1IntroWdEncodeY,
+ kEoB1IntroWdEncodeWH,
+ kEoB1IntroWdDsX,
+ kEoB1IntroWdDsY,
+ kEoB1IntroTvlX1,
+ kEoB1IntroTvlY1,
+ kEoB1IntroTvlX2,
+ kEoB1IntroTvlY2,
+ kEoB1IntroTvlW,
+ kEoB1IntroTvlH,
+
+ kEoB1DoorShapeDefs,
+ kEoB1DoorSwitchShapeDefs,
+ kEoB1DoorSwitchCoords,
+ kEoB1MonsterProperties,
+
+ kEoB1EnemyMageSpellList,
+ kEoB1EnemyMageSfx,
+ kEoB1BeholderSpellList,
+ kEoB1BeholderSfx,
+ kEoB1TurnUndeadString,
+
+ kEoB1CgaMappingDefault,
+ kEoB1CgaMappingAlt,
+ kEoB1CgaMappingInv,
+ kEoB1CgaMappingItemsL,
+ kEoB1CgaMappingItemsS,
+ kEoB1CgaMappingThrown,
+ kEoB1CgaMappingIcons,
+ kEoB1CgaMappingDeco,
+ kEoB1CgaLevelMappingIndex,
+ kEoB1CgaMappingLevel0,
+ kEoB1CgaMappingLevel1,
+ kEoB1CgaMappingLevel2,
+ kEoB1CgaMappingLevel3,
+ kEoB1CgaMappingLevel4,
+
+ kEoB1NpcShpData,
+ kEoB1NpcSubShpIndex1,
+ kEoB1NpcSubShpIndex2,
+ kEoB1NpcSubShpY,
+ kEoB1Npc0Strings,
+ kEoB1Npc11Strings,
+ kEoB1Npc12Strings,
+ kEoB1Npc21Strings,
+ kEoB1Npc22Strings,
+ kEoB1Npc31Strings,
+ kEoB1Npc32Strings,
+ kEoB1Npc4Strings,
+ kEoB1Npc5Strings,
+ kEoB1Npc6Strings,
+ kEoB1Npc7Strings,
+
+ kEoB2MainMenuStrings,
+
+ kEoB2TransferPortraitFrames,
+ kEoB2TransferConvertTable,
+ kEoB2TransferItemTable,
+ kEoB2TransferExpTable,
+ kEoB2TransferStrings1,
+ kEoB2TransferStrings2,
+ kEoB2TransferLabels,
+
+ kEoB2IntroStrings,
+ kEoB2IntroCPSFiles,
+ kEob2IntroAnimData00,
+ kEob2IntroAnimData01,
+ kEob2IntroAnimData02,
+ kEob2IntroAnimData03,
+ kEob2IntroAnimData04,
+ kEob2IntroAnimData05,
+ kEob2IntroAnimData06,
+ kEob2IntroAnimData07,
+ kEob2IntroAnimData08,
+ kEob2IntroAnimData09,
+ kEob2IntroAnimData10,
+ kEob2IntroAnimData11,
+ kEob2IntroAnimData12,
+ kEob2IntroAnimData13,
+ kEob2IntroAnimData14,
+ kEob2IntroAnimData15,
+ kEob2IntroAnimData16,
+ kEob2IntroAnimData17,
+ kEob2IntroAnimData18,
+ kEob2IntroAnimData19,
+ kEob2IntroAnimData20,
+ kEob2IntroAnimData21,
+ kEob2IntroAnimData22,
+ kEob2IntroAnimData23,
+ kEob2IntroAnimData24,
+ kEob2IntroAnimData25,
+ kEob2IntroAnimData26,
+ kEob2IntroAnimData27,
+ kEob2IntroAnimData28,
+ kEob2IntroAnimData29,
+ kEob2IntroAnimData30,
+ kEob2IntroAnimData31,
+ kEob2IntroAnimData32,
+ kEob2IntroAnimData33,
+ kEob2IntroAnimData34,
+ kEob2IntroAnimData35,
+ kEob2IntroAnimData36,
+ kEob2IntroAnimData37,
+ kEob2IntroAnimData38,
+ kEob2IntroAnimData39,
+ kEob2IntroAnimData40,
+ kEob2IntroAnimData41,
+ kEob2IntroAnimData42,
+ kEob2IntroAnimData43,
+ kEoB2IntroShapes00,
+ kEoB2IntroShapes01,
+ kEoB2IntroShapes04,
+ kEoB2IntroShapes07,
+
+ kEoB2FinaleStrings,
+ kEoB2CreditsData,
+ kEoB2FinaleCPSFiles,
+ kEob2FinaleAnimData00,
+ kEob2FinaleAnimData01,
+ kEob2FinaleAnimData02,
+ kEob2FinaleAnimData03,
+ kEob2FinaleAnimData04,
+ kEob2FinaleAnimData05,
+ kEob2FinaleAnimData06,
+ kEob2FinaleAnimData07,
+ kEob2FinaleAnimData08,
+ kEob2FinaleAnimData09,
+ kEob2FinaleAnimData10,
+ kEob2FinaleAnimData11,
+ kEob2FinaleAnimData12,
+ kEob2FinaleAnimData13,
+ kEob2FinaleAnimData14,
+ kEob2FinaleAnimData15,
+ kEob2FinaleAnimData16,
+ kEob2FinaleAnimData17,
+ kEob2FinaleAnimData18,
+ kEob2FinaleAnimData19,
+ kEob2FinaleAnimData20,
+ kEoB2FinaleShapes00,
+ kEoB2FinaleShapes03,
+ kEoB2FinaleShapes07,
+ kEoB2FinaleShapes09,
+ kEoB2FinaleShapes10,
+
+ kEoB2NpcShapeData,
+ kEoB2Npc1Strings,
+ kEoB2Npc2Strings,
+ kEoB2MonsterDustStrings,
+
+ kEoB2DreamSteps,
+ kEoB2KheldranStrings,
+ kEoB2HornStrings,
+ kEoB2HornSounds,
+
+ kEoB2WallOfForceDsX,
+ kEoB2WallOfForceDsY,
+ kEoB2WallOfForceNumW,
+ kEoB2WallOfForceNumH,
+ kEoB2WallOfForceShpId,
+
+ kLoLIngamePakFiles,
+ kLoLCharacterDefs,
+ kLoLIngameSfxFiles,
+ kLoLIngameSfxIndex,
+ kLoLMusicTrackMap,
+ kLoLIngameGMSfxIndex,
+ kLoLIngameMT32SfxIndex,
+ kLoLIngamePcSpkSfxIndex,
+ kLoLSpellProperties,
+ kLoLGameShapeMap,
+ kLoLSceneItemOffs,
+ kLoLCharInvIndex,
+ kLoLCharInvDefs,
+ kLoLCharDefsMan,
+ kLoLCharDefsWoman,
+ kLoLCharDefsKieran,
+ kLoLCharDefsAkshel,
+ kLoLExpRequirements,
+ kLoLMonsterModifiers,
+ kLoLMonsterShiftOffsets,
+ kLoLMonsterDirFlags,
+ kLoLMonsterScaleY,
+ kLoLMonsterScaleX,
+ kLoLMonsterScaleWH,
+ kLoLFlyingObjectShp,
+ kLoLInventoryDesc,
+
+ kLoLLevelShpList,
+ kLoLLevelDatList,
+ kLoLCompassDefs,
+ kLoLItemPrices,
+ kLoLStashSetup,
+
+ kLoLDscWalls,
+ kLoLDscOvlMap,
+ kLoLDscScaleWidthData,
+ kLoLDscScaleHeightData,
+ kLoLBaseDscY,
+
+ kLoLDscDoorScale,
+ kLoLDscDoor4,
+ kLoLDscDoorX,
+ kLoLDscDoorY,
+ kLoLDscOvlIndex,
+
+ kLoLScrollXTop,
+ kLoLScrollYTop,
+ kLoLScrollXBottom,
+ kLoLScrollYBottom,
+
+ kLoLButtonDefs,
+ kLoLButtonList1,
+ kLoLButtonList2,
+ kLoLButtonList3,
+ kLoLButtonList4,
+ kLoLButtonList5,
+ kLoLButtonList6,
+ kLoLButtonList7,
+ kLoLButtonList8,
+
+ kLoLLegendData,
+ kLoLMapCursorOvl,
+ kLoLMapStringId,
+
+ kLoLSpellbookAnim,
+ kLoLSpellbookCoords,
+ kLoLHealShapeFrames,
+ kLoLLightningDefs,
+ kLoLFireballCoords,
+
+ kLoLCredits,
+
+ kLoLHistory,
+#endif // ENABLE_EOB || ENABLE_LOL
kMaxResIDs
};
@@ -362,16 +762,23 @@ public:
const Room *loadRoomTable(int id, int &entries);
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);
+ const ItemAnimDefinition *loadItemAnimDefinition(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 DarkMoonAnimCommand *loadEoB2SeqData(int id, int &entries);
+ const DarkMoonShapeDef *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
@@ -390,6 +797,7 @@ private:
const FileType *getFiletype(int type);
const void *getData(int id, int requesttype, int &size);
+ bool loadDummy(Common::SeekableReadStream &stream, void *&ptr, int &size);
bool loadStringTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
bool loadRawData(Common::SeekableReadStream &stream, void *&ptr, int &size);
bool loadShapeTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
@@ -397,17 +805,25 @@ private:
bool loadRoomTable(Common::SeekableReadStream &stream, void *&ptr, int &size);
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);
+ bool loadItemAnimDefinition(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 freeDummy(void *&ptr, int &size);
void freeRawData(void *&ptr, int &size);
void freeStringTable(void *&ptr, int &size);
void freeShapeTable(void *&ptr, int &size);
@@ -415,16 +831,23 @@ private:
void freeRoomTable(void *&ptr, int &size);
void freeHofSequenceData(void *&ptr, int &size);
void freeHofShapeAnimDataV1(void *&ptr, int &size);
- void freeHofShapeAnimDataV2(void *&ptr, int &size);
+ void freeItemAnimDefinition(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,
@@ -435,15 +858,19 @@ private:
k2SeqData = 5,
k2ShpAnimDataV1 = 6,
- k2ShpAnimDataV2 = 7,
-
- kLolCharData = 8,
- kLolSpellData = 9,
- kLolCompassData = 10,
- kLolFlightShpData = 11,
- kLolButtonData = 12,
- kLolRawDataBe16 = 13,
- kLolRawDataBe32 = 14
+ k2ItemAnimDefinition = 7,
+
+ kLoLCharData = 8,
+ kLoLSpellData = 9,
+ kLoLCompassData = 10,
+ kLoLFlightShpData = 11,
+ kLoLButtonData = 12,
+ kRawDataBe16 = 13,
+ kRawDataBe32 = 14,
+
+ kEoB2SequenceData = 15,
+ kEoB2ShapeData = 16,
+ kEoBNpcData = 17
};
struct FileType {
diff --git a/engines/kyra/resource_intern.cpp b/engines/kyra/resource_intern.cpp
index 482bd1a5d6..6f7591ccf1 100644
--- a/engines/kyra/resource_intern.cpp
+++ b/engines/kyra/resource_intern.cpp
@@ -37,11 +37,11 @@ PlainArchive::PlainArchive(Common::ArchiveMemberPtr file)
: _file(file), _files() {
}
-bool PlainArchive::hasFile(const Common::String &name) {
+bool PlainArchive::hasFile(const Common::String &name) const {
return (_files.find(name) != _files.end());
}
-int PlainArchive::listMembers(Common::ArchiveMemberList &list) {
+int PlainArchive::listMembers(Common::ArchiveMemberList &list) const {
int count = 0;
for (FileMap::const_iterator i = _files.begin(); i != _files.end(); ++i) {
@@ -52,7 +52,7 @@ int PlainArchive::listMembers(Common::ArchiveMemberList &list) {
return count;
}
-Common::ArchiveMemberPtr PlainArchive::getMember(const Common::String &name) {
+const Common::ArchiveMemberPtr PlainArchive::getMember(const Common::String &name) const {
if (!hasFile(name))
return Common::ArchiveMemberPtr();
@@ -92,11 +92,11 @@ TlkArchive::~TlkArchive() {
delete[] _fileEntries;
}
-bool TlkArchive::hasFile(const Common::String &name) {
+bool TlkArchive::hasFile(const Common::String &name) const {
return (findFile(name) != 0);
}
-int TlkArchive::listMembers(Common::ArchiveMemberList &list) {
+int TlkArchive::listMembers(Common::ArchiveMemberList &list) const {
uint count = 0;
for (; count < _entryCount; ++count) {
@@ -107,7 +107,7 @@ int TlkArchive::listMembers(Common::ArchiveMemberList &list) {
return count;
}
-Common::ArchiveMemberPtr TlkArchive::getMember(const Common::String &name) {
+const Common::ArchiveMemberPtr TlkArchive::getMember(const Common::String &name) const {
if (!hasFile(name))
return Common::ArchiveMemberPtr();
@@ -186,11 +186,11 @@ CachedArchive::~CachedArchive() {
_files.clear();
}
-bool CachedArchive::hasFile(const Common::String &name) {
+bool CachedArchive::hasFile(const Common::String &name) const {
return (_files.find(name) != _files.end());
}
-int CachedArchive::listMembers(Common::ArchiveMemberList &list) {
+int CachedArchive::listMembers(Common::ArchiveMemberList &list) const {
int count = 0;
for (FileMap::const_iterator i = _files.begin(); i != _files.end(); ++i) {
@@ -201,7 +201,7 @@ int CachedArchive::listMembers(Common::ArchiveMemberList &list) {
return count;
}
-Common::ArchiveMemberPtr CachedArchive::getMember(const Common::String &name) {
+const Common::ArchiveMemberPtr CachedArchive::getMember(const Common::String &name) const {
if (!hasFile(name))
return Common::ArchiveMemberPtr();
@@ -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)
@@ -353,7 +356,7 @@ Common::Archive *ResLoaderPak::load(Common::ArchiveMemberPtr memberFile, Common:
const uint32 magic = stream.readUint32BE();
- if (magic != MKTAG('S','C','V','M'))
+ if (magic != MKTAG('S', 'C', 'V', 'M'))
error("LINKLIST file does not contain 'SCVM' header");
const uint32 links = stream.readUint32BE();
@@ -388,10 +391,10 @@ bool ResLoaderInsMalcolm::isLoadable(const Common::String &filename, Common::See
stream.seek(3, SEEK_SET);
int32 size = stream.readUint32LE();
- if (size+7 > stream.size())
+ if (size + 7 > stream.size())
return false;
- stream.seek(size+5, SEEK_SET);
+ stream.seek(size + 5, SEEK_SET);
uint8 buffer[2];
stream.read(&buffer, 2);
@@ -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);
@@ -697,7 +700,7 @@ bool FileExpander::process(uint8 *dst, const uint8 *src, uint32 outsize, uint32
_src->copyBytes(d);
postprocess = false;
needrefresh = true;
- } else if (mode == 0){
+ } else if (mode == 0) {
uint8 *d2 = _tables[0];
memset(d2, 8, 144);
memset(d2 + 144, 9, 112);
@@ -841,7 +844,7 @@ void FileExpander::generateTables(uint8 srcIndex, uint8 dstIndex, uint8 dstIndex
cnt--;
s = tbl1 + cnt;
d = &_tables16[2][cnt];
- uint16 * bt = (uint16 *)tbl3;
+ uint16 *bt = (uint16 *)tbl3;
uint16 inc = 0;
uint16 cnt2 = 0;
diff --git a/engines/kyra/resource_intern.h b/engines/kyra/resource_intern.h
index 03c9d871e8..9d9574d823 100644
--- a/engines/kyra/resource_intern.h
+++ b/engines/kyra/resource_intern.h
@@ -49,9 +49,9 @@ public:
Entry getFileEntry(const Common::String &name) const;
// Common::Archive API implementation
- bool hasFile(const Common::String &name);
- int listMembers(Common::ArchiveMemberList &list);
- Common::ArchiveMemberPtr getMember(const Common::String &name);
+ bool hasFile(const Common::String &name) const;
+ int listMembers(Common::ArchiveMemberList &list) const;
+ const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
private:
typedef Common::HashMap<Common::String, Entry, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> FileMap;
@@ -65,9 +65,9 @@ public:
TlkArchive(Common::ArchiveMemberPtr file, uint16 entryCount, const uint32 *fileEntries);
~TlkArchive();
- bool hasFile(const Common::String &name);
- int listMembers(Common::ArchiveMemberList &list);
- Common::ArchiveMemberPtr getMember(const Common::String &name);
+ bool hasFile(const Common::String &name) const;
+ int listMembers(Common::ArchiveMemberList &list) const;
+ const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
private:
Common::ArchiveMemberPtr _file;
@@ -92,9 +92,9 @@ public:
CachedArchive(const FileInputList &files);
~CachedArchive();
- bool hasFile(const Common::String &name);
- int listMembers(Common::ArchiveMemberList &list);
- Common::ArchiveMemberPtr getMember(const Common::String &name);
+ bool hasFile(const Common::String &name) const;
+ int listMembers(Common::ArchiveMemberList &list) const;
+ const Common::ArchiveMemberPtr getMember(const Common::String &name) const;
Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const;
private:
struct Entry {
diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp
index 42c5d3e8a8..41ba1e5e50 100644
--- a/engines/kyra/saveload.cpp
+++ b/engines/kyra/saveload.cpp
@@ -29,7 +29,7 @@
#include "graphics/thumbnail.h"
#include "graphics/surface.h"
-#define CURRENT_SAVE_VERSION 16
+#define CURRENT_SAVE_VERSION 17
#define GF_FLOPPY (1 << 0)
#define GF_TALKIE (1 << 1)
@@ -44,22 +44,25 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab
header.flags = 0;
header.thumbnail = 0;
- if (type == MKTAG('K','Y','R','A') || type == MKTAG('A','R','Y','K')) { // old Kyra1 header ID
+ if (type == MKTAG('K', 'Y', 'R', 'A') || type == MKTAG('A', 'R', 'Y', 'K')) { // old Kyra1 header ID
header.gameID = GI_KYRA1;
header.oldHeader = true;
- } else if (type == MKTAG('H','O','F','S')) { // old Kyra2 header ID
+ } else if (type == MKTAG('H', 'O', 'F', 'S')) { // old Kyra2 header ID
header.gameID = GI_KYRA2;
header.oldHeader = true;
- } else if (type == MKTAG('W','W','S','V')) {
+ } else if (type == MKTAG('W', 'W', 'S', 'V')) {
header.gameID = in->readByte();
} else {
// try checking for original save header
- const int descriptionSize[2] = { 30, 80 };
+ const int descriptionSize[3] = { 30, 80, 60 };
char descriptionBuffer[81];
bool saveOk = false;
for (uint i = 0; i < ARRAYSIZE(descriptionSize) && !saveOk; ++i) {
+ if (in->size() < descriptionSize[i] + 6)
+ continue;
+
in->seek(0, SEEK_SET);
in->read(descriptionBuffer, descriptionSize[i]);
descriptionBuffer[descriptionSize[i]] = 0;
@@ -68,16 +71,26 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab
type = in->readUint32BE();
header.version = in->readUint16LE();
- if (type == MKTAG('M','B','L','3') && header.version == 100) {
+ if (type == MKTAG('M', 'B', 'L', '3') && header.version == 100) {
saveOk = true;
header.description = descriptionBuffer;
header.gameID = GI_KYRA2;
break;
- } else if (type == MKTAG('M','B','L','4') && header.version == 102) {
+ } else if (type == MKTAG('M', 'B', 'L', '4') && header.version == 102) {
saveOk = true;
header.description = descriptionBuffer;
header.gameID = GI_KYRA3;
break;
+ } else if (type == MKTAG('C','D','0','4')) {
+ header.version = in->readUint32BE();
+ // We don't check the minor version, since the original doesn't do that either and it isn't required.
+ if (header.version != MKTAG(' ','C','D','1'))
+ continue;
+ saveOk = true;
+ header.description = descriptionBuffer;
+ header.gameID = GI_LOL;
+ in->seek(6, SEEK_CUR);
+ break;
}
}
@@ -91,7 +104,7 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab
}
header.version = in->readUint32BE();
- if (header.version > CURRENT_SAVE_VERSION || (header.oldHeader && header.version > 8) || (type == MKTAG('A','R','Y','K') && header.version > 3))
+ if (header.version > CURRENT_SAVE_VERSION || (header.oldHeader && header.version > 8) || (type == MKTAG('A', 'R', 'Y', 'K') && header.version > 3))
return kRSHEInvalidVersion;
// Versions prior to 9 are using a fixed length description field
@@ -122,7 +135,7 @@ KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::Seekab
return ((in->err() || in->eos()) ? kRSHEIoError : kRSHENoError);
}
-Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filename, SaveHeader &header) {
+Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filename, SaveHeader &header, bool checkID) {
Common::SeekableReadStream *in = 0;
if (!(in = _saveFileMan->openForLoading(filename)))
return 0;
@@ -142,7 +155,7 @@ Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filena
if (!header.originalSave) {
if (!header.oldHeader) {
- if (header.gameID != _flags.gameID) {
+ if (header.gameID != _flags.gameID && checkID) {
warning("Trying to load game state from other game (save game: %u, running game: %u)", header.gameID, _flags.gameID);
delete in;
return 0;
@@ -182,10 +195,10 @@ Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, con
}
// Savegame version
- out->writeUint32BE(MKTAG('W','W','S','V'));
+ out->writeUint32BE(MKTAG('W', 'W', 'S', 'V'));
out->writeByte(_flags.gameID);
out->writeUint32BE(CURRENT_SAVE_VERSION);
- out->write(saveName, strlen(saveName)+1);
+ out->write(saveName, strlen(saveName) + 1);
if (_flags.isTalkie)
out->writeUint32BE(GF_TALKIE);
else if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
diff --git a/engines/kyra/saveload_eob.cpp b/engines/kyra/saveload_eob.cpp
new file mode 100644
index 0000000000..f7d7d95b57
--- /dev/null
+++ b/engines/kyra/saveload_eob.cpp
@@ -0,0 +1,909 @@
+/* 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/resource.h"
+#include "kyra/script_eob.h"
+
+#include "common/system.h"
+#include "common/savefile.h"
+#include "common/substream.h"
+#include "common/config-manager.h"
+#include "common/translation.h"
+
+#include "gui/message.h"
+
+namespace Kyra {
+
+Common::Error EoBCoreEngine::loadGameState(int slot) {
+ // Special slot id -1 for EOB1 party transfer
+ const char *fileName = (slot == -1) ? _savegameFilename.c_str() : getSavegameFilename(slot);
+
+ SaveHeader header;
+ Common::InSaveFile *saveFile = openSaveForReading(fileName, header, (slot != -1));
+ if (!saveFile)
+ return Common::Error(Common::kReadingFailed);
+
+ Common::SeekableSubReadStreamEndian in(saveFile, saveFile->pos(), saveFile->size(), !header.originalSave, DisposeAfterUse::YES);
+ _loading = true;
+
+ if (slot != -1)
+ _screen->fadeToBlack(10);
+
+ 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();
+ if (slot == -1 && c->portrait < 0)
+ c->portrait = -c->portrait + 43;
+ 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->mageSpellsAvailableFlags = 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->loadShapeSetBitmap("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, _cgaMappingDefault);
+ }
+
+ _screen->loadShapeSetBitmap(_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)) << 2, _flags.gameID == GI_EOB2 ? 0 : 160, 4, 32, true, _cgaMappingDefault);
+ }
+ _screen->_curPage = 0;
+
+ if (slot == -1) {
+ // Skip all settings which aren't necessary for party transfer.
+ // Jump directly to the items list.
+ in.skip(108);
+ } else {
+ _currentLevel = in.readByte();
+ _currentSub = in.readSByte();
+ _currentBlock = in.readUint16BE();
+ _currentDirection = in.readUint16BE();
+ _itemInHand = in.readSint16BE();
+ _hasTempDataFlags = in.readUint32BE();
+ _partyEffectFlags = in.readUint32BE();
+
+ _updateFlags = in.readUint16BE();
+ _compassDirection = in.readUint16BE();
+ _currentControlMode = in.readUint16BE();
+ _updateCharNum = in.readSint16BE();
+ _openBookSpellLevel = in.readSByte();
+ _openBookSpellSelectedItem = in.readSByte();
+ _openBookSpellListOffset = in.readSByte();
+ _openBookChar = in.readByte();
+ _openBookType = in.readByte();
+ _openBookCharBackup = in.readByte();
+ _openBookTypeBackup = in.readByte();
+ _activeSpellCharId = in.readByte();
+ _activeSpellCharacterPos = in.readByte();
+ _activeSpell = in.readByte();
+ _returnAfterSpellCallback = in.readByte() ? true : false;
+
+ _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();
+ }
+
+ // No more data needed for party transfer
+ if (slot == -1) {
+ _loading = false;
+ return Common::kNoError;
+ }
+
+ 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]);
+ releaseWallOfForceTempData(_lvlTempData[i]);
+ delete _lvlTempData[i];
+ }
+
+ _lvlTempData[i] = new LevelTempData;
+ LevelTempData *l = _lvlTempData[i];
+ l->wallsXorData = new uint8[4096];
+ l->flags = new uint16[1024];
+ EoBMonsterInPlay *lm = new EoBMonsterInPlay[30];
+ l->monsters = lm;
+ EoBFlyingObject *lf = new EoBFlyingObject[_numFlyingObjects];
+ l->flyingObjects = lf;
+ WallOfForce *lw = new WallOfForce[5];
+ l->wallsOfForce = lw;
+
+ 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->spellStatusLeft = in.readSByte();
+ 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 < _numFlyingObjects; 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->starting = 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();
+ }
+
+ for (int ii = 0; ii < 5; ii++) {
+ WallOfForce *w = &lw[ii];
+ w->block = in.readUint16BE();
+ w->duration = in.readUint32BE();
+ }
+ }
+
+ loadLevel(_currentLevel, _currentSub);
+ _sceneUpdateRequired = true;
+ _screen->setFont(Screen::FID_6_FNT);
+
+ for (int i = 0; i < 6; i++) {
+ for (int ii = 0; ii < 10; ii++) {
+ if (_characters[i].events[ii] == -57)
+ spellCallback_start_trueSeeing();
+ }
+ }
+
+ _screen->setCurPage(0);
+ gui_drawPlayField(false);
+
+ if (_currentControlMode)
+ _screen->copyRegion(176, 0, 0, 0, 144, 168, 0, 5, Screen::CR_NO_P_CHECK);
+
+ _screen->setCurPage(0);
+ gui_drawAllCharPortraitsWithStats();
+ drawScene(1);
+
+ if (_updateFlags) {
+ _updateFlags = 0;
+ useMagicBookOrSymbol(_openBookChar, _openBookType);
+ }
+
+ _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, _useHiResDithering ? 1 : 12, Screen::CR_NO_P_CHECK);
+
+ gui_toggleButtons();
+ setHandItem(_itemInHand);
+
+ while (!_screen->isMouseVisible())
+ _screen->showMouse();
+
+ _loading = false;
+ _screen->fadeFromBlack(20);
+ removeInputTop();
+
+ return Common::kNoError;
+}
+
+Common::Error EoBCoreEngine::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) {
+ Common::String saveNameTmp;
+ const char *fileName = 0;
+
+ // Special slot id -1 to create final save for party transfer
+ if (slot == -1) {
+ _savegameFilename = _targetName + Common::String(".fin");
+ fileName = _savegameFilename.c_str();
+ saveNameTmp = _targetName + Common::String(" final");
+ saveNameTmp.toUppercase();
+ saveName = saveNameTmp.c_str();
+ } else {
+ fileName = getSavegameFilename(slot);
+ }
+
+ Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumbnail);
+ if (!out)
+ return _saveFileMan->getError();
+
+ completeDoorOperations();
+ generateTempData();
+ advanceTimers(_restPartyElapsedTime);
+ _restPartyElapsedTime = 0;
+
+ for (int i = 0; i < 6; i++)
+ timerSpecialCharacterUpdate(0x30 + i);
+
+ for (int i = 0; i < 6; i++) {
+ 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->mageSpellsAvailableFlags);
+ for (int ii = 0; ii < 27; ii++)
+ out->writeSint16BE(c->inventory[ii]);
+ uint32 ct = _system->getMillis();
+ for (int ii = 0; ii < 10; ii++)
+ out->writeUint32BE((c->timers[ii] && c->timers[ii] > ct) ? 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);
+
+ out->writeUint16BE(_updateFlags);
+ out->writeUint16BE(_compassDirection);
+ out->writeUint16BE(_currentControlMode);
+ out->writeSint16BE(_updateCharNum);
+ out->writeSByte(_openBookSpellLevel);
+ out->writeSByte(_openBookSpellSelectedItem);
+ out->writeSByte(_openBookSpellListOffset);
+ out->writeByte(_openBookChar);
+ out->writeByte(_openBookType);
+ out->writeByte(_openBookCharBackup);
+ out->writeByte(_openBookTypeBackup);
+ out->writeByte(_activeSpellCharId);
+ out->writeByte(_activeSpellCharacterPos);
+ out->writeByte(_activeSpell);
+ out->writeByte(_returnAfterSpellCallback ? 1 : 0);
+
+ _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;
+ WallOfForce *lw = (WallOfForce *)_lvlTempData[i]->wallsOfForce;
+
+ 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->writeSByte(m->spellStatusLeft);
+ 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 < _numFlyingObjects; 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->starting);
+ 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);
+ }
+
+ for (int ii = 0; ii < 5; ii++) {
+ WallOfForce *w = &lw[ii];
+ out->writeUint16BE(w->block);
+ out->writeUint32BE(w->duration);
+ }
+ }
+
+ 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;
+
+ _gui->notifyUpdateSaveSlotsList();
+
+ return Common::kNoError;
+}
+
+bool EoBCoreEngine::importOriginalSaveFile(int destSlot, const char *sourceFile) {
+ Common::Array<Common::String> origFiles;
+ Common::Array<int> newSlots;
+
+ if (sourceFile) {
+ // If a source file is specified via the console command we just check whether it exists.
+ if (Common::File::exists(sourceFile))
+ origFiles.push_back(sourceFile);
+ else
+ return false;
+ } else {
+ // Check for original save files in the game path (usually at least the "Quick Start Party" file will be present).
+ int numMax = (_flags.gameID == GI_EOB1) ? 1 : 6;
+ const char *pattern = (_flags.gameID == GI_EOB1) ? "EOBDATA.SAV" : "EOBDATA%d.SAV";
+ for (int i = 0; i < numMax; ++i) {
+ Common::String temp = Common::String::format(pattern, i);
+ Common::SeekableReadStream *fs = _res->createReadStream(temp);
+ if (fs) {
+ Common::String dsc;
+ if (_flags.gameID == GI_EOB2) {
+ char descStr[20];
+ fs->read(descStr, 20);
+ dsc = Common::String::format("(\"%s\")", descStr).c_str();
+ }
+
+ delete fs;
+ ::GUI::MessageDialog dialog(Common::String::format(_("The following original save game file has been found in your game path:\n\n%s %s\n\nDo you wish to use this save game file with ScummVM?\n\n"), temp.c_str(), dsc.c_str()), _("Yes"), _("No"));
+ if (dialog.runModal())
+ origFiles.push_back(temp);
+ }
+ }
+ }
+
+ int numFilesFound = origFiles.size();
+ if (!numFilesFound)
+ return false;
+
+ _gui->updateSaveSlotsList(_targetName, true);
+
+ // Find free save slots for the original save files
+ if (destSlot == -1) {
+ int assignedSlots = 0;
+ for (int testSlot = 0; testSlot < 990 && assignedSlots < numFilesFound; testSlot++) {
+ if (Common::find(_gui->_saveSlots.begin(), _gui->_saveSlots.end(), testSlot) == _gui->_saveSlots.end()) {
+ newSlots.push_back(testSlot);
+ assignedSlots++;
+ }
+ }
+
+ // This will probably never happen, since we do have 990 save slots
+ if (assignedSlots != numFilesFound)
+ warning("%d original save files could not be converted due to missing save game slots", numFilesFound - assignedSlots);
+
+ } else {
+ newSlots.push_back(destSlot);
+ }
+
+ if (destSlot != -1) {
+ if (Common::find(_gui->_saveSlots.begin(), _gui->_saveSlots.end(), destSlot) != _gui->_saveSlots.end()) {
+ ::GUI::MessageDialog dialog(Common::String::format(_("A save game file was found in the specified slot %d. Overwrite?\n\n"), destSlot), _("Yes"), _("No"));
+ if (!dialog.runModal())
+ return false;
+ }
+ }
+
+ int importedCount = 0;
+ for (int i = 0; i < numFilesFound; i++) {
+ Common::String desc = readOriginalSaveFile(origFiles[i]);
+ if (desc.empty()) {
+ warning("Unable to import original save file '%s'", origFiles[i].c_str());
+ } else {
+ // We can't make thumbnails here, since we do not want to load all the level data, monsters, etc. for each save we convert.
+ // Instead, we use an empty surface to avoid that createThumbnailFromScreen() makes a completely pointless thumbnail from
+ // whatever screen that is currently shown when this function is called.
+ Graphics::Surface dummy;
+ saveGameStateIntern(newSlots[i], desc.c_str(), &dummy);
+ warning("Imported original save file '%s' ('%s')", origFiles[i].c_str(), desc.c_str());
+ importedCount++;
+ }
+ }
+
+ _currentLevel = 0;
+ _currentSub = 0;
+ _currentBlock = 0;
+ _currentDirection = 0;
+ _itemInHand = 0;
+ _hasTempDataFlags = 0;
+ _partyEffectFlags = 0;
+ memset(_characters, 0, sizeof(EoBCharacter) * 6);
+ _inf->reset();
+
+ if (destSlot == -1 && importedCount) {
+ ::GUI::MessageDialog dialog(Common::String::format(_("%d original save game files have been successfully imported into\nScummVM. If you want to manually import original save game files later you will\nneed to open the ScummVM debug console and use the command 'import_savefile'.\n\n"), importedCount));
+ dialog.runModal();
+ }
+
+ return true;
+}
+
+Common::String EoBCoreEngine::readOriginalSaveFile(Common::String &file) {
+ Common::String desc;
+
+ Common::SeekableReadStream *fs = _res->createReadStream(file);
+ if (!fs)
+ return desc;
+
+ Common::SeekableSubReadStreamEndian in(fs, 0, fs->size(), _flags.platform == Common::kPlatformAmiga, DisposeAfterUse::YES);
+
+ if (_flags.gameID == GI_EOB1) {
+ // Nothing to read here for EOB 1. Original EOB 1 has
+ // only one save slot without save file description.
+ desc = "<IMPORTED GAME>";
+ } else {
+ char tempStr[20];
+ in.read(tempStr, 20);
+ desc = tempStr;
+ }
+
+ 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 = (_flags.gameID == GI_EOB1) ? in.readSByte() : in.readSint16();
+ c->hitPointsMax = (_flags.gameID == GI_EOB1) ? in.readSByte() : in.readSint16();
+ 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.readUint32();
+ in.skip(4);
+ delete[] c->faceShape;
+ c->faceShape = 0;
+ in.read(c->mageSpells, (_flags.gameID == GI_EOB1) ? 30 :80);
+ in.read(c->clericSpells, (_flags.gameID == GI_EOB1) ? 30 : 80);
+ c->mageSpellsAvailableFlags = in.readUint32();
+ for (int ii = 0; ii < 27; ii++)
+ c->inventory[ii] = in.readSint16();
+ uint32 ct = _system->getMillis();
+ for (int ii = 0; ii < 10; ii++) {
+ c->timers[ii] = in.readUint32() * _tickLength;
+ if (c->timers[ii])
+ c->timers[ii] += ct;
+ }
+ in.read(c->events, 10);
+ in.read(c->effectsRemainder, 4);
+ c->effectFlags = in.readUint32();
+ if (c->effectFlags && _flags.gameID == GI_EOB1) {
+ warning("EoBCoreEngine::readOriginalSaveFile(): Unhandled character effect flags encountered in original EOB1 save file '%s' ('%s')", file.c_str(), desc.c_str());
+ c->effectFlags = 0;
+ }
+ c->damageTaken = in.readByte();
+ in.read(c->slotStatus, 5);
+ in.skip(6);
+ }
+
+ setupCharacterTimers();
+
+ _currentLevel = in.readUint16();
+ _currentSub = (_flags.gameID == GI_EOB1) ? 0 : in.readSint16();
+ _currentBlock = in.readUint16();
+ _currentDirection = in.readUint16();
+ _itemInHand = in.readSint16();
+ _hasTempDataFlags = (_flags.gameID == GI_EOB1) ? in.readUint16() : in.readUint32();
+ _partyEffectFlags = (_flags.gameID == GI_EOB1) ? in.readUint16() : in.readUint32();
+ if (_partyEffectFlags && _flags.gameID == GI_EOB1) {
+ warning("EoBCoreEngine::readOriginalSaveFile(): Unhandled party effect flags encountered in original EOB1 save file '%s' ('%s')", file.c_str(), desc.c_str());
+ _partyEffectFlags = 0;
+ }
+ if (_flags.gameID == GI_EOB2)
+ in.skip(1);
+
+ _inf->loadState(in, true);
+
+ int numItems = (_flags.gameID == GI_EOB1) ? 500 : 600;
+ for (int i = 0; i < numItems; 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.readSint16();
+ t->next = in.readSint16();
+ t->prev = in.readSint16();
+ t->level = in.readByte();
+ t->value = in.readSByte();
+ }
+
+ int numParts = (_flags.gameID == GI_EOB1) ? 13 : 18;
+ int partSize = (_flags.gameID == GI_EOB1) ? 2040 : 2130;
+ uint32 nextPart = in.pos();
+ uint8 *cmpData = new uint8[1200];
+
+ for (int i = 0; i < numParts; i++) {
+ in.seek(nextPart);
+ nextPart += partSize;
+
+ if (!(_hasTempDataFlags & (1 << i)))
+ continue;
+
+ if (_lvlTempData[i]) {
+ delete[] _lvlTempData[i]->wallsXorData;
+ delete[] _lvlTempData[i]->flags;
+ releaseMonsterTempData(_lvlTempData[i]);
+ releaseFlyingObjectTempData(_lvlTempData[i]);
+ releaseWallOfForceTempData(_lvlTempData[i]);
+ delete _lvlTempData[i];
+ }
+
+ _lvlTempData[i] = new LevelTempData;
+ LevelTempData *l = _lvlTempData[i];
+ l->wallsXorData = new uint8[4096];
+ l->flags = new uint16[1024];
+ memset(l->flags, 0, 1024 * sizeof(uint16));
+ EoBMonsterInPlay *lm = new EoBMonsterInPlay[30];
+ l->monsters = lm;
+ EoBFlyingObject *lf = new EoBFlyingObject[_numFlyingObjects];
+ memset(lf, 0, _numFlyingObjects * sizeof(EoBFlyingObject));
+ l->flyingObjects = lf;
+ WallOfForce *lw = new WallOfForce[5];
+ memset(lw, 0, 5 * sizeof(WallOfForce));
+ l->wallsOfForce = lw;
+
+ in.read(cmpData, 1200);
+ _screen->decodeFrame4(cmpData, l->wallsXorData, 4096);
+ _curBlockFile = getBlockFileName(i + 1, 0);
+ const uint8 *p = getBlockFileData();
+ uint16 len = READ_LE_UINT16(p + 4);
+ p += 6;
+
+ uint8 *d = l->wallsXorData;
+ for (int ii = 0; ii < 1024; ii++) {
+ for (int iii = 0; iii < 4; iii++)
+ *d++ ^= p[ii * len + iii];
+ }
+
+ for (int ii = 0; ii < 30; ii++) {
+ EoBMonsterInPlay *m = &lm[ii];
+ m->type = in.readByte();
+ m->unit = in.readByte();
+ m->block = in.readUint16();
+ 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->spellStatusLeft = in.readSByte();
+ m->hitPointsMax = in.readSint16();
+ m->hitPointsCur = in.readSint16();
+ m->dest = in.readUint16();
+ m->randItem = in.readUint16();
+ m->fixedItem = in.readUint16();
+ m->flags = in.readByte();
+ m->idleAnimState = in.readByte();
+
+ if (_flags.gameID == GI_EOB1)
+ m->stepsTillRemoteAttack = in.readByte();
+ else
+ m->curRemoteWeapon = in.readByte();
+
+ m->numRemoteAttacks = in.readByte();
+ m->palette = in.readSByte();
+
+ if (_flags.gameID == GI_EOB1) {
+ in.skip(1);
+ } else {
+ m->directionChanged = in.readByte();
+ m->stepsTillRemoteAttack = in.readByte();
+ m->sub = in.readByte();
+ }
+
+ _levelBlockProperties[m->block].flags++;
+ }
+
+ if (_flags.gameID == GI_EOB1)
+ continue;
+
+ for (int ii = 0; ii < 5; ii++) {
+ WallOfForce *w = &lw[ii];
+ w->block = in.readUint16();
+ w->duration = in.readUint32();
+ }
+ }
+
+ delete[] cmpData;
+
+ restoreBlockTempData(_currentLevel);
+
+ in.skip(3);
+
+ delete[] _itemTypes;
+ _itemTypes = new EoBItemType[65];
+ memset(_itemTypes, 0, sizeof(EoBItemType) * 65);
+
+ if (_flags.gameID == GI_EOB1)
+ return desc;
+
+ for (int i = 51; i < 65; i++) {
+ EoBItemType *t = &_itemTypes[i];
+ t->invFlags = in.readUint16();
+ t->handFlags = in.readUint16();
+ 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.readUint16();
+ }
+
+ return in.err() ? Common::String() : desc;
+}
+
+void *EoBCoreEngine::generateMonsterTempData(LevelTempData *tmp) {
+ EoBMonsterInPlay *m = new EoBMonsterInPlay[30];
+ memcpy(m, _monsters, sizeof(EoBMonsterInPlay) * 30);
+ return m;
+}
+
+void EoBCoreEngine::restoreMonsterTempData(LevelTempData *tmp) {
+ memcpy(_monsters, tmp->monsters, sizeof(EoBMonsterInPlay) * 30);
+}
+
+void EoBCoreEngine::releaseMonsterTempData(LevelTempData *tmp) {
+ EoBMonsterInPlay *p = (EoBMonsterInPlay *)tmp->monsters;
+ delete[] p;
+}
+
+void *EoBCoreEngine::generateWallOfForceTempData(LevelTempData *tmp) {
+ WallOfForce *w = new WallOfForce[5];
+ memcpy(w, _wallsOfForce, sizeof(WallOfForce) * 5);
+ uint32 ct = _system->getMillis();
+ for (int i = 0; i < 5; i++)
+ w[i].duration = (w[i].duration > ct) ? w[i].duration - ct : _tickLength;
+ return w;
+}
+
+void EoBCoreEngine::restoreWallOfForceTempData(LevelTempData *tmp) {
+ memcpy(_wallsOfForce, tmp->wallsOfForce, sizeof(WallOfForce) * 5);
+ uint32 ct = _system->getMillis();
+ for (int i = 0; i < 5; i++)
+ _wallsOfForce[i].duration += ct;
+}
+
+void EoBCoreEngine::releaseWallOfForceTempData(LevelTempData *tmp) {
+ WallOfForce *p = (WallOfForce *)tmp->wallsOfForce;
+ delete[] p;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/saveload_lok.cpp b/engines/kyra/saveload_lok.cpp
index 22d412e7f6..b76d1da52a 100644
--- a/engines/kyra/saveload_lok.cpp
+++ b/engines/kyra/saveload_lok.cpp
@@ -163,7 +163,7 @@ Common::Error KyraEngine_LoK::loadGameState(int slot) {
if (!queryGameFlag(0xF1)) {
for (int i = 0x55; i <= 0x5A; ++i) {
if (queryGameFlag(i))
- seq_createAmuletJewel(i-0x55, 10, 1, 1);
+ seq_createAmuletJewel(i - 0x55, 10, 1, 1);
}
}
diff --git a/engines/kyra/saveload_lol.cpp b/engines/kyra/saveload_lol.cpp
index 1bf26477e6..b6840663e9 100644
--- a/engines/kyra/saveload_lol.cpp
+++ b/engines/kyra/saveload_lol.cpp
@@ -27,6 +27,7 @@
#include "common/savefile.h"
#include "common/substream.h"
+#include "common/memstream.h"
#include "graphics/scaler.h"
@@ -44,6 +45,9 @@ Common::Error LoLEngine::loadGameState(int slot) {
return Common::kNoError;
}
+ if (header.originalSave)
+ warning("Trying to load savegame from original interpreter, while this is possible, it is not officially supported");
+
_screen->fadeClearSceneWindow(10);
completeDoorOperations();
_screen->fillRect(112, 0, 287, 119, 0, 0);
@@ -53,38 +57,40 @@ Common::Error LoLEngine::loadGameState(int slot) {
for (int i = 0; i < 4; i++) {
LoLCharacter *c = &_characters[i];
- c->flags = in.readUint16BE();
+ c->flags = in.readUint16();
in.read(c->name, 11);
c->raceClassSex = in.readByte();
- c->id = in.readSint16BE();
+ c->id = in.readSint16();
c->curFaceFrame = in.readByte();
c->tempFaceFrame = in.readByte();
c->screamSfx = in.readByte();
+ if (header.originalSave)
+ in.skip(4);
for (int ii = 0; ii < 8; ii++)
- c->itemsMight[ii] = in.readUint16BE();
+ c->itemsMight[ii] = in.readUint16();
for (int ii = 0; ii < 8; ii++)
- c->protectionAgainstItems[ii] = in.readUint16BE();
- c->itemProtection = in.readUint16BE();
- c->hitPointsCur = in.readSint16BE();
- c->hitPointsMax = in.readUint16BE();
- c->magicPointsCur = in.readSint16BE();
- c->magicPointsMax = in.readUint16BE();
+ c->protectionAgainstItems[ii] = in.readUint16();
+ c->itemProtection = in.readUint16();
+ c->hitPointsCur = in.readSint16();
+ c->hitPointsMax = in.readUint16();
+ c->magicPointsCur = in.readSint16();
+ c->magicPointsMax = in.readUint16();
c->field_41 = in.readByte();
- c->damageSuffered = in.readUint16BE();
- c->weaponHit = in.readUint16BE();
- c->totalMightModifier = in.readUint16BE();
- c->totalProtectionModifier = in.readUint16BE();
- c->might = in.readUint16BE();
- c->protection = in.readUint16BE();
- c->nextAnimUpdateCountdown = in.readSint16BE();
+ c->damageSuffered = in.readUint16();
+ c->weaponHit = in.readUint16();
+ c->totalMightModifier = in.readUint16();
+ c->totalProtectionModifier = in.readUint16();
+ c->might = in.readUint16();
+ c->protection = in.readUint16();
+ c->nextAnimUpdateCountdown = in.readSint16();
for (int ii = 0; ii < 11; ii++)
- c->items[ii] = in.readUint16BE();
+ c->items[ii] = in.readUint16();
for (int ii = 0; ii < 3; ii++)
c->skillLevels[ii] = in.readByte();
for (int ii = 0; ii < 3; ii++)
c->skillModifiers[ii] = in.readSByte();
for (int ii = 0; ii < 3; ii++)
- c->experiencePts[ii] = in.readUint32BE();
+ c->experiencePts[ii] = in.readUint32();
for (int ii = 0; ii < 5; ii++)
c->characterUpdateEvents[ii] = in.readByte();
for (int ii = 0; ii < 5; ii++)
@@ -96,39 +102,48 @@ Common::Error LoLEngine::loadGameState(int slot) {
}
}
- in.read(_wllBuffer4, 80);
+ if (header.version < 17)
+ in.skip(80);
- _currentBlock = in.readUint16BE();
- _partyPosX = in.readUint16BE();
- _partyPosY = in.readUint16BE();
- _updateFlags = in.readUint16BE();
+ _currentBlock = in.readUint16();
+ _partyPosX = in.readUint16();
+ _partyPosY = in.readUint16();
+ _updateFlags = in.readUint16();
_scriptDirection = in.readByte();
_selectedSpell = in.readByte();
+
+ if (header.originalSave)
+ in.skip(2);
+
_sceneDefaultUpdate = in.readByte();
_compassBroken = in.readByte();
_drainMagic = in.readByte();
- _currentDirection = in.readUint16BE();
- _compassDirection = in.readUint16BE();
+ _currentDirection = in.readUint16();
+ _compassDirection = in.readUint16();
_selectedCharacter = in.readSByte();
+
+ if (header.originalSave)
+ in.skip(1);
+
_currentLevel = in.readByte();
for (int i = 0; i < 48; i++)
- _inventory[i] = in.readSint16BE();
- _inventoryCurItem = in.readSint16BE();
- _itemInHand = in.readSint16BE();
- _lastMouseRegion = in.readSint16BE();
+ _inventory[i] = in.readSint16();
+ _inventoryCurItem = in.readSint16();
+ _itemInHand = in.readSint16();
+ _lastMouseRegion = in.readSint16();
- if (header.version <= 15) {
+ if (header.originalSave || header.version <= 15) {
uint16 flags[40];
memset(flags, 0, sizeof(flags));
if (header.version == 14) {
for (int i = 0; i < 16; i++)
- flags[i] = in.readUint16BE();
- flags[26] = in.readUint16BE();
- flags[36] = in.readUint16BE();
- } else if (header.version == 15) {
+ flags[i] = in.readUint16();
+ flags[26] = in.readUint16();
+ flags[36] = in.readUint16();
+ } else if (header.originalSave || header.version == 15) {
for (int i = 0; i < 40; i++)
- flags[i] = in.readUint16BE();
+ flags[i] = in.readUint16();
}
memset(_flagsTable, 0, sizeof(_flagsTable));
@@ -139,37 +154,52 @@ Common::Error LoLEngine::loadGameState(int slot) {
}
}
} else {
- uint32 flagsSize = in.readUint32BE();
+ uint32 flagsSize = in.readUint32();
assert(flagsSize <= sizeof(_flagsTable));
in.read(_flagsTable, flagsSize);
}
+ if (header.originalSave)
+ in.skip(120);
+
for (int i = 0; i < 24; i++)
- _globalScriptVars[i] = in.readUint16BE();
+ _globalScriptVars[i] = in.readUint16();
+
+ if (header.originalSave)
+ in.skip(152);
+
_brightness = in.readByte();
_lampOilStatus = in.readByte();
_lampEffect = in.readSByte();
- _credits = in.readUint16BE();
+
+ if (header.originalSave)
+ in.skip(1);
+
+ _credits = in.readUint16();
for (int i = 0; i < 8; i++)
- _globalScriptVars2[i] = in.readUint16BE();
+ _globalScriptVars2[i] = in.readUint16();
in.read(_availableSpells, 7);
- _hasTempDataFlags = in.readUint32BE();
+ _hasTempDataFlags = in.readUint32();
+
+ uint8 *origCmp = 0;
+ if (header.originalSave) {
+ in.skip(6);
+ origCmp = new uint8[2496];
+ }
for (int i = 0; i < 400; i++) {
- ItemInPlay *t = &_itemsInPlay[i];
- t->nextAssignedObject = in.readUint16BE();
- t->nextDrawObject = in.readUint16BE();
+ LoLItem *t = &_itemsInPlay[i];
+ t->nextAssignedObject = in.readUint16();
+ t->nextDrawObject = in.readUint16();
t->flyingHeight = in.readByte();
- t->block = in.readUint16BE();
- t->x = in.readUint16BE();
- t->y = in.readUint16BE();
+ t->block = in.readUint16();
+ t->x = in.readUint16();
+ t->y = in.readUint16();
t->level = in.readSByte();
- t->itemPropertyIndex = in.readUint16BE();
- t->shpCurFrame_flg = in.readUint16BE();
- t->destDirection = in.readByte();
- t->hitOffsX = in.readSByte();
- t->hitOffsY = in.readSByte();
- t->currentSubFrame = in.readByte();
+ t->itemPropertyIndex = in.readUint16();
+ t->shpCurFrame_flg = in.readUint16();
+ if (header.version < 17)
+ in.skip(4);
}
for (int i = 0; i < 1024; i++) {
@@ -179,38 +209,61 @@ Common::Error LoLEngine::loadGameState(int slot) {
}
for (int i = 0; i < 29; i++) {
- if (!(_hasTempDataFlags & (1 << i)))
+ if (!(_hasTempDataFlags & (1 << i))) {
+ if (header.originalSave) {
+ if (in.size() - in.pos() >= 2500)
+ in.skip(2500);
+ }
continue;
+ }
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]);
+ releaseWallOfForceTempData(_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];
+ LoLMonster *lm = new LoLMonster[30];
+ _lvlTempData[i]->monsters = lm;
+ FlyingObject *lf = new FlyingObject[_numFlyingObjects];
+ _lvlTempData[i]->flyingObjects = lf;
LevelTempData *l = _lvlTempData[i];
- in.read(l->wallsXorData, 4096);
- in.read(l->flags, 1024);
+ uint32 next = in.pos() + 2500;
+
+ if (header.originalSave) {
+ in.skip(4);
+ in.read(origCmp, in.readUint16());
+ _screen->decodeFrame4(origCmp, _tempBuffer5120, 5120);
+ memcpy(l->wallsXorData, _tempBuffer5120, 4096);
+ for (int ii = 0; ii < 1024; ii++)
+ l->flags[ii] = _tempBuffer5120[4096 + ii];
+ } else {
+ in.read(l->wallsXorData, 4096);
+ for (int ii = 0; ii < 1024; ii++)
+ l->flags[ii] = in.readByte();
+ }
+
+ if (header.originalSave)
+ l->monsterDifficulty = in.readUint16();
for (int ii = 0; ii < 30; ii++) {
- MonsterInPlay *m = &l->monsters[ii];
- m->nextAssignedObject = in.readUint16BE();
- m->nextDrawObject = in.readUint16BE();
+ LoLMonster *m = &lm[ii];
+ m->nextAssignedObject = in.readUint16();
+ m->nextDrawObject = in.readUint16();
m->flyingHeight = in.readByte();
- m->block = in.readUint16BE();
- m->x = in.readUint16BE();
- m->y = in.readUint16BE();
+ m->block = in.readUint16();
+ m->x = in.readUint16();
+ m->y = in.readUint16();
m->shiftStep = in.readSByte();
- m->destX = in.readUint16BE();
- m->destY = in.readUint16BE();
+ m->destX = in.readUint16();
+ m->destY = in.readUint16();
m->destDirection = in.readByte();
m->hitOffsX = in.readSByte();
m->hitOffsY = in.readSByte();
@@ -220,27 +273,31 @@ Common::Error LoLEngine::loadGameState(int slot) {
m->id = in.readByte();
m->direction = in.readByte();
m->facing = in.readByte();
- m->flags = in.readUint16BE();
- m->damageReceived = in.readUint16BE();
- m->hitPoints = in.readSint16BE();
+ m->flags = in.readUint16();
+ m->damageReceived = in.readUint16();
+ m->hitPoints = in.readSint16();
m->speedTick = in.readByte();
m->type = in.readByte();
+
+ if (header.originalSave)
+ in.skip(4);
+
m->numDistAttacks = in.readByte();
m->curDistWeapon = in.readByte();
m->distAttackTick = in.readSByte();
- m->assignedItems = in.readUint16BE();
+ m->assignedItems = in.readUint16();
m->properties = &_monsterProperties[m->type];
in.read(m->equipmentShapes, 4);
}
- for (int ii = 0; ii < 8; ii++) {
- FlyingObject *m = &l->flyingObjects[ii];
+ for (int ii = 0; ii < _numFlyingObjects; ii++) {
+ FlyingObject *m = &lf[ii];
m->enable = in.readByte();
m->objectType = in.readByte();
- m->attackerId = in.readUint16BE();
- m->item = in.readSint16BE();
- m->x = in.readUint16BE();
- m->y = in.readUint16BE();
+ m->attackerId = in.readUint16();
+ m->item = in.readSint16();
+ m->x = in.readUint16();
+ m->y = in.readUint16();
m->flyingHeight = in.readByte();
m->direction = in.readByte();
m->distance = in.readByte();
@@ -249,9 +306,15 @@ Common::Error LoLEngine::loadGameState(int slot) {
m->flags = in.readByte();
m->wallFlags = in.readByte();
}
- l->monsterDifficulty = in.readByte();
+
+ if (header.originalSave)
+ in.seek(next, SEEK_SET);
+ else
+ l->monsterDifficulty = in.readByte();
}
+ delete[] origCmp;
+
calcCharPortraitXpos();
memset(_moneyColumnHeight, 0, sizeof(_moneyColumnHeight));
int t = _credits;
@@ -319,8 +382,6 @@ Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, con
out->writeByte(c->characterUpdateDelay[ii]);
}
- out->write(_wllBuffer4, 80);
-
out->writeUint16BE(_currentBlock);
out->writeUint16BE(_partyPosX);
out->writeUint16BE(_partyPosY);
@@ -355,7 +416,7 @@ Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, con
resetItems(0);
for (int i = 0; i < 400; i++) {
- ItemInPlay *t = &_itemsInPlay[i];
+ LoLItem *t = &_itemsInPlay[i];
out->writeUint16BE(t->nextAssignedObject);
out->writeUint16BE(t->nextDrawObject);
out->writeByte(t->flyingHeight);
@@ -365,10 +426,6 @@ Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, con
out->writeSByte(t->level);
out->writeUint16BE(t->itemPropertyIndex);
out->writeUint16BE(t->shpCurFrame_flg);
- out->writeByte(t->destDirection);
- out->writeSByte(t->hitOffsX);
- out->writeSByte(t->hitOffsY);
- out->writeByte(t->currentSubFrame);
}
addLevelItems();
@@ -379,10 +436,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);
+
+ LoLMonster *lm = (LoLMonster *)_lvlTempData[i]->monsters;
+ FlyingObject *lf = (FlyingObject *)_lvlTempData[i]->flyingObjects;
for (int ii = 0; ii < 30; ii++) {
- MonsterInPlay *m = &l->monsters[ii];
+ LoLMonster *m = &lm[ii];
out->writeUint16BE(m->nextAssignedObject);
out->writeUint16BE(m->nextDrawObject);
out->writeByte(m->flyingHeight);
@@ -413,8 +474,8 @@ Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, con
out->write(m->equipmentShapes, 4);
}
- for (int ii = 0; ii < 8; ii++) {
- FlyingObject *m = &l->flyingObjects[ii];
+ for (int ii = 0; ii < _numFlyingObjects; ii++) {
+ FlyingObject *m = &lf[ii];
out->writeByte(m->enable);
out->writeByte(m->objectType);
out->writeUint16BE(m->attackerId);
@@ -469,6 +530,54 @@ Graphics::Surface *LoLEngine::generateSaveThumbnail() const {
return dst;
}
+void LoLEngine::restoreBlockTempData(int levelIndex) {
+ memset(_tempBuffer5120, 0, 5120);
+ KyraRpgEngine::restoreBlockTempData(levelIndex);
+ restoreTempDataAdjustMonsterStrength(levelIndex - 1);
+}
+
+void *LoLEngine::generateMonsterTempData(LevelTempData *tmp) {
+ LoLMonster *m = new LoLMonster[30];
+ memcpy(m, _monsters, sizeof(LoLMonster) * 30);
+ tmp->monsterDifficulty = _monsterDifficulty;
+ return m;
+}
+
+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(LoLMonster) * 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::releaseMonsterTempData(LevelTempData *tmp) {
+ LoLMonster *p = (LoLMonster *)tmp->monsters;
+ delete[] p;
+}
+
} // End of namespace Kyra
#endif // ENABLE_LOL
diff --git a/engines/kyra/saveload_rpg.cpp b/engines/kyra/saveload_rpg.cpp
new file mode 100644
index 0000000000..d22c50dbeb
--- /dev/null
+++ b/engines/kyra/saveload_rpg.cpp
@@ -0,0 +1,127 @@
+/* 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/resource.h"
+#include "kyra/script_eob.h"
+
+#include "common/system.h"
+#include "common/savefile.h"
+#include "common/substream.h"
+
+namespace Kyra {
+
+void KyraRpgEngine::generateTempData() {
+ int l = _currentLevel - 1;
+ if (_lvlTempData[l]) {
+ delete[] _lvlTempData[l]->wallsXorData;
+ delete[] _lvlTempData[l]->flags;
+ releaseMonsterTempData(_lvlTempData[l]);
+ releaseFlyingObjectTempData(_lvlTempData[l]);
+ releaseWallOfForceTempData(_lvlTempData[l]);
+ delete _lvlTempData[l];
+ }
+
+ _lvlTempData[l] = new LevelTempData;
+
+ _lvlTempData[l]->wallsXorData = new uint8[4096];
+ _lvlTempData[l]->flags = new uint16[1024];
+
+ const uint8 *p = getBlockFileData(_currentLevel);
+ 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]);
+ _lvlTempData[l]->wallsOfForce = generateWallOfForceTempData(_lvlTempData[l]);
+
+ _hasTempDataFlags |= (1 << l);
+}
+
+void KyraRpgEngine::restoreBlockTempData(int levelIndex) {
+ int l = levelIndex - 1;
+ const uint8 *p = getBlockFileData(levelIndex);
+ 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]);
+ restoreWallOfForceTempData(_lvlTempData[l]);
+}
+
+void KyraRpgEngine::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]);
+ releaseWallOfForceTempData(_lvlTempData[i]);
+ delete _lvlTempData[i];
+ _lvlTempData[i] = 0;
+ }
+ }
+}
+
+void *KyraRpgEngine::generateFlyingObjectTempData(LevelTempData *tmp) {
+ assert(_flyingObjectStructSize == sizeof(EoBFlyingObject));
+ EoBFlyingObject *f = new EoBFlyingObject[_numFlyingObjects];
+ memcpy(f, _flyingObjectsPtr, sizeof(EoBFlyingObject) * _numFlyingObjects);
+ return f;
+}
+
+void KyraRpgEngine::restoreFlyingObjectTempData(LevelTempData *tmp) {
+ assert(_flyingObjectStructSize == sizeof(EoBFlyingObject));
+ memcpy(_flyingObjectsPtr, tmp->flyingObjects, sizeof(EoBFlyingObject) * _numFlyingObjects);
+}
+
+void KyraRpgEngine::releaseFlyingObjectTempData(LevelTempData *tmp) {
+ EoBFlyingObject *p = (EoBFlyingObject *)tmp->flyingObjects;
+ delete[] p;
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB || ENABLE_LOL
diff --git a/engines/kyra/scene_eob.cpp b/engines/kyra/scene_eob.cpp
new file mode 100644
index 0000000000..3db055db90
--- /dev/null
+++ b/engines/kyra/scene_eob.cpp
@@ -0,0 +1,890 @@
+/* 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/script_eob.h"
+#include "kyra/timer.h"
+#include "kyra/sound.h"
+
+#include "common/system.h"
+
+
+namespace Kyra {
+
+void EoBCoreEngine::loadLevel(int level, int sub) {
+ _currentLevel = level;
+ _currentSub = sub;
+ uint32 end = _system->getMillis() + 500;
+
+ readLevelFileData(level);
+
+ Common::String gfxFile;
+ // Work around for issue with corrupt (incomplete) monster property data
+ // when loading a savegame saved in a sub level
+ for (int i = 0; i <= sub; i++)
+ gfxFile = initLevelData(i);
+
+ 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.c_str(), (_flags.gameID == GI_EOB1) ? _cgaMappingLevel[_cgaLevelMappingIndex[level - 1]] : 0);
+ _screen->loadEoBBitmap("INVENT", _cgaMappingInv, 5, 3, 2);
+ delayUntil(end);
+ snd_stopSound();
+
+ enableSysTimer(2);
+ _sceneDrawPage1 = 2;
+ _sceneDrawPage2 = 1;
+ _screen->setCurPage(0);
+}
+
+void EoBCoreEngine::readLevelFileData(int level) {
+ Common::String file;
+ Common::SeekableReadStream *s = 0;
+ static const char *suffix[] = { "INF", "DRO", "ELO", 0 };
+
+ for (const char *const *sf = suffix; *sf && !s; sf++) {
+ file = Common::String::format("LEVEL%d.%s", level, *sf);
+ s = _res->createReadStream(file);
+ }
+
+ if (!s)
+ error("Failed to load 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.c_str(), 5, 5, 0);
+ }
+ }
+
+ if (s) {
+ s->seek(0);
+ _screen->loadFileDataToPage(s, 5, 15000);
+ delete s;
+ }
+}
+
+Common::String EoBCoreEngine::initLevelData(int sub) {
+ const uint8 *data = _screen->getCPagePtr(5) + 2;
+ const uint8 *pos = data;
+
+ int slen = (_flags.gameID == GI_EOB1) ? 12 : 13;
+
+ 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;
+
+ const char *vmpPattern = (_flags.gameID == GI_EOB1 && (_configRenderMode == Common::kRenderEGA || _configRenderMode == Common::kRenderCGA)) ? "%s.EMP" : "%s.VMP";
+ Common::SeekableReadStream *s = _res->createReadStream(Common::String::format(vmpPattern, (const char *)pos));
+ _vmpSize = s->readUint16LE();
+ delete[] _vmpPtr;
+ _vmpPtr = new uint16[_vmpSize];
+ for (int i = 0; i < _vmpSize; i++)
+ _vmpPtr[i] = s->readUint16LE();
+ delete s;
+
+ const char *paletteFilePattern = (_flags.gameID == GI_EOB2 && _configRenderMode == Common::kRenderEGA) ? "%s.EGA" : "%s.PAL";
+
+ Common::String tmpStr = Common::String::format(paletteFilePattern, (const char *)pos);
+ _curGfxFile = (const char *)pos;
+ pos += slen;
+
+ if (*pos++ != 0xff && _flags.gameID == GI_EOB2) {
+ tmpStr = Common::String::format(paletteFilePattern, (const char *)pos);
+ pos += 13;
+ }
+
+ if (_flags.gameID == GI_EOB1) {
+ pos += 11;
+ _screen->setShapeFadeMode(0, false);
+ _screen->setShapeFadeMode(1, false);
+ }
+
+ if (_flags.gameID == GI_EOB2 || _configRenderMode != Common::kRenderEGA)
+ _screen->loadPalette(tmpStr.c_str(), _screen->getPalette(0));
+
+ if (_configRenderMode != Common::kRenderCGA) {
+ 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 && _configRenderMode == Common::kRenderEGA)
+ _screen->setScreenPalette(_screen->getPalette(0));
+ }
+ }
+
+ if (_flags.gameID == GI_EOB2) {
+ delay(3 * _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)
+ 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 uint8 *cgaMapping) {
+ if (file)
+ strcpy(_lastBlockDataFile, file);
+
+ const char *filePattern = (_flags.gameID == GI_EOB1 && (_configRenderMode == Common::kRenderEGA || _configRenderMode == Common::kRenderCGA)) ? "%s.ECN" : "%s.VCN";
+ _screen->loadBitmap(Common::String::format(filePattern, _lastBlockDataFile).c_str(), 3, 3, 0);
+ const uint8 *pos = _screen->getCPagePtr(3);
+
+ uint32 vcnSize = READ_LE_UINT16(pos) * _vcnBlockWidth * _vcnBlockHeight;
+ pos += 2;
+
+ const uint8 *colMap = pos;
+ pos += 32;
+
+ delete[] _vcnBlocks;
+ _vcnBlocks = new uint8[vcnSize];
+
+ if (_flags.gameID == GI_EOB2 && _configRenderMode == Common::kRenderEGA) {
+ const uint8 *egaTable = _screen->getEGADitheringTable();
+ assert(_vmpPtr);
+ assert(egaTable);
+
+ delete[] _vcnTransitionMask;
+ _vcnTransitionMask = new uint8[vcnSize];
+
+ for (int i = 0; i < _vmpSize; i++) {
+ uint16 vcnOffs = _vmpPtr[i] & 0x3FFF;
+ const uint8 *src = &pos[vcnOffs << 5];
+ uint8 *dst1 = &_vcnBlocks[vcnOffs << 7];
+ uint8 *dst3 = &_vcnTransitionMask[vcnOffs << 7];
+ int palOffset = (i < 330) ? 0 : _wllVcnOffset;
+
+ for (int y = 0; y < 8; y++) {
+ uint8 *dst2 = dst1 + 8;
+ uint8 *dst4 = dst3 + 8;
+
+ for (int x = 0; x < 4; x++) {
+ uint8 in = *src++;
+
+ dst1[0] = dst2[0] = egaTable[colMap[(in >> 4) + palOffset]];
+ dst1[1] = dst2[1] = egaTable[colMap[(in & 0x0f) + palOffset]];
+ dst3[0] = dst4[0] = (in & 0xf0) ? 0 : 0xff;
+ dst3[1] = dst4[1] = (in & 0x0f) ? 0 : 0xff;
+
+ dst1 += 2;
+ dst2 += 2;
+ dst3 += 2;
+ dst4 += 2;
+ }
+
+ dst1 += 8;
+ dst3 += 8;
+ }
+ }
+ } else if (_configRenderMode == Common::kRenderCGA) {
+ uint8 *tmp = _screen->encodeShape(0, 0, 1, 8, false, cgaMapping);
+ delete[] tmp;
+
+ delete[] _vcnTransitionMask;
+ _vcnTransitionMask = new uint8[vcnSize];
+ uint8 tblSwitch = 0;
+ uint8 *dst = _vcnBlocks;
+ uint8 *dst2 = _vcnTransitionMask;
+
+ while (dst < _vcnBlocks + vcnSize) {
+ const uint16 *table = _screen->getCGADitheringTable((tblSwitch++) & 1);
+ for (int ii = 0; ii < 2; ii++) {
+ *dst++ = ((table[pos[0]] & 0x000f) << 4) | ((table[pos[0]] & 0x0f00) >> 8);
+ *dst++= ((table[pos[1]] & 0x000f) << 4) | ((table[pos[1]] & 0x0f00) >> 8);
+
+ uint8 msk = 0;
+ if (pos[0] & 0xf0)
+ msk |= 0x30;
+ if (pos[0] & 0x0f)
+ msk |= 0x03;
+ *dst2++ = msk ^ 0x33;
+
+ msk = 0;
+ if (pos[1] & 0xf0)
+ msk |= 0x30;
+ if (pos[1] & 0x0f)
+ msk |= 0x03;
+ *dst2++ = msk ^ 0x33;
+
+ pos += 2;
+ }
+ }
+ } else {
+ if (_configRenderMode != Common::kRenderEGA)
+ memcpy(_vcnColTable, colMap, 32);
+ memcpy(_vcnBlocks, pos, vcnSize);
+ }
+}
+
+void EoBCoreEngine::loadBlockProperties(const char *mazFile) {
+ memset(_levelBlockProperties, 0, 1024 * sizeof(LevelBlockProperty));
+ const uint8 *p = getBlockFileData(mazFile) + 6;
+
+ if (_hasTempDataFlags & (1 << (_currentLevel - 1))) {
+ restoreBlockTempData(_currentLevel);
+ return;
+ }
+
+ for (int i = 0; i < 1024; i++) {
+ for (int ii = 0; ii < 4; ii++)
+ _levelBlockProperties[i].walls[ii] = *p++;
+ }
+}
+
+const uint8 *EoBCoreEngine::getBlockFileData(int) {
+ Common::SeekableReadStream *s = _res->createReadStream(_curBlockFile);
+ _screen->loadFileDataToPage(s, 15, s->size());
+ delete s;
+ return _screen->getCPagePtr(15);
+}
+
+Common::String EoBCoreEngine::getBlockFileName(int levelIndex, int sub) {
+ readLevelFileData(levelIndex);
+ const uint8 *data = _screen->getCPagePtr(5) + 2;
+ const uint8 *pos = data;
+
+ 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;
+
+ return Common::String((const char *)pos);
+ }
+
+ return Common::String();
+}
+
+const uint8 *EoBCoreEngine::getBlockFileData(const char *mazFile) {
+ _curBlockFile = mazFile;
+ return getBlockFileData();
+}
+
+void EoBCoreEngine::loadDecorations(const char *cpsFile, const char *decFile) {
+ _screen->loadShapeSetBitmap(cpsFile, 5, 3);
+ Common::SeekableReadStream *s = _res->createReadStream(decFile);
+
+ _levelDecorationDataSize = s->readUint16LE();
+ delete[] _levelDecorationData;
+ _levelDecorationData = new LevelDecorationProperty[_levelDecorationDataSize];
+ memset(_levelDecorationData, 0, _levelDecorationDataSize * sizeof(LevelDecorationProperty));
+
+ 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;
+ for (int i = 0; i < 6; i++) {
+ for (int ii = 0; ii < 10; ii++) {
+ if (_characters[i].events[ii] == -57)
+ spellCallback_start_trueSeeing();
+ }
+ }
+ _wllShapeMap[wallIndex] = _mappedDecorationsCount + 1;
+ _specialWallTypes[wallIndex] = specialType;
+ _wllWallFlags[wallIndex] = flags ^ 4;
+
+ if (decIndex == -1) {
+ _wllShapeMap[wallIndex] = 0;
+ return;
+ }
+
+ do {
+ assert(decIndex < _levelDecorationDataSize);
+ 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, false, (_flags.gameID == GI_EOB1) ? _cgaMappingLevel[_cgaLevelMappingIndex[_currentLevel - 1]] : 0);
+ }
+
+ 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 refresh) {
+ generateBlockDrawingBuffer();
+ drawVcnBlocks();
+ drawSceneShapes();
+
+ if (_sceneDrawPage2) {
+ if (refresh)
+ _screen->fillRect(0, 0, 176, 120, 12);
+
+ if (!_loading)
+ _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)
+ delayUntil(_drawSceneTimer);
+
+ if (refresh && !_partyResting)
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 2, 0, Screen::CR_NO_P_CHECK);
+
+ updateEnvironmentalSfx(0);
+
+ if (!_dialogueField && refresh && !_updateFlags)
+ gui_drawCompass(false);
+
+ if (refresh && !_partyResting && !_loading)
+ _screen->updateScreen();
+
+ if (_sceneDefaultUpdate) {
+ _sceneDefaultUpdate = false;
+ _drawSceneTimer = _system->getMillis() + 4 * _tickLength;
+ }
+
+ _sceneUpdateRequired = false;
+}
+
+void EoBCoreEngine::drawSceneShapes(int start) {
+ for (int i = start; 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) {
+ for (int i = 1; i >= 0; i--) {
+ int s = index * 2 + i;
+ if (_dscWallMapping[s]) {
+ int16 d = *_dscWallMapping[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];
+
+ assert((_flags.gameID == GI_EOB1 && w < 70) || (_flags.gameID == GI_EOB2 && w < 80));
+
+ if (_flags.gameID == GI_EOB2 && w == 74 && _currentBlock == curBlock) {
+ for (int i = 0; i < 5; i++) {
+ if (_wallsOfForce[i].block == b) {
+ destroyWallOfForce(i);
+ f = _wllWallFlags[0];
+ }
+ }
+ }
+
+ 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) {
+ updateAllMonsterDests();
+ uint16 old = _currentBlock;
+ _currentBlock = block;
+
+ runLevelScript(old, 2);
+
+ if (++_moveCounter > 3) {
+ _txt->printMessage("\r");
+ _moveCounter = 0;
+ }
+
+ runLevelScript(block, 1);
+
+ if (_flags.gameID == GI_EOB2 && _levelBlockProperties[block].walls[0] == 26)
+ memset(_levelBlockProperties[block].walls, 0, 4);
+
+ updateAllMonsterDests();
+ _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 (_flags.gameID == GI_EOB1 && _currentLevel >= 4 && _currentLevel <= 6) {
+ if (v >= 30)
+ x1 += 4;
+ else
+ x1 += ((v - _dscDoorXE[v]) * 9);
+ }
+
+ 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_lok.cpp b/engines/kyra/scene_lok.cpp
index ab1670ea6e..ea09091af7 100644
--- a/engines/kyra/scene_lok.cpp
+++ b/engines/kyra/scene_lok.cpp
@@ -158,7 +158,7 @@ void KyraEngine_LoK::enterNewScene(int sceneId, int facing, int unk1, int unk2,
_walkBlockWest = currentRoom->westExit;
if (_walkBlockNorth == 0xFFFF)
- _screen->blockOutRegion(0, 0, 320, (_northExitHeight & 0xFF)+3);
+ _screen->blockOutRegion(0, 0, 320, (_northExitHeight & 0xFF) + 3);
if (_walkBlockEast == 0xFFFF)
_screen->blockOutRegion(312, 0, 8, 139);
if (_walkBlockSouth == 0xFFFF)
@@ -348,22 +348,22 @@ void KyraEngine_LoK::setCharacterPositionHelper(int character, int *facingTable)
};
if (facing == 0) {
- if (maxAnimationFrame[36+character] > ch->currentAnimFrame)
- ch->currentAnimFrame = maxAnimationFrame[36+character];
- if (maxAnimationFrame[30+character] < ch->currentAnimFrame)
- ch->currentAnimFrame = maxAnimationFrame[36+character];
+ if (maxAnimationFrame[36 + character] > ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[36 + character];
+ if (maxAnimationFrame[30 + character] < ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[36 + character];
} else if (facing == 4) {
- if (maxAnimationFrame[18+character] > ch->currentAnimFrame)
- ch->currentAnimFrame = maxAnimationFrame[18+character];
- if (maxAnimationFrame[12+character] < ch->currentAnimFrame)
- ch->currentAnimFrame = maxAnimationFrame[18+character];
+ if (maxAnimationFrame[18 + character] > ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[18 + character];
+ if (maxAnimationFrame[12 + character] < ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[18 + character];
} else {
- if (maxAnimationFrame[18+character] < ch->currentAnimFrame)
- ch->currentAnimFrame = maxAnimationFrame[30+character];
+ if (maxAnimationFrame[18 + character] < ch->currentAnimFrame)
+ ch->currentAnimFrame = maxAnimationFrame[30 + character];
if (maxAnimationFrame[character] == ch->currentAnimFrame)
- ch->currentAnimFrame = maxAnimationFrame[6+character];
+ ch->currentAnimFrame = maxAnimationFrame[6 + character];
if (maxAnimationFrame[character] < ch->currentAnimFrame)
- ch->currentAnimFrame = maxAnimationFrame[6+character]+2;
+ ch->currentAnimFrame = maxAnimationFrame[6 + character] + 2;
}
if (character == 0 && (_brandonStatusBit & 0x10))
@@ -596,7 +596,7 @@ void KyraEngine_LoK::initSceneObjectList(int brandonAlive) {
curAnimState->drawY = _currentCharacter->y1;
curAnimState->sceneAnimPtr = _shapes[_currentCharacter->currentAnimFrame];
curAnimState->animFrameNumber = _currentCharacter->currentAnimFrame;
- startAnimFrame = _currentCharacter->currentAnimFrame-7;
+ startAnimFrame = _currentCharacter->currentAnimFrame - 7;
int xOffset = _defaultShapeTable[startAnimFrame].xOffset;
int yOffset = _defaultShapeTable[startAnimFrame].yOffset;
@@ -638,7 +638,7 @@ void KyraEngine_LoK::initSceneObjectList(int brandonAlive) {
curAnimState->drawY = ch->y1;
curAnimState->sceneAnimPtr = _shapes[ch->currentAnimFrame];
curAnimState->animFrameNumber = ch->currentAnimFrame;
- startAnimFrame = ch->currentAnimFrame-7;
+ startAnimFrame = ch->currentAnimFrame - 7;
xOffset = _defaultShapeTable[startAnimFrame].xOffset;
yOffset = _defaultShapeTable[startAnimFrame].yOffset;
if (_scaleMode) {
@@ -714,7 +714,7 @@ void KyraEngine_LoK::initSceneObjectList(int brandonAlive) {
byte curItem = curRoom->itemsTable[i];
if (curItem != 0xFF) {
curAnimState->drawY = curRoom->itemsYPos[i];
- curAnimState->sceneAnimPtr = _shapes[216+curItem];
+ curAnimState->sceneAnimPtr = _shapes[216 + curItem];
curAnimState->animFrameNumber = (int16)0xFFFF;
curAnimState->y1 = curRoom->itemsYPos[i];
curAnimState->x1 = curRoom->itemsXPos[i];
@@ -780,10 +780,10 @@ void KyraEngine_LoK::initSceneScreen(int brandonAlive) {
} else {
if (_unkScreenVar1 && !queryGameFlag(0xA0)) {
for (int i = 0; i < 60; ++i) {
- uint16 col = _screen->getPalette(0)[684+i];
- col += _screen->getPalette(1)[684+i] << 1;
+ uint16 col = _screen->getPalette(0)[684 + i];
+ col += _screen->getPalette(1)[684 + i] << 1;
col >>= 2;
- _screen->getPalette(0)[684+i] = col;
+ _screen->getPalette(0)[684 + i] = col;
}
_screen->setScreenPalette(_screen->getPalette(0));
}
@@ -847,7 +847,7 @@ int KyraEngine_LoK::handleSceneChange(int xpos, int ypos, int unk1, int frameRes
}
}
- if (ypos <= (_northExitHeight&0xFF)+2) {
+ if (ypos <= (_northExitHeight & 0xFF) + 2) {
if (_roomTable[sceneId].northExit != 0xFFFF) {
xpos = _sceneExits.northXPos;
ypos = _northExitHeight & 0xFF;
@@ -1093,7 +1093,7 @@ void KyraEngine_LoK::setCharactersInDefaultScene() {
Character *cur = &_characterList[i];
//cur->field_20 = 0;
- const uint32 *curTable = defaultSceneTable[i-1];
+ const uint32 *curTable = defaultSceneTable[i - 1];
cur->sceneId = curTable[0];
if (cur->sceneId == _currentCharacter->sceneId)
diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp
index a5a2562448..628654f127 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);
@@ -105,16 +105,16 @@ void LoLEngine::addLevelItems() {
if (_itemsInPlay[i].level != _currentLevel)
continue;
- assignBlockObject(&_levelBlockProperties[_itemsInPlay[i].block], i);
+ assignBlockItem(&_levelBlockProperties[_itemsInPlay[i].block], i);
_levelBlockProperties[_itemsInPlay[i].block].direction = 5;
_itemsInPlay[i].nextDrawObject = 0;
}
}
-void LoLEngine::assignBlockObject(LevelBlockProperty *l, uint16 item) {
+void LoLEngine::assignBlockItem(LevelBlockProperty *l, uint16 item) {
uint16 *index = &l->assignedObjects;
- ItemInPlay *tmp = 0;
+ LoLObject *tmp = 0;
while (*index & 0x8000) {
tmp = findObject(*index);
@@ -122,7 +122,7 @@ void LoLEngine::assignBlockObject(LevelBlockProperty *l, uint16 item) {
}
tmp = findObject(item);
- tmp->level = -1;
+ ((LoLItem *)tmp)->level = -1;
uint16 ix = *index;
@@ -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,35 @@ 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);
+ releaseDecorations(_lvlShapeIndex, 1);
+ _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,57 +233,10 @@ 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::releaseDecorations(int first, int num) {
+ for (int i = first; i < (first + num); i++) {
+ delete[] _levelDecorationShapes[i];
+ _levelDecorationShapes[i] = 0;
}
}
@@ -299,26 +253,31 @@ 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;
}
}
}
+const uint8 *LoLEngine::getBlockFileData(int levelIndex) {
+ _screen->loadBitmap(Common::String::format("LEVEL%d.CMZ", levelIndex).c_str(), 15, 15, 0);
+ return _screen->getCPagePtr(14);
+}
+
void LoLEngine::loadLevelShpDat(const char *shpFile, const char *datFile, bool flag) {
memset(_tempBuffer5120, 0, 5120);
_lvlShpFileHandle = _res->createReadStream(shpFile);
- _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 +293,7 @@ void LoLEngine::loadLevelShpDat(const char *shpFile, const char *datFile, bool f
delete s;
if (!flag) {
- _lvlBlockIndex = 1;
+ _mappedDecorationsCount = 1;
_lvlShapeIndex = 1;
}
}
@@ -399,7 +358,7 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight
memcpy(_vcnShift, v, tlen);
v += tlen;
- memcpy(_vcnExpTable, v, 128);
+ memcpy(_vcnColTable, v, 128);
v += 128;
if (_lastOverridePalFilePtr) {
@@ -492,7 +451,7 @@ void LoLEngine::loadLevelGraphics(const char *file, int specialColor, int weight
for (int i = 0; i < 8; i++) {
uint8 *pl = _screen->getLevelOverlay(7 - i);
for (int ii = 0; ii < 16; ii++)
- _vcnExpTable[(i << 4) + ii] = pl[(ii << 4) | ii];
+ _vcnColTable[(i << 4) + ii] = pl[(ii << 4) | ii];
}
}
@@ -515,17 +474,17 @@ void LoLEngine::resetItems(int flag) {
for (int i = 0; i < 1024; i++) {
_levelBlockProperties[i].direction = 5;
uint16 id = _levelBlockProperties[i].assignedObjects;
- MonsterInPlay *r = 0;
+ LoLObject *r = 0;
while (id & 0x8000) {
- r = (MonsterInPlay *)findObject(id);
+ r = findObject(id);
id = r->nextAssignedObject;
}
if (!id)
continue;
- ItemInPlay *it = &_itemsInPlay[id];
+ LoLItem *it = &_itemsInPlay[id];
it->level = _currentLevel;
it->block = i;
if (r)
@@ -537,7 +496,7 @@ void LoLEngine::resetItems(int flag) {
}
void LoLEngine::disableMonsters() {
- memset(_monsters, 0, 30 * sizeof(MonsterInPlay));
+ memset(_monsters, 0, 30 * sizeof(LoLMonster));
for (int i = 0; i < 30; i++)
_monsters[i].mode = 0x10;
}
@@ -751,11 +710,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 +781,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 +812,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 +1243,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 +1399,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() {
+void LoLEngine::drawSceneShapes(int) {
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 +1436,12 @@ void LoLEngine::drawSceneShapes() {
if (v > 80)
v = 80;
- scaleLevelShapesDim(t, dimY1, dimY2, 13);
+ setDoorShapeDim(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 +1456,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 +1466,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) {
@@ -2101,7 +1491,7 @@ void LoLEngine::drawDecorations(int index) {
ov = 0;
}
ovl = _screen->getLevelOverlay(ov);
- } else if (_levelShapeProperties[l].shapeIndex[shpIx] != 0xffff) {
+ } else if (_levelDecorationProperties[l].shapeIndex[shpIx] != 0xffff) {
scaleW = scaleH = 0x100;
int ov = 7;
if (_flags.use16ColorMode) {
@@ -2114,34 +1504,34 @@ void LoLEngine::drawDecorations(int index) {
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));
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/scene_rpg.cpp b/engines/kyra/scene_rpg.cpp
new file mode 100644
index 0000000000..3a694e05fe
--- /dev/null
+++ b/engines/kyra/scene_rpg.cpp
@@ -0,0 +1,637 @@
+/* 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/kyra_rpg.h"
+#include "kyra/resource.h"
+#include "kyra/timer.h"
+#include "kyra/sound.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void KyraRpgEngine::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))
+ setDoorShapeDim(index, y1, y2, -1);
+ }
+
+ t = _dscDim2[((m + i) << 1) + 1];
+
+ if (t < x2) {
+ x2 = t;
+ if (!(a & 0x10))
+ setDoorShapeDim(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 KyraRpgEngine::setDoorShapeDim(int index, int16 &y1, int16 &y2, int dim) {
+ uint8 a = _dscDimMap[index];
+
+ if (_flags.gameID != GI_EOB1 && dim == -1 && a != 3)
+ a++;
+
+ uint8 b = a;
+ if (_flags.gameID == GI_EOB1) {
+ a += _dscDoorFrameIndex1[_currentLevel - 1];
+ b += _dscDoorFrameIndex2[_currentLevel - 1];
+ }
+
+ y1 = _dscDoorFrameY1[a];
+ y2 = _dscDoorFrameY2[b];
+
+ if (dim == -1)
+ return;
+
+ const ScreenDim *cDim = screen()->getScreenDim(dim);
+
+ screen()->modifyScreenDim(dim, cDim->sx, y1, cDim->w, y2 - y1);
+}
+
+void KyraRpgEngine::drawLevelModifyScreenDim(int dim, int16 x1, int16 y1, int16 x2, int16 y2) {
+ screen()->modifyScreenDim(dim, x1, y1 << 3, x2 - x1, (y2 - y1) << 3);
+}
+
+void KyraRpgEngine::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 KyraRpgEngine::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 KyraRpgEngine::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 KyraRpgEngine::hasWall(int index) {
+ if (!index || (_wllWallFlags[index] & 8))
+ return false;
+ return true;
+}
+
+void KyraRpgEngine::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 KyraRpgEngine::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 KyraRpgEngine::drawVcnBlocks() {
+ uint8 *d = _sceneWindowBuffer;
+ uint16 *bdb = _blockDrawingBuffer;
+ uint16 pitch = 22 * _vcnBlockWidth * 2;
+ uint8 pxl[2];
+ pxl[0] = pxl[1] = 0;
+
+ for (int y = 0; y < 15; y++) {
+ for (int x = 0; x < 22; x++) {
+ bool horizontalFlip = false;
+ uint16 vcnOffset = *bdb++;
+ uint16 vcnExtraOffsetWll = 0;
+ int wllVcnOffset = 0;
+ int wllVcnRmdOffset = 0;
+
+ if (vcnOffset & 0x8000) {
+ // this renders a wall block over the transparent pixels of a floor/ceiling block
+ vcnExtraOffsetWll = vcnOffset - 0x8000;
+ vcnOffset = 0;
+ wllVcnRmdOffset = _wllVcnOffset;
+ }
+
+ if (vcnOffset & 0x4000) {
+ horizontalFlip = true;
+ vcnOffset &= 0x3fff;
+ }
+
+ uint8 *src = 0;
+ if (vcnOffset) {
+ src = &_vcnBlocks[vcnOffset * _vcnBlockWidth * _vcnBlockHeight];
+ wllVcnOffset = _wllVcnOffset;
+ } else {
+ // floor/ceiling blocks
+ vcnOffset = bdb[329];
+ if (vcnOffset & 0x4000) {
+ horizontalFlip = true;
+ vcnOffset &= 0x3fff;
+ }
+
+ src = (_vcfBlocks ? _vcfBlocks : _vcnBlocks) + (vcnOffset * _vcnBlockWidth * _vcnBlockHeight);
+ }
+
+ uint8 shift = _vcnShift ? _vcnShift[vcnOffset] : _blockBrightness;
+
+ if (horizontalFlip) {
+ for (int blockY = 0; blockY < _vcnBlockHeight; blockY++) {
+ src += (_vcnBlockWidth - 1);
+ for (int blockX = 0; blockX < _vcnBlockWidth; blockX++) {
+ uint8 bl = *src--;
+ d[_vcnFlip0] = _vcnColTable[((bl & 0x0f) + wllVcnOffset) | shift];
+ d[_vcnFlip1] = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift];
+ d += 2;
+ }
+ src += (_vcnBlockWidth + 1);
+ d += (pitch - 2 * _vcnBlockWidth);
+ }
+ } else {
+ for (int blockY = 0; blockY < _vcnBlockHeight; blockY++) {
+ for (int blockX = 0; blockX < _vcnBlockWidth; blockX++) {
+ uint8 bl = *src++;
+ *d++ = _vcnColTable[((bl >> 4) + wllVcnOffset) | shift];
+ *d++ = _vcnColTable[((bl & 0x0f) + wllVcnOffset) | shift];
+ }
+ d += (pitch - 2 * _vcnBlockWidth);
+ }
+ }
+ d -= (pitch * _vcnBlockHeight - 2 * _vcnBlockWidth);
+
+ if (vcnExtraOffsetWll) {
+ d -= (2 * _vcnBlockWidth);
+ horizontalFlip = false;
+
+ if (vcnExtraOffsetWll & 0x4000) {
+ vcnExtraOffsetWll &= 0x3fff;
+ horizontalFlip = true;
+ }
+
+ shift = _vcnShift ? _vcnShift[vcnExtraOffsetWll] : _blockBrightness;
+ src = &_vcnBlocks[vcnExtraOffsetWll * _vcnBlockWidth * _vcnBlockHeight];
+ uint8 *maskTable = _vcnTransitionMask ? &_vcnTransitionMask[vcnExtraOffsetWll * _vcnBlockWidth * _vcnBlockHeight] : 0;
+
+ if (horizontalFlip) {
+ for (int blockY = 0; blockY < _vcnBlockHeight; blockY++) {
+ src += (_vcnBlockWidth - 1);
+ maskTable += (_vcnBlockWidth - 1);
+ for (int blockX = 0; blockX < _vcnBlockWidth; blockX++) {
+ uint8 bl = *src--;
+ uint8 mask = _vcnTransitionMask ? *maskTable-- : 0;
+ pxl[_vcnFlip0] = _vcnColTable[((bl & 0x0f) + wllVcnRmdOffset) | shift];
+ pxl[_vcnFlip1] = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift];
+
+ if (_vcnTransitionMask)
+ *d = (*d & (mask & 0x0f)) | pxl[0];
+ else if (pxl[0])
+ *d = pxl[0];
+ d++;
+
+ if (_vcnTransitionMask)
+ *d = (*d & (mask >> 4)) | pxl[1];
+ else if (pxl[1])
+ *d = pxl[1];
+ d++;
+ }
+ src += (_vcnBlockWidth + 1);
+ maskTable += (_vcnBlockWidth + 1);
+ d += (pitch - 2 * _vcnBlockWidth);
+ }
+ } else {
+ for (int blockY = 0; blockY < _vcnBlockHeight; blockY++) {
+ for (int blockX = 0; blockX < _vcnBlockWidth; blockX++) {
+ uint8 bl = *src++;
+ uint8 mask = _vcnTransitionMask ? *maskTable++ : 0;
+ uint8 h = _vcnColTable[((bl >> 4) + wllVcnRmdOffset) | shift];
+ uint8 l = _vcnColTable[((bl & 0x0f) + wllVcnRmdOffset) | shift];
+
+ if (_vcnTransitionMask)
+ *d = (*d & (mask >> 4)) | h;
+ else if (h)
+ *d = h;
+ d++;
+
+ if (_vcnTransitionMask)
+ *d = (*d & (mask & 0x0f)) | l;
+ else if (l)
+ *d = l;
+ d++;
+ }
+ d += (pitch - 2 * _vcnBlockWidth);
+ }
+ }
+ d -= (pitch * _vcnBlockHeight - 2 * _vcnBlockWidth);
+ }
+ }
+ d += (pitch * (_vcnBlockHeight - 1));
+ }
+
+ screen()->copyBlockToPage(_sceneDrawPage1, _sceneXoffset, 0, 176, 120, _sceneWindowBuffer);
+}
+
+uint16 KyraRpgEngine::calcNewBlockPosition(uint16 curBlock, uint16 direction) {
+ static const int16 blockPosTable[] = { -32, 1, 32, -1 };
+ return (curBlock + blockPosTable[direction]) & 0x3ff;
+}
+
+int KyraRpgEngine::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 KyraRpgEngine::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 KyraRpgEngine::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 KyraRpgEngine::clickedWallOnlyScript(uint16 block) {
+ runLevelScript(block, _clickedSpecialFlag);
+ return 1;
+}
+
+void KyraRpgEngine::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 KyraRpgEngine::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 : 4);
+
+ } else {
+ while (!(flg & _wllWallFlags[v]))
+ v += openClose;
+
+ _levelBlockProperties[block].walls[c] = _levelBlockProperties[block].walls[c ^ 2] = v;
+ checkSceneUpdateNeed(block);
+ }
+}
+
+void KyraRpgEngine::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
diff --git a/engines/kyra/scene_v1.cpp b/engines/kyra/scene_v1.cpp
index bc90f49002..36798970e3 100644
--- a/engines/kyra/scene_v1.cpp
+++ b/engines/kyra/scene_v1.cpp
@@ -115,7 +115,7 @@ int KyraEngine_v1::findWay(int x, int y, int toX, int toY, int *moveTable, int m
delete[] pathTable2;
return 0x7D00;
}
- memcpy(&moveTable[lastUsedEntry], pathTable1, temp*sizeof(int));
+ memcpy(&moveTable[lastUsedEntry], pathTable1, temp * sizeof(int));
lastUsedEntry += temp;
} else {
if (lastUsedEntry + tempValue > moveTableSize) {
@@ -123,7 +123,7 @@ int KyraEngine_v1::findWay(int x, int y, int toX, int toY, int *moveTable, int m
delete[] pathTable2;
return 0x7D00;
}
- memcpy(&moveTable[lastUsedEntry], pathTable2, tempValue*sizeof(int));
+ memcpy(&moveTable[lastUsedEntry], pathTable2, tempValue * sizeof(int));
lastUsedEntry += tempValue;
}
x = curX;
@@ -161,16 +161,16 @@ int KyraEngine_v1::findSubPath(int x, int y, int toX, int toY, int *moveTable, i
while (position != end) {
int newFacing2 = newFacing;
while (true) {
- changePosTowardsFacing(xpos1, ypos1, facingTable1[start*8 + newFacing2]);
+ changePosTowardsFacing(xpos1, ypos1, facingTable1[start * 8 + newFacing2]);
if (!lineIsPassable(xpos1, ypos1)) {
- if (facingTable1[start*8 + newFacing2] == newFacing)
+ if (facingTable1[start * 8 + newFacing2] == newFacing)
return 0x7D00;
- newFacing2 = facingTable1[start*8 + newFacing2];
+ newFacing2 = facingTable1[start * 8 + newFacing2];
xpos1 = x;
ypos1 = y;
continue;
}
- newFacing = facingTable1[start*8 + newFacing2];
+ newFacing = facingTable1[start * 8 + newFacing2];
break;
}
// debug drawing
@@ -200,7 +200,7 @@ int KyraEngine_v1::findSubPath(int x, int y, int toX, int toY, int *moveTable, i
if (xpos1 == xpos2 && ypos1 == ypos2)
break;
- newFacing = facingTable3[start*8 + newFacing];
+ newFacing = facingTable3[start * 8 + newFacing];
}
return 0x7D00;
diff --git a/engines/kyra/scene_v2.cpp b/engines/kyra/scene_v2.cpp
index 061ce4c21a..9b6897f2ab 100644
--- a/engines/kyra/scene_v2.cpp
+++ b/engines/kyra/scene_v2.cpp
@@ -42,7 +42,7 @@ void KyraEngine_v2::updateSpecialSceneScripts() {
while (_system->getMillis() <= nextTime) {
if (_sceneSpecialScriptsTimer[_lastProcessedSceneScript] <= _system->getMillis() &&
- !_specialSceneScriptState[_lastProcessedSceneScript]) {
+ !_specialSceneScriptState[_lastProcessedSceneScript]) {
_specialSceneScriptRunFlag = true;
while (_specialSceneScriptRunFlag && _sceneSpecialScriptsTimer[_lastProcessedSceneScript] <= _system->getMillis()) {
@@ -52,7 +52,7 @@ void KyraEngine_v2::updateSpecialSceneScripts() {
}
if (!_emc->isValid(&_sceneSpecialScripts[_lastProcessedSceneScript])) {
- _emc->start(&_sceneSpecialScripts[_lastProcessedSceneScript], _desc.firstAnimSceneScript+_lastProcessedSceneScript);
+ _emc->start(&_sceneSpecialScripts[_lastProcessedSceneScript], _desc.firstAnimSceneScript + _lastProcessedSceneScript);
_specialSceneScriptRunFlag = false;
}
@@ -155,14 +155,14 @@ int KyraEngine_v2::pathfinderInitPositionTable(int *moveTable) {
}
lastEntry = pathfinderAddToPositionTable(lastEntry, newX, newY);
- _pathfinderPositionTable[lastEntry*2+0] = -1;
- _pathfinderPositionTable[lastEntry*2+1] = -1;
+ _pathfinderPositionTable[lastEntry * 2 + 0] = -1;
+ _pathfinderPositionTable[lastEntry * 2 + 1] = -1;
return lastEntry;
}
int KyraEngine_v2::pathfinderAddToPositionTable(int index, int v1, int v2) {
- _pathfinderPositionTable[index<<1] = v1;
- _pathfinderPositionTable[(index<<1)+1] = v2;
+ _pathfinderPositionTable[index << 1] = v1;
+ _pathfinderPositionTable[(index << 1) + 1] = v2;
++index;
if (index >= 199)
--index;
@@ -173,23 +173,23 @@ int KyraEngine_v2::pathfinderInitPositionIndexTable(int tableLen, int x, int y)
int x1 = 0, y1 = 0;
int x2 = 0, y2 = 0;
int lastEntry = 0;
- int index2 = tableLen-1, index1 = 0;
+ int index2 = tableLen - 1, index1 = 0;
while (index2 > index1) {
- x1 = _pathfinderPositionTable[index1*2+0] + x;
- y1 = _pathfinderPositionTable[index1*2+1] + y;
- x2 = _pathfinderPositionTable[index2*2+0] + x;
- y2 = _pathfinderPositionTable[index2*2+1] + y;
+ x1 = _pathfinderPositionTable[index1 * 2 + 0] + x;
+ y1 = _pathfinderPositionTable[index1 * 2 + 1] + y;
+ x2 = _pathfinderPositionTable[index2 * 2 + 0] + x;
+ y2 = _pathfinderPositionTable[index2 * 2 + 1] + y;
if (directLinePassable(x1, y1, x2, y2)) {
lastEntry = pathfinderAddToPositionIndexTable(lastEntry, index2);
- if (tableLen-1 == index2)
+ if (tableLen - 1 == index2)
break;
index1 = index2;
- index2 = tableLen-1;
- } else if (index1+1 == index2) {
+ index2 = tableLen - 1;
+ } else if (index1 + 1 == index2) {
lastEntry = pathfinderAddToPositionIndexTable(lastEntry, index2);
index1 = index2;
- index2 = tableLen-1;
+ index2 = tableLen - 1;
} else {
--index2;
}
@@ -212,14 +212,14 @@ void KyraEngine_v2::pathfinderFinializePath(int *moveTable, int tableLen, int x,
int sizeLeft = moveTableSize;
for (int i = 0; i < tableLen; ++i) {
index2 = _pathfinderPositionIndexTable[i];
- x1 = _pathfinderPositionTable[index1*2+0] + x;
- y1 = _pathfinderPositionTable[index1*2+1] + y;
- x2 = _pathfinderPositionTable[index2*2+0] + x;
- y2 = _pathfinderPositionTable[index2*2+1] + y;
+ x1 = _pathfinderPositionTable[index1 * 2 + 0] + x;
+ y1 = _pathfinderPositionTable[index1 * 2 + 1] + y;
+ x2 = _pathfinderPositionTable[index2 * 2 + 0] + x;
+ y2 = _pathfinderPositionTable[index2 * 2 + 1] + y;
int wayLen = findWay(x1, y1, x2, y2, moveTable, sizeLeft);
moveTable += wayLen;
- sizeLeft -= wayLen; // unlike the original we want to be sure that the size left is correct
+ sizeLeft -= wayLen; // unlike the original we want to be sure that the size left is correct
index1 = index2;
}
}
diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp
index 4eae89e0d4..d3b4d6f943 100644
--- a/engines/kyra/screen.cpp
+++ b/engines/kyra/screen.cpp
@@ -27,6 +27,7 @@
#include "common/endian.h"
#include "common/memstream.h"
#include "common/system.h"
+#include "common/config-manager.h"
#include "engines/util.h"
@@ -36,9 +37,9 @@
namespace Kyra {
-Screen::Screen(KyraEngine_v1 *vm, OSystem *system)
- : _system(system), _vm(vm), _sjisInvisibleColor(0),
- _cursorColorKey((vm->game() == GI_KYRA1) ? 0xFF : 0x00) {
+Screen::Screen(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, const int dimTableSize)
+ : _system(system), _vm(vm), _sjisInvisibleColor(0), _dimTable(dimTable), _dimTableCount(dimTableSize),
+ _cursorColorKey((vm->game() == GI_KYRA1 || vm->game() == GI_EOB1 || vm->game() == GI_EOB2) ? 0xFF : 0) {
_debugEnabled = false;
_maskMinY = _maskMaxY = -1;
@@ -49,8 +50,18 @@ Screen::Screen(KyraEngine_v1 *vm, OSystem *system)
memset(_fonts, 0, sizeof(_fonts));
+ memset(_pagePtrs, 0, sizeof(_pagePtrs));
+ // Set scale factor to 1 (no scaling) for all pages
+ memset(_pageScaleFactor, 1, sizeof(_pageScaleFactor));
+ // In VGA mode the odd and even page pointers point to the same buffers.
+ for (int i = 0; i < SCREEN_PAGE_NUM; i++)
+ _pageMapping[i] = i & ~1;
+
+ _renderMode = Common::kRenderDefault;
+
_currentFont = FID_8_FNT;
_paletteChanged = true;
+ _curDim = 0;
}
Screen::~Screen() {
@@ -69,6 +80,10 @@ Screen::~Screen() {
for (uint i = 0; i < _palettes.size(); ++i)
delete _palettes[i];
+
+ for (int i = 0; i < _dimTableCount; ++i)
+ delete _customDimTable[i];
+ delete[] _customDimTable;
}
bool Screen::init() {
@@ -79,10 +94,21 @@ bool Screen::init() {
_useSJIS = false;
_use16ColorMode = _vm->gameFlags().use16ColorMode;
_isAmiga = (_vm->gameFlags().platform == Common::kPlatformAmiga);
+
+ if (ConfMan.hasKey("render_mode"))
+ _renderMode = Common::parseRenderMode(ConfMan.get("render_mode"));
+
+ // CGA and EGA modes use additional pages to do the CGA/EGA specific graphics conversions.
+ if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) {
+ for (int i = 0; i < 8; i++)
+ _pageMapping[i] = i;
+ }
+
memset(_fonts, 0, sizeof(_fonts));
- if (_vm->gameFlags().useHiResOverlay) {
- _useOverlays = true;
+ _useOverlays = (_vm->gameFlags().useHiRes && _renderMode != Common::kRenderEGA);
+
+ if (_useOverlays) {
_useSJIS = (_vm->gameFlags().lang == Common::JA_JPN);
_sjisInvisibleColor = (_vm->game() == GI_KYRA1) ? 0x80 : 0xF6;
@@ -105,15 +131,36 @@ bool Screen::init() {
}
_curPage = 0;
- uint8 *pagePtr = new uint8[SCREEN_PAGE_SIZE * 8];
- for (int pageNum = 0; pageNum < SCREEN_PAGE_NUM; pageNum += 2)
- _pagePtrs[pageNum] = _pagePtrs[pageNum + 1] = pagePtr + (pageNum >> 1) * SCREEN_PAGE_SIZE;
- memset(pagePtr, 0, SCREEN_PAGE_SIZE * 8);
+
+ Common::Array<uint8> realPages;
+ for (int i = 0; i < SCREEN_PAGE_NUM; i++) {
+ if (Common::find(realPages.begin(), realPages.end(), _pageMapping[i]) == realPages.end())
+ realPages.push_back(_pageMapping[i]);
+ }
+
+ int numPages = realPages.size();
+ uint32 bufferSize = 0;
+ for (int i = 0; i < numPages; i++)
+ bufferSize += (SCREEN_PAGE_SIZE * _pageScaleFactor[realPages[i]] * _pageScaleFactor[realPages[i]]);
+
+ uint8 *pagePtr = new uint8[bufferSize];
+ memset(pagePtr, 0, bufferSize);
+
+ memset(_pagePtrs, 0, sizeof(_pagePtrs));
+ for (int i = 0; i < SCREEN_PAGE_NUM; i++) {
+ if (_pagePtrs[_pageMapping[i]]) {
+ _pagePtrs[i] = _pagePtrs[_pageMapping[i]];
+ } else {
+ _pagePtrs[i] = pagePtr;
+ pagePtr += (SCREEN_PAGE_SIZE * _pageScaleFactor[i] * _pageScaleFactor[i]);
+ }
+ }
memset(_shapePages, 0, sizeof(_shapePages));
const int paletteCount = _isAmiga ? 13 : 4;
- const int numColors = _use16ColorMode ? 16 : (_isAmiga ? 32 : 256);
+ // We allow 256 color palettes in EGA mode, since original EOB II code does the same and requires it
+ const int numColors = _use16ColorMode ? 16 : (_isAmiga ? 32 : (_renderMode == Common::kRenderCGA ? 4 : 256));
_interfacePaletteEnabled = false;
@@ -126,6 +173,15 @@ bool Screen::init() {
assert(_palettes[i]);
}
+ // Setup CGA colors (if CGA mode is selected)
+ if (_renderMode == Common::kRenderCGA) {
+ Palette pal(5);
+ pal.setCGAPalette(1, Palette::kIntensityHigh);
+ // create additional black color 4 for use with the mouse cursor manager
+ pal.fill(4, 1, 0);
+ Screen::setScreenPalette(pal);
+ }
+
_internFadePalette = new Palette(numColors);
assert(_internFadePalette);
@@ -145,6 +201,10 @@ bool Screen::init() {
_system->getPaletteManager()->setPalette(palette, 16, 8);
}
+ _customDimTable = new ScreenDim *[_dimTableCount];
+ memset(_customDimTable, 0, sizeof(ScreenDim *) * _dimTableCount);
+
+ _curDimIndex = -1;
_curDim = 0;
_charWidth = 0;
_charOffset = 0;
@@ -182,7 +242,7 @@ void Screen::setResolution() {
int width = 320, height = 200;
bool defaultTo1xScaler = false;
- if (_vm->gameFlags().useHiResOverlay) {
+ if (_vm->gameFlags().useHiRes) {
defaultTo1xScaler = true;
height = 400;
@@ -217,7 +277,7 @@ void Screen::updateScreen() {
needRealUpdate = true;
if (!_useOverlays)
- _system->copyRectToScreen(getPagePtr(2), SCREEN_W, 320, 0, SCREEN_W, SCREEN_H);
+ _system->copyRectToScreen(getPagePtr(2), SCREEN_W, 320, 0, SCREEN_W * _pageScaleFactor[2], SCREEN_H * _pageScaleFactor[2]);
else
_system->copyRectToScreen(getPagePtr(2), SCREEN_W, 640, 0, SCREEN_W, SCREEN_H);
}
@@ -228,12 +288,12 @@ void Screen::updateScreen() {
void Screen::updateDirtyRects() {
if (_forceFullUpdate) {
- _system->copyRectToScreen(getCPagePtr(0), SCREEN_W, 0, 0, SCREEN_W, SCREEN_H);
+ _system->copyRectToScreen(getCPagePtr(0), SCREEN_W * _pageScaleFactor[0], 0, 0, SCREEN_W * _pageScaleFactor[0], SCREEN_H * _pageScaleFactor[0]);
} else {
const byte *page0 = getCPagePtr(0);
Common::List<Common::Rect>::iterator it;
for (it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
- _system->copyRectToScreen(page0 + it->top * SCREEN_W + it->left, SCREEN_W, it->left, it->top, it->width(), it->height());
+ _system->copyRectToScreen(page0 + it->top * SCREEN_W * _pageScaleFactor[0] + it->left, SCREEN_W * _pageScaleFactor[0], it->left, it->top, it->width(), it->height());
}
}
_forceFullUpdate = false;
@@ -374,6 +434,29 @@ void Screen::mergeOverlay(int x, int y, int w, int h) {
}
}
+const ScreenDim *Screen::getScreenDim(int dim) const {
+ assert(dim < _dimTableCount);
+ return _customDimTable[dim] ? _customDimTable[dim] : &_dimTable[dim];
+}
+
+void Screen::modifyScreenDim(int dim, int x, int y, int w, int h) {
+ if (!_customDimTable[dim])
+ _customDimTable[dim] = new ScreenDim;
+
+ memcpy(_customDimTable[dim], &_dimTable[dim], sizeof(ScreenDim));
+ _customDimTable[dim]->sx = x;
+ _customDimTable[dim]->sy = y;
+ _customDimTable[dim]->w = w;
+ _customDimTable[dim]->h = h;
+ if (dim == _curDimIndex || _vm->game() == GI_LOL)
+ setScreenDim(dim);
+}
+
+void Screen::setScreenDim(int dim) {
+ _curDim = getScreenDim(dim);
+ _curDimIndex = dim;
+}
+
uint8 *Screen::getPagePtr(int pageNum) {
assert(pageNum < SCREEN_PAGE_NUM);
return _pagePtrs[pageNum];
@@ -395,7 +478,7 @@ void Screen::clearPage(int pageNum) {
assert(pageNum < SCREEN_PAGE_NUM);
if (pageNum == 0 || pageNum == 1)
_forceFullUpdate = true;
- memset(getPagePtr(pageNum), 0, SCREEN_PAGE_SIZE);
+ memset(getPagePtr(pageNum), 0, SCREEN_PAGE_SIZE * _pageScaleFactor[_curPage] * _pageScaleFactor[_curPage]);
clearOverlayPage(pageNum);
}
@@ -409,7 +492,7 @@ int Screen::setCurPage(int pageNum) {
void Screen::clearCurPage() {
if (_curPage == 0 || _curPage == 1)
_forceFullUpdate = true;
- memset(getPagePtr(_curPage), 0, SCREEN_PAGE_SIZE);
+ memset(getPagePtr(_curPage), 0, SCREEN_PAGE_SIZE * _pageScaleFactor[_curPage] * _pageScaleFactor[_curPage]);
clearOverlayPage(_curPage);
}
@@ -565,12 +648,17 @@ uint8 Screen::getPagePixel(int pageNum, int x, int y) {
void Screen::setPagePixel(int pageNum, int x, int y, uint8 color) {
assert(pageNum < SCREEN_PAGE_NUM);
assert(x >= 0 && x < SCREEN_W && y >= 0 && y < SCREEN_H);
+
if (pageNum == 0 || pageNum == 1)
addDirtyRect(x, y, 1, 1);
if (_use16ColorMode) {
color &= 0x0F;
color |= (color << 4);
+ } else if (_renderMode == Common::kRenderCGA) {
+ color &= 0x03;
+ } else if (_renderMode == Common::kRenderEGA) {
+ color &= 0x0F;
}
_pagePtrs[pageNum][y * SCREEN_W + x] = color;
@@ -581,13 +669,22 @@ void Screen::fadeFromBlack(int delay, const UpdateFunctor *upFunc) {
}
void Screen::fadeToBlack(int delay, const UpdateFunctor *upFunc) {
+ if (_renderMode == Common::kRenderEGA)
+ return;
+
Palette pal(getPalette(0).getNumColors());
fadePalette(pal, delay, upFunc);
}
void Screen::fadePalette(const Palette &pal, int delay, const UpdateFunctor *upFunc) {
+ if (_renderMode == Common::kRenderEGA)
+ setScreenPalette(pal);
+
updateScreen();
+ if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA)
+ return;
+
int diff = 0, delayInc = 0;
getFadeParams(pal, delay, delayInc, diff);
@@ -769,16 +866,26 @@ void Screen::copyToPage0(int y, int h, uint8 page, uint8 *seqBuf) {
}
void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage, int flags) {
+ // Since we don't (need to) do any actual scaling, we check for compatible pages here
+ assert(_pageScaleFactor[srcPage] == _pageScaleFactor[dstPage]);
+
+ x1 *= _pageScaleFactor[srcPage];
+ y1 *= _pageScaleFactor[srcPage];
+ x2 *= _pageScaleFactor[dstPage];
+ y2 *= _pageScaleFactor[dstPage];
+ w *= _pageScaleFactor[srcPage];
+ h *= _pageScaleFactor[srcPage];
+
if (x2 < 0) {
if (x2 <= -w)
return;
w += x2;
x1 -= x2;
x2 = 0;
- } else if (x2 + w >= SCREEN_W) {
- if (x2 > SCREEN_W)
+ } else if (x2 + w >= SCREEN_W * _pageScaleFactor[dstPage]) {
+ if (x2 > SCREEN_W * _pageScaleFactor[dstPage])
return;
- w = SCREEN_W - x2;
+ w = SCREEN_W * _pageScaleFactor[srcPage] - x2;
}
if (y2 < 0) {
@@ -787,14 +894,17 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag
h += y2;
y1 -= y2;
y2 = 0;
- } else if (y2 + h >= SCREEN_H) {
- if (y2 > SCREEN_H)
+ } else if (y2 + h >= SCREEN_H * _pageScaleFactor[dstPage]) {
+ if (y2 > SCREEN_H * _pageScaleFactor[dstPage])
return;
- h = SCREEN_H - y2;
+ h = SCREEN_H * _pageScaleFactor[srcPage] - y2;
}
- const uint8 *src = getPagePtr(srcPage) + y1 * SCREEN_W + x1;
- uint8 *dst = getPagePtr(dstPage) + y2 * SCREEN_W + x2;
+ const uint8 *src = getPagePtr(srcPage) + y1 * SCREEN_W * _pageScaleFactor[srcPage] + x1;
+ uint8 *dst = getPagePtr(dstPage) + y2 * SCREEN_W * _pageScaleFactor[dstPage] + x2;
+
+ if (src == dst)
+ return;
if (dstPage == 0 || dstPage == 1)
addDirtyRect(x2, y2, w, h);
@@ -803,9 +913,9 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag
if (flags & CR_NO_P_CHECK) {
while (h--) {
- memcpy(dst, src, w);
- src += SCREEN_W;
- dst += SCREEN_W;
+ memmove(dst, src, w);
+ src += SCREEN_W * _pageScaleFactor[srcPage];
+ dst += SCREEN_W * _pageScaleFactor[dstPage];
}
} else {
while (h--) {
@@ -813,19 +923,24 @@ void Screen::copyRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPag
if (src[i])
dst[i] = src[i];
}
- src += SCREEN_W;
- dst += SCREEN_W;
+ src += SCREEN_W * _pageScaleFactor[srcPage];
+ dst += SCREEN_W * _pageScaleFactor[dstPage];
}
}
}
void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 *dest) {
+ x *= _pageScaleFactor[pageNum];
+ y *= _pageScaleFactor[pageNum];
+ w *= _pageScaleFactor[pageNum];
+ h *= _pageScaleFactor[pageNum];
+
if (y < 0) {
dest += (-y) * w;
h += y;
y = 0;
} else if (y + h > SCREEN_H) {
- h = SCREEN_H - y;
+ h = SCREEN_H * _pageScaleFactor[pageNum] - y;
}
if (x < 0) {
@@ -833,7 +948,7 @@ void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 *
w += x;
x = 0;
} else if (x + w > SCREEN_W) {
- w = SCREEN_W - x;
+ w = SCREEN_W * _pageScaleFactor[pageNum] - x;
}
if (w < 0 || h < 0)
@@ -842,13 +957,17 @@ void Screen::copyRegionToBuffer(int pageNum, int x, int y, int w, int h, uint8 *
uint8 *pagePtr = getPagePtr(pageNum);
for (int i = y; i < y + h; ++i)
- memcpy(dest + (i - y) * w, pagePtr + i * SCREEN_W + x, w);
+ memcpy(dest + (i - y) * w, pagePtr + i * SCREEN_W * _pageScaleFactor[pageNum] + x, w);
}
void Screen::copyPage(uint8 srcPage, uint8 dstPage) {
+ // Since we don't (need to) do any actual scaling, we check for compatible pages here
+ assert(_pageScaleFactor[srcPage] == _pageScaleFactor[dstPage]);
+
uint8 *src = getPagePtr(srcPage);
uint8 *dst = getPagePtr(dstPage);
- memcpy(dst, src, SCREEN_W * SCREEN_H);
+ if (src != dst)
+ memcpy(dst, src, SCREEN_W * _pageScaleFactor[srcPage] * SCREEN_H * _pageScaleFactor[srcPage]);
copyOverlayRegion(0, 0, 0, 0, SCREEN_W, SCREEN_H, srcPage, dstPage);
if (dstPage == 0 || dstPage == 1)
@@ -875,7 +994,12 @@ void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint
if (w < 0 || h < 0)
return;
- uint8 *dst = getPagePtr(pageNum) + y * SCREEN_W + x;
+ x *= _pageScaleFactor[pageNum];
+ y *= _pageScaleFactor[pageNum];
+ w *= _pageScaleFactor[pageNum];
+ h *= _pageScaleFactor[pageNum];
+
+ uint8 *dst = getPagePtr(pageNum) + y * SCREEN_W * _pageScaleFactor[pageNum] + x;
if (pageNum == 0 || pageNum == 1)
addDirtyRect(x, y, w, h);
@@ -884,7 +1008,7 @@ void Screen::copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint
while (h--) {
memcpy(dst, src, w);
- dst += SCREEN_W;
+ dst += SCREEN_W * _pageScaleFactor[pageNum];
src += w;
}
}
@@ -960,6 +1084,10 @@ void Screen::fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum,
if (_use16ColorMode) {
color &= 0x0F;
color |= (color << 4);
+ } else if (_renderMode == Common::kRenderCGA) {
+ color &= 0x03;
+ } else if (_renderMode == Common::kRenderEGA) {
+ color &= 0x0F;
}
if (xored) {
@@ -1037,6 +1165,10 @@ void Screen::drawLine(bool vertical, int x, int y, int length, int color) {
if (_use16ColorMode) {
color &= 0x0F;
color |= (color << 4);
+ } else if (_renderMode == Common::kRenderCGA) {
+ color &= 0x03;
+ } else if (_renderMode == Common::kRenderEGA) {
+ color &= 0x0F;
}
if (vertical) {
@@ -1044,7 +1176,7 @@ void Screen::drawLine(bool vertical, int x, int y, int length, int color) {
int currLine = 0;
while (currLine < length) {
*ptr = color;
- ptr += SCREEN_W;
+ ptr += SCREEN_W * _pageScaleFactor[_curPage];
currLine++;
}
} else {
@@ -1088,6 +1220,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(_renderMode, _vm->gameFlags().useHiRes);
+#endif // ENABLE_EOB
else
fnt = new DOSFont();
@@ -1173,12 +1309,12 @@ void Screen::printText(const char *str, int x, int y, uint8 color1, uint8 color2
break;
} else if (c == '\r') {
x = x_start;
- y += charHeightFnt + _charOffset;
+ y += (charHeightFnt + _charOffset);
} else {
int charWidth = getCharWidth(c);
if (x + charWidth > SCREEN_W) {
x = x_start;
- y += charHeightFnt + _charOffset;
+ y += (charHeightFnt + _charOffset);
if (y >= SCREEN_H)
break;
}
@@ -1215,6 +1351,9 @@ void Screen::drawChar(uint16 c, int x, int y) {
if (x + charWidth > SCREEN_W || y + charHeight > SCREEN_H)
return;
+ x *= _pageScaleFactor[_curPage];
+ y *= _pageScaleFactor[_curPage];
+
if (useOverlay) {
uint8 *destPage = getOverlayPtr(_curPage);
if (!destPage) {
@@ -1226,11 +1365,11 @@ void Screen::drawChar(uint16 c, int x, int y) {
fnt->drawChar(c, destPage, 640);
} else {
- fnt->drawChar(c, getPagePtr(_curPage) + y * SCREEN_W + x, SCREEN_W);
+ fnt->drawChar(c, getPagePtr(_curPage) + y * SCREEN_W * _pageScaleFactor[_curPage] + x, SCREEN_W * _pageScaleFactor[_curPage]);
}
if (_curPage == 0 || _curPage == 1)
- addDirtyRect(x, y, charWidth, charHeight);
+ addDirtyRect(x, y, charWidth * _pageScaleFactor[_curPage], charHeight * _pageScaleFactor[_curPage]);
}
void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int sd, int flags, ...) {
@@ -1298,6 +1437,8 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int
if ((flags & 0x2000) && _vm->game() != GI_KYRA1)
_dsTable5 = va_arg(args, uint8 *);
+ va_end(args);
+
static const DsMarginSkipFunc dsMarginFunc[] = {
&Screen::drawShapeMarginNoScaleUpwind,
&Screen::drawShapeMarginNoScaleDownwind,
@@ -1383,7 +1524,6 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int
warning("Missing drawShape plotting method type %d", ppc);
if (dsPlot3 != dsPlot2 && !dsPlot3)
warning("Missing drawShape plotting method type %d", (((flags >> 8) & 0xF7) & 0x3F));
- va_end(args);
return;
}
@@ -1416,10 +1556,8 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int
shapeHeight = (shapeHeight * _dsScaleH) >> 8;
shpWidthScaled1 = shpWidthScaled2 = (shapeWidth * _dsScaleW) >> 8;
- if (!shapeHeight || !shpWidthScaled1) {
- va_end(args);
+ if (!shapeHeight || !shpWidthScaled1)
return;
- }
}
if (flags & DSF_CENTER) {
@@ -1449,7 +1587,6 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int
if (t < 0) {
shapeHeight += t;
if (shapeHeight <= 0) {
- va_end(args);
return;
}
@@ -1483,10 +1620,8 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int
}
t = (flags & 2) ? y + shapeHeight - y1 : y2 - y;
- if (t <= 0) {
- va_end(args);
+ if (t <= 0)
return;
- }
if (t < shapeHeight) {
shapeHeight = t;
@@ -1498,20 +1633,16 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int
if (x < 0) {
shpWidthScaled1 += x;
_dsOffscreenLeft = -x;
- if (_dsOffscreenLeft >= shpWidthScaled2) {
- va_end(args);
+ if (_dsOffscreenLeft >= shpWidthScaled2)
return;
- }
x = 0;
}
_dsOffscreenRight = 0;
t = x2 - x;
- if (t <= 0) {
- va_end(args);
+ if (t <= 0)
return;
- }
if (t < shpWidthScaled1) {
shpWidthScaled1 = t;
@@ -1591,8 +1722,6 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int
scaleCounterV -= 0x100;
} while (scaleCounterV & 0xFF00);
}
-
- va_end(args);
}
int Screen::drawShapeMarginNoScaleUpwind(uint8 *&dst, const uint8 *&src, int &cnt) {
@@ -1994,6 +2123,86 @@ void Screen::drawShapePlotType52(uint8 *dst, uint8 cmd) {
*dst = cmd;
}
+void Screen::decodeFrame1(const uint8 *src, uint8 *dst, uint32 size) {
+ const uint8 *dstEnd = dst + size;
+
+ struct Pattern {
+ const uint8 *pos;
+ uint16 len;
+ };
+
+ Pattern *patterns = new Pattern[3840];
+ uint16 numPatterns = 0;
+ uint8 nib = 0;
+
+ uint16 code = decodeEGAGetCode(src, nib);
+ uint8 last = code & 0xff;
+
+ uint8 *dstPrev = dst;
+ uint16 count = 1;
+ uint16 countPrev = 1;
+
+ *dst++ = last;
+
+ while (dst < dstEnd) {
+ code = decodeEGAGetCode(src, nib);
+ uint8 cmd = code >> 8;
+
+ if (cmd--) {
+ code = (cmd << 8) | (code & 0xff);
+ uint8 *tmpDst = dst;
+
+ if (code < numPatterns) {
+ const uint8 *tmpSrc = patterns[code].pos;
+ countPrev = patterns[code].len;
+ last = *tmpSrc;
+ for (int i = 0; i < countPrev; i++)
+ *dst++ = *tmpSrc++;
+
+ } else {
+ const uint8 *tmpSrc = dstPrev;
+ count = countPrev;
+ for (int i = 0; i < countPrev; i++)
+ *dst++ = *tmpSrc++;
+ *dst++ = last;
+ countPrev++;
+ }
+
+ if (numPatterns < 3840) {
+ patterns[numPatterns].pos = dstPrev;
+ patterns[numPatterns++].len = ++count;
+ }
+
+ dstPrev = tmpDst;
+ count = countPrev;
+
+ } else {
+ *dst++ = last = (code & 0xff);
+
+ if (numPatterns < 3840) {
+ patterns[numPatterns].pos = dstPrev;
+ patterns[numPatterns++].len = ++count;
+ }
+
+ dstPrev = dst - 1;
+ count = 1;
+ countPrev = 1;
+ }
+ }
+ delete[] patterns;
+}
+
+uint16 Screen::decodeEGAGetCode(const uint8 *&pos, uint8 &nib) {
+ uint16 res = READ_BE_UINT16(pos++);
+ if ((++nib) & 1) {
+ res >>= 4;
+ } else {
+ pos++;
+ res &= 0xfff;
+ }
+ return res;
+}
+
void Screen::decodeFrame3(const uint8 *src, uint8 *dst, uint32 size) {
const uint8 *dstEnd = dst + size;
while (dst < dstEnd) {
@@ -2070,7 +2279,7 @@ void Screen::decodeFrameDelta(uint8 *dst, const uint8 *src, bool noXor) {
wrapped_decodeFrameDelta<false>(dst, src);
}
-template <bool noXor>
+template<bool noXor>
void Screen::wrapped_decodeFrameDelta(uint8 *dst, const uint8 *src) {
while (1) {
uint8 code = *src++;
@@ -2683,21 +2892,20 @@ void Screen::setMouseCursor(int x, int y, const byte *shape) {
if (_vm->gameFlags().useAltShapeHeader)
shape -= 2;
- if (_vm->gameFlags().useHiResOverlay) {
+ if (_vm->gameFlags().useHiRes) {
x <<= 1;
y <<= 1;
mouseWidth <<= 1;
mouseHeight <<= 1;
}
-
uint8 *cursor = new uint8[mouseHeight * mouseWidth];
fillRect(0, 0, mouseWidth, mouseHeight, _cursorColorKey, 8);
drawShape(8, shape, 0, 0, 0, 0);
int xOffset = 0;
- if (_vm->gameFlags().useHiResOverlay) {
+ if (_vm->gameFlags().useHiRes) {
xOffset = mouseWidth;
scale2x(getPagePtr(8) + mouseWidth, SCREEN_W, getPagePtr(8), SCREEN_W, mouseWidth, mouseHeight);
postProcessCursor(getPagePtr(8) + mouseWidth, mouseWidth, mouseHeight, SCREEN_W);
@@ -2859,7 +3067,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)
@@ -2875,6 +3083,9 @@ void Screen::loadBitmap(const char *filename, int tempPage, int dstPage, Palette
case 0:
memcpy(dstData, srcPtr, imgSize);
break;
+ case 1:
+ Screen::decodeFrame1(srcPtr, dstData, imgSize);
+ break;
case 3:
Screen::decodeFrame3(srcPtr, dstData, imgSize);
break;
@@ -2899,6 +3110,9 @@ void Screen::loadBitmap(const char *filename, int tempPage, int dstPage, Palette
}
bool Screen::loadPalette(const char *filename, Palette &pal) {
+ if (_renderMode == Common::kRenderCGA)
+ return true;
+
Common::SeekableReadStream *stream = _vm->resource()->createReadStream(filename);
if (!stream)
@@ -2915,6 +3129,12 @@ bool Screen::loadPalette(const char *filename, Palette &pal) {
} else if (_vm->gameFlags().platform == Common::kPlatformPC98 && _use16ColorMode) {
numCols = stream->size() / Palette::kPC98BytesPerColor;
pal.loadPC98Palette(*stream, 0, MIN(maxCols, numCols));
+ } else if (_renderMode == Common::kRenderEGA) {
+ numCols = stream->size();
+ // There aren't any 16 color EGA palette files. So this shouldn't ever get triggered.
+ assert (numCols != 16);
+ numCols /= Palette::kVGABytesPerColor;
+ pal.loadVGAPalette(*stream, 0, numCols);
} else {
numCols = stream->size() / Palette::kVGABytesPerColor;
pal.loadVGAPalette(*stream, 0, MIN(maxCols, numCols));
@@ -2962,7 +3182,14 @@ void Screen::loadPalette(const byte *data, Palette &pal, int bytes) {
pal.loadAmigaPalette(stream, 0, stream.size() / Palette::kAmigaBytesPerColor);
else if (_vm->gameFlags().platform == Common::kPlatformPC98 && _use16ColorMode)
pal.loadPC98Palette(stream, 0, stream.size() / Palette::kPC98BytesPerColor);
- else
+ else if (_renderMode == Common::kRenderEGA) {
+ // EOB II checks the number of palette bytes to distinguish between real EGA palettes
+ // and normal palettes (which are used to generate a color map).
+ if (stream.size() == 16)
+ pal.loadEGAPalette(stream, 0, stream.size());
+ else
+ pal.loadVGAPalette(stream, 0, stream.size() / Palette::kVGABytesPerColor);
+ } else
pal.loadVGAPalette(stream, 0, stream.size() / Palette::kVGABytesPerColor);
}
@@ -2977,7 +3204,7 @@ void Screen::addDirtyRect(int x, int y, int w, int h) {
Common::Rect r(x, y, x + w, y + h);
// Clip rectangle
- r.clip(SCREEN_W, SCREEN_H);
+ r.clip(SCREEN_W * _pageScaleFactor[0], SCREEN_H * _pageScaleFactor[0]);
// If it is empty after clipping, we are done
if (r.isEmpty())
@@ -3080,6 +3307,59 @@ void Screen::copyOverlayRegion(int x, int y, int x2, int y2, int w, int h, int s
}
}
+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.");
+
+ assert(_pageScaleFactor[srcPage] == _pageScaleFactor[dstPage]);
+
+ 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]);
+
+ for (int i = 0; i < h; i++) {
+ int iH = i;
+ uint32 end = _system->getMillis() + 3;
+ 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;
+
+ setPagePixel(dstPage, dX, dY, getPagePixel(srcPage, sX, sY));
+ }
+
+ // This tries to speed things up, to get similiar speeds as in DOSBox etc.
+ // We can't write single pixels directly into the video memory like the original did.
+ // We also (unlike the original) want to aim at similiar speeds for all platforms.
+ if (!(i % 10))
+ updateScreen();
+
+ uint32 cur = _system->getMillis();
+ if (end > cur)
+ _system->delayMillis(end - cur);
+ }
+
+ updateScreen();
+ showMouse();
+}
+
#pragma mark -
DOSFont::DOSFont() {
@@ -3379,7 +3659,27 @@ Palette::~Palette() {
void Palette::loadVGAPalette(Common::ReadStream &stream, int startIndex, int colors) {
assert(startIndex + colors <= _numColors);
- stream.read(_palData + startIndex * 3, colors * 3);
+ uint8 *pos = _palData + startIndex * 3;
+ for (int i = 0 ; i < colors * 3; i++)
+ *pos++ = stream.readByte() & 0x3f;
+}
+
+void Palette::loadEGAPalette(Common::ReadStream &stream, int startIndex, int colors) {
+ assert(startIndex + colors <= 16);
+
+ uint8 *dst = _palData + startIndex * 3;
+ for (int i = 0; i < colors; i++) {
+ uint8 index = stream.readByte();
+ assert(index < _egaNumColors);
+ memcpy(dst, &_egaColors[index * 3], 3);
+ dst += 3;
+ }
+}
+
+void Palette::setCGAPalette(int palIndex, CGAIntensity intensity) {
+ assert(_numColors >= _cgaNumColors);
+ assert(!(palIndex & ~1));
+ memcpy(_palData, _cgaColors[palIndex * 2 + intensity], _numColors * 3);
}
void Palette::loadAmigaPalette(Common::ReadStream &stream, int startIndex, int colors) {
@@ -3458,4 +3758,22 @@ uint8 *Palette::fetchRealPalette() const {
return buffer;
}
+const uint8 Palette::_egaColors[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0x00, 0xAA, 0xAA,
+ 0xAA, 0x00, 0x00, 0xAA, 0x00, 0xAA, 0xAA, 0x55, 0x00, 0xAA, 0xAA, 0xAA,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0x55, 0x55, 0xFF, 0xFF,
+ 0xFF, 0x55, 0x55, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF
+};
+
+const int Palette::_egaNumColors = ARRAYSIZE(_egaColors) / 3;
+
+const uint8 Palette::_cgaColors[4][12] = {
+ { 0x00, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x2A, 0x00, 0x00, 0x2A, 0x15, 0x00 },
+ { 0x00, 0x00, 0x00, 0x15, 0x3F, 0x15, 0x3F, 0x15, 0x15, 0x3F, 0x3F, 0x15 },
+ { 0x00, 0x00, 0x00, 0x00, 0x2A, 0x2A, 0x2A, 0x00, 0x2A, 0x2A, 0x2A, 0x2A },
+ { 0x00, 0x00, 0x00, 0x15, 0x3F, 0x3F, 0x3F, 0x15, 0x3F, 0x3F, 0x3F, 0x3F }
+};
+
+const int Palette::_cgaNumColors = ARRAYSIZE(_cgaColors[0]) / 3;
+
} // End of namespace Kyra
diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h
index 51a9a7f744..b064c72bb0 100644
--- a/engines/kyra/screen.h
+++ b/engines/kyra/screen.h
@@ -28,6 +28,7 @@
#include "common/list.h"
#include "common/array.h"
#include "common/rect.h"
+#include "common/rendermode.h"
#include "common/stream.h"
class OSystem;
@@ -137,6 +138,44 @@ 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(Common::RenderMode mode, bool useHiResEGADithering);
+ ~OldDOSFont();
+
+ 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;
+
+ Common::RenderMode _renderMode;
+ bool _useHiResEGADithering;
+ bool _useLoResEGA;
+
+ static uint16 *_cgaDitheringTable;
+ static int _numRef;
+};
+#endif // ENABLE_EOB
+
/**
* Implementation of the Font interface for AMIGA fonts.
*/
@@ -221,6 +260,21 @@ public:
void loadVGAPalette(Common::ReadStream &stream, int startIndex, int colors);
/**
+ * Load a EGA palette from the given stream.
+ */
+ void loadEGAPalette(Common::ReadStream &stream, int startIndex, int colors);
+
+ /**
+ * Set default CGA palette. We only need the cyan/magenta/grey mode.
+ */
+ enum CGAIntensity {
+ kIntensityLow = 0,
+ kIntensityHigh = 1
+ };
+
+ void setCGAPalette(int palIndex, CGAIntensity intensity);
+
+ /**
* Load a AMIGA palette from the given stream.
*/
void loadAmigaPalette(Common::ReadStream &stream, int startIndex, int colors);
@@ -294,9 +348,15 @@ public:
*/
uint8 *getData() { return _palData; }
const uint8 *getData() const { return _palData; }
+
private:
uint8 *_palData;
const int _numColors;
+
+ static const uint8 _egaColors[];
+ static const int _egaNumColors;
+ static const uint8 _cgaColors[4][12];
+ static const int _cgaNumColors;
};
class Screen {
@@ -335,7 +395,7 @@ public:
FID_NUM
};
- Screen(KyraEngine_v1 *vm, OSystem *system);
+ Screen(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, const int dimTableSize);
virtual ~Screen();
// init
@@ -367,12 +427,12 @@ public:
void copyBlockToPage(int pageNum, int x, int y, int w, int h, const uint8 *src);
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);
+ virtual void fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum = -1, bool xored = false);
void clearPage(int pageNum);
- uint8 getPagePixel(int pageNum, int x, int y);
- void setPagePixel(int pageNum, int x, int y, uint8 color);
+ virtual uint8 getPagePixel(int pageNum, int x, int y);
+ virtual void setPagePixel(int pageNum, int x, int y, uint8 color);
const uint8 *getCPagePtr(int pageNum) const;
uint8 *getPageRect(int pageNum, int x, int y, int w, int h);
@@ -393,12 +453,12 @@ public:
void enableInterfacePalette(bool e);
void setInterfacePalette(const Palette &pal, uint8 r, uint8 g, uint8 b);
- void getRealPalette(int num, uint8 *dst);
+ virtual void getRealPalette(int num, uint8 *dst);
Palette &getPalette(int num);
void copyPalette(const int dst, const int src);
// gui specific (processing on _curPage)
- void drawLine(bool vertical, int x, int y, int length, int color);
+ virtual void drawLine(bool vertical, int x, int y, int length, int color);
void drawClippedLine(int x1, int y1, int x2, int y2, int color);
virtual void drawShadedBox(int x1, int y1, int x2, int y2, int color1, int color2);
void drawBox(int x1, int y1, int x2, int y2, int color);
@@ -413,14 +473,17 @@ public:
int getCharWidth(uint16 c) const;
int getTextWidth(const char *str) const;
- void printText(const char *str, int x, int y, uint8 color1, uint8 color2);
+ virtual void printText(const char *str, int x, int y, uint8 color1, uint8 color2);
virtual void setTextColorMap(const uint8 *cmap) = 0;
void setTextColor(const uint8 *cmap, int a, int b);
- virtual void setScreenDim(int dim) = 0;
- virtual const ScreenDim *getScreenDim(int dim) = 0;
- virtual int screenDimTableCount() const = 0;
+ const ScreenDim *getScreenDim(int dim) const;
+ void modifyScreenDim(int dim, int x, int y, int w, int h);
+ int screenDimTableCount() const { return _dimTableCount; }
+
+ void setScreenDim(int dim);
+ int curDimIndex() const { return _curDimIndex; }
const ScreenDim *_curDim;
@@ -430,13 +493,13 @@ 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 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;
@@ -446,9 +509,9 @@ public:
// misc
void loadBitmap(const char *filename, int tempPage, int dstPage, Palette *pal, bool skip=false);
- bool loadPalette(const char *filename, Palette &pal);
+ virtual bool loadPalette(const char *filename, Palette &pal);
bool loadPaletteTable(const char *filename, int firstPalette);
- void loadPalette(const byte *data, Palette &pal, int bytes);
+ virtual void loadPalette(const byte *data, Palette &pal, int bytes);
void setAnimBlockPtr(int size);
@@ -471,6 +534,9 @@ public:
FontId _currentFont;
// decoding functions
+ static void decodeFrame1(const uint8 *src, uint8 *dst, uint32 size);
+ static uint16 decodeEGAGetCode(const uint8 *&pos, uint8 &nib);
+
static void decodeFrame3(const uint8 *src, uint8 *dst, uint32 size);
static uint decodeFrame4(const uint8 *src, uint8 *dst, uint32 dstSize);
static void decodeFrameDelta(uint8 *dst, const uint8 *src, bool noXor = false);
@@ -479,6 +545,9 @@ public:
static void convertAmigaGfx(uint8 *data, int w, int h, int depth = 5, bool wsa = false, int bytesPerPlane = -1);
static void convertAmigaMsc(uint8 *data);
+ // RPG specific, this does not belong here
+ void crossFadeRegion(int x1, int y1, int x2, int y2, int w, int h, int srcPage, int dstPage);
+
protected:
uint8 *getPagePtr(int pageNum);
void updateDirtyRects();
@@ -505,11 +574,16 @@ protected:
uint8 *_pagePtrs[16];
uint8 *_sjisOverlayPtrs[SCREEN_OVLS_NUM];
+ uint8 _pageScaleFactor[SCREEN_PAGE_NUM];
+ uint8 _pageMapping[SCREEN_PAGE_NUM];
bool _useOverlays;
bool _useSJIS;
bool _use16ColorMode;
+ bool _useHiResEGADithering;
+ bool _useLoResEGA;
bool _isAmiga;
+ Common::RenderMode _renderMode;
uint8 _sjisInvisibleColor;
@@ -526,6 +600,12 @@ protected:
uint8 *_animBlockPtr;
int _animBlockSize;
+ // dimension handling
+ const ScreenDim * const _dimTable;
+ ScreenDim **_customDimTable;
+ const int _dimTableCount;
+ int _curDimIndex;
+
// mouse handling
int _mouseLockCount;
const uint8 _cursorColorKey;
diff --git a/engines/kyra/screen_eob.cpp b/engines/kyra/screen_eob.cpp
new file mode 100644
index 0000000000..e06ca42c40
--- /dev/null
+++ b/engines/kyra/screen_eob.cpp
@@ -0,0 +1,1781 @@
+/* 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"
+#include "graphics/palette.h"
+
+namespace Kyra {
+
+Screen_EoB::Screen_EoB(EoBCoreEngine *vm, OSystem *system) : Screen(vm, system, _screenDimTable, _screenDimTableCount) {
+ _shapeFadeMode[0] = _shapeFadeMode[1] = 0;
+ _shapeFadeInternal = 0;
+ _fadeData = 0;
+ _fadeDataIndex = 0;
+ _dsX1 = _dsX2 = _dsY1 = _dsY2 = 0;
+ _gfxX = _gfxY = 0;
+ _gfxCol = 0;
+ _dsTempPage = 0;
+ _dsDiv = 0;
+ _dsRem = 0;
+ _dsScaleTrans = 0;
+ _cgaScaleTable = 0;
+ _gfxMaxY = 0;
+ _egaDitheringTable = 0;
+ _egaPixelValueTable = 0;
+ _cgaMappingDefault = 0;
+ _cgaDitheringTables[0] = _cgaDitheringTables[1] = 0;
+ _useLoResEGA = _useHiResEGADithering = false;
+}
+
+Screen_EoB::~Screen_EoB() {
+ delete[] _fadeData;
+ delete[] _dsTempPage;
+ delete[] _cgaScaleTable;
+ delete[] _egaDitheringTable;
+ delete[] _egaPixelValueTable;
+ delete[] _cgaDitheringTables[0];
+ delete[] _cgaDitheringTables[1];
+}
+
+bool Screen_EoB::init() {
+ // Define hi-res pages for EGA mode in EOB II
+ if (_vm->gameFlags().useHiRes) {
+ for (int i = 0; i < 8; i++)
+ _pageScaleFactor[i] = 2;
+ }
+
+ if (Screen::init()) {
+ int temp;
+ _gfxMaxY = _vm->staticres()->loadRawData(kEoBBaseExpObjectY, temp);
+
+ if (_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA)
+ _fadeData = _vm->resource()->fileData("FADING.DAT", 0);
+
+ if (!_fadeData) {
+ _fadeData = new uint8[0x700];
+ memset(_fadeData, 0, 0x700);
+ if (_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) {
+ uint8 *pal = _vm->resource()->fileData("PALETTE1.PAL", 0);
+ for (int i = 0; i < 7; i++)
+ createFadeTable(pal, &_fadeData[i << 8], 18, (i + 1) * 36);
+ delete[] pal;
+ }
+ }
+
+ _dsTempPage = new uint8[12000];
+
+ if (_vm->gameFlags().useHiRes && _renderMode == Common::kRenderEGA) {
+ _useHiResEGADithering = true;
+ _egaDitheringTable = new uint8[256];
+ _egaPixelValueTable = new uint8[256];
+ for (int i = 0; i < 256; i++) {
+ _egaDitheringTable[i] = i & 0x0f;
+ _egaPixelValueTable[i] = i & 0x0f;
+ }
+ } else if (_renderMode == Common::kRenderEGA) {
+ _useLoResEGA = true;
+ } else if (_renderMode == Common::kRenderCGA) {
+ _cgaMappingDefault = _vm->staticres()->loadRawData(kEoB1CgaMappingDefault, temp);
+ _cgaDitheringTables[0] = new uint16[256];
+ memset(_cgaDitheringTables[0], 0, 256 * sizeof(uint16));
+ _cgaDitheringTables[1] = new uint16[256];
+ memset(_cgaDitheringTables[1], 0, 256 * sizeof(uint16));
+
+ _cgaScaleTable = new uint8[256];
+ memset(_cgaScaleTable, 0, 256 * sizeof(uint8));
+ for (int i = 0; i < 256; i++)
+ _cgaScaleTable[i] = ((i & 0xf0) >> 2) | (i & 0x03);
+ }
+
+ return true;
+ }
+ return false;
+}
+
+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) {
+ setMouseCursor(x, y, shape, 0);
+}
+
+void Screen_EoB::setMouseCursor(int x, int y, const byte *shape, const uint8 *ovl) {
+ if (!shape)
+ return;
+
+ int mouseW = (shape[2] << 3);
+ int mouseH = (shape[3]);
+ int colorKey = (_renderMode == Common::kRenderCGA) ? 0 : _cursorColorKey;
+
+ uint8 *cursor = new uint8[mouseW * _pageScaleFactor[6] * mouseH * _pageScaleFactor[6]];
+ // We use memset and copyBlockToPage instead of fillRect to make sure that the
+ // color key 0xFF doesn't get converted into EGA color
+ memset(cursor, colorKey, mouseW * _pageScaleFactor[6] * mouseH * _pageScaleFactor[6]);
+ copyBlockToPage(6, 0, 0, mouseW, mouseH, cursor);
+ drawShape(6, shape, 0, 0, 0, 2, ovl);
+ CursorMan.showMouse(false);
+ copyRegionToBuffer(6, 0, 0, mouseW, mouseH, cursor);
+
+ // Mouse cursor post processing for CGA mode. Unlike the original (which uses drawShape for the mouse cursor)
+ // the cursor manager cannot know whether a pixel value of 0 is supposed to be black or transparent. Thus, we
+ // go over the transparency mask again and turn the black pixels to color 4.
+ if (_renderMode == Common::kRenderCGA) {
+ const uint8 *maskTbl = shape + 4 + ((mouseW * mouseH) >> 2);
+ uint8 *dst = cursor;
+ uint8 trans = 0;
+ uint8 shift = 6;
+
+ uint16 mH = mouseH;
+ while (mH--) {
+ uint16 mW = mouseW;
+ while (mW--) {
+ if (shift == 6)
+ trans = *maskTbl++;
+ if (!*dst && !((trans >> shift) & 3))
+ *dst = 4;
+ dst++;
+ shift = (shift - 2) & 7;
+ }
+ }
+ }
+
+ CursorMan.replaceCursor(cursor, mouseW * _pageScaleFactor[6], mouseH * _pageScaleFactor[6], x, y, colorKey);
+ 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::printText(const char *str, int x, int y, uint8 color1, uint8 color2) {
+ if (_useHiResEGADithering) {
+ // This is sort of an abuse of the text color map. But since EOB doesn't use it anyway
+ // and the font drawing code needs access to both the original color values and the
+ // EGA dithering colors we pass them on like this.
+ uint8 cmap[2];
+ cmap[0] = _egaDitheringTable[color2];
+ cmap[1] = _egaDitheringTable[color1];
+ setTextColor(cmap, 2, 3);
+ }
+ Screen::printText(str, x, y, color1, color2);
+}
+
+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::loadShapeSetBitmap(const char *file, int tempPage, int destPage) {
+ loadEoBBitmap(file, _cgaMappingDefault, tempPage, destPage, -1);
+ _curPage = 2;
+}
+
+void Screen_EoB::loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage) {
+ const char *filePattern = (_vm->game() == GI_EOB1 && (_renderMode == Common::kRenderEGA || _renderMode == Common::kRenderCGA)) ? "%s.EGA" : "%s.CPS";
+ Common::String tmp = Common::String::format(filePattern, 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.c_str(), tempPage, destPage, 0);
+ else
+ loadAlternative = true;
+
+ delete s;
+ } else {
+ loadAlternative = true;
+ }
+
+ if (loadAlternative) {
+ if (_vm->game() == GI_EOB1) {
+ tmp.insertChar('1', tmp.size() - 4);
+ loadBitmap(tmp.c_str(), tempPage, destPage, 0);
+ } else {
+ tmp.setChar('X', 0);
+ s = _vm->resource()->createReadStream(tmp);
+ if (!s)
+ error("Screen_EoB::loadEoBBitmap(): Failed to load file '%s'", file);
+ s->seek(768);
+ loadFileDataToPage(s, destPage, 64000);
+ delete s;
+ }
+ }
+
+ if (convertToPage == -1) {
+ return;
+ } else if (convertToPage == 2 && _renderMode == Common::kRenderCGA) {
+ convertPage(destPage, 4, cgaMapping);
+ copyRegion(0, 0, 0, 0, 320, 200, 4, 2, Screen::CR_NO_P_CHECK);
+ } else if (convertToPage == 0) {
+ convertPage(destPage, 2, cgaMapping);
+ copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ convertPage(destPage, convertToPage, cgaMapping);
+ }
+}
+
+void Screen_EoB::convertPage(int srcPage, int dstPage, const uint8 *cgaMapping) {
+ uint8 *src = getPagePtr(srcPage);
+ uint8 *dst = getPagePtr(dstPage);
+ if (src == dst)
+ return;
+
+ if (_renderMode == Common::kRenderCGA) {
+ if (cgaMapping)
+ generateCGADitheringTables(cgaMapping);
+
+ uint16 *d = (uint16*)dst;
+ uint8 tblSwitch = 0;
+ for (int height = SCREEN_H; height; height--) {
+ const uint16 *table = _cgaDitheringTables[(tblSwitch++) & 1];
+ for (int width = SCREEN_W / 2; width; width--) {
+ WRITE_LE_UINT16(d++, table[((src[1] & 0x0f) << 4) | (src[0] & 0x0f)]);
+ src += 2;
+ }
+ }
+
+ } else if (_useHiResEGADithering) {
+ for (int height = SCREEN_H; height; height--) {
+ uint8 *dst2 = dst + SCREEN_W * 2;
+ for (int width = SCREEN_W; width; width--) {
+ uint8 in = _egaDitheringTable[*src++];
+ *dst++ = *dst2++ = in >> 4;
+ *dst++ = *dst2++ = in & 0x0f;
+ }
+ dst += (SCREEN_W * 2);
+ }
+
+ } else if (_renderMode == Common::kRenderEGA) {
+ uint32 len = SCREEN_W * SCREEN_H;
+ while (len--)
+ *dst++ = *src++ & 0x0f;
+
+ } else {
+ copyPage(srcPage, dstPage);
+ }
+
+ if (dstPage == 0 || dstPage == 1)
+ _forceFullUpdate = true;
+}
+
+void Screen_EoB::fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum, bool xored) {
+ if (!_useHiResEGADithering) {
+ Screen::fillRect(x1, y1, x2, y2, color, pageNum, xored);
+ return;
+ }
+
+ assert(x2 < SCREEN_W && y2 < SCREEN_H);
+ if (pageNum == -1)
+ pageNum = _curPage;
+
+ uint16 pitch = (SCREEN_W - (x2 - x1 + 1)) * _pageScaleFactor[pageNum];
+ uint8 col1 = (_egaDitheringTable[color] >> 4);
+ uint8 col2 = (_egaDitheringTable[color] & 0x0f);
+
+ x1 *= _pageScaleFactor[pageNum];
+ y1 *= _pageScaleFactor[pageNum];
+ x2 *= _pageScaleFactor[pageNum];
+ y2 *= _pageScaleFactor[pageNum];
+ uint16 w = x2 - x1 + _pageScaleFactor[pageNum];
+ uint16 h = y2 - y1 + _pageScaleFactor[pageNum];
+
+ uint8 *dst = getPagePtr(pageNum) + y1 * SCREEN_W * _pageScaleFactor[pageNum] + x1;
+ if (pageNum == 0 || pageNum == 1)
+ addDirtyRect(x1, y1, w, h);
+
+ while (h--) {
+ for (uint16 w1 = w; w1; w1 -= 2) {
+ *dst++ = col1;
+ *dst++ = col2;
+ }
+ dst += pitch;
+ }
+}
+
+void Screen_EoB::drawLine(bool vertical, int x, int y, int length, int color) {
+ if (!_useHiResEGADithering) {
+ Screen::drawLine(vertical, x, y, length, color);
+ return;
+ }
+
+ uint16 pitch = (SCREEN_W - 1) * _pageScaleFactor[_curPage];
+ uint8 col1 = (_egaDitheringTable[color] >> 4);
+ uint8 col2 = (_egaDitheringTable[color] & 0x0f);
+
+ x *= _pageScaleFactor[_curPage];
+ y *= _pageScaleFactor[_curPage];
+ length *= _pageScaleFactor[_curPage];
+ uint8 *ptr = getPagePtr(_curPage) + y * SCREEN_W * _pageScaleFactor[_curPage] + x;
+ uint8 *ptr2 = ptr + SCREEN_W * _pageScaleFactor[_curPage];
+
+ if (vertical) {
+ assert((y + length) <= SCREEN_H * _pageScaleFactor[_curPage]);
+ int currLine = 0;
+ while (currLine < length) {
+ *ptr++ = col1;
+ *ptr++ = col2;
+ ptr += pitch;
+ currLine++;
+ }
+ } else {
+ assert((x + length) <= SCREEN_W * _pageScaleFactor[_curPage]);
+ int currLine = 0;
+ while (currLine < length) {
+ *ptr++ = *ptr2++ = col1;
+ *ptr++ = *ptr2++ = col2;
+ currLine += 2;
+ }
+ }
+
+ if (_curPage == 0 || _curPage == 1)
+ addDirtyRect(x, y, (vertical) ? _pageScaleFactor[_curPage] : length, (vertical) ? length : _pageScaleFactor[_curPage]);
+}
+
+uint8 Screen_EoB::getPagePixel(int pageNum, int x, int y) {
+ if (!_useHiResEGADithering)
+ return Screen::getPagePixel(pageNum, x, y);
+
+ x *= _pageScaleFactor[_curPage];
+ y *= _pageScaleFactor[_curPage];
+ uint8 *pos = &_pagePtrs[pageNum][y * SCREEN_W * _pageScaleFactor[_curPage] + x];
+
+ return _egaPixelValueTable[(pos[0] << 4) | (pos[1] & 0x0f)];
+}
+
+void Screen_EoB::setPagePixel(int pageNum, int x, int y, uint8 color) {
+ if (!_useHiResEGADithering) {
+ Screen::setPagePixel(pageNum, x, y, color);
+ return;
+ }
+
+ assert(pageNum < SCREEN_PAGE_NUM);
+ assert(x >= 0 && x < SCREEN_W && y >= 0 && y < SCREEN_H);
+
+ x *= _pageScaleFactor[_curPage];
+ y *= _pageScaleFactor[_curPage];
+
+ if (pageNum == 0 || pageNum == 1)
+ addDirtyRect(x, y, _pageScaleFactor[pageNum], _pageScaleFactor[pageNum]);
+
+ uint8 *pos = &_pagePtrs[pageNum][y * SCREEN_W * _pageScaleFactor[_curPage] + x];
+ uint8 *pos2 = pos + SCREEN_W * _pageScaleFactor[_curPage];
+ pos[0] = pos2[0] = _egaDitheringTable[color] >> 4;
+ pos[1] = pos2[1] = _egaDitheringTable[color] & 0x0f;
+}
+
+void Screen_EoB::setScreenPalette(const Palette &pal) {
+ if (_useHiResEGADithering && pal.getNumColors() != 16) {
+ generateEGADitheringTable(pal);
+ } else if (_renderMode == Common::kRenderEGA && pal.getNumColors() == 16) {
+ _screenPalette->copy(pal);
+ _system->getPaletteManager()->setPalette(_screenPalette->getData(), 0, _screenPalette->getNumColors());
+ } else if (_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) {
+ Screen::setScreenPalette(pal);
+ }
+}
+
+void Screen_EoB::getRealPalette(int num, uint8 *dst) {
+ if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) {
+ const uint8 *pal = _screenPalette->getData();
+ for (int i = 0; i < 16; ++i) {
+ dst[0] = (pal[0] << 2) | (pal[0] & 3);
+ dst[1] = (pal[1] << 2) | (pal[1] & 3);
+ dst[2] = (pal[2] << 2) | (pal[2] & 3);
+ dst += 3;
+ pal += 3;
+ }
+ } else {
+ Screen::getRealPalette(num, dst);
+ }
+}
+
+uint8 *Screen_EoB::encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool encode8bit, const uint8 *cgaMapping) {
+ uint8 *shp = 0;
+ uint16 shapesize = 0;
+
+ uint8 *srcLineStart = getPagePtr(_curPage | 1) + y * 320 + (x << 3);
+ uint8 *src = srcLineStart;
+
+ if (_useLoResEGA)
+ encode8bit = false;
+
+ if (_renderMode == Common::kRenderCGA) {
+ if (cgaMapping)
+ generateCGADitheringTables(cgaMapping);
+ shapesize = h * (w << 2) + 4;
+ shp = new uint8[shapesize];
+ memset(shp, 0, shapesize);
+ uint8 *dst = shp;
+
+ *dst++ = 4;
+ *dst++ = (h & 0xff);
+ *dst++ = (w & 0xff);
+ *dst++ = (h & 0xff);
+
+ uint8 *dst2 = dst + (h * (w << 1));
+
+ uint8 tblSwitch = 0;
+ uint16 h1 = h;
+ while (h1--) {
+ uint16 w1 = w << 1;
+ const uint16 *table = _cgaDitheringTables[(tblSwitch++) & 1];
+
+ while (w1--) {
+ uint16 p0 = table[((src[1] & 0x0f) << 4) | (src[0] & 0x0f)];
+ uint16 p1 = table[((src[3] & 0x0f) << 4) | (src[2] & 0x0f)];
+
+ *dst++ = ((p0 & 0x0003) << 6) | ((p0 & 0x0300) >> 4) | ((p1 & 0x0003) << 2) | ((p1 & 0x0300) >> 8);
+
+ uint8 msk = 0;
+ for (int i = 0; i < 4; i++) {
+ if (!src[3 - i])
+ msk |= (3 << (i << 1));
+ }
+ *dst2++ = msk;
+ src += 4;
+ }
+ srcLineStart += SCREEN_W;
+ src = srcLineStart;
+ }
+
+ } else if (encode8bit) {
+ 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);
+
+ srcLineStart += SCREEN_W;
+ src = srcLineStart;
+ }
+
+ shapesize += 4;
+
+ shp = new uint8[shapesize];
+ memset(shp, 0, shapesize);
+ uint8 *dst = shp;
+
+ *dst++ = 8;
+ *dst++ = (h & 0xff);
+ *dst++ = (w & 0xff);
+ *dst++ = (h & 0xff);
+
+ srcLineStart = getPagePtr(_curPage | 1) + y * 320 + (x << 3);
+ src = srcLineStart;
+
+ h1 = h;
+ while (h1--) {
+ uint8 *lineEnd = src + (w << 3);
+ do {
+ uint8 val = *src++;
+ if (!val) {
+ *dst++ = 0;
+ uint8 *startZeroPos = src;
+
+ while (src != lineEnd && *src == 0)
+ src++;
+
+ uint16 numZero = src - startZeroPos + 1;
+ if (numZero >> 8) {
+ *dst++ = 255;
+ *dst++ = 0;
+ numZero -= 255;
+ }
+ val = numZero & 0xff;
+ }
+ *dst++ = val;
+ } while (src != lineEnd);
+
+ srcLineStart += SCREEN_W;
+ src = srcLineStart;
+ }
+
+ } else {
+ uint8 nib = 0, col = 0;
+ uint8 *colorMap = 0;
+
+ if (_renderMode != Common::kRenderEGA || _useHiResEGADithering) {
+ colorMap = new uint8[0x100];
+ memset(colorMap, 0xff, 0x100);
+ }
+
+ shapesize = h * (w << 2) + 20;
+ shp = new uint8[shapesize];
+ memset(shp, 0, shapesize);
+ uint8 *dst = shp;
+
+ *dst++ = 2;
+ *dst++ = (h & 0xff);
+ *dst++ = (w & 0xff);
+ *dst++ = (h & 0xff);
+
+ if (_useLoResEGA) {
+ for (int i = 0; i < 16; i++)
+ dst[i] = i;
+ } else {
+ memset(dst, 0xff, 0x10);
+ }
+
+ uint8 *pal = dst;
+ dst += 16;
+ nib = col = 0;
+
+ uint16 h1 = h;
+ while (h1--) {
+ uint16 w1 = w << 3;
+ while (w1--) {
+ uint8 s = *src++;
+ uint8 c = s & 0x0f;
+ if (colorMap) {
+ 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;
+ }
+ srcLineStart += SCREEN_W;
+ src = srcLineStart;
+ }
+ 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) * _pageScaleFactor[pageNum];
+ int16 dX = x - (_dsX1 << 3);
+ int16 dY = y;
+ int16 dW = _dsX2 - _dsX1;
+ uint8 pixelsPerByte = *src++ ;
+
+ uint16 dH = *src++;
+ uint16 width = (*src++) << 3;
+ uint16 transOffset = (pixelsPerByte == 4) ? (dH * width) >> 2 : 0;
+ 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 (pixelsPerByte == 8) {
+ uint16 marginLeft = 0;
+ uint16 marginRight = 0;
+
+ if (d < 0) {
+ dH += d;
+ if (dH <= 0)
+ return;
+ d = -d;
+
+ for (int i = 0; i < d; i++) {
+ marginLeft = width;
+ for (int ii = 0; ii < marginLeft; ii++) {
+ if (!*src++)
+ marginLeft = marginLeft + 1 - *src++;
+ }
+ }
+ 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 += (dY * SCREEN_W * _pageScaleFactor[pageNum] * _pageScaleFactor[pageNum] + dX * _pageScaleFactor[pageNum]);
+ uint8 *dstL = dst;
+
+ if (pageNum == 0 || pageNum == 1)
+ addDirtyRect(rX * _pageScaleFactor[pageNum], rY * _pageScaleFactor[pageNum], rW * _pageScaleFactor[pageNum], rH * _pageScaleFactor[pageNum]);
+
+ while (dH--) {
+ int16 xpos = (int16) marginLeft;
+
+ if (flags & 1) {
+ for (int i = 0; i < w2; i++) {
+ if (*src++ == 0) {
+ i += (*src - 1);
+ src += (*src - 1);
+ }
+ }
+ src--;
+ }
+ const uint8 *src2 = src;
+
+ if (xpos) {
+ do {
+ uint8 val = (flags & 1) ? *(src - 1) : *src;
+ while (val && xpos) {
+ src += pixelStep;
+ xpos--;
+ val = (flags & 1) ? *(src - 1) : *src;
+ }
+
+ val = (flags & 1) ? *(src - 1) : *src;
+ if (!val) {
+ src += pixelStep;
+ uint8 bt = (flags & 1) ? src[1] : src[0];
+ src += pixelStep;
+ xpos = xpos - bt;
+ }
+ } while (xpos > 0);
+ }
+
+ dst -= (xpos * _pageScaleFactor[pageNum]);
+ xpos += width;
+
+ while (xpos > 0) {
+ uint8 c = *src;
+ uint8 m = (flags & 1) ? *(src - 1) : c;
+ src += pixelStep;
+
+ if (m) {
+ drawShapeSetPixel(dst, c, SCREEN_W * _pageScaleFactor[pageNum]);
+ dst += _pageScaleFactor[pageNum];
+ xpos--;
+ } else {
+ uint8 len = (flags & 1) ? src[1] : src[0];
+ dst += (len * _pageScaleFactor[pageNum]);
+ xpos -= len;
+ src += pixelStep;
+ }
+ }
+ xpos += marginRight;
+
+ if (xpos) {
+ do {
+ uint8 val = (flags & 1) ? *(src - 1) : *src;
+ while (val && xpos) {
+ src += pixelStep;
+ xpos--;
+ val = (flags & 1) ? *(src - 1) : *src;
+ }
+
+ val = (flags & 1) ? *(src - 1) : *src;
+ if (!val) {
+ src += pixelStep;
+ uint8 bt = (flags & 1) ? src[1] : src[0];
+ src += pixelStep;
+ xpos = xpos - bt;
+ }
+ } while (xpos > 0);
+ }
+
+ dstL += SCREEN_W * _pageScaleFactor[pageNum] * _pageScaleFactor[pageNum];
+ dst = dstL;
+ if (flags & 1)
+ src = src2 + 1;
+ }
+ } else {
+ const uint8 *pal = 0;
+ uint8 cgaPal[4];
+ memset(cgaPal, 0, 4);
+
+ if (pixelsPerByte == 2) {
+ pal = ovl ? ovl : src;
+ src += 16;
+ } else {
+ static const uint8 cgaDefOvl[] = { 0x00, 0x55, 0xaa, 0xff };
+ pal = ovl ? ovl : cgaDefOvl;
+ for (int i = 0; i < 4; i++)
+ cgaPal[i] = pal[i] & 3;
+ pal = cgaPal;
+ }
+
+ if (d < 0) {
+ d = -d;
+ if (d >= dH)
+ return;
+ src += (d * (width / pixelsPerByte));
+ 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;
+
+ bool trimL = false;
+ uint8 dXbitAlign = dX & (pixelsPerByte - 1);
+
+ if (dX < 0) {
+ width += dX;
+ d = -dX;
+ if (flags & 1)
+ src -= (d / pixelsPerByte);
+ else
+ src += (d / pixelsPerByte);
+
+ if (d >= w2)
+ return;
+
+ dX = 0;
+ trimL = true;
+ }
+
+ d = (dW << 3) - dX;
+
+ if (d < 1)
+ return;
+
+ if (d < width)
+ width = d;
+
+ dst += (dY * _pageScaleFactor[pageNum] * SCREEN_W * _pageScaleFactor[pageNum] + dX * _pageScaleFactor[pageNum]);
+
+ if (pageNum == 0 || pageNum == 1)
+ addDirtyRect(rX * _pageScaleFactor[pageNum], rY * _pageScaleFactor[pageNum], rW * _pageScaleFactor[pageNum], rH * _pageScaleFactor[pageNum]);
+
+ int pitch = SCREEN_W * _pageScaleFactor[pageNum] * _pageScaleFactor[pageNum] - width * _pageScaleFactor[pageNum];
+ int16 lineSrcStep = (w2 - width) / pixelsPerByte;
+ uint8 lineSrcStepRemainder = (w2 - width) % pixelsPerByte;
+
+ w2 /= pixelsPerByte;
+ if (flags & 1)
+ src += (w2 - 1);
+
+ uint8 pixelPacking = 8 / pixelsPerByte;
+ uint8 pixelPackingMask = 0;
+
+ for (int i = 0; i < pixelPacking; i++)
+ pixelPackingMask |= (1 << i);
+
+ if (trimL && (dXbitAlign > lineSrcStepRemainder))
+ lineSrcStep--;
+
+ uint8 bitShDef = 8 - pixelPacking;
+ if (flags & 1) {
+ lineSrcStep = (w2 << 1) - lineSrcStep;
+ bitShDef = 0;
+ }
+
+ uint8 bitShLineStart = bitShDef;
+ if (trimL)
+ bitShLineStart -= (dXbitAlign * pixelStep * pixelPacking);
+
+ while (dH--) {
+ int16 wd = width;
+ uint8 in = 0;
+ uint8 trans = 0;
+ uint8 shift = bitShLineStart;
+ uint8 shSwtch = bitShLineStart;
+
+ while (wd--) {
+ if (shift == shSwtch) {
+ in = *src;
+ trans = src[transOffset];
+ src += pixelStep;
+ shSwtch = bitShDef;
+ }
+ uint8 col = (pixelsPerByte == 2) ? pal[(in >> shift) & pixelPackingMask] : (*dst & ((trans >> shift) & (pixelPackingMask))) | pal[(in >> shift) & pixelPackingMask];
+ if (col || pixelsPerByte == 4)
+ drawShapeSetPixel(dst, col, SCREEN_W * _pageScaleFactor[pageNum]);
+ dst += _pageScaleFactor[pageNum];
+ shift = ((shift - (pixelStep * pixelPacking)) & 7);
+ }
+ src += lineSrcStep;
+ dst += pitch;
+ }
+ }
+}
+
+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 *dst = (shp != _dsTempPage) ? _dsTempPage : _dsTempPage + 6000;
+ uint8 *d = dst;
+ uint8 pixelsPerByte = *d++ = *shp++;
+ assert (pixelsPerByte > 1);
+
+ uint16 h = shp[0] + 1;
+ d[0] = d[2] = (h << 1) / 3;
+
+ uint16 w = shp[1];
+ uint16 w2 = (w << 3) / pixelsPerByte;
+ uint16 t = ((w << 1) % 3) ? 1 : 0;
+ d[1] = ((w << 1) / 3) + t;
+
+ uint32 transOffsetSrc = (pixelsPerByte == 4) ? (shp[0] * shp[1]) << 1 : 0;
+ uint32 transOffsetDst = (pixelsPerByte == 4) ? (d[0] * d[1]) << 1 : 0;
+ shp += 3;
+ d += 3;
+
+ if (pixelsPerByte == 2) {
+ int i = 0;
+ while (i < 16) {
+ if (!shp[i]) {
+ i = -i;
+ break;
+ }
+ i++;
+ }
+
+ if (i >= 0)
+ i = 0;
+ else
+ i = -i;
+
+ _dsScaleTrans = (i << 4) | (i & 0x0f);
+ for (int ii = 0; ii < 16; ii++)
+ *d++ = *shp++;
+ }
+
+ _dsDiv = w2 / 3;
+ _dsRem = w2 % 3;
+
+ while (--h) {
+ if (pixelsPerByte == 2)
+ scaleShapeProcessLine4Bit(d, shp);
+ else
+ scaleShapeProcessLine2Bit(d, shp, transOffsetDst, transOffsetSrc);
+ if (!--h)
+ break;
+ if (pixelsPerByte == 2)
+ scaleShapeProcessLine4Bit(d, shp);
+ else
+ scaleShapeProcessLine2Bit(d, shp, transOffsetDst, transOffsetSrc);
+ if (!--h)
+ break;
+ shp += w2;
+ }
+
+ return (const uint8*)dst;
+}
+
+const uint8 *Screen_EoB::generateShapeOverlay(const uint8 *shp, int paletteOverlayIndex) {
+ if (*shp != 2)
+ return 0;
+
+ shp += 4;
+ uint8 *ovl = getFadeTable(paletteOverlayIndex);
+ for (int i = 0; i < 16; i++)
+ _shapeOverlay[i] = ovl[shp[i]];
+ return _shapeOverlay;
+}
+
+void Screen_EoB::setShapeFrame(int x1, int y1, int x2, int y2) {
+ _dsX1 = x1;
+ _dsY1 = y1;
+ _dsX2 = x2;
+ _dsY2 = y2;
+}
+
+void Screen_EoB::setShapeFadeMode(uint8 i, bool b) {
+ if (!i || i == 1)
+ _shapeFadeMode[i] = b;
+}
+
+void Screen_EoB::setGfxParameters(int x, int y, int col) {
+ _gfxX = x;
+ _gfxY = y;
+ _gfxCol = col;
+}
+
+void Screen_EoB::drawExplosion(int scale, int radius, int numElements, int stepSize, int aspectRatio, const uint8 *colorTable, int colorTableSize) {
+ int ymin = 0;
+ int ymax = _gfxMaxY[scale];
+ int xmin = -100;
+ int xmax = 276;
+
+ if (scale)
+ --scale;
+
+ hideMouse();
+
+ const ScreenDim *dm = getScreenDim(5);
+ int rX1 = dm->sx << 3;
+ int rY1 = dm->sy;
+ int rX2 = rX1 + (dm->w << 3);
+ int rY2 = rY1 + dm->h - 1;
+
+ int16 gx2 = _gfxX;
+ int16 gy2 = _gfxY;
+
+ int16 *ptr2 = (int16 *)_dsTempPage;
+ int16 *ptr3 = (int16 *)&_dsTempPage[300];
+ int16 *ptr4 = (int16 *)&_dsTempPage[600];
+ int16 *ptr5 = (int16 *)&_dsTempPage[900];
+ int16 *ptr6 = (int16 *)&_dsTempPage[1200];
+ int16 *ptr7 = (int16 *)&_dsTempPage[1500];
+ int16 *ptr8 = (int16 *)&_dsTempPage[1800];
+
+ if (numElements > 150)
+ numElements = 150;
+
+ for (int i = 0; i < numElements; i++) {
+ ptr2[i] = ptr3[i] = 0;
+ ptr4[i] = _vm->_rnd.getRandomNumberRng(0, radius) - (radius >> 1);
+ ptr5[i] = _vm->_rnd.getRandomNumberRng(0, radius) - (radius >> 1) - (radius >> (8 - aspectRatio));
+ ptr7[i] = _vm->_rnd.getRandomNumberRng(1024 / stepSize, 2048 / stepSize);
+ ptr8[i] = scale << 8;
+ }
+
+ for (int l = 2; l;) {
+ if (l != 2) {
+ for (int i = numElements - 1; i >= 0; i--) {
+ int16 px = ((ptr2[i] >> 6) >> scale) + gx2;
+ int16 py = ((ptr3[i] >> 6) >> scale) + gy2;
+ if (py > ymax)
+ py = ymax;
+ if (posWithinRect(px, py, rX1, rY1, rX2, rY2))
+ setPagePixel(0, px, py, ptr6[i]);
+ }
+ }
+
+ l = 0;
+
+ for (int i = 0; i < numElements; i++) {
+ uint32 end = _system->getMillis() + 1;
+ if (ptr4[i] <= 0)
+ ptr4[i]++;
+ else
+ ptr4[i]--;
+ ptr2[i] += ptr4[i];
+ ptr5[i] += 5;
+ ptr3[i] += ptr5[i];
+ ptr8[i] += ptr7[i];
+
+ int16 px = ((ptr2[i] >> 6) >> scale) + gx2;
+ int16 py = ((ptr3[i] >> 6) >> scale) + gy2;
+ if (py >= ymax || py < ymin)
+ ptr5[i] = -(ptr5[i] >> 1);
+ if (px >= xmax || px < xmin)
+ ptr4[i] = -(ptr4[i] >> 1);
+
+ if (py > ymax)
+ py = ymax;
+
+ int pxVal1 = 0;
+ if (posWithinRect(px, py, 0, 0, 319, 199)) {
+ pxVal1 = getPagePixel(2, px, py);
+ ptr6[i] = getPagePixel(0, px, py);
+ }
+
+ assert((ptr8[i] >> 8) < colorTableSize);
+ int pxVal2 = colorTable[ptr8[i] >> 8];
+ if (pxVal2) {
+ l = 1;
+ if (pxVal1 == _gfxCol && posWithinRect(px, py, rX1, rY1, rX2, rY2)) {
+ setPagePixel(0, px, py, pxVal2);
+ if (i % 5 == 0) {
+ updateScreen();
+ uint32 cur = _system->getMillis();
+ if (end > cur)
+ _system->delayMillis(end - cur);
+ }
+ }
+ } else {
+ ptr7[i] = 0;
+ }
+ }
+ }
+
+ showMouse();
+}
+
+void Screen_EoB::drawVortex(int numElements, int radius, int stepSize, int, int disorder, const uint8 *colorTable, int colorTableSize) {
+ int16 *xCoords = (int16 *)_dsTempPage;
+ int16 *yCoords = (int16 *)&_dsTempPage[300];
+ int16 *xMod = (int16 *)&_dsTempPage[600];
+ int16 *yMod = (int16 *)&_dsTempPage[900];
+ int16 *pixBackup = (int16 *)&_dsTempPage[1200];
+ int16 *colTableStep = (int16 *)&_dsTempPage[1500];
+ int16 *colTableIndex = (int16 *)&_dsTempPage[1800];
+ int16 *pixDelay = (int16 *)&_dsTempPage[2100];
+
+ hideMouse();
+ int cp = _curPage;
+
+ if (numElements > 150)
+ numElements = 150;
+
+ int cx = 88;
+ int cy = 48;
+ radius <<= 6;
+
+ for (int i = 0; i < numElements; i++) {
+ int16 v38 = _vm->_rnd.getRandomNumberRng(radius >> 2, radius);
+ int16 stepSum = 0;
+ int16 sqsum = 0;
+ while (sqsum < v38) {
+ stepSum += stepSize;
+ sqsum += stepSum;
+ }
+
+ switch (_vm->_rnd.getRandomNumber(255) & 3) {
+ case 0:
+ xCoords[i] = 32;
+ yCoords[i] = sqsum;
+ xMod[i] = stepSum;
+ yMod[i] = 0;
+ break;
+
+ case 1:
+ xCoords[i] = sqsum;
+ yCoords[i] = 32;
+ xMod[i] = 0;
+ yMod[i] = stepSum;
+ break;
+
+ case 2:
+ xCoords[i] = 32;
+ yCoords[i] = -sqsum;
+ xMod[i] = stepSum;
+ yMod[i] = 0;
+ break;
+
+ default:
+ xCoords[i] = -sqsum;
+ yCoords[i] = 32;
+ xMod[i] = 0;
+ yMod[i] = stepSum;
+ break;
+ }
+
+ if (_vm->_rnd.getRandomBit()) {
+ xMod[i] *= -1;
+ yMod[i] *= -1;
+ }
+
+ colTableStep[i] = _vm->_rnd.getRandomNumberRng(1024 / disorder, 2048 / disorder);
+ colTableIndex[i] = 0;
+ pixDelay[i] = _vm->_rnd.getRandomNumberRng(0, disorder >> 2);
+ }
+
+ int d = 0;
+ for (int i = 2; i;) {
+ if (i != 2) {
+ for (int ii = numElements - 1; ii >= 0; ii--) {
+ int16 px = CLIP((xCoords[ii] >> 6) + cx, 0, SCREEN_W - 1);
+ int16 py = CLIP((yCoords[ii] >> 6) + cy, 0, SCREEN_H - 1);
+ setPagePixel(0, px, py, pixBackup[ii]);
+ }
+ }
+
+ i = 0;
+ int r = (stepSize >> 1) + (stepSize >> 2) + (stepSize >> 3);
+ uint32 nextDelay = _system->getMillis() + 1;
+
+ for (int ii = 0; ii < numElements; ii++) {
+ if (pixDelay[ii] == 0) {
+ if (xCoords[ii] > 0) {
+ xMod[ii] -= ((xMod[ii] > 0) ? stepSize : r);
+ } else {
+ xMod[ii] += ((xMod[ii] < 0) ? stepSize : r);
+ }
+
+ if (yCoords[ii] > 0) {
+ yMod[ii] -= ((yMod[ii] > 0) ? stepSize : r);
+ } else {
+ yMod[ii] += ((yMod[ii] < 0) ? stepSize : r);
+ }
+
+ xCoords[ii] += xMod[ii];
+ yCoords[ii] += yMod[ii];
+ colTableIndex[ii] += colTableStep[ii];
+
+ } else {
+ pixDelay[ii]--;
+ }
+
+ int16 px = CLIP((xCoords[ii] >> 6) + cx, 0, SCREEN_W - 1);
+ int16 py = CLIP((yCoords[ii] >> 6) + cy, 0, SCREEN_H - 1);
+
+ uint8 tc1 = ((disorder >> 2) <= d) ? getPagePixel(2, px, py) : 0;
+ pixBackup[ii] = getPagePixel(0, px, py);
+ uint8 tblIndex = CLIP(colTableIndex[ii] >> 8, 0, colorTableSize - 1);
+ uint8 tc2 = colorTable[tblIndex];
+
+ if (tc2) {
+ i = 1;
+ if (tc1 == _gfxCol && !pixDelay[ii]) {
+ setPagePixel(0, px, py, tc2);
+ if (ii % 15 == 0) {
+ updateScreen();
+ uint32 cur = _system->getMillis();
+ if (nextDelay > cur)
+ _system->delayMillis(nextDelay - cur);
+ nextDelay += 1;
+ }
+ }
+ } else {
+ colTableStep[ii] = 0;
+ }
+ }
+ d++;
+ }
+
+ _curPage = cp;
+ showMouse();
+}
+
+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() + _vm->tickLength();
+
+ 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;
+}
+
+int Screen_EoB::getRectSize(int w, int h) {
+ return w * h;
+}
+
+void Screen_EoB::setFadeTableIndex(int index) {
+ _fadeDataIndex = (CLIP(index, 0, 7) << 8);
+}
+
+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;
+ }
+}
+
+uint8 *Screen_EoB::getFadeTable(int index) {
+ return (index >= 0 && index < 5) ? &_fadeData[index << 8] : 0;
+}
+
+const uint16 *Screen_EoB::getCGADitheringTable(int index) {
+ return !(index & ~1) ? _cgaDitheringTables[index] : 0;
+}
+
+const uint8 *Screen_EoB::getEGADitheringTable() {
+ return _egaDitheringTable;
+}
+
+void Screen_EoB::drawShapeSetPixel(uint8 *dst, uint8 col, uint16 pitch) {
+ if ((_renderMode != Common::kRenderCGA && _renderMode != Common::kRenderEGA) || _useHiResEGADithering) {
+ if (_shapeFadeMode[0]) {
+ if (_shapeFadeMode[1]) {
+ col = _useHiResEGADithering ? _egaPixelValueTable[(dst[0] << 4) | (dst[1] & 0x0f)] : *dst;
+ } else {
+ _shapeFadeInternal &= 7;
+ col = _useHiResEGADithering ? _egaPixelValueTable[(dst[_shapeFadeInternal] << 4) | (dst[_shapeFadeInternal + 1] & 0x0f)] : dst[_shapeFadeInternal];
+ _shapeFadeInternal++;
+ }
+ }
+
+ if (_shapeFadeMode[1]) {
+ uint8 cnt = _shapeFadeMode[1];
+ while (cnt--)
+ col = _fadeData[_fadeDataIndex + col];
+ }
+ }
+
+ if (_useHiResEGADithering) {
+ col = _egaDitheringTable[col];
+ dst[0] = dst[pitch] = col >> 4;
+ dst[1] = dst[pitch + 1] = col & 0x0f;
+ } else {
+ *dst = col;
+ }
+}
+
+void Screen_EoB::scaleShapeProcessLine2Bit(uint8 *&shpDst, const uint8 *&shpSrc, uint32 transOffsetDst, uint32 transOffsetSrc) {
+ for (int i = 0; i < _dsDiv; i++) {
+ shpDst[0] = (_cgaScaleTable[shpSrc[0]] << 2) | (shpSrc[1] >> 6);
+ shpDst[1] = ((shpSrc[1] & 0x0f) << 4) | ((shpSrc[2] >> 2) & 0x0f);
+ shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | (shpSrc[transOffsetSrc + 1] >> 6);
+ shpDst[transOffsetDst + 1] = ((shpSrc[transOffsetSrc + 1] & 0x0f) << 4) | ((shpSrc[transOffsetSrc + 2] >> 2) & 0x0f);
+ shpSrc += 3;
+ shpDst += 2;
+ }
+
+ if (_dsRem == 1) {
+ shpDst[0] = _cgaScaleTable[shpSrc[0]] << 2;
+ shpDst[1] = 0;
+ shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | 3;
+ shpDst[transOffsetDst + 1] = 0xff;
+ shpSrc++;
+ shpDst += 2;
+
+ } else if (_dsRem == 2) {
+ shpDst[0] = (_cgaScaleTable[shpSrc[0]] << 2) | (shpSrc[1] >> 6);
+ shpDst[1] = (shpSrc[1] & 0x3f) << 2;
+ shpDst[transOffsetDst] = (_cgaScaleTable[shpSrc[transOffsetSrc]] << 2) | (shpSrc[transOffsetSrc + 1] >> 6);
+ shpDst[transOffsetDst + 1] = ((shpSrc[transOffsetSrc + 1] & 0x3f) << 2) | 3;
+ shpSrc += 2;
+ shpDst += 2;
+ }
+}
+
+void Screen_EoB::scaleShapeProcessLine4Bit(uint8 *&dst, const uint8 *&src) {
+ for (int i = 0; i < _dsDiv; i++) {
+ *dst++ = *src++;
+ *dst++ = (READ_BE_UINT16(src) >> 4) & 0xff;
+ src += 2;
+ }
+
+ if (_dsRem == 1) {
+ *dst++ = *src++;
+ *dst++ = _dsScaleTrans;
+ } else if (_dsRem == 2) {
+ *dst++ = (src[0] & 0xf0) | (src[1] >> 4);
+ src += 2;
+ *dst++ = _dsScaleTrans;
+ *dst++ = _dsScaleTrans;
+ *dst++ = _dsScaleTrans;
+ }
+}
+
+bool Screen_EoB::posWithinRect(int posX, int posY, int x1, int y1, int x2, int y2) {
+ if (posX < x1 || posX > x2 || posY < y1 || posY > y2)
+ return false;
+ return true;
+}
+
+void Screen_EoB::generateEGADitheringTable(const Palette &pal) {
+ assert(_egaDitheringTable);
+ const uint8 *src = pal.getData();
+ uint8 *dst = _egaDitheringTable;
+
+ for (int i = 256; i; i--) {
+ int r = *src++;
+ int g = *src++;
+ int b = *src++;
+
+ uint8 col = 0;
+ uint16 min = 0x2E83;
+
+ for (int ii = 256; ii; ii--) {
+ const uint8 *palEntry = _egaMatchTable + (ii - 1) * 3;
+ if (*palEntry == 0xff)
+ continue;
+
+ int e_r = palEntry[0] - r;
+ int e_g = palEntry[1] - g;
+ int e_b = palEntry[2] - b;
+
+ uint16 s = (e_r * e_r) + (e_g * e_g) + (e_b * e_b);
+
+ if (s <= min) {
+ min = s;
+ col = ii - 1;
+ }
+ }
+ *dst++ = col;
+ }
+
+ memset(_egaPixelValueTable, 0, 256);
+ for (int i = 0; i < 256; i++)
+ _egaPixelValueTable[_egaDitheringTable[i]] = i;
+}
+
+void Screen_EoB::generateCGADitheringTables(const uint8 *mappingData) {
+ for (int i = 0; i < 256; i++) {
+ _cgaDitheringTables[0][i] = (mappingData[(i >> 4) + 16] << 8) | mappingData[i & 0x0f];
+ _cgaDitheringTables[1][i] = (mappingData[i >> 4] << 8) | mappingData[(i & 0x0f) + 16];
+ }
+}
+
+const uint8 Screen_EoB::_egaMatchTable[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x1E, 0x1E, 0x00, 0x00, 0x1E,
+ 0x00, 0x1E, 0x1E, 0x0F, 0x00, 0x1E, 0x1E, 0x1E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x2D, 0x0F, 0x2D,
+ 0x0F, 0x0F, 0x2D, 0x2D, 0x2D, 0x0F, 0x0F, 0x2D, 0x0F, 0x2D, 0x2D, 0x2D, 0x0F, 0x2D, 0x2D, 0x2D,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x2A, 0x00, 0x1E, 0x1E, 0x00, 0x1E, 0x2A, 0x1E, 0x00, 0x1E, 0x1E,
+ 0x00, 0x2A, 0x1E, 0x0F, 0x1E, 0x1E, 0x1E, 0x2A, 0x0F, 0x0F, 0x21, 0x0F, 0x0F, 0x36, 0x0F, 0x2D,
+ 0x21, 0x0F, 0x2D, 0x36, 0x2D, 0x0F, 0x21, 0x2D, 0x0F, 0x36, 0x2D, 0x2D, 0x21, 0x2D, 0x2D, 0x36,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x2A, 0x00, 0x00, 0x2A, 0x1E, 0x1E, 0x1E, 0x00, 0x1E,
+ 0x1E, 0x1E, 0x1E, 0x21, 0x00, 0x1E, 0x2A, 0x1E, 0x0F, 0x21, 0x0F, 0x0F, 0x21, 0x2D, 0x0F, 0x36,
+ 0x0F, 0x0F, 0x36, 0x2D, 0x2D, 0x21, 0x0F, 0x2D, 0x21, 0x2D, 0x2D, 0x36, 0x0F, 0x2D, 0x36, 0x2D,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x2A, 0x2A, 0x1E, 0x1E, 0x1E, 0x1E,
+ 0x1E, 0x2A, 0x1E, 0x21, 0x1E, 0x1E, 0x2A, 0x2A, 0x0F, 0x21, 0x21, 0x0F, 0x21, 0x36, 0x0F, 0x36,
+ 0x21, 0x0F, 0x36, 0x36, 0x2D, 0x21, 0x21, 0x2D, 0x21, 0x36, 0x2D, 0x36, 0x21, 0x2D, 0x36, 0x36,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x00, 0x00, 0x2A,
+ 0x00, 0x1E, 0x2A, 0x0F, 0x00, 0x2A, 0x1E, 0x1E, 0x21, 0x0F, 0x0F, 0x21, 0x0F, 0x2D, 0x21, 0x2D,
+ 0x0F, 0x21, 0x2D, 0x2D, 0x36, 0x0F, 0x0F, 0x36, 0x0F, 0x2D, 0x36, 0x2D, 0x0F, 0x36, 0x2D, 0x2D,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A,
+ 0x00, 0x2A, 0x2A, 0x0F, 0x1E, 0x2A, 0x1E, 0x2A, 0x21, 0x0F, 0x21, 0x21, 0x0F, 0x36, 0x21, 0x2D,
+ 0x21, 0x21, 0x2D, 0x36, 0x36, 0x0F, 0x21, 0x36, 0x0F, 0x36, 0x36, 0x2D, 0x21, 0x36, 0x2D, 0x36,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x2A, 0x15, 0x00, 0x2A, 0x21, 0x1E, 0x21, 0x15, 0x0F, 0x21, 0x15, 0x2D, 0x21, 0x2F,
+ 0x0F, 0x21, 0x2F, 0x2D, 0x36, 0x15, 0x0F, 0x36, 0x15, 0x2D, 0x36, 0x2F, 0x0F, 0x36, 0x2F, 0x2D,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2A, 0x2A, 0x2A, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x21, 0x36,
+ 0x21, 0x21, 0x36, 0x36, 0x36, 0x21, 0x21, 0x36, 0x21, 0x36, 0x36, 0x36, 0x21, 0x36, 0x36, 0x36,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x15, 0x15, 0x15, 0x15, 0x2F, 0x15, 0x2F,
+ 0x15, 0x15, 0x2F, 0x2F, 0x2F, 0x15, 0x15, 0x2F, 0x15, 0x2F, 0x2F, 0x2F, 0x15, 0x2F, 0x2F, 0x2F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x15, 0x3F, 0x15, 0x2F,
+ 0x2F, 0x15, 0x2F, 0x3F, 0x2F, 0x15, 0x2F, 0x2F, 0x15, 0x3F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x15, 0x3F,
+ 0x15, 0x15, 0x3F, 0x2F, 0x2F, 0x2F, 0x15, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F, 0x15, 0x2F, 0x3F, 0x2F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x15, 0x3F, 0x3F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x3F, 0x2F, 0x3F, 0x2F, 0x2F, 0x3F, 0x3F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x15, 0x15, 0x3F, 0x15, 0x2F, 0x3F, 0x2F, 0x15, 0x3F, 0x2F, 0x2F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x15, 0x3F, 0x3F, 0x2F, 0x2F, 0x3F, 0x2F, 0x3F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x15, 0x3F, 0x3F, 0x2F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x3F, 0x3F
+};
+
+uint16 *OldDOSFont::_cgaDitheringTable = 0;
+int OldDOSFont::_numRef = 0;
+
+OldDOSFont::OldDOSFont(Common::RenderMode mode, bool useHiResEGADithering) : _renderMode(mode), _useHiResEGADithering(useHiResEGADithering) {
+ _data = 0;
+ _width = _height = _numGlyphs = 0;
+ _bitmapOffsets = 0;
+ _useLoResEGA = (_renderMode == Common::kRenderEGA && !_useHiResEGADithering);
+
+ _numRef++;
+ if (!_cgaDitheringTable && _numRef == 1) {
+ _cgaDitheringTable = new uint16[256];
+ memset(_cgaDitheringTable, 0, 256 * sizeof(uint16));
+ static const uint bits[] = { 0, 3, 12, 15 };
+ for (int i = 0; i < 256; i++)
+ _cgaDitheringTable[i] = (bits[i & 3] << 8) | (bits[(i >> 2) & 3] << 12) | (bits[(i >> 4) & 3] << 0) | (bits[(i >> 6) & 3] << 4);
+ }
+}
+
+OldDOSFont::~OldDOSFont() {
+ unload();
+
+ if (_numRef)
+ --_numRef;
+
+ if (_cgaDitheringTable && !_numRef) {
+ delete[] _cgaDitheringTable;
+ _cgaDitheringTable = 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]];
+ uint8 *dst2 = dst + pitch;
+
+ int w = (_width - 1) >> 3;
+ pitch -= _width;
+
+ if (_useHiResEGADithering)
+ pitch *= 2;
+
+ uint8 color1 = _colorMap[1];
+ uint8 color2 = _colorMap[0];
+
+ uint8 colEGA11 = _colorMap[3] >> 4;
+ uint8 colEGA12 = _colorMap[3] & 0x0f;
+ uint8 colEGA21 = _colorMap[2] >> 4;
+ uint8 colEGA22 = _colorMap[2] & 0x0f;
+
+ static const uint16 cgaColorMask[] = { 0, 0x5555, 0xAAAA, 0xFFFF };
+ uint16 cgaMask1 = cgaColorMask[color1 & 3];
+ uint16 cgaMask2 = cgaColorMask[color2 & 3];
+
+ if (_renderMode == Common::kRenderCGA || _useLoResEGA) {
+ color1 &= 0x0f;
+ color2 &= 0x0f;
+ }
+
+ int cH = _height;
+ while (cH--) {
+ int cW = w;
+ uint8 last = 0;
+ const uint8 *mtbl = _width == 8 ? renderMaskTable8 : renderMaskTable6;
+
+ if (_renderMode == Common::kRenderCGA) {
+ uint8 s = *src++;
+ uint8 m = *mtbl++;
+
+ uint8 in = s | last;
+ uint16 cmp1 = 0;
+ uint16 cmp2 = 0;
+
+ if (color1) {
+ in &= m;
+ cmp1 = _cgaDitheringTable[in];
+ }
+
+ if (color2) {
+ in = ~in & m;
+ cmp2 = _cgaDitheringTable[in];
+ }
+
+ uint16 cDst = 0;
+ uint8 sh = 6;
+ for (int i = 0; i < _width; i++) {
+ cDst |= ((dst[i] & 3) << sh);
+ sh = (sh - 2) & 0x0f;
+ }
+
+ uint16 out = (~(cmp1 | cmp2) & cDst) | (cmp1 & cgaMask1) | (cmp2 & cgaMask2);
+
+ sh = 6;
+ for (int i = 0; i < _width; i++) {
+ *dst++ = (out >> sh) & 3;
+ sh = (sh - 2) & 0x0f;
+ }
+
+ last = s;
+
+ } else {
+ 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 (_useHiResEGADithering) {
+ if (s & i) {
+ if (color1) {
+ dst[0] = dst2[0] = colEGA11;
+ dst[1] = dst2[1] = colEGA12;
+ }
+ } else if (color2) {
+ dst[0] = dst2[0] = colEGA21;
+ dst[1] = dst2[1] = colEGA22;
+ }
+ dst += 2;
+ dst2 += 2;
+ } else {
+ if (s & i) {
+ if (color1)
+ *dst = color1;
+ } else if (color2) {
+ *dst = color2;
+ }
+ dst++;
+ }
+ }
+
+ if (cW)
+ cW--;
+ else
+ runWidthLoop = false;
+ }
+ }
+
+ dst += pitch;
+ dst2 += 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..fc40cfe903
--- /dev/null
+++ b/engines/kyra/screen_eob.h
@@ -0,0 +1,129 @@
+/* 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 setClearScreenDim(int dim);
+ void clearCurDim();
+
+ void setMouseCursor(int x, int y, const byte *shape);
+ void setMouseCursor(int x, int y, const byte *shape, const uint8 *ovl);
+
+ void loadFileDataToPage(Common::SeekableReadStream *s, int pageNum, uint32 size);
+
+ void printText(const char *str, int x, int y, uint8 color1, uint8 color2);
+ void printShadedText(const char *string, int x, int y, int col1, int col2);
+
+ void loadEoBBitmap(const char *file, const uint8 *cgaMapping, int tempPage, int destPage, int convertToPage);
+ void loadShapeSetBitmap(const char *file, int tempPage, int destPage);
+
+ void convertPage(int srcPage, int dstPage, const uint8 *cgaMapping);
+
+ void fillRect(int x1, int y1, int x2, int y2, uint8 color, int pageNum = -1, bool xored = false);
+ void drawLine(bool vertical, int x, int y, int length, int color);
+ uint8 getPagePixel(int pageNum, int x, int y);
+ void setPagePixel(int pageNum, int x, int y, uint8 color);
+
+ void setScreenPalette(const Palette &pal);
+ void getRealPalette(int num, uint8 *dst);
+
+ uint8 *encodeShape(uint16 x, uint16 y, uint16 w, uint16 h, bool encode8bit = false, const uint8 *cgaMapping = 0);
+ 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);
+ const uint8 *generateShapeOverlay(const uint8 *shp, int paletteOverlayIndex);
+
+ void setShapeFrame(int x1, int y1, int x2, int y2);
+ void setShapeFadeMode (uint8 i, bool b);
+
+ void setGfxParameters(int x, int y, int col);
+ void drawExplosion(int scale, int radius, int numElements, int stepSize, int aspectRatio, const uint8 *colorTable, int colorTableSize);
+ void drawVortex(int numElements, int radius, int stepSize, int, int disorder, const uint8 *colorTable, int colorTableSize);
+
+ 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);
+
+ void setFadeTableIndex(int index);
+ void createFadeTable(uint8 *palData, uint8 *dst, uint8 rootColor, uint8 weight);
+ uint8 *getFadeTable(int index);
+
+ const uint16 *getCGADitheringTable(int index);
+ const uint8 *getEGADitheringTable();
+
+private:
+ void drawShapeSetPixel(uint8 *dst, uint8 col, uint16 pitch);
+ void scaleShapeProcessLine2Bit(uint8 *&shpDst, const uint8 *&shpSrc, uint32 transOffsetDst, uint32 transOffsetSrc);
+ void scaleShapeProcessLine4Bit(uint8 *&dst, const uint8 *&src);
+ bool posWithinRect(int posX, int posY, int x1, int y1, int x2, int y2);
+
+ void generateEGADitheringTable(const Palette &pal);
+ void generateCGADitheringTables(const uint8 *mappingData);
+
+ int _dsDiv, _dsRem, _dsScaleTrans;
+ uint8 *_cgaScaleTable;
+ int16 _gfxX, _gfxY;
+ uint8 _gfxCol;
+ const uint8 *_gfxMaxY;
+
+ int16 _dsX1, _dsX2, _dsY1, _dsY2;
+ bool _shapeFadeMode[2];
+ uint16 _shapeFadeInternal;
+ uint8 *_fadeData;
+ int _fadeDataIndex;
+ uint8 _shapeOverlay[16];
+
+ uint8 *_dsTempPage;
+
+ uint16 *_cgaDitheringTables[2];
+ const uint8 *_cgaMappingDefault;
+
+ uint8 *_egaDitheringTable;
+ uint8 *_egaPixelValueTable;
+
+ static const uint8 _egaMatchTable[];
+ static const ScreenDim _screenDimTable[];
+ static const int _screenDimTableCount;
+};
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
+
+#endif
diff --git a/engines/kyra/screen_hof.cpp b/engines/kyra/screen_hof.cpp
index 24e0751c0e..ac6ee5eb77 100644
--- a/engines/kyra/screen_hof.cpp
+++ b/engines/kyra/screen_hof.cpp
@@ -26,17 +26,7 @@
namespace Kyra {
Screen_HoF::Screen_HoF(KyraEngine_HoF *vm, OSystem *system)
- : Screen_v2(vm, system), _vm(vm) {
-}
-
-void Screen_HoF::setScreenDim(int dim) {
- assert(dim < _screenDimTableCount);
- _curDim = &_screenDimTable[dim];
-}
-
-const ScreenDim *Screen_HoF::getScreenDim(int dim) {
- assert(dim < _screenDimTableCount);
- return &_screenDimTable[dim];
+ : Screen_v2(vm, system, _screenDimTable, _screenDimTableCount), _vm(vm) {
}
void Screen_HoF::generateGrayOverlay(const Palette &srcPal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool flag) {
diff --git a/engines/kyra/screen_hof.h b/engines/kyra/screen_hof.h
index edcb339da9..51c6a001fa 100644
--- a/engines/kyra/screen_hof.h
+++ b/engines/kyra/screen_hof.h
@@ -34,10 +34,6 @@ friend class Debugger_v2;
public:
Screen_HoF(KyraEngine_HoF *vm, OSystem *system);
- void setScreenDim(int dim);
- const ScreenDim *getScreenDim(int dim);
- int screenDimTableCount() const { return _screenDimTableCount; }
-
// sequence player
void generateGrayOverlay(const Palette &pal, uint8 *grayOverlay, int factor, int addR, int addG, int addB, int lastColor, bool flag);
void cmpFadeFrameStep(int srcPage, int srcW, int srcH, int srcX, int srcY, int dstPage, int dstW, int dstH, int dstX, int dstY, int cmpW, int cmpH, int cmpPage);
diff --git a/engines/kyra/screen_lok.cpp b/engines/kyra/screen_lok.cpp
index 106ef5df29..f32a898dd9 100644
--- a/engines/kyra/screen_lok.cpp
+++ b/engines/kyra/screen_lok.cpp
@@ -30,7 +30,7 @@
namespace Kyra {
Screen_LoK::Screen_LoK(KyraEngine_LoK *vm, OSystem *system)
- : Screen(vm, system) {
+ : Screen(vm, system, _screenDimTable, _screenDimTableCount) {
_vm = vm;
_unkPtr1 = _unkPtr2 = 0;
_bitBlitNum = 0;
@@ -70,16 +70,6 @@ bool Screen_LoK::init() {
return true;
}
-void Screen_LoK::setScreenDim(int dim) {
- assert(dim < _screenDimTableCount);
- _curDim = &_screenDimTable[dim];
-}
-
-const ScreenDim *Screen_LoK::getScreenDim(int dim) {
- assert(dim < _screenDimTableCount);
- return &_screenDimTable[dim];
-}
-
void Screen_LoK::fadeSpecialPalette(int palIndex, int startIndex, int size, int fadeTime) {
if (_vm->gameFlags().platform == Common::kPlatformAmiga)
return;
@@ -90,7 +80,7 @@ void Screen_LoK::fadeSpecialPalette(int palIndex, int startIndex, int size, int
tempPal.copy(getPalette(0));
tempPal.copy(_vm->palTable1()[palIndex], 0, size, startIndex);
- fadePalette(tempPal, fadeTime*18);
+ fadePalette(tempPal, fadeTime * 18);
getPalette(0).copy(tempPal, startIndex, size);
setScreenPalette(getPalette(0));
@@ -118,16 +108,16 @@ void Screen_LoK::bitBlitRects() {
}
void Screen_LoK::savePageToDisk(const char *file, int page) {
- if (!_saveLoadPage[page/2]) {
- _saveLoadPage[page/2] = new uint8[SCREEN_W * SCREEN_H];
- assert(_saveLoadPage[page/2]);
+ if (!_saveLoadPage[page / 2]) {
+ _saveLoadPage[page / 2] = new uint8[SCREEN_W * SCREEN_H];
+ assert(_saveLoadPage[page / 2]);
}
- memcpy(_saveLoadPage[page/2], getPagePtr(page), SCREEN_W * SCREEN_H);
+ memcpy(_saveLoadPage[page / 2], getPagePtr(page), SCREEN_W * SCREEN_H);
if (_useOverlays) {
- if (!_saveLoadPageOvl[page/2]) {
- _saveLoadPageOvl[page/2] = new uint8[SCREEN_OVL_SJIS_SIZE];
- assert(_saveLoadPageOvl[page/2]);
+ if (!_saveLoadPageOvl[page / 2]) {
+ _saveLoadPageOvl[page / 2] = new uint8[SCREEN_OVL_SJIS_SIZE];
+ assert(_saveLoadPageOvl[page / 2]);
}
uint8 *srcPage = getOverlayPtr(page);
@@ -136,49 +126,49 @@ void Screen_LoK::savePageToDisk(const char *file, int page) {
return;
}
- memcpy(_saveLoadPageOvl[page/2], srcPage, SCREEN_OVL_SJIS_SIZE);
+ memcpy(_saveLoadPageOvl[page / 2], srcPage, SCREEN_OVL_SJIS_SIZE);
}
}
void Screen_LoK::loadPageFromDisk(const char *file, int page) {
- if (!_saveLoadPage[page/2]) {
+ if (!_saveLoadPage[page / 2]) {
warning("trying to restore page %d, but no backup found", page);
return;
}
- copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page/2]);
- delete[] _saveLoadPage[page/2];
- _saveLoadPage[page/2] = 0;
+ copyBlockToPage(page, 0, 0, SCREEN_W, SCREEN_H, _saveLoadPage[page / 2]);
+ delete[] _saveLoadPage[page / 2];
+ _saveLoadPage[page / 2] = 0;
- if (_saveLoadPageOvl[page/2]) {
+ if (_saveLoadPageOvl[page / 2]) {
uint8 *dstPage = getOverlayPtr(page);
if (!dstPage) {
warning("trying to restore unsupported overlay page %d", page);
return;
}
- memcpy(dstPage, _saveLoadPageOvl[page/2], SCREEN_OVL_SJIS_SIZE);
- delete[] _saveLoadPageOvl[page/2];
- _saveLoadPageOvl[page/2] = 0;
+ memcpy(dstPage, _saveLoadPageOvl[page / 2], SCREEN_OVL_SJIS_SIZE);
+ delete[] _saveLoadPageOvl[page / 2];
+ _saveLoadPageOvl[page / 2] = 0;
}
}
void Screen_LoK::queryPageFromDisk(const char *file, int page, uint8 *buffer) {
- if (!_saveLoadPage[page/2]) {
+ if (!_saveLoadPage[page / 2]) {
warning("trying to query page %d, but no backup found", page);
return;
}
- memcpy(buffer, _saveLoadPage[page/2], SCREEN_W*SCREEN_H);
+ memcpy(buffer, _saveLoadPage[page / 2], SCREEN_W * SCREEN_H);
}
void Screen_LoK::deletePageFromDisk(int page) {
- delete[] _saveLoadPage[page/2];
- _saveLoadPage[page/2] = 0;
+ delete[] _saveLoadPage[page / 2];
+ _saveLoadPage[page / 2] = 0;
- if (_saveLoadPageOvl[page/2]) {
- delete[] _saveLoadPageOvl[page/2];
- _saveLoadPageOvl[page/2] = 0;
+ if (_saveLoadPageOvl[page / 2]) {
+ delete[] _saveLoadPageOvl[page / 2];
+ _saveLoadPageOvl[page / 2] = 0;
}
}
@@ -204,16 +194,16 @@ void Screen_LoK::copyBackgroundBlock(int x, int page, int flag) {
copyRegionToBuffer(_curPage, 8, 8, 8, height, ptr2);
for (int i = 0; i < 19; ++i) {
int tempX = curX + 1;
- copyRegionToBuffer(_curPage, tempX<<3, 8, 8, height, ptr1);
- copyBlockToPage(_curPage, tempX<<3, 8, 8, height, ptr2);
+ copyRegionToBuffer(_curPage, tempX << 3, 8, 8, height, ptr1);
+ copyBlockToPage(_curPage, tempX << 3, 8, 8, height, ptr2);
int newXPos = curX + x;
if (newXPos > 37)
newXPos = newXPos % 38;
tempX = newXPos + 1;
- copyRegionToBuffer(_curPage, tempX<<3, 8, 8, height, ptr2);
- copyBlockToPage(_curPage, tempX<<3, 8, 8, height, ptr1);
- curX += x*2;
+ copyRegionToBuffer(_curPage, tempX << 3, 8, 8, height, ptr2);
+ copyBlockToPage(_curPage, tempX << 3, 8, 8, height, ptr1);
+ curX += x * 2;
if (curX > 37) {
curX = curX % 38;
}
@@ -241,7 +231,7 @@ int Screen_LoK::getRectSize(int x, int y) {
else if (y > 200)
y = 200;
- return ((x*y) << 3);
+ return ((x * y) << 3);
}
void Screen_LoK::postProcessCursor(uint8 *data, int width, int height, int pitch) {
@@ -342,7 +332,7 @@ void Screen_LoK_16::getFadeParams(const Palette &pal, int delay, int &delayInc,
int Screen_LoK_16::fadePalStep(const Palette &pal, int diff) {
error("Screen_LoK_16::fadePalStep called");
- return 0; // for compilers that don't support NORETURN
+ return 0; // for compilers that don't support NORETURN
}
void Screen_LoK_16::paletteMap(uint8 idx, int r, int g, int b) {
diff --git a/engines/kyra/screen_lok.h b/engines/kyra/screen_lok.h
index 3b74912986..3cb92543e5 100644
--- a/engines/kyra/screen_lok.h
+++ b/engines/kyra/screen_lok.h
@@ -38,10 +38,6 @@ public:
int getRectSize(int w, int h);
- void setScreenDim(int dim);
- const ScreenDim *getScreenDim(int dim);
- int screenDimTableCount() const { return _screenDimTableCount; }
-
void setTextColorMap(const uint8 *cmap);
void fadeSpecialPalette(int palIndex, int startIndex, int size, int fadeTime);
diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp
index 6d0460e0a1..08b232f400 100644
--- a/engines/kyra/screen_lol.cpp
+++ b/engines/kyra/screen_lol.cpp
@@ -31,7 +31,7 @@
namespace Kyra {
-Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system), _vm(vm) {
+Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system, vm->gameFlags().use16ColorMode ? _screenDimTable16C : _screenDimTable256C, _screenDimTableCount), _vm(vm) {
_paletteOverlay1 = new uint8[0x100];
_paletteOverlay2 = new uint8[0x100];
_grayOverlay = new uint8[0x100];
@@ -43,14 +43,9 @@ Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system),
_levelOverlays[i] = new uint8[256];
_fadeFlag = 2;
- _curDimIndex = 0;
}
Screen_LoL::~Screen_LoL() {
- for (int i = 0; i < _screenDimTableCount; i++)
- delete _customDimTable[i];
- delete[] _customDimTable;
-
for (int i = 0; i < 8; i++)
delete[] _levelOverlays[i];
@@ -59,39 +54,6 @@ Screen_LoL::~Screen_LoL() {
delete[] _grayOverlay;
}
-bool Screen_LoL::init() {
- if (Screen::init()) {
- _screenDimTable = _use16ColorMode ? _screenDimTable16C : _screenDimTable256C;
- _customDimTable = new ScreenDim*[_screenDimTableCount];
- memset(_customDimTable, 0, sizeof(ScreenDim *)* _screenDimTableCount);
- return true;
- }
- return false;
-}
-
-
-void Screen_LoL::setScreenDim(int dim) {
- assert(dim < _screenDimTableCount);
- _curDim = _customDimTable[dim] ? (const ScreenDim *)_customDimTable[dim] : &_screenDimTable[dim];
- _curDimIndex = dim;
-}
-
-const ScreenDim *Screen_LoL::getScreenDim(int dim) {
- assert(dim < _screenDimTableCount);
- return _customDimTable[dim] ? (const ScreenDim *)_customDimTable[dim] : &_screenDimTable[dim];
-}
-
-void Screen_LoL::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;
- setScreenDim(dim);
-}
-
void Screen_LoL::fprintString(const char *format, int x, int y, uint8 col1, uint8 col2, uint16 flags, ...) {
if (!format)
return;
@@ -142,8 +104,8 @@ void Screen_LoL::fprintStringIntro(const char *format, int x, int y, uint8 c1, u
x -= getTextWidth(buffer);
if ((flags & 0x00F0) == 0x20) {
- printText(buffer, x-1, y, c3, c2);
- printText(buffer, x, y+1, c3, c2);
+ printText(buffer, x - 1, y, c3, c2);
+ printText(buffer, x, y + 1, c3, c2);
}
printText(buffer, x, y, c1, c2);
diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h
index 02b78606b9..3bba9f8b70 100644
--- a/engines/kyra/screen_lol.h
+++ b/engines/kyra/screen_lol.h
@@ -36,14 +36,6 @@ public:
Screen_LoL(LoLEngine *vm, OSystem *system);
~Screen_LoL();
- 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 fprintString(const char *format, int x, int y, uint8 col1, uint8 col2, uint16 flags, ...) GCC_PRINTF(2, 8);
void fprintStringIntro(const char *format, int x, int y, uint8 c1, uint8 c2, uint8 c3, uint16 flags, ...) GCC_PRINTF(2, 9);
@@ -99,14 +91,9 @@ public:
private:
LoLEngine *_vm;
- const ScreenDim *_screenDimTable;
- static const int _screenDimTableCount;
-
static const ScreenDim _screenDimTable256C[];
static const ScreenDim _screenDimTable16C[];
-
- ScreenDim **_customDimTable;
- int _curDimIndex;
+ static const int _screenDimTableCount;
uint8 *_levelOverlays[8];
diff --git a/engines/kyra/screen_mr.cpp b/engines/kyra/screen_mr.cpp
index 2687dc8041..337860db30 100644
--- a/engines/kyra/screen_mr.cpp
+++ b/engines/kyra/screen_mr.cpp
@@ -25,22 +25,13 @@
namespace Kyra {
-Screen_MR::Screen_MR(KyraEngine_MR *vm, OSystem *system) : Screen_v2(vm, system) {
+Screen_MR::Screen_MR(KyraEngine_MR *vm, OSystem *system)
+ : Screen_v2(vm, system, _screenDimTable, _screenDimTableCount) {
}
Screen_MR::~Screen_MR() {
}
-void Screen_MR::setScreenDim(int dim) {
- assert(dim < _screenDimTableCount);
- _curDim = &_screenDimTable[dim];
-}
-
-const ScreenDim *Screen_MR::getScreenDim(int dim) {
- assert(dim < _screenDimTableCount);
- return &_screenDimTable[dim];
-}
-
int Screen_MR::getLayer(int x, int y) {
if (x < 0)
x = 0;
diff --git a/engines/kyra/screen_mr.h b/engines/kyra/screen_mr.h
index 0cb3240954..e10afcc5d2 100644
--- a/engines/kyra/screen_mr.h
+++ b/engines/kyra/screen_mr.h
@@ -34,10 +34,6 @@ public:
Screen_MR(KyraEngine_MR *vm, OSystem *system);
~Screen_MR();
- void setScreenDim(int dim);
- const ScreenDim *getScreenDim(int dim);
- int screenDimTableCount() const { return _screenDimTableCount; }
-
int getLayer(int x, int y);
byte getShapeFlag1(int x, int y);
diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp
index 57581fa750..7d4b064e2a 100644
--- a/engines/kyra/screen_v2.cpp
+++ b/engines/kyra/screen_v2.cpp
@@ -26,7 +26,8 @@
namespace Kyra {
-Screen_v2::Screen_v2(KyraEngine_v1 *vm, OSystem *system) : Screen(vm, system), _wsaFrameAnimBuffer(0) {
+Screen_v2::Screen_v2(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, const int dimTableSize)
+ : Screen(vm, system, dimTable, dimTableSize), _wsaFrameAnimBuffer(0) {
_wsaFrameAnimBuffer = new uint8[1024];
assert(_wsaFrameAnimBuffer);
}
@@ -186,7 +187,7 @@ uint8 *Screen_v2::getPtrToShape(uint8 *shpFile, int shape) {
int Screen_v2::getShapeScaledWidth(const uint8 *shpFile, int scale) {
if (!shpFile)
return 0;
- int width = READ_LE_UINT16(shpFile+3);
+ int width = READ_LE_UINT16(shpFile + 3);
return (width * scale) >> 8;
}
@@ -200,7 +201,7 @@ int Screen_v2::getShapeScaledHeight(const uint8 *shpFile, int scale) {
uint16 Screen_v2::getShapeSize(const uint8 *shp) {
if (!shp)
return 0;
- return READ_LE_UINT16(shp+6);
+ return READ_LE_UINT16(shp + 6);
}
uint8 *Screen_v2::makeShapeCopy(const uint8 *src, int index) {
@@ -241,7 +242,7 @@ int Screen_v2::getLayer(int x, int y) {
int Screen_v2::getRectSize(int w, int h) {
if (w > 320 || h > 200)
return 0;
- return w*h;
+ return w * h;
}
void Screen_v2::setTextColorMap(const uint8 *cmap) {
@@ -249,7 +250,7 @@ void Screen_v2::setTextColorMap(const uint8 *cmap) {
}
void Screen_v2::wsaFrameAnimationStep(int x1, int y1, int x2, int y2,
- int w1, int h1, int w2, int h2, int srcPage, int dstPage, int dim) {
+ int w1, int h1, int w2, int h2, int srcPage, int dstPage, int dim) {
if (!(w1 || h1 || w2 || h2))
return;
@@ -280,7 +281,7 @@ void Screen_v2::wsaFrameAnimationStep(int x1, int y1, int x2, int y2,
memcpy(dt, s, w2);
} else if (t > 0) {
if (w1 == 1) {
- memset(dt, *s, w2);
+ memset(dt, *s, w2);
} else {
t = ((((((w2 - w1 + 1) & 0xffff) << 8) / w1) + 0x100) & 0xffff) << 8;
int bp = 0;
@@ -352,7 +353,7 @@ bool Screen_v2::calcBounds(int w0, int h0, int &x1, int &y1, int &w1, int &h1, i
h1 = t;
y1 = 0;
}
- t = h0 - y1;
+ t = h0 - y1;
if (t < 1) {
w1 = h1 = -1;
} else {
@@ -364,7 +365,7 @@ bool Screen_v2::calcBounds(int w0, int h0, int &x1, int &y1, int &w1, int &h1, i
}
}
- return (w1 == -1) ? false : true;
+ return w1 != -1;
}
void Screen_v2::checkedPageUpdate(int srcPage, int dstPage) {
diff --git a/engines/kyra/screen_v2.h b/engines/kyra/screen_v2.h
index d85c762038..f84c923128 100644
--- a/engines/kyra/screen_v2.h
+++ b/engines/kyra/screen_v2.h
@@ -30,7 +30,7 @@ namespace Kyra {
class Screen_v2 : public Screen {
public:
- Screen_v2(KyraEngine_v1 *vm, OSystem *system);
+ Screen_v2(KyraEngine_v1 *vm, OSystem *system, const ScreenDim *dimTable, const int dimTableSize);
~Screen_v2();
// screen page handling
diff --git a/engines/kyra/script.h b/engines/kyra/script.h
index 5bd75f7b80..ccbe733e4d 100644
--- a/engines/kyra/script.h
+++ b/engines/kyra/script.h
@@ -81,6 +81,23 @@ public:
// Both lead to some problems in our IFF parser, either reading after the end
// of file or producing a "Chunk overread" error message. To work around this
// we need to adjust the size field properly.
+
+ // Fix for certain Russian fan translations:
+ // Westwood's original code completely ignores the FORM chunk and its size
+ // setting. After opening a TIM or EMC file they just check whether the FORM
+ // chunk exists (as a kind of file type verification) and then immediately seek
+ // behind the FORM chunk.
+ // This means that their parser is immune to weird fan translation scripts
+ // where the file size doesn't match the form chunk size. In our implemetation
+ // this would produce "Chunk overread" errors.
+ // Westwood also always pads all chunk sizes to 2 byte alignment after reading
+ // them from the file (not with FORM though, since they completely ignore it).
+ // This seems to do the trick for our FORM chunk size issue with the Russian
+ // fan translations. Another method which I have tried and which seems to work
+ // well would be simply setting _formChunk.size to the file size (-12 for TIM).
+
+ _formChunk.size = (_formChunk.size + 1) & ~1;
+
if (_formType == MKTAG('E','M','C','2'))
_formChunk.size -= 8;
else if (_formType == MKTAG('A','V','F','S'))
diff --git a/engines/kyra/script_eob.cpp b/engines/kyra/script_eob.cpp
new file mode 100644
index 0000000000..c07c41f706
--- /dev/null
+++ b/engines/kyra/script_eob.cpp
@@ -0,0 +1,1611 @@
+/* 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::setScriptFlags(uint32 flags) {
+ _inf->setFlags(flags);
+}
+
+void EoBCoreEngine::clearScriptFlags(uint32 flags) {
+ _inf->clearFlags(flags);
+}
+
+bool EoBCoreEngine::checkScriptFlags(uint32 flags) {
+ return _inf->checkFlags(flags);
+}
+
+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 = READ_LE_UINT16(pos) * 18;
+ _scriptTimers[_scriptTimersCount].ticks = ticks;
+ pos += 2;
+ _scriptTimers[_scriptTimersCount++].next = _system->getMillis() + ticks * _tickLength;
+ }
+
+ return pos;
+}
+
+void EoBCoreEngine::updateScriptTimers() {
+ bool timerUpdate = false;
+ if ((_scriptTimersMode & 2) && _stepsUntilScriptCall && _stepCounter > _stepsUntilScriptCall) {
+ _inf->run(0, 0x20);
+ _stepCounter = 0;
+ timerUpdate = true;
+ }
+
+ if (_scriptTimersMode & 1) {
+ 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;
+ timerUpdate = true;
+ }
+ }
+ }
+
+ if (timerUpdate)
+ updateScriptTimersExtra();
+}
+
+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 InfOpcode(new InfProc(this, &EoBInfProcessor::x), #x))
+#define OpcodeAlt(x) if (_vm->game() == GI_EOB1) { Opcode(x##_v1); } else { Opcode(x##_v2); }
+ Opcode(oeob_setWallType);
+ Opcode(oeob_toggleWallState);
+ Opcode(oeob_openDoor);
+ Opcode(oeob_closeDoor);
+ Opcode(oeob_replaceMonster);
+ Opcode(oeob_movePartyOrObject);
+ Opcode(oeob_moveInventoryItemToBlock);
+ OpcodeAlt(oeob_printMessage);
+ Opcode(oeob_setFlags);
+ Opcode(oeob_playSoundEffect);
+ Opcode(oeob_removeFlags);
+ Opcode(oeob_modifyCharacterHitPoints);
+ Opcode(oeob_calcAndInflictCharacterDamage);
+ Opcode(oeob_jump);
+ Opcode(oeob_end);
+ Opcode(oeob_returnFromSubroutine);
+ Opcode(oeob_callSubroutine);
+ OpcodeAlt(oeob_eval);
+ Opcode(oeob_deleteItem);
+ Opcode(oeob_loadNewLevelOrMonsters);
+ Opcode(oeob_increasePartyExperience);
+ OpcodeAlt(oeob_createItem);
+ 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;
+ _scriptSize = 0;
+
+ _abortScript = 0;
+ _abortAfterSubroutine = 0;
+ _dlgResult = 0;
+ _preventRest = 0;
+
+ _lastScriptFunc = 0;
+ _lastScriptFlags = 0;
+
+ _subroutineStack = new int8*[10];
+ memset(_subroutineStack, 0, 10 * sizeof(int8 *));
+ _subroutineStackPos = 0;
+
+ _flagTable = new uint32[18];
+ memset(_flagTable, 0, 18 * sizeof(uint32));
+
+ _stack = new int16[30];
+ memset(_stack, 0, 30 * sizeof(int16));
+ _stackIndex = 0;
+
+ _activeCharacter = -1;
+}
+
+EoBInfProcessor::~EoBInfProcessor() {
+ delete[] _subroutineStack;
+ delete[] _flagTable;
+ delete[] _stack;
+ delete[] _scriptData;
+
+ for (Common::Array<const InfOpcode *>::const_iterator a = _opcodes.begin(); a != _opcodes.end(); ++a)
+ delete *a;
+
+ _opcodes.clear();
+}
+
+void EoBInfProcessor::loadData(const uint8 *data, uint32 dataSize) {
+ delete[] _scriptData;
+ _scriptSize = dataSize;
+ _scriptData = new int8[_scriptSize];
+ memcpy(_scriptData, data, _scriptSize);
+}
+
+void EoBInfProcessor::run(int func, int flags) {
+ int o = _vm->_levelBlockProperties[func].assignedObjects;
+ if (!o)
+ return;
+
+ uint16 f = _vm->_levelBlockProperties[func].flags;
+
+ uint16 subFlags = ((f & 0xfff8) >> 3) | 0xe0;
+ if (!(flags & subFlags))
+ return;
+
+ _abortScript = 0;
+ _abortAfterSubroutine = 0;
+ _dlgResult = 0;
+ _activeCharacter = -1;
+
+ _lastScriptFunc = func;
+ _lastScriptFlags = flags;
+
+ int8 *pos = (int8 *)(_scriptData + o);
+
+ do {
+ int8 cmd = *pos++;
+ if (cmd <= _commandMin || cmd >= 0)
+ continue;
+ debugC(3, kDebugLevelScript, "[0x%.04X] EoBInfProcessor::%s()", (uint32)(pos - _scriptData), _opcodes[-(cmd + 1)]->desc.c_str());
+ pos += (*_opcodes[-(cmd + 1)]->proc)(pos);
+ } while (!_abortScript && !_abortAfterSubroutine);
+}
+
+void EoBInfProcessor::setFlags(uint32 flags) {
+ _flagTable[17] |= flags;
+}
+
+void EoBInfProcessor::clearFlags(uint32 flags) {
+ _flagTable[17] &= ~flags;
+}
+
+bool EoBInfProcessor::checkFlags(uint32 flags) const {
+ return ((_flagTable[17] & flags) == flags) ? true : false;
+}
+
+bool EoBInfProcessor::preventRest() const {
+ return _preventRest ? true : false;
+}
+
+void EoBInfProcessor::loadState(Common::SeekableSubReadStreamEndian &in, bool origFile) {
+ _preventRest = (_vm->game() == GI_EOB1 && origFile) ? 0 : in.readByte();
+ int numFlags = (_vm->game() == GI_EOB1 && origFile) ? 13 : 18;
+ for (int i = 0; i < numFlags; i++)
+ _flagTable[i] = in.readUint32();
+}
+
+void EoBInfProcessor::saveState(Common::OutSaveFile *out) {
+ out->writeByte(_preventRest);
+ for (int i = 0; i < 18; i++)
+ out->writeUint32BE(_flagTable[i]);
+}
+
+void EoBInfProcessor::reset() {
+ _preventRest = 0;
+ memset(_flagTable, 0, 18 * sizeof(uint32));
+}
+
+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);
+ }
+ debugC(5, kDebugLevelScript, " - move monsters on block '0x%.04X' to block '0x%.04X'", c, d);
+
+ } else if (a == -24) {
+ // move party to block d
+ int ba = _dlgResult;
+ int bb = _lastScriptFunc;
+ int bc = _lastScriptFlags;
+ int bd = _abortScript;
+ int be = _activeCharacter;
+ int bf = _subroutineStackPos;
+
+ _vm->moveParty(d);
+ debugC(5, kDebugLevelScript, " - move party to block '0x%.04X'", d);
+
+ _dlgResult = ba;
+ _lastScriptFunc = bb;
+ _lastScriptFlags = bc;
+ _abortScript = bd;
+ _activeCharacter = be;
+ if (!_abortAfterSubroutine)
+ _subroutineStackPos = 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;
+ }
+ }
+ debugC(5, kDebugLevelScript, " - move items from level '%d', block '0x%.04X' to level '%d', block '0x%.04X'", c, e, d, f);
+ }
+
+ _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[] = "\x6\x21\x2\x21";
+ 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:
+ _preventRest = 0;
+ debugC(5, kDebugLevelScript, " - set preventRest to 0");
+ break;
+
+ case -28:
+ _dlgResult = 1;
+ debugC(5, kDebugLevelScript, " - set dlgResult to 1");
+ break;
+
+ case -17:
+ _flagTable[_vm->_currentLevel] |= (1 << (*pos++));
+ debugC(5, kDebugLevelScript, " - set level flag '%d' for current level (current level = '%d')", *(pos - 1), _vm->_currentLevel);
+ break;
+
+ case -16:
+ _flagTable[17] |= (1 << (*pos++));
+ debugC(5, kDebugLevelScript, " - set global flag '%d'", *(pos - 1));
+ break;
+
+ case -13:
+ b = *pos++;
+ _vm->_monsters[b].flags |= (1 << (*pos++));
+ _vm->_monsters[b].mode = 0;
+ debugC(5, kDebugLevelScript, " - set monster flag '%d' for monster '%d'", *(pos - 1), b);
+ 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++;
+
+ switch (a) {
+ case -47:
+ _preventRest = 1;
+ debugC(5, kDebugLevelScript, " - set preventRest to 1");
+ break;
+
+ case -28:
+ _dlgResult = 0;
+ debugC(5, kDebugLevelScript, " - set dlgResult to 0");
+ break;
+
+ case -17:
+ _flagTable[_vm->_currentLevel] &= ~(1 << (*pos++));
+ debugC(5, kDebugLevelScript, " - clear level flag '%d' for current level (current level = '%d')", *(pos - 1), _vm->_currentLevel);
+ break;
+
+ case -16:
+ _flagTable[17] &= ~(1 << (*pos++));
+ debugC(5, kDebugLevelScript, " - clear global flag '%d'", *(pos - 1));
+ 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 savingThrowType = 5;
+ int savingThrowEffect = 1;
+
+ if (_vm->game() == GI_EOB2) {
+ flg = *pos++;
+ savingThrowType = *pos++;
+ savingThrowEffect = *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, savingThrowType, savingThrowEffect);
+ } else {
+ _vm->calcAndInflictCharacterDamage(charIndex, times, itemOrPips, useStrModifierOrBase, flg, savingThrowType, savingThrowEffect);
+ }
+ 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;
+ _subroutineStackPos = 0;
+ return 0;
+}
+
+int EoBInfProcessor::oeob_returnFromSubroutine(int8 *data) {
+ int8 *pos = data;
+
+ if (_subroutineStackPos)
+ pos = _subroutineStack[--_subroutineStackPos];
+ else
+ _abortScript = 1;
+
+ return pos - data;
+}
+
+int EoBInfProcessor::oeob_callSubroutine(int8 *data) {
+ int8 *pos = data;
+ uint16 offs = READ_LE_UINT16(pos);
+ assert(offs < _scriptSize);
+ pos += 2;
+
+ if (_subroutineStackPos < 10) {
+ _subroutineStack[_subroutineStackPos++] = 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 = 1;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if (_vm->_characters[i].effectFlags & 0x40)
+ continue;
+ a = 0;
+ break;
+ }
+ _stack[_stackIndex++] = a;
+ debugC(5, kDebugLevelScript, " - check if whole party is invisible - PUSH result: '%d'", a);
+ break;
+
+ case 1:
+ _stack[_stackIndex++] = _vm->rollDice(pos[0], pos[1], pos[2]);
+ debugC(9, kDebugLevelScript, " - throw dice(s): num = '%d', pips = '%d', offset = '%d' - PUSH result: '%d'", pos[0], pos[1], pos[2], _stack[_stackIndex - 1]);
+ 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;
+ debugC(5, kDebugLevelScript, " - check if character with class flags '0x%.02X' is present - PUSH result: '%d'", cmd, b);
+ break;
+
+ case 3:
+ cmd = *pos++;
+ b = 0;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if ((_vm->_characters[i].raceSex >> 1) == cmd) {
+ b = 1;
+ break;
+ }
+ }
+ _stack[_stackIndex++] = b;
+ debugC(5, kDebugLevelScript, " - check if character with race '%d' is present - PUSH result: '%d'", cmd, b);
+ break;
+
+ case 6:
+ _stack[_stackIndex++] = _lastScriptFlags;
+ debugC(5, kDebugLevelScript, " - get script execution flags - PUSH result: '%d'", _lastScriptFlags);
+ break;
+
+ case 13:
+ itm = &_vm->_items[_vm->_itemInHand];
+ switch (*pos++) {
+ case -31:
+ _stack[_stackIndex++] = itm->type;
+ debugC(5, kDebugLevelScript, " - get hand item type (hand item number = '%d') - PUSH result: '%d'", _vm->_itemInHand, itm->type);
+ break;
+
+ case -11:
+ _stack[_stackIndex++] = _vm->_itemInHand;
+ debugC(5, kDebugLevelScript, " - get hand item number - PUSH result: '%d'", _vm->_itemInHand);
+ break;
+
+ default:
+ _stack[_stackIndex++] = itm->value;
+ debugC(5, kDebugLevelScript, " - get hand item value (hand item number = '%d') - PUSH result: '%d'", _vm->_itemInHand, itm->value);
+ break;
+ }
+ break;
+
+ case 15:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos + 1)].walls[pos[0]];
+ debugC(5, kDebugLevelScript, " - get wall index for block '0x%.04X', direction '%d' - PUSH result: '%d'", READ_LE_UINT16(pos + 1), pos[0], _stack[_stackIndex - 1]);
+ pos += 3;
+ break;
+
+ case 19:
+ _stack[_stackIndex++] = _vm->_currentDirection;
+ debugC(5, kDebugLevelScript, " - get current direction - PUSH result: '%d'", _vm->_currentDirection);
+ break;
+
+ case 21:
+ _stack[_stackIndex++] = (_flagTable[_vm->_currentLevel] & (1 << (*pos++))) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - test level flag '%d' (current level = '%d') - PUSH result: '%d'", *(pos - 1), _vm->_currentLevel, _stack[_stackIndex - 1]);
+ break;
+
+ case 22:
+ _stack[_stackIndex++] = (_flagTable[17] & (1 << (*pos++))) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - test global flag '%d' - PUSH result: '%d'", *(pos - 1), _stack[_stackIndex - 1]);
+ break;
+
+ case 23:
+ _stack[_stackIndex++] = (_vm->_currentBlock == READ_LE_UINT16(pos)) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - compare current block with block '0x%.04X' (current block = '0x%.04X') - PUSH result: '%d'", _vm->_currentBlock, READ_LE_UINT16(pos), _stack[_stackIndex - 1]);
+ 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);
+ debugC(5, kDebugLevelScript, " - find item number '%d' on block '0x%.04X' - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 25:
+ _stack[_stackIndex++] = (_vm->_levelBlockProperties[READ_LE_UINT16(pos)].flags & 1) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - test block flag '1' for block '0x%.04X' - PUSH result: '%d'", READ_LE_UINT16(pos), _stack[_stackIndex - 1]);
+ 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);
+ debugC(5, kDebugLevelScript, " - count items of type '%d' on block '0x%.04X' - PUSH result: '%d'", b, i, _stack[_stackIndex - 1]);
+ break;
+
+ case 29:
+ _stack[_stackIndex++] = _vm->_levelBlockProperties[READ_LE_UINT16(pos)].walls[0];
+ debugC(5, kDebugLevelScript, " - get wall index 0 for block '0x%.04X' - PUSH result: '%d'", READ_LE_UINT16(pos), _stack[_stackIndex - 1]);
+ pos += 2;
+ break;
+
+ case 30:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a || b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') || POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 31:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a && b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') && POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 32:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a <= b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') <= POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 33:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a < b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') < POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 34:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a >= b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') >= POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 35:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a > b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') > POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 36:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a != b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') != POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ case 37:
+ a = _stack[--_stackIndex];
+ b = _stack[--_stackIndex];
+ _stack[_stackIndex++] = (a == b) ? 1 : 0;
+ debugC(5, kDebugLevelScript, " - evaluate: POP('%d') == POP('%d') - PUSH result: '%d'", a, b, _stack[_stackIndex - 1]);
+ break;
+
+ default:
+ a = cmd;
+ if (a >= 0 && a < 128)
+ _stack[_stackIndex++] = a;
+ debugC(5, kDebugLevelScript, " - PUSH value: '%d'", a);
+ break;
+ }
+ cmd = *pos++;
+ }
+
+ cmd = _stack[--_stackIndex];
+ if (cmd)
+ pos += 2;
+ else
+ pos = _scriptData + READ_LE_UINT16(pos);
+ debugC(5, kDebugLevelScript, " - conditional jump depending on POP('%d')", cmd);
+
+ 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 = 1;
+ for (i = 0; i < 6; i++) {
+ if (!(_vm->_characters[i].flags & 1))
+ continue;
+ if (_vm->_characters[i].effectFlags & 0x40)
+ continue;
+ a = 0;
+ 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++] = _lastScriptFlags;
+ 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);
+ debugC(5, kDebugLevelScript, " - delete hand item");
+ } else {
+ _vm->deleteBlockItem(READ_LE_UINT16(pos), (c == -2) ? -1 : c);
+ debugC(5, kDebugLevelScript, " - delete item(s) of type '%d' on block '0x%.04X'", (c == -2) ? -1 : c, READ_LE_UINT16(pos));
+ 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);
+ debugC(5, kDebugLevelScript, " - entering level '%d', sub level '%d', start block '0x%.04X', start direction '%d'", index, cmd, _vm->_currentBlock, _vm->_currentDirection);
+
+ if (_vm->_dialogueField)
+ _vm->restoreAfterDialogueSequence();
+
+ _vm->moveParty(_vm->_currentBlock);
+
+ _abortScript = 1;
+ _abortAfterSubroutine = 1;
+ _vm->_sceneUpdateRequired = true;
+
+ _vm->gui_drawAllCharPortraitsWithStats();
+ _subroutineStackPos = 0;
+
+ } else {
+ cmd = *pos++;
+ _vm->releaseMonsterShapes(cmd * 18, 18);
+ _vm->loadMonsterShapes((const char *)pos, cmd * 18, true, index * 18);
+ debugC(5, kDebugLevelScript, " - loading monster shapes '%s', monster number '%d', encode type '%d'", (const char *)pos, cmd, index);
+ 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));
+ debugC(5, kDebugLevelScript, " - award '%d' experience points", 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);
+ debugC(5, kDebugLevelScript, " - create hand item '%d'", itm);
+ } else if (block != 0xffff) {
+ _vm->setItemPosition((Item *)&_vm->_levelBlockProperties[block & 0x3ff].drawObjects, block, itm, itmPos);
+ debugC(5, kDebugLevelScript, " - create item '%d' on block '0x%.04X', position '%d'", itm, block, 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);
+ debugC(5, kDebugLevelScript, " - create hand item '%d' (value '%d', flags '0x%X', icon number '%d')", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon);
+ } else {
+ _vm->setItemPosition((Item *)&_vm->_levelBlockProperties[_vm->_currentBlock & 0x3ff].drawObjects, _vm->_currentBlock, itm, _itemPos[_vm->rollDice(1, 2, -1)]);
+ debugC(5, kDebugLevelScript, " - create item '%d' (value '%d', flags '0x%X', icon number '%d') on current block", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon);
+ }
+ } 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)]);
+ debugC(5, kDebugLevelScript, " - create item '%d' (value '%d', flags '0x%X', icon number '%d') on current block", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon);
+ } else {
+ _vm->setItemPosition((Item *)&_vm->_levelBlockProperties[block & 0x3ff].drawObjects, block, itm, itmPos);
+ debugC(5, kDebugLevelScript, " - create item '%d' (value '%d', flags '0x%X', icon number '%d') on block '0x%.04X', position '%d'", itm, _vm->_items[itm].value, _vm->_items[itm].flags, _vm->_items[itm].icon, block, 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->_npcSequenceSub = -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:
+ _vm->seq_xdeath();
+ _vm->_runFlag = false;
+ _vm->_playFinale = true;
+ _abortScript = 1;
+ return 0;
+
+ case -2:
+ _vm->seq_portal();
+ break;
+
+ case -1:
+ _vm->_runFlag = _vm->checkPassword();
+ 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 ? 2 : 3, getString(READ_LE_UINT16(pos + 2)), getString(READ_LE_UINT16(pos + 4)), getString(READ_LE_UINT16(pos + 6)));
+ 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->deletePartyItems(46, 5);
+ _vm->deletePartyItems(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..fc8b4cfc31
--- /dev/null
+++ b/engines/kyra/script_eob.h
@@ -0,0 +1,132 @@
+/* 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 KyraRpgEngine;
+
+class EoBInfProcessor {
+public:
+ EoBInfProcessor(EoBCoreEngine *engine, Screen_EoB *_screen);
+ ~EoBInfProcessor();
+
+ void loadData(const uint8 *data, uint32 dataSize);
+ void run(int func, int flags);
+
+ void setFlags(uint32 flags);
+ void clearFlags(uint32 flags);
+ bool checkFlags(uint32 flags) const;
+ bool preventRest() const;
+
+ void loadState(Common::SeekableSubReadStreamEndian &in, bool origFile = false);
+ void saveState(Common::OutSaveFile *out);
+ void reset();
+
+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_returnFromSubroutine(int8 *data);
+ int oeob_callSubroutine(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;
+ struct InfOpcode : private Common::NonCopyable {
+ InfOpcode(InfProc *p, const char *d) : proc(p), desc(d) {}
+ ~InfOpcode() { delete proc; }
+
+ InfProc *proc;
+ Common::String desc;
+ };
+ Common::Array<const InfOpcode *> _opcodes;
+
+ int8 *_scriptData;
+ uint16 _scriptSize;
+
+ uint8 _abortScript;
+ uint16 _abortAfterSubroutine;
+ int _dlgResult;
+ uint8 _preventRest;
+
+ uint16 _lastScriptFunc;
+ uint16 _lastScriptFlags;
+
+ int8 **_subroutineStack;
+ int _subroutineStackPos;
+
+ 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_lok.cpp b/engines/kyra/script_lok.cpp
index 4d40971124..8342bccab6 100644
--- a/engines/kyra/script_lok.cpp
+++ b/engines/kyra/script_lok.cpp
@@ -326,7 +326,7 @@ int KyraEngine_LoK::o1_delaySecs(EMCState *script) {
} else {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_delaySecs(%p) (%d)", (const void *)script, stackPos(0));
if (stackPos(0) >= 0 && !skipFlag())
- delay(stackPos(0)*1000, true);
+ delay(stackPos(0) * 1000, true);
}
resetSkipFlag();
@@ -689,7 +689,7 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) {
if (specialTime) {
uint32 voiceTime = snd_getVoicePlayTime();
if (voiceTime) {
- int displayFrames = ABS(endFrame-startFrame)+1;
+ int displayFrames = ABS(endFrame - startFrame) + 1;
displayFrames *= maxTime;
assert(displayFrames != 0);
@@ -720,14 +720,19 @@ int KyraEngine_LoK::o1_displayWSASequentialFrames(EMCState *script) {
if (maxTime - 1 <= 0)
maxTime = 1;
- // Workaround for bug #1498221 "KYRA1: Glitches when meeting Zanthia"
- // the original didn't do a forced screen update after displaying a wsa frame
- // while we have to do it, which make brandon disappear for a short moment,
- // what shouldn't happen. So we're not updating the screen for this special
- // case too.
- if (startFrame == 18 && endFrame == 18 && _currentRoom == 45) {
+ // WORKAROUND for bug #1498221 "KYRA1: Glitches when meeting Zanthia".
+ // The original did not do a forced screen update after displaying a WSA
+ // frame while we have to do it, which makes Brandon disappear for a short
+ // moment. That is not supposed to happen. So we're not updating the
+ // screen for this special case.
+ // This is only an issue for the CD version, but since the floppy version
+ // does not use the specified paramaeters like these, it is safe to enable
+ // it for all versions.
+ if (startFrame == 18 && endFrame == 18 && waitTime == 10 && wsaIndex == 0 && _currentRoom == 45) {
_movieObjects[wsaIndex]->displayFrame(18, 0, xpos, ypos, 0, 0, 0);
- delay(waitTime * _tickLength);
+ // We call delayMillis manually here to avoid the screen getting
+ // updated.
+ _system->delayMillis(waitTime * _tickLength);
return 0;
}
@@ -1085,7 +1090,7 @@ int KyraEngine_LoK::o1_sceneAnimationActive(EMCState *script) {
int KyraEngine_LoK::o1_setCharacterMovementDelay(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_setCharacterMovementDelay(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
- _timer->setDelay(stackPos(0)+5, stackPos(1));
+ _timer->setDelay(stackPos(0) + 5, stackPos(1));
return 0;
}
@@ -1124,7 +1129,7 @@ int KyraEngine_LoK::o1_findBrightestFireberry(EMCState *script) {
// return a glow value of "29" over here, when we are running a CD version.
if (_flags.isTalkie) {
if (_currentCharacter->sceneId == 133 || _currentCharacter->sceneId == 137 ||
- _currentCharacter->sceneId == 165 || _currentCharacter->sceneId == 173)
+ _currentCharacter->sceneId == 165 || _currentCharacter->sceneId == 173)
return 29;
}
@@ -1173,7 +1178,7 @@ int KyraEngine_LoK::o1_setFireberryGlowPalette(EMCState *script) {
case -1:
// The original seemed to draw some lines on page 2 here, which looks strange...
//if (!(_brandonStatusBit & 2))
- // warning("Unimplemented case for o1_setFireberryGlowPalette");
+ // warning("Unimplemented case for o1_setFireberryGlowPalette");
palIndex = 9;
break;
@@ -1190,7 +1195,7 @@ int KyraEngine_LoK::o1_setFireberryGlowPalette(EMCState *script) {
palIndex = 9;
break;
- case 28: case 29: default:
+ case 28: case 29: default:
palIndex = 6;
}
@@ -1227,8 +1232,8 @@ int KyraEngine_LoK::o1_setFireberryGlowPalette(EMCState *script) {
if (_brandonStatusBit & 2) {
if (_currentCharacter->sceneId != 133 && _currentCharacter->sceneId != 137 &&
- _currentCharacter->sceneId != 165 && _currentCharacter->sceneId != 173 &&
- (_currentCharacter->sceneId < 187 || _currentCharacter->sceneId > 198)) {
+ _currentCharacter->sceneId != 165 && _currentCharacter->sceneId != 173 &&
+ (_currentCharacter->sceneId < 187 || _currentCharacter->sceneId > 198)) {
palIndex = 14;
}
}
@@ -1291,12 +1296,12 @@ int KyraEngine_LoK::o1_drawItemShapeIntoScene(EMCState *script) {
flags = 1;
if (onlyHidPage) {
- _screen->drawShape(2, _shapes[216+item], x, y, 0, flags);
+ _screen->drawShape(2, _shapes[216 + item], x, y, 0, flags);
} else {
_screen->hideMouse();
_animator->restoreAllObjectBackgrounds();
- _screen->drawShape(2, _shapes[216+item], x, y, 0, flags);
- _screen->drawShape(0, _shapes[216+item], x, y, 0, flags);
+ _screen->drawShape(2, _shapes[216 + item], x, y, 0, flags);
+ _screen->drawShape(0, _shapes[216 + item], x, y, 0, flags);
_animator->flagAllObjectsForBkgdChange();
_animator->preserveAnyChangedBackgrounds();
_animator->flagAllObjectsForRefresh();
@@ -1409,7 +1414,7 @@ int KyraEngine_LoK::o1_fillFlaskWithWater(EMCState *script) {
int KyraEngine_LoK::o1_getCharacterMovementDelay(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getCharacterMovementDelay(%p) (%d)", (const void *)script, stackPos(0));
- return _timer->getDelay(stackPos(0)+5);
+ return _timer->getDelay(stackPos(0) + 5);
}
int KyraEngine_LoK::o1_getBirthstoneGem(EMCState *script) {
@@ -1715,13 +1720,13 @@ int KyraEngine_LoK::o1_pauseMusicSeconds(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_pauseMusicSeconds(%p) ()", (const void *)script);
// if music disabled
// return
- delay(stackPos(0)*1000, true);
+ delay(stackPos(0) * 1000, true);
return 0;
}
int KyraEngine_LoK::o1_resetMaskRegion(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_resetMaskRegion(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
- _screen->fillRect(stackPos(1), stackPos(2), stackPos(1)+stackPos(3), stackPos(2)+stackPos(4), 0, 5);
+ _screen->fillRect(stackPos(1), stackPos(2), stackPos(1) + stackPos(3), stackPos(2) + stackPos(4), 0, 5);
return 0;
}
diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp
index d8ba32ce09..c5d1d49030 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) {
@@ -305,7 +286,7 @@ int LoLEngine::olol_getItemPara(EMCState *script) {
if (!stackPos(0))
return 0;
- ItemInPlay *i = &_itemsInPlay[stackPos(0)];
+ LoLItem *i = &_itemsInPlay[stackPos(0)];
ItemProperty *p = &_itemProperties[i->itemPropertyIndex];
switch (stackPos(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) {
@@ -811,7 +792,7 @@ int LoLEngine::olol_resetBlockShapeAssignment(EMCState *script) {
int LoLEngine::olol_copyRegion(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_copyRegion(%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));
+ (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
_screen->copyRegion(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), Screen::CR_NO_P_CHECK);
if (!stackPos(7))
_screen->updateScreen();
@@ -820,7 +801,7 @@ int LoLEngine::olol_copyRegion(EMCState *script) {
int LoLEngine::olol_initMonster(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_initMonster(%p) (%d, %d, %d, %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), stackPos(8), stackPos(9), stackPos(10));
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9), stackPos(10));
uint16 x = 0;
uint16 y = 0;
calcCoordinates(x, y, stackPos(0), stackPos(1), stackPos(2));
@@ -830,11 +811,11 @@ int LoLEngine::olol_initMonster(EMCState *script) {
return -1;
for (uint8 i = 0; i < 30; i++) {
- MonsterInPlay *l = &_monsters[i];
+ LoLMonster *l = &_monsters[i];
if (l->hitPoints || l->mode == 13)
continue;
- memset(l, 0, sizeof(MonsterInPlay));
+ memset(l, 0, sizeof(LoLMonster));
l->id = i;
l->x = x;
l->y = y;
@@ -938,14 +919,14 @@ int LoLEngine::olol_dummy0(EMCState *script) {
int LoLEngine::olol_loadMonsterProperties(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_loadMonsterProperties(%p) (%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %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), stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPos(12), stackPos(13),
- stackPos(14), stackPos(15), stackPos(16), stackPos(17), stackPos(18), stackPos(19), stackPos(20),
- stackPos(21), stackPos(22), stackPos(23), stackPos(24), stackPos(25), stackPos(26), stackPos(27),
- 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)];
+ (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5),
+ stackPos(6), stackPos(7), stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPos(12), stackPos(13),
+ stackPos(14), stackPos(15), stackPos(16), stackPos(17), stackPos(18), stackPos(19), stackPos(20),
+ stackPos(21), stackPos(22), stackPos(23), stackPos(24), stackPos(25), stackPos(26), stackPos(27),
+ 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));
+
+ LoLMonsterProperty *l = &_monsterProperties[stackPos(0)];
l->shapeIndex = stackPos(1) & 0xff;
int shpWidthMax = 0;
@@ -958,14 +939,14 @@ int LoLEngine::olol_loadMonsterProperties(EMCState *script) {
l->maxWidth = shpWidthMax;
- l->fightingStats[0] = (stackPos(2) << 8) / 100; // hit chance
- l->fightingStats[1] = 256; //
- l->fightingStats[2] = (stackPos(3) << 8) / 100; // protection
- l->fightingStats[3] = stackPos(4); // evade chance
- l->fightingStats[4] = (stackPos(5) << 8) / 100; // speed
- l->fightingStats[5] = (stackPos(6) << 8) / 100; //
- l->fightingStats[6] = (stackPos(7) << 8) / 100; //
- l->fightingStats[7] = (stackPos(8) << 8) / 100; //
+ l->fightingStats[0] = (stackPos(2) << 8) / 100; // hit chance
+ l->fightingStats[1] = 256; //
+ l->fightingStats[2] = (stackPos(3) << 8) / 100; // protection
+ l->fightingStats[3] = stackPos(4); // evade chance
+ l->fightingStats[4] = (stackPos(5) << 8) / 100; // speed
+ l->fightingStats[5] = (stackPos(6) << 8) / 100; //
+ l->fightingStats[6] = (stackPos(7) << 8) / 100; //
+ l->fightingStats[7] = (stackPos(8) << 8) / 100; //
l->fightingStats[8] = 0;
for (int i = 0; i < 8; i++) {
@@ -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)];
+ LoLMonster *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];
+ LoLMonster *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];
+ LoLMonster *m = &_monsters[stackPos(0) & 0x7fff];
int d = stackPos(1);
switch (d) {
@@ -1385,14 +1365,14 @@ int LoLEngine::olol_countBlockItems(EMCState *script) {
return res;
}
-int LoLEngine::olol_characterSkillTest(EMCState *script){
+int LoLEngine::olol_characterSkillTest(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_characterSkillTest(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
int skill = stackPos(0);
int n = countActiveCharacters();
int m = 0;
int c = 0;
- for (int i = 0; i < n; i++) {
+ for (int i = 0; i < n; i++) {
int v = _characters[i].skillModifiers[skill] + _characters[i].skillLevels[skill] + 25;
if (v > m) {
m = v;
@@ -1403,7 +1383,7 @@ int LoLEngine::olol_characterSkillTest(EMCState *script){
return (rollDice(1, 100) > m) ? -1 : c;
}
-int LoLEngine::olol_countAllMonsters(EMCState *script){
+int LoLEngine::olol_countAllMonsters(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_countAllMonsters(%p)", (const void *)script);
int res = 0;
@@ -1415,7 +1395,7 @@ int LoLEngine::olol_countAllMonsters(EMCState *script){
return res;
}
-int LoLEngine::olol_playEndSequence(EMCState *script){
+int LoLEngine::olol_playEndSequence(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playEndSequence(%p)", (const void *)script);
int c = 0;
@@ -1567,7 +1547,7 @@ int LoLEngine::olol_moveBlockObjects(EMCState *script) {
l &= 0x7fff;
- MonsterInPlay *m = &_monsters[l];
+ LoLMonster *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];
+ LoLMonster *m = &_monsters[stackPos(0) & 0x7fff];
setMonsterMode(m, 14);
checkSceneUpdateNeed(m->block);
placeMonster(m, 0, 0);
@@ -1705,7 +1685,7 @@ int LoLEngine::olol_countSpecificMonsters(EMCState *script) {
int LoLEngine::olol_updateBlockAnimations2(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_updateBlockAnimations2(%p) (%d, %d, %d, %d, ...)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
int numFrames = stackPos(3);
- assert (numFrames <= 97);
+ assert(numFrames <= 97);
int curFrame = stackPos(2) % numFrames;
setWallType(stackPos(0), stackPos(1), stackPos(4 + curFrame));
return 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);
@@ -2012,7 +1992,7 @@ int LoLEngine::olol_findInventoryItem(EMCState *script) {
cur = 0;
last = 4;
}
- for (;cur < last; cur++) {
+ for (; cur < last; cur++) {
if (!(_characters[cur].flags & 1))
continue;
for (int i = 0; i < 11; i++) {
@@ -2055,7 +2035,7 @@ int LoLEngine::olol_changeItemTypeOrFlag(EMCState *script) {
if (stackPos(0) < 1)
return 0;
- ItemInPlay *i = &_itemsInPlay[stackPos(0)];
+ LoLItem *i = &_itemsInPlay[stackPos(0)];
int16 val = stackPos(2);
if (stackPos(1) == 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;
}
@@ -2376,7 +2356,7 @@ int LoLEngine::tlol_setupPaletteFade(const TIM *tim, const uint16 *param) {
int LoLEngine::tlol_loadPalette(const TIM *tim, const uint16 *param) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_loadPalette(%p, %p) (%d)", (const void *)tim, (const void *)param, param[0]);
- const char *palFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0]<<1)));
+ const char *palFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0] << 1)));
_screen->loadPalette(palFile, _screen->getPalette(0));
return 1;
}
@@ -2392,7 +2372,7 @@ int LoLEngine::tlol_setupPaletteFadeEx(const TIM *tim, const uint16 *param) {
int LoLEngine::tlol_processWsaFrame(const TIM *tim, const uint16 *param) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_processWsaFrame(%p, %p) (%d, %d, %d, %d, %d)",
- (const void *)tim, (const void *)param, param[0], param[1], param[2], param[3], param[4]);
+ (const void *)tim, (const void *)param, param[0], param[1], param[2], param[3], param[4]);
const int animIndex = tim->wsa[param[0]].anim - 1;
const int frame = param[1];
@@ -2590,8 +2570,8 @@ int LoLEngine::tlol_stopBackgroundAnimation(const TIM *tim, const uint16 *param)
int LoLEngine::tlol_fadeInScene(const TIM *tim, const uint16 *param) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_fadeInScene(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], param[1]);
- const char *sceneFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0]<<1)));
- const char *overlayFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[1]<<1)));
+ const char *sceneFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0] << 1)));
+ const char *overlayFile = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[1] << 1)));
_screen->copyRegion(0, 0, 0, 0, 320, 200, 0, 2, Screen::CR_NO_P_CHECK);
@@ -2642,7 +2622,7 @@ int LoLEngine::tlol_unusedResourceFunc(const TIM *tim, const uint16 *param) {
int LoLEngine::tlol_fadeInPalette(const TIM *tim, const uint16 *param) {
debugC(3, kDebugLevelScriptFuncs, "LoLEngine::tlol_fadeInPalette(%p, %p) (%d, %d)", (const void *)tim, (const void *)param, param[0], param[1]);
- const char *bitmap = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0]<<1)));
+ const char *bitmap = (const char *)(tim->text + READ_LE_UINT16(tim->text + (param[0] << 1)));
Palette pal(_screen->getPalette(0).getNumColors());
_screen->loadBitmap(bitmap, 3, 3, &pal);
@@ -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);
diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp
index 83d03d1f63..177d7993a0 100644
--- a/engines/kyra/script_tim.cpp
+++ b/engines/kyra/script_tim.cpp
@@ -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
@@ -905,12 +893,10 @@ TIMInterpreter_LoL::TIMInterpreter_LoL(LoLEngine *engine, Screen_v2 *screen_v2,
_screen = engine->_screen;
+ delete _animator;
_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 +964,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 +1009,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 +1054,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 +1091,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..aa512daae8 100644
--- a/engines/kyra/script_tim.h
+++ b/engines/kyra/script_tim.h
@@ -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/script_v1.cpp b/engines/kyra/script_v1.cpp
index 4cfbdf8ab8..aaa07e6d61 100644
--- a/engines/kyra/script_v1.cpp
+++ b/engines/kyra/script_v1.cpp
@@ -106,13 +106,13 @@ int KyraEngine_v1::o1_fillRect(EMCState *script) {
int KyraEngine_v1::o1_blockInWalkableRegion(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_blockInWalkableRegion(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
- screen()->blockInRegion(stackPos(0), stackPos(1), stackPos(2)-stackPos(0)+1, stackPos(3)-stackPos(1)+1);
+ screen()->blockInRegion(stackPos(0), stackPos(1), stackPos(2) - stackPos(0) + 1, stackPos(3) - stackPos(1) + 1);
return 0;
}
int KyraEngine_v1::o1_blockOutWalkableRegion(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v1::o1_blockOutWalkableRegion(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3));
- screen()->blockOutRegion(stackPos(0), stackPos(1), stackPos(2)-stackPos(0)+1, stackPos(3)-stackPos(1)+1);
+ screen()->blockOutRegion(stackPos(0), stackPos(1), stackPos(2) - stackPos(0) + 1, stackPos(3) - stackPos(1) + 1);
return 0;
}
diff --git a/engines/kyra/script_v2.cpp b/engines/kyra/script_v2.cpp
index e42cdf9ff4..c38a144537 100644
--- a/engines/kyra/script_v2.cpp
+++ b/engines/kyra/script_v2.cpp
@@ -57,7 +57,7 @@ int KyraEngine_v2::o2_setCharacterFacingOverwrite(EMCState *script) {
int KyraEngine_v2::o2_trySceneChange(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_trySceneChange(%p) (%d, %d, %d, %d)", (const void *)script,
- stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3));
_unkHandleSceneChangeFlag = 1;
int success = inputSceneChange(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
@@ -87,7 +87,7 @@ int KyraEngine_v2::o2_checkForItem(EMCState *script) {
int KyraEngine_v2::o2_defineItem(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_defineItem(%p) (%d, %d, %d, %d)", (const void *)script,
- stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3));
int freeItem = findFreeItem();
if (freeItem >= 0) {
@@ -102,13 +102,13 @@ int KyraEngine_v2::o2_defineItem(EMCState *script) {
int KyraEngine_v2::o2_addSpecialExit(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_addSpecialExit(%p) (%d, %d, %d, %d, %d)", (const void *)script,
- stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
if (_specialExitCount < 5) {
- _specialExitTable[_specialExitCount+0] = stackPos(0);
- _specialExitTable[_specialExitCount+5] = stackPos(1);
- _specialExitTable[_specialExitCount+10] = stackPos(2) + stackPos(0) - 1;
- _specialExitTable[_specialExitCount+15] = stackPos(3) + stackPos(1) - 1;
- _specialExitTable[_specialExitCount+20] = stackPos(4);
+ _specialExitTable[_specialExitCount + 0] = stackPos(0);
+ _specialExitTable[_specialExitCount + 5] = stackPos(1);
+ _specialExitTable[_specialExitCount + 10] = stackPos(2) + stackPos(0) - 1;
+ _specialExitTable[_specialExitCount + 15] = stackPos(3) + stackPos(1) - 1;
+ _specialExitTable[_specialExitCount + 20] = stackPos(4);
++_specialExitCount;
}
return 0;
@@ -226,7 +226,7 @@ int KyraEngine_v2::o2_defineRoomEntrance(EMCState *script) {
int KyraEngine_v2::o2_runAnimationScript(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_runAnimationScript(%p) ('%s', %d, %d, %d)", (const void *)script, stackPosString(0), stackPos(1),
- stackPos(2), stackPos(3));
+ stackPos(2), stackPos(3));
runAnimationScript(stackPosString(0), stackPos(3), stackPos(2) ? 1 : 0, stackPos(1), stackPos(2));
return 0;
@@ -241,7 +241,7 @@ int KyraEngine_v2::o2_setSpecialSceneScriptRunTime(EMCState *script) {
int KyraEngine_v2::o2_defineScene(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2_defineScene(%p) (%d, '%s', %d, %d, %d, %d, %d, %d)",
- (const void *)script, stackPos(0), stackPosString(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ (const void *)script, stackPos(0), stackPosString(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
const int scene = stackPos(0);
strcpy(_sceneList[scene].filename1, stackPosString(1));
strcpy(_sceneList[scene].filename2, stackPosString(1));
@@ -323,7 +323,7 @@ int KyraEngine_v2::o2_getVocHigh(EMCState *script) {
int KyraEngine_v2::o2a_setAnimationShapes(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_v2::o2a_setAnimationShapes(%p) ('%s', %d, %d, %d, %d, %d)", (const void *)script,
- stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
+ stackPosString(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5));
strcpy(_animShapeFilename, stackPosString(0));
_animShapeLastEntry = stackPos(1);
_animShapeWidth = stackPos(2);
diff --git a/engines/kyra/seqplayer.cpp b/engines/kyra/seqplayer.cpp
index 531d864293..1f9097d09d 100644
--- a/engines/kyra/seqplayer.cpp
+++ b/engines/kyra/seqplayer.cpp
@@ -375,15 +375,14 @@ void SeqPlayer::s1_copyRegionSpecial() {
_screen->copyRegion(152, 56, 152, 56, 48, 48, 2, 0);
break;
case 4: {
- _screen->_charWidth = -2;
- const int x = (Screen::SCREEN_W - _screen->getTextWidth(copyStr)) / 2;
- const int y = 179;
- _screen->setTextColorMap(colorMap);
- if (_vm->gameFlags().platform != Common::kPlatformAmiga)
- _screen->printText(copyStr, x + 1, y + 1, 0xB, 0xC);
- _screen->printText(copyStr, x, y, 0xF, 0xC);
- }
- break;
+ _screen->_charWidth = -2;
+ const int x = (Screen::SCREEN_W - _screen->getTextWidth(copyStr)) / 2;
+ const int y = 179;
+ _screen->setTextColorMap(colorMap);
+ if (_vm->gameFlags().platform != Common::kPlatformAmiga)
+ _screen->printText(copyStr, x + 1, y + 1, 0xB, 0xC);
+ _screen->printText(copyStr, x, y, 0xF, 0xC);
+ } break;
case 5:
_screen->_curPage = 2;
break;
@@ -624,7 +623,7 @@ bool SeqPlayer::playSequence(const uint8 *seqData, bool skipSeq) {
if (_vm->gameFlags().lang == Common::JA_JPN)
charStr[1] = _vm->seqTextsTable()[_seqDisplayedText][++_seqDisplayedChar];
_screen->printText(charStr, _seqDisplayedTextX, 180, 0xF, 0xC);
- _seqDisplayedTextX += _screen->getCharWidth(charStr[0]);
+ _seqDisplayedTextX += _screen->getCharWidth((uint8)charStr[0]);
++_seqDisplayedChar;
if (_vm->seqTextsTable()[_seqDisplayedText][_seqDisplayedChar] == '\0')
diff --git a/engines/kyra/sequences_darkmoon.cpp b/engines/kyra/sequences_darkmoon.cpp
new file mode 100644
index 0000000000..d4f5c847fd
--- /dev/null
+++ b/engines/kyra/sequences_darkmoon.cpp
@@ -0,0 +1,1436 @@
+/* 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/darkmoon.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
+ };
+
+ struct Config {
+ Config(Mode m, const char *const *str, const char *const *cps, const char *const *pal, const DarkMoonShapeDef **shp, const DarkMoonAnimCommand **anim, bool paletteFading) : mode(m), strings(str), cpsFiles(cps), palFiles(pal), shapeDefs(shp), animData(anim), palFading(paletteFading) {}
+ Mode mode;
+ const char *const *strings;
+ const char *const *cpsFiles;
+ const char *const *palFiles;
+ const DarkMoonShapeDef **shapeDefs;
+ const DarkMoonAnimCommand **animData;
+ bool palFading;
+ };
+
+ DarkmoonSequenceHelper(OSystem *system, DarkMoonEngine *vm, Screen_EoB *screen, const Config *config);
+ ~DarkmoonSequenceHelper();
+
+ void loadScene(int index, int pageNum);
+ void animCommand(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;
+ const Config *_config;
+
+ Palette *_palettes[12];
+
+ const uint8 **_shapes;
+
+ uint32 _fadePalTimer;
+ int _fadePalRate;
+ int _fadePalIndex;
+};
+
+int DarkMoonEngine::mainMenu() {
+ int menuChoice = _menuChoiceInit;
+ _menuChoiceInit = 0;
+
+ _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, 3, &_screen->getPalette(0));
+ }
+
+ if (_configRenderMode == Common::kRenderEGA)
+ _screen->loadPalette("MENU.EGA", _screen->getPalette(0));
+
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->convertPage(3, 2, 0);
+
+ of = _screen->setFont(Screen::FID_6_FNT);
+ op = _screen->setCurPage(2);
+ Common::String versionString(Common::String::format("ScummVM %s", gScummVMVersion));
+ _screen->printText(versionString.c_str(), 267 - versionString.size() * 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();
+ _allowImport = true;
+ menuChoice = mainMenuLoop();
+ _allowImport = false;
+ } 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->simpleMenu_setup(6, 0, _mainMenuStrings, -1, 0, 0);
+
+ while (sel == -1 && !shouldQuit())
+ sel = _gui->simpleMenu_process(6, _mainMenuStrings, 0, -1, 0);
+ } while ((sel < 0 || sel > 5) && !shouldQuit());
+
+ return sel + 1;
+}
+
+void DarkMoonEngine::seq_playIntro() {
+ DarkmoonSequenceHelper::Config config(DarkmoonSequenceHelper::kIntro, _introStrings, _cpsFilesIntro, _configRenderMode == Common::kRenderEGA ? _palFilesIntroEGA : _palFilesIntroVGA, _shapesIntro, _animIntro, false);
+ DarkmoonSequenceHelper sq(_system, this, _screen, &config);
+
+ _screen->setCurPage(0);
+ _screen->clearCurPage();
+
+ snd_stopSound();
+
+ sq.loadScene(4, 2);
+ sq.loadScene(0, 2);
+ sq.delay(1);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSong(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.animCommand(3, 18);
+ sq.animCommand(6, 18);
+ sq.animCommand(0);
+
+ sq.waitForSongNotifier(1);
+
+ sq.animCommand(_configRenderMode == Common::kRenderEGA ? 12 : 11);
+ sq.animCommand(7, 6);
+ sq.animCommand(2, 6);
+
+ sq.waitForSongNotifier(2);
+
+ sq.animCommand(_configRenderMode == Common::kRenderEGA ? 39 : 38);
+ sq.animCommand(3);
+ sq.animCommand(8);
+ sq.animCommand(1, 10);
+ sq.animCommand(0, 6);
+ sq.animCommand(2);
+
+ sq.waitForSongNotifier(3);
+
+ _screen->setClearScreenDim(17);
+ _screen->setCurPage(2);
+ _screen->setClearScreenDim(17);
+ _screen->setCurPage(0);
+
+ sq.animCommand(_configRenderMode == Common::kRenderEGA ? 41 : 40);
+ sq.animCommand(7, 18);
+
+ sq.printText(0, 16); // You were settling...
+ sq.animCommand(7, 90);
+ sq.fadeText();
+
+ sq.printText(1, 16); // Then a note was slipped to you
+ sq.animCommand(8);
+ sq.animCommand(2, 72);
+ sq.fadeText();
+
+ sq.printText(2, 16); // It was from your friend Khelben Blackstaff...
+ sq.animCommand(2);
+ sq.animCommand(6, 36);
+ sq.animCommand(3);
+ sq.fadeText();
+
+ sq.printText(3, 16); // The message was urgent.
+
+ sq.loadScene(1, 2);
+ sq.waitForSongNotifier(4);
+
+ // intro scroll
+ if (!skipFlag() && !shouldQuit()) {
+ if (_configRenderMode == Common::kRenderEGA) {
+ for (int i = 0; i < 35; i++) {
+ uint32 endtime = _system->getMillis() + 2 * _tickLength;
+ _screen->copyRegion(16, 8, 8, 8, 296, 128, 0, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(i << 3, 0, 304, 8, 8, 128, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ if (i == 12)
+ sq.animCommand(42);
+ else if (i == 25)
+ snd_playSoundEffect(11);
+ delayUntil(endtime);
+ }
+ } else {
+ 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.animCommand(42);
+ delayUntil(endtime);
+ }
+ }
+ }
+
+ _screen->copyRegion(8, 8, 0, 0, 304, 128, 0, 2, Screen::CR_NO_P_CHECK);
+ sq.animCommand(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.animCommand(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.animCommand(10);
+ sq.animCommand(10);
+ sq.animCommand(9);
+ sq.animCommand(9);
+ sq.fadeText();
+
+ sq.printText(6, 15); // Khelben awaits you in his study
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(10);
+ sq.animCommand(9);
+ sq.animCommand(14);
+ sq.loadScene(5, 2);
+
+ sq.waitForSongNotifier(5);
+
+ sq.fadeText();
+ _screen->clearCurPage();
+ _screen->updateScreen();
+
+ for (int i = 0; i < 6; i++)
+ sq.animCommand(15);
+
+ if (_configRenderMode == Common::kRenderEGA && !skipFlag() && !shouldQuit()) {
+ _screen->loadPalette("INTRO.EGA", _screen->getPalette(0));
+ _screen->setScreenPalette(_screen->getPalette(0));
+ }
+
+ sq.loadScene(6, 2);
+ sq.loadScene(7, 2);
+ _screen->clearCurPage();
+ sq.update(2);
+
+ sq.animCommand(16);
+ sq.printText(7, 15); // Thank you for coming so quickly
+ sq.animCommand(16);
+ sq.animCommand(17);
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(16);
+ sq.fadeText();
+ sq.animCommand(16);
+
+ sq.loadScene(8, 2);
+ sq.update(2);
+ sq.animCommand(32);
+ sq.printText(8, 15); // I am troubled my friend
+ sq.animCommand(33);
+ sq.animCommand(33);
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(32);
+ sq.fadeText();
+
+ sq.printText(9, 15); // Ancient evil stirs in the Temple Darkmoon
+ sq.animCommand(33);
+ sq.animCommand(43);
+ sq.animCommand(33);
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(32);
+ sq.fadeText();
+
+ sq.printText(10, 15); // I fear for the safety of our city
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(33);
+ sq.animCommand(32);
+ sq.animCommand(32);
+
+ sq.loadScene(9, 2);
+ sq.fadeText();
+
+ sq.waitForSongNotifier(6);
+
+ sq.update(2);
+ sq.animCommand(34);
+
+ sq.printText(11, 15); // I need your help
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(34);
+ sq.animCommand(35);
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(34);
+ sq.fadeText();
+
+ sq.loadScene(12, 2);
+ sq.update(2);
+ sq.loadScene(6, 2);
+ sq.animCommand(18);
+
+ sq.printText(12, 15); // Three nights ago I sent forth a scout
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(22);
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.fadeText();
+
+ sq.printText(13, 15); // She has not yet returned
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(23);
+ sq.animCommand(24);
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(17);
+ sq.animCommand(18);
+ sq.fadeText();
+
+ sq.printText(14, 15); // I fear for her safety
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.animCommand(25);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+ sq.animCommand(18);
+ sq.animCommand(18);
+
+ sq.printText(15, 15); // Take this coin
+ sq.animCommand(28);
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+
+ sq.loadScene(10, 2);
+ _screen->clearCurPage();
+ _screen->updateScreen();
+
+ sq.animCommand(37, 18);
+ sq.animCommand(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.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+
+ sq.printText(17, 15); // You must act quickly
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+ sq.animCommand(18);
+
+ sq.printText(18, 15); // I will teleport you near Darkmoon
+ sq.animCommand(20);
+ sq.animCommand(27);
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(18);
+ sq.animCommand(18);
+ sq.fadeText();
+ sq.animCommand(18);
+
+ sq.printText(19, 15); // May luck be with you my friend
+ sq.animCommand(19);
+ sq.animCommand(19);
+ sq.animCommand(20);
+ sq.animCommand(18);
+ sq.fadeText();
+ sq.animCommand(29);
+
+ sq.waitForSongNotifier(7);
+
+ sq.animCommand(30);
+ sq.animCommand(31);
+
+ sq.waitForSongNotifier(8, true);
+
+ if (skipFlag() || shouldQuit()) {
+ snd_fadeOut();
+ } else {
+ _screen->setScreenDim(17);
+ _screen->clearCurDim();
+ snd_playSoundEffect(14);
+
+ if (_configRenderMode != Common::kRenderEGA)
+ sq.fadePalette(10, 1);
+ _screen->setClearScreenDim(18);
+ sq.delay(6);
+ if (_configRenderMode != Common::kRenderEGA)
+ sq.fadePalette(9, 1);
+ _screen->clearCurPage();
+ }
+ sq.fadePalette(9, 10);
+}
+
+void DarkMoonEngine::seq_playFinale() {
+ DarkmoonSequenceHelper::Config config(DarkmoonSequenceHelper::kFinale, _finaleStrings, _cpsFilesFinale, _configRenderMode == Common::kRenderEGA ? _palFilesFinaleEGA : _palFilesFinaleVGA, _shapesFinale, _animFinale, true);
+ DarkmoonSequenceHelper sq(_system, this, _screen, &config);
+
+ _screen->setCurPage(0);
+ _screen->setFont(Screen::FID_8_FNT);
+
+ _sound->loadSoundFile("FINALE1");
+ snd_stopSound();
+ sq.delay(3);
+
+ _screen->clearCurPage();
+ _screen->updateScreen();
+
+ sq.loadScene(0, 2);
+ sq.delay(18);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSong(1);
+ sq.update(2);
+
+ sq.loadScene(1, 2);
+
+ sq.animCommand(0);
+ sq.animCommand(0);
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(2);
+ sq.animCommand(1);
+ sq.animCommand(2);
+ sq.animCommand(2);
+
+ sq.printText(0, 10); // Finally, Dran has been defeated
+ for (int i = 0; i < 7; i++)
+ sq.animCommand(2);
+ sq.fadeText();
+ sq.animCommand(2);
+
+ sq.waitForSongNotifier(1);
+
+ sq.printText(1, 10); // Suddenly, your friend Khelben appears
+ sq.animCommand(4);
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(2, 15); // Greetings, my victorious friends
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+ sq.animCommand(6);
+
+ sq.printText(3, 15); // You have defeated Dran
+ for (int i = 0; i < 5; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(4, 15); // I did not know Dran was a dragon
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(5, 15); // He must have been over 300 years old
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(6, 15); // His power is gone
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(7, 15); // But Darkmoon is still a source of great evil
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(2);
+ sq.fadeText();
+
+ sq.printText(8, 15); // And many of his minions remain
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(5);
+ sq.animCommand(2);
+ sq.animCommand(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.animCommand(7);
+ sq.animCommand(8);
+ sq.animCommand(7);
+ sq.animCommand(7, 36);
+ sq.fadeText();
+
+ sq.printText(10, 15); // So my forces can destroy it..
+ for (int i = 0; i < 3; i++)
+ sq.animCommand(7);
+ sq.animCommand(8);
+ sq.animCommand(7);
+ sq.animCommand(7, 36);
+ sq.animCommand(8, 18);
+ sq.fadeText();
+
+ sq.printText(11, 15); // Follow me
+ sq.animCommand(7, 18);
+ sq.animCommand(9, 18);
+ sq.animCommand(8, 18);
+ sq.fadeText();
+
+ sq.loadScene(7, 2);
+
+ if (_configRenderMode != Common::kRenderEGA)
+ 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())
+ snd_playSoundEffect(7);
+ sq.delay(8);
+
+ sq.animCommand(10);
+ sq.animCommand(13);
+ sq.initDelayedPaletteFade(4, 1);
+
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(14);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.initDelayedPaletteFade(2, 1);
+
+ sq.animCommand(15);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(15);
+ sq.animCommand(15);
+ sq.animCommand(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())
+ snd_playSoundEffect(7);
+ sq.delay(8);
+
+ sq.animCommand(10);
+ sq.initDelayedPaletteFade(5, 1);
+ sq.animCommand(13);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(13);
+ sq.animCommand(14);
+ sq.animCommand(14);
+ sq.animCommand(13);
+ sq.animCommand(12);
+ for (int i = 0; i < 4; i++)
+ sq.animCommand(16);
+ sq.animCommand(17);
+ sq.animCommand(18);
+
+ sq.printText(15, 10); // The temple ceases to exist
+ sq.initDelayedPaletteFade(6, 1);
+ sq.delay(36);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+
+ sq.delay(54);
+ sq.fadeText();
+ sq.loadScene(12, 2);
+
+ sq.waitForSongNotifier(5);
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(6);
+
+ if (!skipFlag() && !shouldQuit()) {
+ if (_configRenderMode != Common::kRenderEGA)
+ sq.setPaletteWithoutTextColor(0);
+ _screen->crossFadeRegion(0, 0, 8, 8, 304, 128, 2, 0);
+ }
+ sq.delay(18);
+
+ sq.printText(16, 15); // My friends, our work is done
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(19, 36);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(12);
+ sq.fadeText();
+
+ sq.printText(17, 15); // Thank you
+ sq.animCommand(19);
+ sq.animCommand(20, 36);
+ sq.fadeText();
+
+ sq.printText(18, 15); // You have earned my deepest respect
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.animCommand(20);
+ sq.animCommand(19);
+ sq.animCommand(19);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.delay(36);
+ sq.fadeText();
+
+ sq.printText(19, 15); // We will remember you always
+ sq.animCommand(19);
+ sq.animCommand(19, 18);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.animCommand(20, 18);
+ sq.fadeText();
+
+ sq.delay(28);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(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 {
+ snd_playSoundEffect(6);
+ if (_configRenderMode != Common::kRenderEGA)
+ sq.setPaletteWithoutTextColor(0);
+ _screen->crossFadeRegion(0, 0, 8, 8, 304, 128, 2, 0);
+ }
+
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(12);
+ sq.delay(5);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.delay(11);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(12);
+ sq.delay(7);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(11);
+ sq.delay(12);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSoundEffect(12);
+
+ removeInputTop();
+ resetSkipFlag(true);
+
+ sq.loadScene(10, 2);
+ sq.loadScene(9, 2);
+ snd_stopSound();
+ sq.delay(3);
+
+ _sound->loadSoundFile("FINALE2");
+
+ sq.delay(18);
+ if (!skipFlag() && !shouldQuit())
+ snd_playSong(1);
+
+ seq_playCredits(&sq, _creditsData, 18, 2, 6, 2);
+
+ sq.delay(90);
+
+ resetSkipFlag(true);
+
+ if (_configRenderMode != Common::kRenderEGA) {
+ 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);
+
+ snd_stopSound();
+ 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, const Config *config) :
+ _system(system), _vm(vm), _screen(screen), _config(config) {
+
+ for (int i = 0; _config->palFiles[i]; i++) {
+ if (i < 4)
+ _palettes[i] = &_screen->getPalette(i);
+ else
+ _palettes[i] = new Palette(256);
+ _screen->loadPalette(_config->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->setFont(Screen::FID_8_FNT);
+ _screen->hideMouse();
+
+ _vm->delay(150);
+ _vm->_eventList.clear();
+ _vm->_allowSkip = true;
+}
+
+DarkmoonSequenceHelper::~DarkmoonSequenceHelper() {
+ for (int i = 4; _config->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);
+ _vm->_allowSkip = false;
+}
+
+void DarkmoonSequenceHelper::loadScene(int index, int pageNum) {
+ char file[13];
+ strcpy(file, _config->cpsFiles[index]);
+
+ Common::SeekableReadStream *s = _vm->resource()->createReadStream(file);
+ uint32 chunkID = 0;
+ if (s) {
+ chunkID = s->readUint32LE();
+ s->seek(0);
+ }
+
+ if (s && chunkID == MKTAG('F', 'O', 'R', 'M')) {
+ // The original code also handles files with FORM chunks and ILBM and PBM sub chunks. This will probably be necessary for Amiga versions.
+ // The DOS versions do not need this, but still have the code for it. We error out for now.
+ error("DarkmoonSequenceHelper::loadScene(): CPS file loading failure in scene %d - unhandled FORM chunk encountered", index);
+ } else if (s && file[0] != 'X') {
+ delete s;
+ _screen->loadBitmap(_config->cpsFiles[index], pageNum | 1, pageNum | 1, _palettes[0]);
+ } else {
+ if (!s) {
+ file[0] = 'X';
+ s = _vm->resource()->createReadStream(file);
+ }
+
+ if (!s)
+ error("DarkmoonSequenceHelper::loadScene(): CPS file loading failure in scene %d", index);
+
+ if (_config->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 (_config->shapeDefs[index]) {
+ for (const DarkMoonShapeDef *df = _config->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);
+
+ if (_vm->_configRenderMode == Common::kRenderEGA)
+ setPalette(0);
+
+ _screen->convertPage(pageNum | 1, pageNum, 0);
+
+ if ((pageNum == 0 || pageNum == 1) && !_vm->skipFlag() && !_vm->shouldQuit())
+ _screen->updateScreen();
+}
+
+void DarkmoonSequenceHelper::animCommand(int index, int del) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+
+ uint32 end = 0;
+
+ for (const DarkMoonAnimCommand *s = _config->animData[index]; s->command != 0xff && !_vm->skipFlag() && !_vm->shouldQuit(); s++) {
+ int palIndex = _config->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 (_vm->_configRenderMode != Common::kRenderEGA && s->pal)
+ setPaletteWithoutTextColor(palIndex);
+ delay(s->delay);
+ if (_vm->_configRenderMode != Common::kRenderEGA && _config->mode == kIntro && s->pal)
+ setPaletteWithoutTextColor(0);
+ break;
+
+ case 1:
+ // draw shape, then restore background
+ shapeW = _shapes[s->obj][2];
+ shapeH = _shapes[s->obj][3];
+
+ if (_config->mode == 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, _config->mode == kIntro ? 0 : 18);
+
+ if (_vm->_configRenderMode != Common::kRenderEGA && s->pal)
+ setPaletteWithoutTextColor(palIndex);
+ else
+ _screen->updateScreen();
+
+ delay(s->delay);
+
+ if (_config->mode == kIntro) {
+ if (_vm->_configRenderMode != Common::kRenderEGA && 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 (_vm->_configRenderMode != Common::kRenderEGA && s->pal)
+ setPaletteWithoutTextColor(palIndex);
+ else if (!_screen->_curPage)
+ _screen->updateScreen();
+
+ delay(s->delay);
+
+ if (_vm->_configRenderMode != Common::kRenderEGA && _config->mode == kIntro && s->pal)
+ setPaletteWithoutTextColor(0);
+ break;
+
+ case 3:
+ case 4:
+ // fade shape in or out or restore background
+ if (_config->mode == kFinale)
+ break;
+
+ if (_vm->_configRenderMode == Common::kRenderEGA) {
+ if (palIndex)
+ _screen->drawShape(0, _shapes[s->obj], s->x1, y, 0);
+ 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();
+ delay(s->delay /** 7*/);
+ } else {
+ _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:
+ // copy region
+ if (_config->mode == kFinale && s->pal)
+ setPaletteWithoutTextColor(palIndex);
+
+ _screen->copyRegion(s->x2 << 3, s->y2, s->x1, s->y1, s->w << 3, s->h, (s->obj && _config->mode == 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->snd_playSoundEffect(s->obj);
+ break;
+
+ case 7:
+ // restore background (only used in EGA mode)
+ delay(s->delay);
+ _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();
+ break;
+
+ default:
+ error("DarkmoonSequenceHelper::animCommand(): 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);
+ uint8 col1 = 15;
+
+ if (_vm->_configRenderMode != Common::kRenderEGA) {
+ _palettes[0]->copy(*_palettes[0], color, 1, 255);
+ setPalette(0);
+ col1 = 255;
+ }
+
+ char *temp = new char[strlen(_config->strings[index]) + 1];
+ char *str = temp;
+ strcpy(str, _config->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, col1, 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;
+ if (_vm->_configRenderMode != Common::kRenderEGA)
+ _screen->fadeTextColor(_palettes[0], 255, 8);
+ _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);
+
+ if (_vm->_configRenderMode != Common::kRenderEGA)
+ setPaletteWithoutTextColor(0);
+}
+
+void DarkmoonSequenceHelper::setPaletteWithoutTextColor(int index) {
+ if (_vm->_configRenderMode == Common::kRenderEGA || _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();
+ _system->delayMillis(10);
+}
+
+void DarkmoonSequenceHelper::setPalette(int index) {
+ _screen->setScreenPalette(*_palettes[index]);
+}
+
+void DarkmoonSequenceHelper::fadePalette(int index, int del) {
+ if (_vm->skipFlag() || _vm->shouldQuit())
+ return;
+ if (_vm->_configRenderMode == Common::kRenderEGA) {
+ setPalette(index);
+ _screen->updateScreen();
+ } else {
+ _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 (_vm->_configRenderMode == Common::kRenderEGA || !_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 (_config->palFading) {
+ 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 (_vm->sound()->checkTrigger() < index && !(_vm->skipFlag() || _vm->shouldQuit())) {
+ if (introUpdateAnim) {
+ animCommand(30 | seq);
+ seq ^= 1;
+ }
+
+ if (_config->palFading)
+ processDelayedPaletteFade();
+
+ _vm->updateInput();
+ }
+}
+
+void DarkMoonEngine::seq_nightmare() {
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+ _screen->copyRegion(0, 0, 0, 120, 176, 24, 12, 2, Screen::CR_NO_P_CHECK);
+
+ initDialogueSequence();
+ gui_drawDialogueBox();
+
+ _txt->printDialogueText(99, 0);
+ snd_playSoundEffect(54);
+
+ static const uint8 seqX[] = { 0, 20, 0, 20 };
+ static const uint8 seqY[] = { 0, 0, 96, 96 };
+ static const uint8 seqDelay[] = { 12, 7, 7, 12 };
+
+ for (const int8 *i = _dreamSteps; *i != -1; ++i) {
+ drawSequenceBitmap("DREAM", 0, seqX[*i], seqY[*i], 0);
+ delay(seqDelay[*i] * _tickLength);
+ }
+
+ _txt->printDialogueText(20, _okStrings[0]);
+
+ restoreAfterDialogueSequence();
+
+ _screen->setFont(of);
+}
+
+void DarkMoonEngine::seq_kheldran() {
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+
+ initDialogueSequence();
+ gui_drawDialogueBox();
+
+ static const char file[] = "KHELDRAN";
+ _txt->printDialogueText(_kheldranStrings[0]);
+ drawSequenceBitmap(file, 0, 0, 0, 0);
+ _txt->printDialogueText(20, _moreStrings[0]);
+ snd_playSoundEffect(56);
+ drawSequenceBitmap(file, 0, 20, 0, 0);
+ delay(10 * _tickLength);
+ drawSequenceBitmap(file, 0, 0, 96, 0);
+ delay(10 * _tickLength);
+ drawSequenceBitmap(file, 0, 20, 96, 0);
+ delay(7 * _tickLength);
+ _txt->printDialogueText(76, _okStrings[0]);
+
+ restoreAfterDialogueSequence();
+
+ _screen->setFont(of);
+}
+
+void DarkMoonEngine::seq_dranDragonTransformation() {
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+
+ initDialogueSequence();
+ gui_drawDialogueBox();
+
+ static const char file[] = "DRANX";
+ drawSequenceBitmap(file, 0, 0, 0, 0);
+ _txt->printDialogueText(120, _moreStrings[0]);
+ snd_playSoundEffect(56);
+ drawSequenceBitmap(file, 0, 20, 0, 0);
+ delay(7 * _tickLength);
+ drawSequenceBitmap(file, 0, 0, 96, 0);
+ delay(7 * _tickLength);
+ drawSequenceBitmap(file, 0, 20, 96, 0);
+ delay(18 * _tickLength);
+
+ restoreAfterDialogueSequence();
+
+ _screen->setFont(of);
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/sequences_eob.cpp b/engines/kyra/sequences_eob.cpp
new file mode 100644
index 0000000000..4a9f7d8a65
--- /dev/null
+++ b/engines/kyra/sequences_eob.cpp
@@ -0,0 +1,1152 @@
+/* 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/eob.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 EoBIntroPlayer {
+public:
+ EoBIntroPlayer(EoBEngine *vm, Screen_EoB *screen);
+ ~EoBIntroPlayer() {}
+
+ void start();
+
+private:
+ void openingCredits();
+ void tower();
+ void orb();
+ void waterdeepEntry();
+ void king();
+ void hands();
+ void waterdeepExit();
+ void tunnel();
+
+ void loadAndSetPalette(const char *filename);
+ void copyBlurRegion(int x1, int y1, int x2, int y2, int w, int h, int step);
+ void boxMorphTransition(int targetDestX, int targetDestY, int targetFinalX, int targetFinalY, int targetSrcX, int targetSrcY, int targetFinalW, int targetFinalH, int originX1, int originY1, int originW, int originH);
+ void whirlTransition();
+
+ EoBEngine *_vm;
+ Screen_EoB *_screen;
+
+ const char *const *_filesOpening;
+ const char *const *_filesTower;
+ const char *const *_filesOrb;
+ const char *const *_filesWdEntry;
+ const char *const *_filesKing;
+ const char *const *_filesHands;
+ const char *const *_filesWdExit;
+ const char *const *_filesTunnel;
+ const uint8 *_openingFrmDelay;
+ const uint8 *_wdEncodeX;
+ const uint8 *_wdEncodeY;
+ const uint8 *_wdEncodeWH;
+ const uint16 *_wdDsX;
+ const uint8 *_wdDsY;
+ const uint8 *_tvlX1;
+ const uint8 *_tvlY1;
+ const uint8 *_tvlX2;
+ const uint8 *_tvlY2;
+ const uint8 *_tvlW;
+ const uint8 *_tvlH;
+};
+
+EoBIntroPlayer::EoBIntroPlayer(EoBEngine *vm, Screen_EoB *screen) : _vm(vm), _screen(screen) {
+ int temp = 0;
+ _filesOpening = _vm->staticres()->loadStrings(kEoB1IntroFilesOpening, temp);
+ _filesTower = _vm->staticres()->loadStrings(kEoB1IntroFilesTower, temp);
+ _filesOrb = _vm->staticres()->loadStrings(kEoB1IntroFilesOrb, temp);
+ _filesWdEntry = _vm->staticres()->loadStrings(kEoB1IntroFilesWdEntry, temp);
+ _filesKing = _vm->staticres()->loadStrings(kEoB1IntroFilesKing, temp);
+ _filesHands = _vm->staticres()->loadStrings(kEoB1IntroFilesHands, temp);
+ _filesWdExit = _vm->staticres()->loadStrings(kEoB1IntroFilesWdExit, temp);
+ _filesTunnel = _vm->staticres()->loadStrings(kEoB1IntroFilesTunnel, temp);
+ _openingFrmDelay = _vm->staticres()->loadRawData(kEoB1IntroOpeningFrmDelay, temp);
+ _wdEncodeX = _vm->staticres()->loadRawData(kEoB1IntroWdEncodeX, temp);
+ _wdEncodeY = _vm->staticres()->loadRawData(kEoB1IntroWdEncodeY, temp);
+ _wdEncodeWH = _vm->staticres()->loadRawData(kEoB1IntroWdEncodeWH, temp);
+ _wdDsX = _vm->staticres()->loadRawDataBe16(kEoB1IntroWdDsX, temp);
+ _wdDsY = _vm->staticres()->loadRawData(kEoB1IntroWdDsY, temp);
+ _tvlX1 = _vm->staticres()->loadRawData(kEoB1IntroTvlX1, temp);
+ _tvlY1 = _vm->staticres()->loadRawData(kEoB1IntroTvlY1, temp);
+ _tvlX2 = _vm->staticres()->loadRawData(kEoB1IntroTvlX2, temp);
+ _tvlY2 = _vm->staticres()->loadRawData(kEoB1IntroTvlY2, temp);
+ _tvlW = _vm->staticres()->loadRawData(kEoB1IntroTvlW, temp);
+ _tvlH = _vm->staticres()->loadRawData(kEoB1IntroTvlH, temp);
+}
+
+void EoBIntroPlayer::start() {
+ _vm->_allowSkip = true;
+ openingCredits();
+
+ if (!_vm->shouldQuit() && !_vm->skipFlag()) {
+ _vm->snd_playSong(2);
+ _screen->loadBitmap((_vm->_configRenderMode == Common::kRenderCGA || _vm->_configRenderMode == Common::kRenderEGA) ? "TITLE-E.CMP" : "TITLE-V.CMP", 3, 5, 0);
+ _screen->convertPage(5, 2, _vm->_cgaMappingDefault);
+ _screen->crossFadeRegion(0, 0, 0, 0, 320, 200, 2, 0);
+ _vm->delay(120 * _vm->_tickLength);
+ }
+
+ Common::SeekableReadStream *s = _vm->resource()->createReadStream("TEXT.RAW");
+ if (s) {
+ s->seek(768);
+ _screen->loadFileDataToPage(s, 5, s->size() - 768);
+ delete s;
+ } else {
+ _screen->loadBitmap("TEXT.CMP", 3, 5, 0);
+ }
+ _screen->convertPage(5, 6, _vm->_cgaMappingAlt);
+
+ tower();
+ orb();
+ waterdeepEntry();
+ king();
+ hands();
+ waterdeepExit();
+ tunnel();
+
+ whirlTransition();
+ _vm->snd_stopSound();
+ _vm->_allowSkip = false;
+}
+
+void EoBIntroPlayer::openingCredits() {
+ loadAndSetPalette(_filesOpening[5]);
+
+ _screen->loadBitmap(_filesOpening[4], 5, 3, 0);
+ _screen->convertPage(3, 0, _vm->_cgaMappingAlt);
+ _screen->updateScreen();
+
+ _vm->snd_playSong(1);
+ _vm->delay(_openingFrmDelay[0] * _vm->_tickLength);
+
+ for (int i = 0; i < 4 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ _screen->loadBitmap(_filesOpening[i], 5, 3, 0);
+ uint32 nextFrameTimer = _vm->_system->getMillis() + _openingFrmDelay[i + 1] * _vm->_tickLength;
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->crossFadeRegion(0, 50, 0, 50, 320, 102, 4, 0);
+ _vm->delayUntil(nextFrameTimer);
+ }
+}
+
+void EoBIntroPlayer::tower() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ _screen->loadBitmap(_filesTower[1], 5, 3, 0);
+ _screen->setCurPage(2);
+ uint8 *shp = _screen->encodeShape(0, 0, 16, 56, true, _vm->_cgaMappingAlt);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->clearCurPage();
+
+ for (int i = 0; i < 200; i += 64)
+ _screen->copyRegion(128, 104, 96, i, 128, 64, 4, 2, Screen::CR_NO_P_CHECK);
+
+ _screen->fillRect(0, 184, 319, 199, 12);
+ int cp = _screen->setCurPage(0);
+ whirlTransition();
+ loadAndSetPalette(_filesTower[0]);
+
+ _screen->setCurPage(cp);
+ _screen->clearCurPage();
+
+ for (int i = 0; i < 200; i += 64)
+ _screen->copyRegion(128, 104, 0, i, 128, 64, 4, 2, Screen::CR_NO_P_CHECK);
+
+ _screen->setCurPage(0);
+
+ for (int i = 0; i < 64 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 2) {
+ uint32 end = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+ _screen->copyRegion(0, 142 - i, 96, 0, 128, i + 1, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 96, i + 1, 128, 167 - i, 2, 0, Screen::CR_NO_P_CHECK);
+ if (!i)
+ _screen->copyRegion(0, 0, 0, 168, 320, 32, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 0; i < 24 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 2) {
+ uint32 end = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+ _screen->copyRegion(0, 79 - i, 96, 0, 24, 65 + i, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(104, 79 - i, 200, 0, 24, 65 + i, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(24, 110, 120, i + 31, 80, 34, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(152, 0, 120, 32, 80, i + 1, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 96, 65 + i, 128, 103 - i, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 0; i < 56 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 2) {
+ uint32 end = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+ _screen->copyRegion(0, 56, 96, i, 24, 54, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(104, 56, 200, i, 24, 54, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 110, 96, 54 + i, 128, 34, 4, 0, Screen::CR_NO_P_CHECK);
+
+ if (i < 32) {
+ _screen->fillRect(128, 0, 255, i + 1, 12, 2);
+ _screen->copyRegion(152, 0, 120, 32, 80, i + 25, 4, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ _screen->fillRect(128, 0, 255, i + 1, 12, 2);
+ _screen->copyRegion(152, i + 1, 120, 32 + i + 1, 80, 23, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(152, 0, 152, 32, 80, i + 1, 4, 2, Screen::CR_NO_P_CHECK);
+ }
+
+ _screen->drawShape(2, shp, 128, i - 55, 0);
+ _screen->copyRegion(128, 0, 96, 0, 128, i + 1, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, 96, i + 89, 128, 79 - i, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 32, 0, 168, 320, 32, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(65 * _vm->_tickLength);
+ delete[] shp;
+}
+
+void EoBIntroPlayer::orb() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ uint8 *shp[5];
+ _screen->loadBitmap(_filesOrb[0], 5, 3, 0);
+ _screen->setCurPage(2);
+ shp[4] = _screen->encodeShape(0, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ _screen->loadBitmap(_filesOrb[1], 5, 3, 0);
+ shp[3] = _screen->encodeShape(16, 0, 16, 104, true, _vm->_cgaMappingAlt);
+
+ _screen->fillRect(0, 0, 127, 103, 12);
+ for (int i = 1; i < 4; i++) {
+ copyBlurRegion(128, 0, 0, 0, 128, 104, i);
+ shp[3 - i] = _screen->encodeShape(0, 0, 16, 104, true, _vm->_cgaMappingAlt);
+ }
+
+ _screen->fillRect(0, 0, 159, 135, 12);
+ _screen->setCurPage(0);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->clearCurPage();
+
+ _vm->snd_playSoundEffect(6);
+
+ for (int i = -1; i < 4 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ if (i >= 0)
+ _screen->drawShape(2, shp[i], 16, 16, 0);
+ _screen->drawShape(2, shp[4], 0, 0, 0);
+ _screen->copyRegion(0, 0, 80, 24, 160, 136, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 64, 0, 168, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(40 * _vm->_tickLength);
+
+ _vm->snd_playSoundEffect(6);
+
+ for (int i = 3; i > -2 && !_vm->shouldQuit() && !_vm->skipFlag(); i--) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ _screen->fillRect(16, 16, 143, 119, 12, 2);
+ if (i >= 0)
+ _screen->drawShape(2, shp[i], 16, 16, 0);
+ _screen->drawShape(2, shp[4], 0, 0, 0);
+ _screen->copyRegion(0, 0, 80, 24, 160, 136, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->delay(40 * _vm->_tickLength);
+
+ for (int i = 0; i < 5; i++)
+ delete[] shp[i];
+}
+
+void EoBIntroPlayer::waterdeepEntry() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ uint8 *shp[4];
+ uint8 *shp2[31];
+ uint8 *shp3[3];
+
+ loadAndSetPalette(_filesWdEntry[0]);
+ _screen->loadBitmap(_filesWdEntry[1], 5, 3, 0);
+ _screen->setCurPage(2);
+ shp[3] = _screen->encodeShape(0, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ for (int i = 1; i < 4; i++) {
+ copyBlurRegion(0, 0, 0, 0, 160, 136, i);
+ shp[3 - i] = _screen->encodeShape(0, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ }
+ _screen->setCurPage(0);
+
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _vm->snd_playSoundEffect(6);
+
+ for (int i = 0; i < 4 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ _screen->drawShape(0, shp[i], 80, 24, 0);
+ delete[] shp[i];
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 80, 0, 168, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(50 * _vm->_tickLength);
+
+ _screen->setCurPage(2);
+ shp[0] = _screen->encodeShape(20, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ _screen->loadBitmap(_filesWdEntry[2], 5, 3, 0);
+ shp[1] = _screen->encodeShape(0, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ shp[2] = _screen->encodeShape(20, 0, 20, 136, true, _vm->_cgaMappingAlt);
+ _screen->loadBitmap(_filesWdEntry[3], 5, 3, 0);
+
+ for (int i = 0; i < 31; i++)
+ shp2[i] = _screen->encodeShape(_wdEncodeX[i], 136 + (_wdEncodeY[i] << 3), _wdEncodeWH[i], _wdEncodeWH[i] << 3, true, _vm->_cgaMappingAlt);
+ for (int i = 0; i < 3; i++)
+ shp3[i] = _screen->encodeShape(5 * i, 152, 5, 32, true, _vm->_cgaMappingAlt);
+
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+
+ for (int i = 0; i < 3 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ _screen->fillRect(0, 0, 159, 135, 12, 2);
+ _screen->drawShape(2, shp[i], 0, 0, 0);
+ _screen->copyRegion(0, 0, 80, 24, 160, 136, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 0, 80, 24, 160, 136, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(4 * _vm->_tickLength);
+ _screen->copyRegion(160, 0, 80, 24, 160, 136, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _screen->updateScreen();
+ _vm->delay(4 * _vm->_tickLength);
+ _screen->copyRegion(0, 184, 40, 184, 232, 16, 4, 0, Screen::CR_NO_P_CHECK);
+
+ int cx = 264;
+ int cy = 11;
+
+ for (int i = 0; i < 70 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+
+ _screen->copyRegion(cx - 2, cy - 2, 0, 0, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(4, shp3[((i & 3) == 3) ? 1 : (i & 3)], cx, cy, 0);
+ _screen->copyRegion(cx - 2, cy - 2, cx - 82, cy + 22, 48, 36, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, cx - 2, cy - 2, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ cx--;
+ cy++;
+
+ for (int ii = 0; ii < 5; ii++) {
+ int s = _vm->_rnd.getRandomNumber(255) % 31;
+ _screen->drawShape(0, shp2[s], _wdDsX[s] - 80, _wdDsY[s] + 24, 0);
+ }
+
+ if (!(_vm->_rnd.getRandomNumber(255) & 7))
+ _vm->snd_playSoundEffect(_vm->_rnd.getRandomBit() ? 5 : 14);
+
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 0; i < 3; i++) {
+ delete[] shp[i];
+ delete[] shp3[i];
+ }
+
+ for (int i = 0; i < 31; i++)
+ delete[] shp2[i];
+}
+
+void EoBIntroPlayer::king() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ _screen->loadBitmap(_filesKing[0], 5, 3, 0);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+
+ int x = 15;
+ int y = 14;
+ int w = 1;
+ int h = 1;
+
+ for (int i = 0; i < 10 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(x << 3, y << 3, x << 3, y << 3, w << 3, h << 3, 4, 0, Screen::CR_NO_P_CHECK);
+ if (x > 6)
+ x --;
+ if (y > 0)
+ y -= 2;
+ w += 3;
+ if (x + w > 34)
+ w = 34 - x;
+ h += 3;
+ if (y + h > 23)
+ h = 23 - y;
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->delay(25 * _vm->_tickLength);
+
+ uint8 *shp[4];
+ int16 dy[4];
+ int16 stepY[4];
+
+ static const uint8 advEncX[] = { 0, 6, 12, 19 };
+ static const uint8 advEncW[] = { 6, 6, 7, 6 };
+ static const int8 modY[] = { -4, -8, -2, -2, 1, 0, 0, 0 };
+
+ _screen->loadBitmap(_filesKing[1], 5, 3, 0);
+ _screen->setCurPage(2);
+ for (int i = 0; i < 4; i++) {
+ shp[i] = _screen->encodeShape(advEncX[i], 0, advEncW[i], 98, true, _vm->_cgaMappingAlt);
+ dy[i] = 180 + ((_vm->_rnd.getRandomNumber(255) & 3) << 3);
+ stepY[i] = (i * 5) & 3;
+ }
+
+ _screen->copyPage(0, 4);
+
+ for (bool runloop = true; runloop && !_vm->shouldQuit() && !_vm->skipFlag();) {
+ runloop = false;
+ uint32 end = _vm->_system->getMillis() + 2 * _vm->_tickLength;
+
+ for (int i = 0; i < 4; i++) {
+ if (dy[i] <= 82)
+ continue;
+ stepY[i] = (stepY[i] + 1) & 7;
+ dy[i] += modY[stepY[i]];
+
+ if (dy[i] < 82)
+ dy[i] = 82;
+
+ if (dy[i] < 180) {
+ _screen->copyRegion((advEncX[i] + 8) << 3, dy[i] - 2, 0, dy[i] - 2, advEncW[i] << 3, 182 - dy[i], 4, 4, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(4, shp[i], 0, dy[i], 0);
+ _screen->copyRegion(0, dy[i] - 2, (advEncX[i] + 8) << 3, dy[i] - 2, advEncW[i] << 3, 182 - dy[i], 4, 0, Screen::CR_NO_P_CHECK);
+ }
+
+ runloop = true;
+ }
+
+ if (!(_vm->_rnd.getRandomNumber(255) & 3))
+ _vm->snd_playSoundEffect(7);
+
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 96, 0, 160, 320, 32, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(70 * _vm->_tickLength);
+
+ for (int i = 0; i < 4; i++)
+ delete[] shp[i];
+}
+
+void EoBIntroPlayer::hands() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ _screen->setCurPage(2);
+ uint8 *shp1 = _screen->encodeShape(0, 140, 21, 60, true, _vm->_cgaMappingAlt);
+ uint8 *shp2 = _screen->encodeShape(21, 140, 12, 60, true, _vm->_cgaMappingAlt);
+ _screen->loadBitmap(_filesHands[0], 3, 5, 0);
+
+ _screen->fillRect(0, 160, 319, 199, 12, 0);
+ _screen->fillRect(0, 0, 191, 63, 157, 2);
+ _screen->drawShape(2, shp1, 0, 4, 0);
+ _screen->drawShape(2, shp2, 151, 4, 0);
+ boxMorphTransition(25, 8, 18, 4, 3, 0, 21, 8, 6, 0, 28, 23);
+ _screen->copyRegion(0, 128, 0, 176, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->updateScreen();
+ _vm->delay(15 * _vm->_tickLength);
+ _vm->snd_playSoundEffect(11);
+
+ for (int i = -22; i <= 20 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 167, 63, 157);
+ _screen->drawShape(2, shp1, i, 4, 0);
+ _screen->drawShape(2, shp2, 105 - i, 4, 0);
+ _screen->copyRegion(0, 0, 144, 32, 168, 64, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSoundEffect(10);
+
+ delete[] shp1;
+ delete[] shp2;
+ _vm->delay(15 * _vm->_tickLength);
+
+ _screen->setCurPage(4);
+ shp1 = _screen->encodeShape(17, 0, 11, 120, true, _vm->_cgaMappingAlt);
+ shp2 = _screen->encodeShape(28, 112, 1, 31, true, _vm->_cgaMappingAlt);
+ uint8 *shp3 = _screen->encodeShape(9, 138, 14, 54, true, _vm->_cgaMappingAlt);
+
+ _screen->setCurPage(2);
+ _screen->fillRect(0, 0, 135, 63, 157);
+ _screen->drawShape(2, shp1, 32, -80, 0);
+ _screen->drawShape(2, shp2, 40, -16, 0);
+ boxMorphTransition(18, 16, 10, 12, 0, 0, 17, 8, 17, 3, 25, 10);
+ _vm->delay(15 * _vm->_tickLength);
+
+ for (int i = -80; i <= 0 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 135, 63, 157);
+ _screen->drawShape(2, shp1, 32, i, 0);
+ _screen->drawShape(2, shp2, 40, i + 64, 0);
+ _screen->copyRegion(0, 0, 80, 96, 136, 64, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSoundEffect(12);
+ _vm->delay(5 * _vm->_tickLength);
+
+ for (int i = 0; i > -54 && !_vm->shouldQuit() && !_vm->skipFlag(); i -= 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 135, 63, 157);
+ _screen->drawShape(2, shp3, 12, 64 + i, 0);
+ _screen->drawShape(2, shp1, 32, i, 0);
+ _screen->copyRegion(0, 0, 80, 96, 136, 64, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ delete[] shp1;
+ delete[] shp2;
+ delete[] shp3;
+ _vm->delay(15 * _vm->_tickLength);
+
+ _screen->setCurPage(4);
+ shp1 = _screen->encodeShape(0, 0, 17, 136, true, _vm->_cgaMappingAlt);
+ shp2 = _screen->encodeShape(0, 136, 9, 48, true, _vm->_cgaMappingAlt);
+
+ _screen->setCurPage(2);
+ _screen->fillRect(0, 0, 143, 95, 157);
+ _screen->drawShape(2, shp1, -56, -56, 0);
+ _screen->drawShape(2, shp2, 52, 49, 0);
+ boxMorphTransition(9, 6, 0, 0, 0, 0, 18, 12, 8, 11, 21, 10);
+ _vm->delay(15 * _vm->_tickLength);
+ _vm->snd_playSoundEffect(11);
+
+ for (int i = -56; i <= -8 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 143, 95, 157);
+ _screen->drawShape(2, shp1, i, i, 0);
+ _screen->drawShape(2, shp2, (i == -8) ? 55 : 52, (i == -8) ? 52 : 49, 0);
+ _screen->copyRegion(0, 0, 0, 0, 144, 96, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSoundEffect(10);
+ delete[] shp1;
+ delete[] shp2;
+ _vm->delay(30 * _vm->_tickLength);
+
+ _screen->setCurPage(4);
+ shp1 = _screen->encodeShape(28, 0, 11, 40, true, _vm->_cgaMappingAlt);
+ shp2 = _screen->encodeShape(28, 40, 10, 72, true, _vm->_cgaMappingAlt);
+
+ _screen->setCurPage(2);
+ _screen->fillRect(0, 0, 87, 112, 157);
+ _screen->drawShape(2, shp2, 0, 90, 0);
+ boxMorphTransition(20, 13, 15, 6, 0, 0, 11, 14, 0, 0, 24, 16);
+ _vm->delay(15 * _vm->_tickLength);
+
+ int dy = 90;
+ for (int i = -40; i <= 0 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 87, 112, 157);
+ _screen->drawShape(2, shp2, 0, dy, 0);
+ _screen->copyRegion(0, 0, 120, 48, 88, 112, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ dy -= 5;
+ }
+
+ _vm->snd_playSoundEffect(13);
+
+ for (int i = -40; i <= 0 && !_vm->shouldQuit() && !_vm->skipFlag(); i += 4) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->fillRect(0, 0, 87, 39, 157);
+ _screen->drawShape(2, shp1, 0, i, 0);
+ _screen->copyRegion(0, 0, 120, 48, 88, 112, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ delete[] shp1;
+ delete[] shp2;
+ _vm->delay(48 * _vm->_tickLength);
+}
+
+void EoBIntroPlayer::waterdeepExit() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ uint8 *shp2[31];
+ uint8 *shp3[3];
+
+ _screen->loadBitmap(_filesWdExit[0], 5, 3, 0);
+ _screen->setCurPage(2);
+ for (int i = 0; i < 31; i++)
+ shp2[i] = _screen->encodeShape(_wdEncodeX[i], 136 + (_wdEncodeY[i] << 3), _wdEncodeWH[i], _wdEncodeWH[i] << 3, true, _vm->_cgaMappingAlt);
+ for (int i = 0; i < 3; i++)
+ shp3[i] = _screen->encodeShape(5 * i + 15, 152, 5, 32, true, _vm->_cgaMappingAlt);
+ uint8 *shp1 = _screen->encodeShape(31, 136, 5, 32, true, _vm->_cgaMappingAlt);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->copyRegion(0, 0, 0, 136, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _screen->copyRegion(160, 0, 80, 24, 160, 136, 4, 0, Screen::CR_NO_P_CHECK);
+
+ int cx = 140;
+ int cy = 128;
+
+ for (int i = 0; i < 70 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 3 * _vm->_tickLength;
+ int fx = cx - 2;
+ if (fx < 160)
+ fx = 160;
+ int fy = cy - 2;
+ if (fy > 98)
+ fy = 98;
+
+ _screen->copyRegion(fx, fy, 0, 0, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(4, shp3[((i & 3) == 3) ? 1 : (i & 3)], cx, cy, 0);
+ _screen->drawShape(4, shp1, 160, 104, 0);
+ _screen->copyRegion(fx, fy, fx - 80, fy + 24, 48, 36, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 0, fx, fy, 48, 36, 4, 4, Screen::CR_NO_P_CHECK);
+ cx++;
+ cy--;
+
+ for (int ii = 0; ii < 5; ii++) {
+ int s = _vm->_rnd.getRandomNumber(255) % 31;
+ _screen->drawShape(0, shp2[s], _wdDsX[s] - 80, _wdDsY[s] + 24, 0);
+ }
+
+ if (!(_vm->_rnd.getRandomNumber(255) & 7))
+ _vm->snd_playSoundEffect(_vm->_rnd.getRandomBit() ? 5 : 14);
+
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 0; i < 3; i++)
+ delete[] shp3[i];
+
+ for (int i = 0; i < 31; i++)
+ delete[] shp2[i];
+ delete[] shp1;
+
+ _screen->setCurPage(0);
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _screen->copyRegion(0, 136, 0, 0, 48, 36, 0, 4, Screen::CR_NO_P_CHECK);
+
+ loadAndSetPalette(_filesWdExit[1]);
+ _screen->loadBitmap(_filesWdExit[2], 3, 5, 0);
+ _screen->convertPage(5, 2, _vm->_cgaMappingAlt);
+ whirlTransition();
+ _vm->delay(6 * _vm->_tickLength);
+
+ _screen->copyRegion(0, 144, 0, 184, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+
+ cx = 0;
+ cy = 136;
+ int dy = 0;
+ for (int i = 0; i < 19 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(cx, cy, 80, dy + 16, 160, 8, 2, 0, Screen::CR_NO_P_CHECK);
+ cy += 8;
+ dy += 8;
+ if (i == 6) {
+ cx = 160;
+ cy = 0;
+ }
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSong(3);
+ _vm->delay(60 * _vm->_tickLength);
+
+ for (int i = 0; i < 56 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() +_vm->_tickLength;
+ _screen->copyRegion(0, 136 + i, 80, 16, 160, 56 - i, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(160, 0, 80, 72 - i, 160, 96 + i, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ for (int i = 1; i < 48 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(160, i, 80, 16, 160, 152, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->loadBitmap(_filesWdExit[3], 3, 5, 0);
+ _screen->convertPage(5, 2, _vm->_cgaMappingAlt);
+ _vm->delay(30 * _vm->_tickLength);
+ _screen->setCurPage(0);
+ _screen->fillRect(0, 16, 319, 31, 12);
+ _screen->fillRect(0, 136, 319, 199, 12);
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ loadAndSetPalette(_filesWdExit[4]);
+ _screen->updateScreen();
+ _vm->delay(50 * _vm->_tickLength);
+}
+
+void EoBIntroPlayer::tunnel() {
+ if (_vm->shouldQuit() || _vm->skipFlag())
+ return;
+
+ _screen->setCurPage(4);
+ uint8 *shp2 = _screen->encodeShape(20, 0, 20, 120, true, _vm->_cgaMappingAlt);
+ uint8 *shp1 = _screen->encodeShape(0, 0, 20, 120, true, _vm->_cgaMappingAlt);
+ _vm->drawBlockObject(1, 4, shp2, 160, 0, 0);
+ _vm->drawBlockObject(1, 4, shp1, 0, 0, 0);
+ delete[] shp1;
+ delete[] shp2;
+
+ for (int i = 0; i < 3 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + 8 * _vm->_tickLength;
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ _vm->snd_playSoundEffect(7);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ _vm->snd_playSoundEffect(7);
+ end = _vm->_system->getMillis() + 8 * _vm->_tickLength;
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _screen->copyRegion(0, 160, 0, 184, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(18 * _vm->_tickLength);
+ _screen->copyRegion(160, 0, 80, 32, 160, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(5 * _vm->_tickLength);
+ _screen->copyRegion(0, 122, 80, 32, 160, 60, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(160, 122, 80, 92, 160, 60, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(5 * _vm->_tickLength);
+ _screen->copyRegion(160, 0, 80, 32, 160, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ for (int i = 0; i < 6; i++)
+ _screen->copyRegion(i * 48, 185, 56, (i << 3) + 24, 48, 8, 2, 2, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(5 * _vm->_tickLength);
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 2, 0, Screen::CR_NO_P_CHECK);
+
+ _screen->loadBitmap(_filesTunnel[0], 5, 3, 0);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _screen->updateScreen();
+ _vm->delay(40 * _vm->_tickLength);
+
+ _screen->copyRegion(264, 0, 136, 56, 48, 48, 4, 0, Screen::CR_NO_P_CHECK);
+ _vm->snd_playSoundEffect(8);
+ _screen->copyRegion(0, 0, 0, 0, 320, 184, 0, 2, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(16 * _vm->_tickLength);
+ _vm->snd_playSoundEffect(4);
+
+ for (int i = 0; i < 30 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ if (i == 0)
+ _screen->fillRect(0, 168, 319, 199, 12, 0);
+ _screen->copyRegion(80, 25 + (_vm->_rnd.getRandomNumber(255) & 7), 80, 24, 160, 144, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+
+ _vm->snd_playSoundEffect(9);
+
+ for (int i = 0; i < 6 && !_vm->shouldQuit() && !_vm->skipFlag(); i++) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(_tvlX1[i] << 3, _tvlY1[i], _tvlX2[i] << 3, _tvlY2[i], _tvlW[i] << 3, _tvlH[i], 4, 2, Screen::CR_NO_P_CHECK);
+ for (int ii = 0; ii < 4 && !_vm->shouldQuit() && !_vm->skipFlag(); ii++) {
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(80, 25 + (_vm->_rnd.getRandomNumber(255) & 7), 80, 24, 160, 144, 2, 0, Screen::CR_NO_P_CHECK);
+ }
+ }
+ _screen->copyRegion(0, 0, 0, 0, 320, 168, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(40 * _vm->_tickLength);
+
+ _screen->loadBitmap(_filesTunnel[1], 5, 3, 0);
+ _screen->convertPage(3, 4, _vm->_cgaMappingAlt);
+ _vm->snd_playSoundEffect(6);
+ _screen->copyRegion(0, 0, 80, 32, 160, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(2 * _vm->_tickLength);
+ _screen->copyRegion(160, 0, 80, 32, 160, 120, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _vm->delay(2 * _vm->_tickLength);
+ _screen->copyRegion(0, 120, 80, 30, 160, 64, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(160, 120, 80, 94, 160, 64, 4, 0, Screen::CR_NO_P_CHECK);
+ _screen->copyRegion(0, 176, 0, 184, 320, 16, 6, 0, Screen::CR_NO_P_CHECK);
+ _screen->setCurPage(0);
+ _screen->updateScreen();
+ _vm->delay(50 * _vm->_tickLength);
+}
+
+void EoBIntroPlayer::loadAndSetPalette(const char *filename) {
+ if (_vm->_configRenderMode == Common::kRenderCGA || _vm->_configRenderMode == Common::kRenderEGA)
+ return;
+ _screen->loadPalette(filename, _screen->getPalette(0));
+ _screen->getPalette(0).fill(0, 1, 0);
+ _screen->setScreenPalette(_screen->getPalette(0));
+}
+
+void EoBIntroPlayer::copyBlurRegion(int x1, int y1, int x2, int y2, int w, int h, int step) {
+ const uint8 *ptr2 = _screen->getCPagePtr(3) + y1 * 320 + x1;
+
+ if (step == 1) {
+ while (h > 0) {
+ int dx = x2;
+ for (int i = 0; i < w; i += 2) {
+ _screen->setPagePixel(3, dx++, y2, ptr2[i]);
+ _screen->setPagePixel(3, dx++, y2, 0);
+ }
+ dx = x2;
+ y2++;
+ ptr2 += 320;
+ for (int i = 0; i < w; i += 2) {
+ _screen->setPagePixel(3, dx++, y2, 0);
+ _screen->setPagePixel(3, dx++, y2, ptr2[i + 1]);
+ }
+ y2++;
+ ptr2 += 320;
+ h -= 2;
+ }
+ } else if (step == 2) {
+ while (h > 0) {
+ int dx = x2;
+ for (int i = 0; i < w; i += 2) {
+ _screen->setPagePixel(3, dx++, y2, ptr2[i]);
+ _screen->setPagePixel(3, dx++, y2, 0);
+ }
+ dx = x2;
+ y2++;
+ ptr2 += 320;
+ for (int i = 0; i < w; i++)
+ _screen->setPagePixel(3, dx++, y2, 0);
+
+ y2++;
+ ptr2 += 320;
+ h -= 2;
+ }
+ } else if (step == 3) {
+ for (int i = 0; i < h; i++) {
+ int dx = x2;
+ if ((i % 3) == 0) {
+ int ii = 0;
+ for (; ii < w - 3; ii += 3) {
+ _screen->setPagePixel(3, dx++, y2, ptr2[ii]);
+ _screen->setPagePixel(3, dx++, y2, 0);
+ _screen->setPagePixel(3, dx++, y2, 0);
+ }
+ for (; ii < w; ii++)
+ _screen->setPagePixel(3, dx++, y2, 0);
+ } else {
+ for (int ii = 0; ii < w; ii++)
+ _screen->setPagePixel(3, dx++, y2, 0);
+ }
+ y2++;
+ ptr2 += 320;
+ }
+ }
+}
+
+void EoBIntroPlayer::boxMorphTransition(int targetDestX, int targetDestY, int targetFinalX, int targetFinalY, int targetSrcX, int targetSrcY, int targetFinalW, int targetFinalH, int originX1, int originY1, int originW, int originH) {
+ int originX2 = originX1 + originW;
+ int originY2 = originY1 + originH;
+ if (originY2 > 21)
+ originY2 = 21;
+
+ int w = 1;
+ int h = 1;
+ for (bool runloop = true; runloop && !_vm->shouldQuit() && !_vm->skipFlag();) {
+ uint32 end = _vm->_system->getMillis() + _vm->_tickLength;
+ _screen->copyRegion(targetSrcX << 3, targetSrcY << 3, targetDestX << 3, targetDestY << 3, w << 3, h << 3, 2, 0, Screen::CR_NO_P_CHECK);
+ if (originX1 < targetDestX)
+ _screen->copyRegion(312, 0, originX1 << 3, 0, 8, 176, 0, 0, Screen::CR_NO_P_CHECK);
+ if (originY1 < targetDestY)
+ _screen->copyRegion(0, 192, 0, originY1 << 3, 320, 8, 0, 0, Screen::CR_NO_P_CHECK);
+ if ((targetFinalX + targetFinalW) <= originX2)
+ _screen->copyRegion(312, 0, originX2 << 3, 0, 8, 176, 0, 0, Screen::CR_NO_P_CHECK);
+ if ((targetFinalY + targetFinalH) <= originY2)
+ _screen->copyRegion(0, 192, 0, originY2 << 3, 320, 8, 0, 0, Screen::CR_NO_P_CHECK);
+
+ if (!(targetDestX != targetFinalX || targetDestY != targetFinalY || w != targetFinalW || h != targetFinalH || originX1 < targetFinalX || originY1 < targetFinalY || (targetFinalX + targetFinalW) < originX2 || (targetFinalY + targetFinalH) < originY2))
+ runloop = false;
+
+ int v = targetFinalX - targetDestX;
+ v = (v < 0) ? -1 : ((v > 0) ? 1 : 0);
+ targetDestX += v;
+ v = targetFinalY - targetDestY;
+ v = (v < 0) ? -1 : ((v > 0) ? 1 : 0);
+ targetDestY += v;
+
+ if (w != targetFinalW)
+ w += 2;
+ if (w > targetFinalW)
+ w = targetFinalW;
+
+ if (h != targetFinalH)
+ h += 2;
+ if (h > targetFinalH)
+ h = targetFinalH;
+
+ if (++originX1 > targetFinalX)
+ originX1 = targetFinalX;
+
+ if (++originY1 > targetFinalY)
+ originY1 = targetFinalY;
+
+ if ((targetFinalX + targetFinalW) < originX2)
+ originX2--;
+
+ if ((targetFinalY + targetFinalH) < originY2)
+ originY2--;
+
+ _screen->updateScreen();
+ _vm->delayUntil(end);
+ }
+}
+
+void EoBIntroPlayer::whirlTransition() {
+ for (int i = 0; i < 2; i++) {
+ for (int ii = 0; ii < 8; ii++) {
+ uint32 e = _vm->_system->getMillis() + 3;
+ if (ii & 1) {
+ for (int iii = i + ii; iii < 320; iii += 8)
+ _screen->drawClippedLine(iii, 0, iii, 199, 12);
+ } else {
+ for (int iii = i + ii; iii < 200; iii += 8)
+ _screen->drawClippedLine(0, iii, 319, iii, 12);
+ }
+ _screen->updateScreen();
+ uint32 c = _vm->_system->getMillis();
+ if (e > c)
+ _vm->_system->delayMillis(e - c);
+ }
+ }
+}
+
+int EoBEngine::mainMenu() {
+ int menuChoice = _menuChoiceInit;
+ _menuChoiceInit = 0;
+
+ Screen::FontId of = _screen->_currentFont;
+
+ while (menuChoice >= 0 && !shouldQuit()) {
+ switch (menuChoice) {
+ case 0: {
+ if (_configRenderMode != Common::kRenderEGA)
+ _screen->loadPalette("EOBPAL.COL", _screen->getPalette(0));
+ _screen->loadEoBBitmap("INTRO", _cgaMappingDefault, 5, 3, 2);
+ _screen->setScreenPalette(_screen->getPalette(0));
+ _screen->_curPage = 2;
+ of = _screen->setFont(Screen::FID_6_FNT);
+ Common::String versionString(Common::String::format("ScummVM %s", gScummVMVersion));
+ _screen->printText(versionString.c_str(), 280 - versionString.size() * 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, 14, 13, 12);
+ gui_drawBox(76, 164, 175, 31, 14, 13, -1);
+ _screen->_curPage = 0;
+ _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ _allowImport = true;
+ menuChoice = mainMenuLoop();
+ _allowImport = false;
+ } 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_playIntro();
+ _screen->showMouse();
+ _sound->loadSoundFile("ADLIB");
+ menuChoice = 0;
+ break;
+ }
+ }
+
+ return shouldQuit() ? -5 : menuChoice;
+}
+
+int EoBEngine::mainMenuLoop() {
+ int sel = -1;
+ do {
+ _screen->setScreenDim(28);
+ _gui->simpleMenu_setup(8, 0, _mainMenuStrings, -1, 0, 0);
+
+ while (sel == -1 && !shouldQuit())
+ sel = _gui->simpleMenu_process(8, _mainMenuStrings, 0, -1, 0);
+ } while ((sel < 0 || sel > 5) && !shouldQuit());
+
+ return sel + 1;
+}
+
+void EoBEngine::seq_playIntro() {
+ EoBIntroPlayer(this, _screen).start();
+}
+
+void EoBEngine::seq_playFinale() {
+ Common::SeekableReadStream *s = _res->createReadStream("TEXT.DAT");
+ _screen->loadFileDataToPage(s, 5, 32000);
+ delete s;
+
+ snd_playSoundEffect(20);
+
+ _txt->resetPageBreakString();
+ _txt->setWaitButtonMode(1);
+ _txt->setupField(12, true);
+ gui_drawBox(0, 0, 176, 175, guiSettings()->colors.frame1, guiSettings()->colors.frame2, guiSettings()->colors.fill);
+ _txt->printDialogueText(51, _moreStrings[0]);
+
+ if (!checkScriptFlags(0x1ffe)) {
+ _screen->fadeToBlack();
+ return;
+ }
+
+ _txt->printDialogueText(_finBonusStrings[0]);
+ for (int i = 0; i < 6; i++) {
+ _txt->printDialogueText(_finBonusStrings[1]);
+ if (_characters[i].flags & 1)
+ _txt->printDialogueText(_characters[i].name);
+ }
+
+ uint32 password = 0;
+ for (int i = 0; i < 4; i++) {
+ if (!(_characters[i].flags & 1))
+ continue;
+
+ int len = strlen(_characters[i].name);
+ for (int ii = 0; ii < len; ii++) {
+ uint32 c = _characters[i].name[ii];
+ password += (c * c);
+ }
+ }
+
+ _txt->printDialogueText(Common::String::format(_finBonusStrings[2], password).c_str(), true);
+ _screen->fadeToBlack();
+}
+
+void EoBEngine::seq_xdeath() {
+ uint8 *shapes1[5];
+ uint8 *shapes2;
+
+ _screen->loadShapeSetBitmap("XDEATH2", 5, 3);
+ for (int i = 0; i < 4; i++)
+ shapes1[i] = _screen->encodeShape(i / 2 * 14, i / 2 * 88, 14, 88, true, _cgaMappingDefault);
+ _screen->loadShapeSetBitmap("XDEATH3", 5, 3);
+ shapes2 = _screen->encodeShape(22, 0, 16, 95, true, _cgaMappingDefault);
+ _screen->loadEoBBitmap("XDEATH1", _cgaMappingDefault, 5, 3, -1);
+ _screen->convertPage(3, 2, _cgaMappingDefault);
+ _screen->setCurPage(0);
+
+ for (int i = 0; i < 10; i++) {
+ if (i == 2)
+ snd_playSoundEffect(72);
+ else if (i == 4 || i == 6)
+ snd_playSoundEffect(54);
+ else
+ snd_playSoundEffect(34);
+
+ if (i < 6) {
+ _screen->copyRegion((i % 3) * 104, i / 3 * 88, 32, 10, 104, 88, 2, 0, Screen::CR_NO_P_CHECK);
+ } else {
+ snd_playSoundEffect(42);
+ _screen->drawShape(0, shapes1[i - 6], 32, 10, 0);
+ }
+
+ _screen->updateScreen();
+ delay(4 * _tickLength);
+ }
+
+ const ScreenDim *dm = _screen->getScreenDim(5);
+ _screen->modifyScreenDim(5, dm->sx, 8, dm->w, dm->h);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 0, 5, Screen::CR_NO_P_CHECK);
+
+ for (int i = 0; i < 19; i++) {
+ snd_playSoundEffect(119);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 5, 2, Screen::CR_NO_P_CHECK);
+ _screen->drawShape(2, shapes2, 24, i * 5 - 90, 5);
+ _screen->copyRegion(0, 0, 0, 0, 176, 120, 2, 0, Screen::CR_NO_P_CHECK);
+ _screen->updateScreen();
+ delay(2 * _tickLength);
+ }
+
+ _screen->modifyScreenDim(5, dm->sx, 0, dm->w, dm->h);
+
+ snd_playSoundEffect(5);
+ delay(60 * _tickLength);
+
+ for (int i = 0; i < 4; i++)
+ delete[] shapes1[i];
+ delete[] shapes2;
+
+ gui_drawPlayField(false);
+ gui_drawAllCharPortraitsWithStats();
+}
+
+} // End of namespace Kyra
+
+#endif // ENABLE_EOB
diff --git a/engines/kyra/sequences_hof.cpp b/engines/kyra/sequences_hof.cpp
index 50b5db78fc..f2abfb81dc 100644
--- a/engines/kyra/sequences_hof.cpp
+++ b/engines/kyra/sequences_hof.cpp
@@ -32,7 +32,7 @@ namespace Kyra {
void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
seq_init();
- bool allowSkip = (!(_flags.isDemo && !_flags.isTalkie) && (startSeq == kSequenceTitle)) ? false : true;
+ bool allowSkip = (_flags.isDemo && !_flags.isTalkie) || startSeq != kSequenceTitle;
if (endSeq == -1)
endSeq = startSeq;
@@ -74,7 +74,7 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
_seqFrameCounter = 0;
_seqStartTime = _system->getMillis();
- allowSkip = (!(_flags.isDemo && !_flags.isTalkie) && (seqNum == kSequenceTitle)) ? false : true;
+ allowSkip = (_flags.isDemo && !_flags.isTalkie) || seqNum != kSequenceTitle;
Sequence cseq = _sequences->seq[seqNum];
SeqProc cb = _callbackS[seqNum];
@@ -234,6 +234,8 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
int32 dly = _tickLength - (now - _seqSubFrameStartTime);
if (dly > 0)
delay(MIN<uint32>(dly, tdiff));
+ else
+ updateInput();
}
}
@@ -263,6 +265,8 @@ void KyraEngine_HoF::seq_playSequences(int startSeq, int endSeq) {
int32 dly = _tickLength - (now - _seqSubFrameStartTime);
if (dly > 0)
delay(MIN<uint32>(dly, tdiff));
+ else
+ updateInput();
}
seq_sequenceCommand(cseq.finalCommand);
@@ -2622,7 +2626,7 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
while (*str2) {
cChar[0] = *str2;
_screen->printText(cChar, x, y, col1++, 0);
- x += _screen->getCharWidth(*str2++);
+ x += _screen->getCharWidth((uint8)*str2++);
}
palCycle = true;
} else if (!strcmp(str, specialData[1])) {
@@ -2631,7 +2635,7 @@ void KyraEngine_HoF::seq_displayScrollText(uint8 *data, const ScreenDim *d, int
while (*str2) {
cChar[0] = *str2;
_screen->printText(cChar, x, y, col1--, 0);
- x += _screen->getCharWidth(*str2++);
+ x += _screen->getCharWidth((uint8)*str2++);
}
palCycle = true;
} else {
@@ -2773,15 +2777,15 @@ void KyraEngine_HoF::seq_init() {
return;
if (_flags.isDemo && !_flags.isTalkie) {
- _demoAnimData = _staticres->loadShapeAnimData_v1(k2SeqplayShapeAnimData, _itemAnimDataSize);
+ _demoAnimData = _staticres->loadShapeAnimData_v1(k2SeqplayShapeAnimData, _itemAnimDefinitionSize);
uint8 *shp = _res->fileData("icons.shp", 0);
uint32 outsize = READ_LE_UINT16(shp + 4);
_animShapeFiledata = new uint8[outsize];
Screen::decodeFrame4(shp + 10, _animShapeFiledata, outsize);
delete[] shp;
- for (int numShp = 0; getShapePtr(numShp); ++numShp)
- addShapeToPool(_screen->getPtrToShape(_animShapeFiledata, numShp), numShp);
+ for (int i = 0; i < 20; i++)
+ addShapeToPool(_screen->getPtrToShape(_animShapeFiledata, i), i);
} else {
const MainMenu::StaticData data = {
{ _sequenceStrings[97], _sequenceStrings[96], _sequenceStrings[95], _sequenceStrings[98], 0 },
diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp
index 99ae2ad7b3..3475402a98 100644
--- a/engines/kyra/sequences_lok.cpp
+++ b/engines/kyra/sequences_lok.cpp
@@ -381,10 +381,10 @@ void KyraEngine_LoK::seq_createAmuletJewel(int jewel, int page, int noSound, int
}
}
}
- _screen->drawShape(page, _shapes[323+jewel], _amuletX2[jewel], _amuletY2[jewel], 0, 0);
+ _screen->drawShape(page, _shapes[323 + jewel], _amuletX2[jewel], _amuletY2[jewel], 0, 0);
_screen->updateScreen();
_screen->showMouse();
- setGameFlag(0x55+jewel);
+ setGameFlag(0x55 + jewel);
}
void KyraEngine_LoK::seq_brandonHealing() {
@@ -764,7 +764,7 @@ void KyraEngine_LoK::seq_makeBrandonWisp() {
if (_flags.platform == Common::kPlatformAmiga) {
if ((_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245) ||
- (_currentCharacter->sceneId >= 118 && _currentCharacter->sceneId <= 186))
+ (_currentCharacter->sceneId >= 118 && _currentCharacter->sceneId <= 186))
_screen->fadePalette(_screen->getPalette(10), 0x54);
} else {
if (_currentCharacter->sceneId >= 229 && _currentCharacter->sceneId <= 245)
@@ -1730,7 +1730,7 @@ int KyraEngine_LoK::handleBeadState() {
if (_system->getMillis() > _beadStateTimer2 && _malcolmFlag == 7 && !_unkAmuletVar && !_text->printed()) {
snd_playSoundEffect(0x0B);
if (_currentCharacter->x1 > 233 && _currentCharacter->x1 < 305 && _currentCharacter->y1 > 85 && _currentCharacter->y1 < 105 &&
- (_brandonStatusBit & 0x20)) {
+ (_brandonStatusBit & 0x20)) {
_beadState1.unk8 = 290;
_beadState1.unk9 = 40;
_beadStateVar = 5;
diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp
index 01db92c225..a06f2077ba 100644
--- a/engines/kyra/sequences_lol.cpp
+++ b/engines/kyra/sequences_lol.cpp
@@ -55,6 +55,8 @@ int LoLEngine::processPrologue() {
preInit();
+ Common::String versionString(Common::String::format("ScummVM %s", gScummVMVersion));
+
int processSelection = -1;
while (!shouldQuit() && processSelection == -1) {
_screen->loadBitmap("TITLE.CPS", 2, 2, &_screen->getPalette(0));
@@ -62,8 +64,8 @@ int LoLEngine::processPrologue() {
_screen->setFont(Screen::FID_6_FNT);
// Original version: (260|193) "V CD1.02 D"
- const int width = _screen->getTextWidth(gScummVMVersion);
- _screen->fprintString("SVM %s", 300 - width, 193, 0x67, 0x00, 0x04, gScummVMVersion);
+ const int width = _screen->getTextWidth(versionString.c_str());
+ _screen->fprintString("%s", 320 - width, 193, 0x67, 0x00, 0x04, versionString.c_str());
_screen->setFont(_flags.lang == Common::JA_JPN ? Screen::FID_SJIS_FNT : Screen::FID_9_FNT);
_screen->fadePalette(_screen->getPalette(0), 0x1E);
@@ -88,25 +90,25 @@ int LoLEngine::processPrologue() {
// quit instantly.
break;
- case 0: // New game
+ case 0: // New game
processSelection = 0;
break;
- case 1: // Show intro
+ case 1: // Show intro
showIntro();
break;
- case 2: { // "Lore of the Lands" (only CD version)
+ case 2: { // "Lore of the Lands" (only CD version)
HistoryPlayer history(this);
history.play();
- } break;
+ } break;
- case 3: // Load game
+ case 3: // Load game
if (_gui->runMenu(_gui->_loadMenu))
processSelection = 3;
break;
- case 4: // Quit game
+ case 4: // Quit game
default:
quitGame();
updateInput();
@@ -127,17 +129,17 @@ int LoLEngine::processPrologue() {
}
void LoLEngine::setupPrologueData(bool load) {
- static const char * const fileListCD[] = {
+ static const char *const fileListCD[] = {
"GENERAL.PAK", "INTROVOC.PAK", "STARTUP.PAK", "INTRO1.PAK",
"INTRO2.PAK", "INTRO3.PAK", "INTRO4.PAK", "INTRO5.PAK",
"INTRO6.PAK", "INTRO7.PAK", "INTRO8.PAK", "INTRO9.PAK",
"HISTORY.PAK", 0
};
- static const char * const fileListFloppy[] = {
+ static const char *const fileListFloppy[] = {
"INTRO.PAK", "INTROVOC.PAK", 0
};
- const char * const *fileList = _flags.isTalkie ? fileListCD : fileListFloppy;
+ const char *const *fileList = _flags.isTalkie ? fileListCD : fileListFloppy;
char filename[32];
for (uint i = 0; fileList[i]; ++i) {
@@ -408,10 +410,10 @@ void LoLEngine::kingSelectionIntro() {
index = MAX(index, 4);
_chargenWSA->displayFrame(_chargenFrameTable[index], 0, 113, 0, 0, 0, 0);
- _screen->copyRegion(_selectionPosTable[_selectionChar1IdxTable[index]*2+0], _selectionPosTable[_selectionChar1IdxTable[index]*2+1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0);
- _screen->copyRegion(_selectionPosTable[_selectionChar2IdxTable[index]*2+0], _selectionPosTable[_selectionChar2IdxTable[index]*2+1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0);
- _screen->copyRegion(_selectionPosTable[_selectionChar3IdxTable[index]*2+0], _selectionPosTable[_selectionChar3IdxTable[index]*2+1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0);
- _screen->copyRegion(_selectionPosTable[_selectionChar4IdxTable[index]*2+0], _selectionPosTable[_selectionChar4IdxTable[index]*2+1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar1IdxTable[index] * 2 + 0], _selectionPosTable[_selectionChar1IdxTable[index] * 2 + 1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar2IdxTable[index] * 2 + 0], _selectionPosTable[_selectionChar2IdxTable[index] * 2 + 1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar3IdxTable[index] * 2 + 0], _selectionPosTable[_selectionChar3IdxTable[index] * 2 + 1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_selectionChar4IdxTable[index] * 2 + 0], _selectionPosTable[_selectionChar4IdxTable[index] * 2 + 1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0);
_screen->updateScreen();
uint32 waitEnd = _system->getMillis() + 7 * _tickLength;
@@ -428,7 +430,7 @@ void LoLEngine::kingSelectionIntro() {
resetSkipFlag();
- _chargenWSA->displayFrame(0x10, 0,113, 0, 0, 0, 0);
+ _chargenWSA->displayFrame(0x10, 0, 113, 0, 0, 0, 0);
_screen->updateScreen();
_sound->voiceStop(&_speechHandle);
}
@@ -450,11 +452,11 @@ void LoLEngine::kingSelectionReminder() {
int index = 0;
while ((!speechEnabled() || (speechEnabled() && _sound->voiceIsPlaying(&_speechHandle))) && _charSelection == -1 && !shouldQuit() && index < 15) {
- _chargenWSA->displayFrame(_chargenFrameTable[index+9], 0, 113, 0, 0, 0, 0);
- _screen->copyRegion(_selectionPosTable[_reminderChar1IdxTable[index]*2+0], _selectionPosTable[_reminderChar1IdxTable[index]*2+1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0);
- _screen->copyRegion(_selectionPosTable[_reminderChar2IdxTable[index]*2+0], _selectionPosTable[_reminderChar2IdxTable[index]*2+1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0);
- _screen->copyRegion(_selectionPosTable[_reminderChar3IdxTable[index]*2+0], _selectionPosTable[_reminderChar3IdxTable[index]*2+1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0);
- _screen->copyRegion(_selectionPosTable[_reminderChar4IdxTable[index]*2+0], _selectionPosTable[_reminderChar4IdxTable[index]*2+1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0);
+ _chargenWSA->displayFrame(_chargenFrameTable[index + 9], 0, 113, 0, 0, 0, 0);
+ _screen->copyRegion(_selectionPosTable[_reminderChar1IdxTable[index] * 2 + 0], _selectionPosTable[_reminderChar1IdxTable[index] * 2 + 1], _charPreviews[0].x, _charPreviews[0].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_reminderChar2IdxTable[index] * 2 + 0], _selectionPosTable[_reminderChar2IdxTable[index] * 2 + 1], _charPreviews[1].x, _charPreviews[1].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_reminderChar3IdxTable[index] * 2 + 0], _selectionPosTable[_reminderChar3IdxTable[index] * 2 + 1], _charPreviews[2].x, _charPreviews[2].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[_reminderChar4IdxTable[index] * 2 + 0], _selectionPosTable[_reminderChar4IdxTable[index] * 2 + 1], _charPreviews[3].x, _charPreviews[3].y, 32, 32, 4, 0);
_screen->updateScreen();
uint32 waitEnd = _system->getMillis() + 8 * _tickLength;
@@ -524,7 +526,7 @@ void LoLEngine::updateSelectionAnims() {
continue;
const int index = _selectionAnimIndexTable[_selectionAnimFrames[i] + i * 2];
- _screen->copyRegion(_selectionPosTable[index*2+0], _selectionPosTable[index*2+1], _charPreviews[i].x, _charPreviews[i].y, 32, 32, 4, 0);
+ _screen->copyRegion(_selectionPosTable[index * 2 + 0], _selectionPosTable[index * 2 + 1], _charPreviews[i].x, _charPreviews[i].y, 32, 32, 4, 0);
int delayTime = 0;
if (_selectionAnimFrames[i] == 1)
@@ -581,12 +583,12 @@ int LoLEngine::selectionCharInfo(int character) {
if (_flags.platform == Common::kPlatformPC98) {
for (int i = 0; i < 5; ++i)
- _screen->printText(_tim->getCTableEntry(idx+i), 60, 128 + i * 8, 0x41, 0x00);
+ _screen->printText(_tim->getCTableEntry(idx + i), 60, 128 + i * 8, 0x41, 0x00);
_screen->printText(_tim->getCTableEntry(69), 112, 168, 0x01, 0x00);
} else {
for (int i = 0; i < 5; ++i)
- _screen->fprintStringIntro("%s", 50, 127 + i * 10, 0x53, 0x00, 0xCF, 0x20, _tim->getCTableEntry(idx+i));
+ _screen->fprintStringIntro("%s", 50, 127 + i * 10, 0x53, 0x00, 0xCF, 0x20, _tim->getCTableEntry(idx + i));
_screen->fprintStringIntro("%s", 100, 168, 0x32, 0x00, 0xCF, 0x20, _tim->getCTableEntry(69));
}
@@ -613,10 +615,10 @@ int LoLEngine::selectionCharInfo(int character) {
if (_flags.platform == Common::kPlatformPC98) {
for (int i = 0; i < 5; ++i)
- _screen->printText(_tim->getCTableEntry(64+i), 16, 32 + i * 8, 0xC1, 0x00);
+ _screen->printText(_tim->getCTableEntry(64 + i), 16, 32 + i * 8, 0xC1, 0x00);
} else {
for (int i = 0; i < 5; ++i)
- _screen->fprintStringIntro("%s", 3, 28 + i * 10, 0x32, 0x00, 0x9C, 0x20, _tim->getCTableEntry(64+i));
+ _screen->fprintStringIntro("%s", 3, 28 + i * 10, 0x32, 0x00, 0x9C, 0x20, _tim->getCTableEntry(64 + i));
}
resetSkipFlag();
@@ -668,7 +670,7 @@ int LoLEngine::getCharSelection() {
if (inputFlag == 200) {
for (int i = 0; i < 4; ++i) {
if (_charPreviews[i].x <= _mouseX && _mouseX <= _charPreviews[i].x + 31 &&
- _charPreviews[i].y <= _mouseY && _mouseY <= _charPreviews[i].y + 31)
+ _charPreviews[i].y <= _mouseY && _mouseY <= _charPreviews[i].y + 31)
return i;
}
}
@@ -752,7 +754,7 @@ HistoryPlayer::~HistoryPlayer() {
void HistoryPlayer::play() {
int dataSize = 0;
- const char *data = (const char *)_vm->staticres()->loadRawData(kLolHistory, dataSize);
+ const char *data = (const char *)_vm->staticres()->loadRawData(kLoLHistory, dataSize);
if (!data)
error("Could not load history data");
@@ -998,16 +1000,16 @@ void HistoryPlayer::updateFire() {
// outro
void LoLEngine::setupEpilogueData(bool load) {
- static const char * const fileListCD[] = {
+ static const char *const fileListCD[] = {
"GENERAL.PAK", "INTROVOC.PAK", "STARTUP.PAK",
"FINALE.PAK", "FINALE1.PAK", "FINALE2.PAK", 0
};
- static const char * const fileListFloppy[] = {
+ static const char *const fileListFloppy[] = {
"GENERAL.PAK", "INTRO.PAK", "FINALE1.PAK", "FINALE2.PAK", 0
};
- const char * const *fileList = _flags.isTalkie ? fileListCD : fileListFloppy;
+ const char *const *fileList = _flags.isTalkie ? fileListCD : fileListFloppy;
assert(fileList);
char filename[32];
@@ -1195,14 +1197,14 @@ void LoLEngine::showCredits() {
if (_flags.platform == Common::kPlatformPC98) {
int size = 0;
- const uint8 *internCredits = _staticres->loadRawData(kLolCredits, size);
+ const uint8 *internCredits = _staticres->loadRawData(kLoLCredits, size);
assert(size > 0);
credits = new char[size];
assert(credits);
memcpy(credits, internCredits, size);
- _staticres->unloadId(kLolCredits);
+ _staticres->unloadId(kLoLCredits);
} else {
credits = (char *)_res->fileData("CREDITS.TXT", 0);
}
@@ -1446,7 +1448,7 @@ void LoLEngine::processCredits(char *t, int dimState, int page, int delayTime) {
}
for (int i = 0; i < countStrings; ++i) {
- CreditsString &s = strings[i+1];
+ CreditsString &s = strings[i + 1];
int x = s.x, y = s.y;
if (y < _screen->_curDim->h) {
@@ -1512,7 +1514,7 @@ void LoLEngine::loadOutroShapes(int file, uint8 **storage) {
if (i < 8)
storage[i] = _screen->makeShapeCopy(_screen->getCPagePtr(5), i);
else
- storage[i] = _screen->makeShapeCopy(_screen->getCPagePtr(5), i+4);
+ storage[i] = _screen->makeShapeCopy(_screen->getCPagePtr(5), i + 4);
}
}
diff --git a/engines/kyra/sound.cpp b/engines/kyra/sound.cpp
index a1af1ad6f8..73c20ee6df 100644
--- a/engines/kyra/sound.cpp
+++ b/engines/kyra/sound.cpp
@@ -229,8 +229,8 @@ bool MixedSoundDriver::isPlaying() const {
return _music->isPlaying() | _sfx->isPlaying();
}
-void MixedSoundDriver::playSoundEffect(uint8 track) {
- _sfx->playSoundEffect(track);
+void MixedSoundDriver::playSoundEffect(uint8 track, uint8 volume) {
+ _sfx->playSoundEffect(track, volume);
}
void MixedSoundDriver::stopAllSoundEffects() {
@@ -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.h b/engines/kyra/sound.h
index f3de56520e..63cec48d00 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -128,7 +128,7 @@ public:
*
* @param track sound effect id
*/
- virtual void playSoundEffect(uint8 track) = 0;
+ virtual void playSoundEffect(uint8 track, uint8 volume = 0xff) = 0;
/**
* Stop playback of all sfx tracks.
@@ -217,6 +217,16 @@ public:
* Stops playback of the current voice.
*/
void voiceStop(const Audio::SoundHandle *handle = 0);
+
+ /**
+ * Receive notifications from a song at certain points.
+ */
+ virtual int checkTrigger() { return 0; }
+
+ /**
+ * Reset sound trigger.
+ */
+ virtual void resetTrigger() {}
protected:
const char *fileListEntry(int file) const { return (_soundDataList != 0 && file >= 0 && file < _soundDataList->fileListLen) ? _soundDataList->fileList[file] : ""; }
int fileListLen() const { return _soundDataList->fileListLen; }
@@ -273,7 +283,7 @@ public:
virtual void haltTrack();
virtual bool isPlaying() const;
- virtual void playSoundEffect(uint8 track);
+ virtual void playSoundEffect(uint8 track, uint8 volume = 0xff);
virtual void stopAllSoundEffects();
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index b04abea080..668e662413 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -57,15 +57,16 @@ namespace Kyra {
class AdLibDriver : public Audio::AudioStream {
public:
- AdLibDriver(Audio::Mixer *mixer, bool v2);
+ AdLibDriver(Audio::Mixer *mixer, int version);
~AdLibDriver();
void initDriver();
void setSoundData(uint8 *data);
- void queueTrack(int track);
+ void queueTrack(int track, int volume);
bool isChannelPlaying(int channel) const;
void stopAllChannels();
int getSoundTrigger() const { return _soundTrigger; }
+ void resetSoundTrigger() { _soundTrigger = 0; }
void callback();
@@ -106,7 +107,7 @@ private:
// These variables have not yet been named, but some of them are partly
// known nevertheless:
//
- // unk16 - Sound-related. Possibly some sort of pitch bend.
+ // pitchBend - Sound-related. Possibly some sort of pitch bend.
// unk18 - Sound-effect. Used for secondaryEffect1()
// unk19 - Sound-effect. Used for secondaryEffect1()
// unk20 - Sound-effect. Used for secondaryEffect1()
@@ -175,7 +176,7 @@ private:
uint16 offset;
uint8 tempoReset;
uint8 rawNote;
- int8 unk16;
+ int8 pitchBend;
uint8 volumeModifier;
};
@@ -223,7 +224,7 @@ private:
}
uint8 *getInstrument(int instrumentId) {
- return _soundData + READ_LE_UINT16(_soundData + (_v2 ? 1000 : 500) + 2 * instrumentId);
+ return getProgram(_numPrograms + instrumentId);
}
void setupPrograms();
@@ -279,7 +280,7 @@ private:
int updateCallback38(uint8 *&dataptr, Channel &channel, uint8 value);
int updateCallback39(uint8 *&dataptr, Channel &channel, uint8 value);
int update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel, uint8 value);
- int updateCallback41(uint8 *&dataptr, Channel &channel, uint8 value);
+ int update_pitchBend(uint8 *&dataptr, Channel &channel, uint8 value);
int update_resetToGlobalTempo(uint8 *&dataptr, Channel &channel, uint8 value);
int update_nop(uint8 *&dataptr, Channel &channel, uint8 value);
int update_setDurationRandomness(uint8 *&dataptr, Channel &channel, uint8 value);
@@ -317,7 +318,7 @@ private:
// _unkValue18 - Unknown. Rhythm section volume?
// _unkValue19 - Unknown. Rhythm section volume?
// _unkValue20 - Unknown. Rhythm section volume?
- // _unkTable[] - Probably frequences for the 12-tone scale.
+ // _freqTable[] - Probably frequences for the 12-tone scale.
// _unkTable2[] - Unknown. Currently only used by updateCallback46()
// _unkTable2_1[] - One of the tables in _unkTable2[]
// _unkTable2_2[] - One of the tables in _unkTable2[]
@@ -358,11 +359,20 @@ private:
uint8 *_soundData;
+ struct QueueEntry {
+ QueueEntry() : data(0), id(0), volume(0) {}
+ QueueEntry(uint8 *ptr, uint8 track, uint8 vol) : data(ptr), id(track), volume(vol) {}
+ uint8 *data;
+ uint8 id;
+ uint8 volume;
+ };
+
+ QueueEntry _programQueue[16];
int _programStartTimeout;
- uint8 *_programQueue[16];
int _programQueueStart, _programQueueEnd;
+ bool _retrySounds;
- void adjustSfxData(uint8 *data);
+ void adjustSfxData(uint8 *data, int volume);
uint8 *_sfxPointer;
int _sfxPriority;
int _sfxVelocity;
@@ -379,12 +389,12 @@ private:
const uint8 *_tablePtr2;
static const uint8 _regOffset[];
- static const uint16 _unkTable[];
+ static const uint16 _freqTable[];
static const uint8 *const _unkTable2[];
static const uint8 _unkTable2_1[];
static const uint8 _unkTable2_2[];
static const uint8 _unkTable2_3[];
- static const uint8 _unkTables[][32];
+ static const uint8 _pitchBendTables[][32];
uint16 _syncJumpMask;
@@ -394,13 +404,15 @@ private:
uint8 _musicVolume, _sfxVolume;
- bool _v2;
+ int _numPrograms;
+ int _version;
};
-AdLibDriver::AdLibDriver(Audio::Mixer *mixer, bool v2) {
+AdLibDriver::AdLibDriver(Audio::Mixer *mixer, int version) {
setupParserOpcodeTable();
- _v2 = v2;
+ _version = version;
+ _numPrograms = (_version == 1) ? 150 : ((_version == 4) ? 500 : 250);
_mixer = mixer;
@@ -442,6 +454,7 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, bool v2) {
_sfxPointer = 0;
_programQueueStart = _programQueueEnd = 0;
+ _retrySounds = false;
}
AdLibDriver::~AdLibDriver() {
@@ -466,8 +479,8 @@ void AdLibDriver::setMusicVolume(uint8 volume) {
writeOPL(0x43 + regOffset, calculateOpLevel2(chan));
}
- // For now we use the music volume for both sfx and music in Kyra1.
- if (!_v2) {
+ // For now we use the music volume for both sfx and music in Kyra1 and EoB
+ if (_version < 4) {
_sfxVolume = volume;
for (uint i = 6; i < 9; ++i) {
@@ -484,8 +497,8 @@ void AdLibDriver::setMusicVolume(uint8 volume) {
}
void AdLibDriver::setSfxVolume(uint8 volume) {
- // We only support sfx volume in v2 games.
- if (!_v2)
+ // We only support sfx volume in version 4 games.
+ if (_version < 4)
return;
Common::StackLock lock(_mutex);
@@ -519,26 +532,28 @@ void AdLibDriver::setSoundData(uint8 *data) {
if (_soundData) {
delete[] _soundData;
- _soundData = 0;
+ _soundData = _sfxPointer = 0;
}
_soundData = data;
}
-void AdLibDriver::queueTrack(int track) {
+void AdLibDriver::queueTrack(int track, int volume) {
Common::StackLock lock(_mutex);
uint8 *trackData = getProgram(track);
if (!trackData)
return;
- if (_programQueueEnd == _programQueueStart && _programQueue[_programQueueEnd] != 0) {
+ // Don't drop tracks in EoB. The queue is always full there if a couple of monsters are around.
+ // If we drop the incoming tracks we get no sound effects, but tons of warnings instead.
+ if (_version >= 3 && _programQueueEnd == _programQueueStart && _programQueue[_programQueueEnd].data != 0) {
warning("AdLibDriver: Program queue full, dropping track %d", track);
return;
}
- _programQueue[_programQueueEnd++] = trackData;
- _programQueueEnd &= 15;
+ _programQueue[_programQueueEnd] = QueueEntry(trackData, track, volume);
+ _programQueueEnd = (_programQueueEnd + 1) & 15;
}
bool AdLibDriver::isChannelPlaying(int channel) const {
@@ -561,6 +576,7 @@ void AdLibDriver::stopAllChannels() {
if (channel != 9)
noteOff(chan);
}
+ _retrySounds = false;
}
// timer callback
@@ -588,13 +604,25 @@ void AdLibDriver::setupPrograms() {
if (_programQueueStart == _programQueueEnd)
return;
- uint8 *ptr = _programQueue[_programQueueStart];
- // Clear the queue entry
- _programQueue[_programQueueStart] = 0;
- _programQueueStart = (_programQueueStart + 1) & 15;
+ uint8 *ptr = _programQueue[_programQueueStart].data;
+
+ // The AdLib driver (in its old versions used for EOB) is not suitable for modern (fast) CPUs.
+ // The stop sound track (track 0 which has a priority of 50) will often still be busy when the
+ // next sound (with a lower priority) starts which will cause that sound to be skipped. We simply
+ // restart incoming sounds during stop sound execution.
+ // UPDATE: This stilly applies after introduction of the _programQueue.
+ QueueEntry retrySound;
+ if (_version < 3 && _programQueue[_programQueueStart].id == 0)
+ _retrySounds = true;
+ else if (_retrySounds)
+ retrySound = _programQueue[_programQueueStart];
// Adjust data in case we hit a sound effect.
- adjustSfxData(ptr);
+ adjustSfxData(ptr, _programQueue[_programQueueStart].volume);
+
+ // Clear the queue entry
+ _programQueue[_programQueueStart].data = 0;
+ _programQueueStart = (_programQueueStart + 1) & 15;
const int chan = *ptr++;
const int priority = *ptr++;
@@ -623,10 +651,17 @@ void AdLibDriver::setupPrograms() {
// This is (probably) required to assure that the sfx are started with
// the correct priority and velocity.
_programStartTimeout = 2;
+
+ retrySound = QueueEntry();
+ }
+
+ if (retrySound.data) {
+ debugC(9, kDebugLevelSound, "AdLibDriver::setupPrograms(): WORKAROUND - Restarting skipped sound %d)", retrySound.id);
+ queueTrack(retrySound.id, retrySound.volume);
}
}
-void AdLibDriver::adjustSfxData(uint8 *ptr) {
+void AdLibDriver::adjustSfxData(uint8 *ptr, int volume) {
// Check whether we need to reset the data of an old sfx which has been
// started.
if (_sfxPointer) {
@@ -647,21 +682,18 @@ void AdLibDriver::adjustSfxData(uint8 *ptr) {
_sfxPriority = ptr[1];
_sfxVelocity = ptr[3];
- // In the cases I've seen, the mysterious fourth byte has been
- // the parameter for the update_setExtraLevel3() callback.
- //
- // The extra level is part of the channels "total level", which
- // is a six-bit value where larger values means softer volume.
- //
- // So what seems to be happening here is that sounds which are
- // started by this function are given a slightly lower priority
- // and a slightly higher (i.e. softer) extra level 3 than they
- // would have if they were started from anywhere else. Strange.
-
// Adjust the values.
- int newVal = ((((ptr[3]) + 63) * 0xFF) >> 8) & 0xFF;
- ptr[3] = -newVal + 63;
- ptr[1] = ((ptr[1] * 0xFF) >> 8) & 0xFF;
+ if (volume != 0xff) {
+ if (_version >= 3) {
+ int newVal = ((((ptr[3]) + 63) * volume) >> 8) & 0xFF;
+ ptr[3] = -newVal + 63;
+ ptr[1] = ((ptr[1] * volume) >> 8) & 0xFF;
+ } else {
+ int newVal = ((_sfxVelocity << 2) ^ 0xff) * volume;
+ ptr[3] = (newVal >> 10) ^ 0x3f;
+ ptr[1] = newVal >> 11;
+ }
+ }
}
// A few words on opcode parsing and timing:
@@ -973,20 +1005,20 @@ void AdLibDriver::setupNote(uint8 rawNote, Channel &channel, bool flag) {
// octave bits, and that could possibly have been used in some sound.
// But as it is now, I can't see any way it would happen.
- uint16 freq = _unkTable[note] + channel.baseFreq;
+ uint16 freq = _freqTable[note] + channel.baseFreq;
// When called from callback 41, the behavior is slightly different:
- // We adjust the frequency, even when channel.unk16 is 0.
+ // We adjust the frequency, even when channel.pitchBend is 0.
- if (channel.unk16 || flag) {
+ if (channel.pitchBend || flag) {
const uint8 *table;
- if (channel.unk16 >= 0) {
- table = _unkTables[(channel.rawNote & 0x0F) + 2];
- freq += table[channel.unk16];
+ if (channel.pitchBend >= 0) {
+ table = _pitchBendTables[(channel.rawNote & 0x0F) + 2];
+ freq += table[channel.pitchBend];
} else {
- table = _unkTables[channel.rawNote & 0x0F];
- freq -= table[-channel.unk16];
+ table = _pitchBendTables[channel.rawNote & 0x0F];
+ freq -= table[-channel.pitchBend];
}
}
@@ -1366,7 +1398,10 @@ int AdLibDriver::update_setNoteSpacing(uint8 *&dataptr, Channel &channel, uint8
int AdLibDriver::update_jump(uint8 *&dataptr, Channel &channel, uint8 value) {
--dataptr;
int16 add = READ_LE_UINT16(dataptr); dataptr += 2;
- dataptr += add;
+ if (_version == 1)
+ dataptr = _soundData + add - 191;
+ else
+ dataptr += add;
if (_syncJumpMask & (1 << (&channel - _channels)))
channel.lock = true;
return 0;
@@ -1376,7 +1411,10 @@ int AdLibDriver::update_jumpToSubroutine(uint8 *&dataptr, Channel &channel, uint
--dataptr;
int16 add = READ_LE_UINT16(dataptr); dataptr += 2;
channel.dataptrStack[channel.dataptrStackPos++] = dataptr;
- dataptr += add;
+ if (_version < 3)
+ dataptr = _soundData + add - 191;
+ else
+ dataptr += add;
return 0;
}
@@ -1426,7 +1464,21 @@ int AdLibDriver::update_setupSecondaryEffect1(uint8 *&dataptr, Channel &channel,
channel.unk19 = value;
channel.unk20 = channel.unk21 = *dataptr++;
channel.unk22 = *dataptr++;
- channel.offset = READ_LE_UINT16(dataptr); dataptr += 2;
+ // WORKAROUND: The original code reads a true offset which later gets translated via xlat (in
+ // the current segment). This means that the outcome depends on the sound data offset.
+ // Unfortunately this offset is different in most implementations of the audio driver and
+ // probably also different from the offset assumed by the sequencer.
+ // It seems that the driver assumes an offset of 191 which is wrong for all the game driver
+ // implementations.
+ // This bug has probably not been noticed, since the effect is hardly used and the sounds are
+ // not necessarily worse. I noticed the difference between ScummVM and DOSBox for the EOB II
+ // teleporter sound. I also found the location of the table which is supposed to be used here
+ // (simple enough: it is located at the end of the track after the 0x88 ending opcode).
+ // Teleporters in EOB I and II now sound exactly the same which I am sure was the intended way,
+ // since the sound data is exactly the same.
+ // In DOSBox the teleporters will sound different in EOB I and II, due to different sound
+ // data offsets.
+ channel.offset = READ_LE_UINT16(dataptr) - 191; dataptr += 2;
channel.secondaryEffect = &AdLibDriver::secondaryEffect1;
return 0;
}
@@ -1668,8 +1720,8 @@ int AdLibDriver::update_removePrimaryEffect2(uint8 *&dataptr, Channel &channel,
return 0;
}
-int AdLibDriver::updateCallback41(uint8 *&dataptr, Channel &channel, uint8 value) {
- channel.unk16 = value;
+int AdLibDriver::update_pitchBend(uint8 *&dataptr, Channel &channel, uint8 value) {
+ channel.pitchBend = value;
setupNote(channel.rawNote, channel, true);
return 0;
}
@@ -2020,7 +2072,7 @@ void AdLibDriver::setupParserOpcodeTable() {
// 56
COMMAND(update_stopChannel),
- COMMAND(updateCallback41),
+ COMMAND(update_pitchBend),
COMMAND(update_resetToGlobalTempo),
COMMAND(update_nop),
@@ -2061,11 +2113,10 @@ const uint8 AdLibDriver::_regOffset[] = {
0x12
};
-// Given the size of this table, and the range of its values, it's probably the
-// F-Numbers (10 bits) for the notes of the 12-tone scale. However, it does not
-// match the table in the AdLib documentation I've seen.
+//These are the F-Numbers (10 bits) for the notes of the 12-tone scale.
+// However, it does not match the table in the AdLib documentation I've seen.
-const uint16 AdLibDriver::_unkTable[] = {
+const uint16 AdLibDriver::_freqTable[] = {
0x0134, 0x0147, 0x015A, 0x016F, 0x0184, 0x019C, 0x01B4, 0x01CE, 0x01E9,
0x0207, 0x0225, 0x0246
};
@@ -2143,13 +2194,11 @@ const uint8 AdLibDriver::_unkTable2_3[] = {
};
// This table is used to modify the frequency of the notes, depending on the
-// note value and unk16. In theory, we could very well try to access memory
-// outside this table, but in reality that probably won't happen.
+// note value and the pitch bend value. In theory, we could very well try to
+// access memory outside this table, but in reality that probably won't happen.
//
-// This could be some sort of pitch bend, but I have yet to see it used for
-// anything so it's hard to say.
-const uint8 AdLibDriver::_unkTables[][32] = {
+const uint8 AdLibDriver::_pitchBendTables[][32] = {
// 0
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
@@ -2238,21 +2287,36 @@ const int SoundAdLibPC::_kyra1NumSoundTriggers = ARRAYSIZE(SoundAdLibPC::_kyra1S
SoundAdLibPC::SoundAdLibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer)
: Sound(vm, mixer), _driver(0), _trackEntries(), _soundDataPtr(0) {
memset(_trackEntries, 0, sizeof(_trackEntries));
- _v2 = (_vm->game() == GI_KYRA2) || (_vm->game() == GI_LOL && !_vm->gameFlags().isDemo);
- _driver = new AdLibDriver(mixer, _v2);
- assert(_driver);
+ _soundTriggers = 0;
+ _numSoundTriggers = 0;
_sfxPlayingSound = -1;
_soundFileLoaded.clear();
- if (_v2) {
- // TODO: Figure out if Kyra 2 uses sound triggers at all.
- _soundTriggers = 0;
- _numSoundTriggers = 0;
- } else {
+ switch (vm->game()) {
+ case GI_LOL:
+ _version = _vm->gameFlags().isDemo ? 3 : 4;
+ break;
+ case GI_KYRA2:
+ _version = 4;
+ break;
+ case GI_KYRA1:
+ _version = 3;
_soundTriggers = _kyra1SoundTriggers;
_numSoundTriggers = _kyra1NumSoundTriggers;
+ break;
+ case GI_EOB2:
+ _version = 2;
+ break;
+ case GI_EOB1:
+ _version = 1;
+ break;
+ default:
+ break;
}
+
+ _driver = new AdLibDriver(mixer, _version);
+ assert(_driver);
}
SoundAdLibPC::~SoundAdLibPC() {
@@ -2307,13 +2371,13 @@ void SoundAdLibPC::playTrack(uint8 track) {
_driver->setSyncJumpMask(0x000F);
else
_driver->setSyncJumpMask(0);
- play(track);
+ play(track, 0xff);
}
}
void SoundAdLibPC::haltTrack() {
- play(0);
- play(0);
+ play(0, 0);
+ play(0, 0);
//_vm->_system->delayMillis(3 * 60);
}
@@ -2321,27 +2385,35 @@ bool SoundAdLibPC::isPlaying() const {
return _driver->isChannelPlaying(0);
}
-void SoundAdLibPC::playSoundEffect(uint8 track) {
+void SoundAdLibPC::playSoundEffect(uint8 track, uint8 volume) {
if (_sfxEnabled)
- play(track);
+ play(track, volume);
}
-void SoundAdLibPC::play(uint8 track) {
+void SoundAdLibPC::play(uint8 track, uint8 volume) {
uint16 soundId = 0;
- if (_v2)
+ if (_version == 4)
soundId = READ_LE_UINT16(&_trackEntries[track<<1]);
else
soundId = _trackEntries[track];
- if ((soundId == 0xFFFF && _v2) || (soundId == 0xFF && !_v2) || !_soundDataPtr)
+ if ((soundId == 0xFFFF && _version == 4) || (soundId == 0xFF && _version < 4) || !_soundDataPtr)
return;
- _driver->queueTrack(soundId);
+ _driver->queueTrack(soundId, volume);
}
void SoundAdLibPC::beginFadeOut() {
- play(1);
+ play(_version > 2 ? 1 : 15, 0xff);
+}
+
+int SoundAdLibPC::checkTrigger() {
+ return _driver->getSoundTrigger();
+}
+
+void SoundAdLibPC::resetTrigger() {
+ _driver->resetSoundTrigger();
}
void SoundAdLibPC::loadSoundFile(uint file) {
@@ -2353,7 +2425,7 @@ void SoundAdLibPC::loadSoundFile(Common::String file) {
}
void SoundAdLibPC::internalLoadFile(Common::String file) {
- file += ".ADL";
+ file += ((_version == 1) ? ".DAT" : ".ADL");
if (_soundFileLoaded == file)
return;
@@ -2377,7 +2449,7 @@ void SoundAdLibPC::internalLoadFile(Common::String file) {
int soundDataSize = fileSize;
uint8 *p = fileData;
- if (_v2) {
+ if (_version == 4) {
memcpy(_trackEntries, p, 500);
p += 500;
soundDataSize -= 500;
diff --git a/engines/kyra/sound_adlib.h b/engines/kyra/sound_adlib.h
index 923a4cb75f..8492f3b99a 100644
--- a/engines/kyra/sound_adlib.h
+++ b/engines/kyra/sound_adlib.h
@@ -76,17 +76,20 @@ public:
virtual void haltTrack();
virtual bool isPlaying() const;
- virtual void playSoundEffect(uint8 track);
+ virtual void playSoundEffect(uint8 track, uint8 volume = 0xff);
virtual void beginFadeOut();
+
+ virtual int checkTrigger();
+ virtual void resetTrigger();
private:
void internalLoadFile(Common::String file);
- void play(uint8 track);
+ void play(uint8 track, uint8 volume);
AdLibDriver *_driver;
- bool _v2;
+ int _version;
uint8 _trackEntries[500];
uint8 *_soundDataPtr;
int _sfxPlayingSound;
diff --git a/engines/kyra/sound_amiga.cpp b/engines/kyra/sound_amiga.cpp
index dfb0aa8bf3..ec2748dd38 100644
--- a/engines/kyra/sound_amiga.cpp
+++ b/engines/kyra/sound_amiga.cpp
@@ -173,7 +173,7 @@ void SoundAmiga::beginFadeOut() {
_driver->setVolume(0x40);
}
-void SoundAmiga::playSoundEffect(uint8 track) {
+void SoundAmiga::playSoundEffect(uint8 track, uint8) {
debugC(5, kDebugLevelSound, "SoundAmiga::playSoundEffect(%d)", track);
const AmigaSfxTable *sfx = 0;
bool pan = false;
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
index be3c09de96..427bef66e2 100644
--- a/engines/kyra/sound_intern.h
+++ b/engines/kyra/sound_intern.h
@@ -67,7 +67,7 @@ public:
void haltTrack();
bool isPlaying() const;
- void playSoundEffect(uint8 track);
+ void playSoundEffect(uint8 track, uint8 volume = 0xff);
void stopAllSoundEffects();
void beginFadeOut();
@@ -116,7 +116,7 @@ public:
void playTrack(uint8 track);
void haltTrack();
- void playSoundEffect(uint8);
+ void playSoundEffect(uint8 track, uint8 volume = 0xff);
void stopAllSoundEffects();
void beginFadeOut();
@@ -166,7 +166,7 @@ public:
void beginFadeOut();
int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx) { return -1; }
- void playSoundEffect(uint8);
+ void playSoundEffect(uint8 track, uint8 volume = 0xff);
void updateVolumeSettings();
@@ -195,7 +195,7 @@ public:
void beginFadeOut();
int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx);
- void playSoundEffect(uint8 track);
+ void playSoundEffect(uint8 track, uint8 volume = 0xff);
void updateVolumeSettings();
@@ -304,7 +304,7 @@ public:
void beginFadeOut();
int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx) { return -1; }
- void playSoundEffect(uint8);
+ void playSoundEffect(uint8 track, uint8 volume = 0xff);
protected:
Audio::MaxTrax *_driver;
diff --git a/engines/kyra/sound_lol.cpp b/engines/kyra/sound_lol.cpp
index 968488eef3..cb9be43b07 100644
--- a/engines/kyra/sound_lol.cpp
+++ b/engines/kyra/sound_lol.cpp
@@ -167,8 +167,8 @@ void LoLEngine::snd_playSoundEffect(int track, int volume) {
volume &= 0xff;
int16 volIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2 + 1]);
- volume = (volIndex > 0) ? (volIndex * volume) >> 8 : -volIndex;
- volume = CLIP(volume >> 4, 2, 13) * 7 + 164;
+ uint16 vocLevel = (volIndex > 0) ? (volIndex * volume) >> 8 : -volIndex;
+ vocLevel = CLIP(volume >> 4, 2, 13) * 7 + 164;
int16 vocIndex = (int16)READ_LE_UINT16(&_ingameSoundIndex[track * 2]);
@@ -180,7 +180,7 @@ void LoLEngine::snd_playSoundEffect(int track, int volume) {
if (hasVocFile) {
if (_sound->isVoicePresent(_ingameSoundList[vocIndex]))
- _sound->voicePlay(_ingameSoundList[vocIndex], 0, volume & 0xff, true);
+ _sound->voicePlay(_ingameSoundList[vocIndex], 0, vocLevel & 0xff, true);
} else if (_flags.platform == Common::kPlatformPC) {
if (_sound->getSfxType() == Sound::kMidiMT32)
track = (track < _ingameMT32SoundIndexSize) ? (_ingameMT32SoundIndex[track] - 1) : -1;
@@ -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 (!KyraRpgEngine::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/sound_midi.cpp b/engines/kyra/sound_midi.cpp
index 1a5c2f94ac..0004395f6f 100644
--- a/engines/kyra/sound_midi.cpp
+++ b/engines/kyra/sound_midi.cpp
@@ -684,7 +684,7 @@ bool SoundMidiPC::isPlaying() const {
return _music->isPlaying();
}
-void SoundMidiPC::playSoundEffect(uint8 track) {
+void SoundMidiPC::playSoundEffect(uint8 track, uint8) {
if (!_sfxEnabled)
return;
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index c851842f22..2f996de1ac 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -125,7 +125,7 @@ void SoundTowns::loadSoundFile(uint file) {
_sfxFileData = _vm->resource()->fileData(fileListEntry(file), 0);
}
-void SoundTowns::playSoundEffect(uint8 track) {
+void SoundTowns::playSoundEffect(uint8 track, uint8) {
if (!_sfxEnabled || !_sfxFileData)
return;
@@ -414,14 +414,9 @@ void SoundPC98::playTrack(uint8 track) {
beginFadeOut();
- char musicfile[13];
- sprintf(musicfile, fileListEntry(0), track);
- if (fileListLen() == 1)
- sprintf(musicfile, fileListEntry(0), track);
- else
- strcpy(musicfile, fileListEntry(track));
+ Common::String musicFile = fileListLen() == 1 ? Common::String::format(fileListEntry(0), track) : fileListEntry(track);
delete[] _musicTrackData;
- _musicTrackData = _vm->resource()->fileData(musicfile, 0);
+ _musicTrackData = _vm->resource()->fileData(musicFile.c_str(), 0);
if (_musicEnabled)
_driver->loadMusicData(_musicTrackData);
@@ -446,7 +441,7 @@ void SoundPC98::beginFadeOut() {
haltTrack();
}
-void SoundPC98::playSoundEffect(uint8 track) {
+void SoundPC98::playSoundEffect(uint8 track, uint8) {
if (!_sfxTrackData)
return;
@@ -537,17 +532,12 @@ void SoundTownsPC98_v2::playTrack(uint8 track) {
beginFadeOut();
- char musicfile[13];
- if (fileListLen() == 1) {
- sprintf(musicfile, fileListEntry(0), track);
- } else {
- strcpy(musicfile, fileListEntry(track));
- if (!musicfile[0])
- return;
- }
+ Common::String musicFile = fileListLen() == 1 ? Common::String::format(fileListEntry(0), track) : fileListEntry(track);
+ if (musicFile.empty())
+ return;
delete[] _musicTrackData;
- _musicTrackData = _vm->resource()->fileData(musicfile, 0);
+ _musicTrackData = _vm->resource()->fileData(musicFile.c_str(), 0);
_driver->loadMusicData(_musicTrackData, true);
if (_musicEnabled == 2 && trackNum != -1) {
@@ -592,11 +582,9 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle,
return 0;
}
- char filename[13];
- const char *pattern = _vm->game() == GI_LOL ? patternLOL : patternHOF;
- sprintf(filename, pattern, file);
+ Common::String fileName = Common::String::format( _vm->game() == GI_LOL ? patternLOL : patternHOF, file);
- uint8 *data = _vm->resource()->fileData(filename, 0);
+ uint8 *data = _vm->resource()->fileData(fileName.c_str(), 0);
uint8 *src = data;
if (!src)
return 0;
@@ -650,7 +638,7 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, Audio::SoundHandle *handle,
return 1;
}
-void SoundTownsPC98_v2::playSoundEffect(uint8 track) {
+void SoundTownsPC98_v2::playSoundEffect(uint8 track, uint8) {
if (!_useFmSfx || !_sfxTrackData)
return;
diff --git a/engines/kyra/sprites_eob.cpp b/engines/kyra/sprites_eob.cpp
new file mode 100644
index 0000000000..5c679f5cb4
--- /dev/null
+++ b/engines/kyra/sprites_eob.cpp
@@ -0,0 +1,1259 @@
+/* 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/script_eob.h"
+#include "kyra/resource.h"
+#include "kyra/timer.h"
+
+#include "common/system.h"
+
+
+namespace Kyra {
+
+void EoBCoreEngine::loadMonsterShapes(const char *filename, int monsterIndex, bool hasDecorations, int encodeTableIndex) {
+ _screen->loadShapeSetBitmap(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], false, _cgaMappingDefault);
+
+ 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 = (int8)*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[2].base = (int8)*data++;
+ d->immunityFlags = READ_LE_UINT16(data);
+ data += 2;
+ d->capsFlags = READ_LE_UINT16(data);
+ data += 2;
+ d->typeFlags = READ_LE_UINT16(data);
+ data += 2;
+ d->experience = READ_LE_UINT16(data);
+ data += 2;
+
+ d->u30 = *data++;
+ d->sound1 = (int8)*data++;
+ d->sound2 = (int8)*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->tuResist = (int8)*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);
+ }
+
+ uint32 ct = _system->getMillis();
+ for (int i = 0x20; i < 0x24; i++) {
+ int32 del = _timer->getDelay(i);
+ _timer->setNextRun(i, (i & 1) ? ct + (del >> 1) * _tickLength : ct + del * _tickLength);
+ }
+ _timer->resetNextRun();
+
+ 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) : 5;
+ m->type = type;
+ m->numRemoteAttacks = p->numRemoteAttacks;
+ m->curRemoteWeapon = 0;
+ m->unit = unit;
+ m->pos = pos;
+ m->shpIndex = shpIndex;
+ m->mode = mode;
+ m->spellStatusLeft = 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->level == -1 ? rollDice(1, 4, 0) : rollDice(p->level, 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 (killMonsterExtra(m)) {
+ placeMonster(m, 0, -1);
+
+ if ((_flags.gameID == GI_EOB1) && (m->type == 21)) {
+ _playFinale = true;
+ _runFlag = false;
+ }
+
+ if (m->mode == 8)
+ updateAttackingMonsterFlags();
+ }
+}
+
+bool EoBCoreEngine::killMonsterExtra(EoBMonsterInPlay *) {
+ return true;
+}
+
+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)
+ setScriptFlags(4);
+
+ if (m2->type == 12)
+ setScriptFlags(0x800);
+}
+
+const int8 *EoBCoreEngine::getMonstersOnBlockPositions(uint16 block) {
+ memset(_monsterBlockPosArray, -1, sizeof(_monsterBlockPosArray));
+ for (int8 i = 0; i < 30; i++) {
+ if (_monsters[i].block != block)
+ continue;
+ assert(_monsters[i].pos < sizeof(_monsterBlockPosArray));
+ _monsterBlockPosArray[_monsters[i].pos] = i;
+ }
+ return _monsterBlockPosArray;
+}
+
+int EoBCoreEngine::getClosestMonster(int charIndex, int block) {
+ const int8 *pos = getMonstersOnBlockPositions(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 include4 = (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 || include4))
+ *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, include4))
+ *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);
+ if (_flags.gameID == GI_EOB1)
+ x &= ~1;
+ _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 = _monsterFlashOverlay;
+ else if (_flags.gameID == GI_EOB2 && flags & 0x20)
+ ovl = _monsterStoneOverlay;
+ 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 updateShp = false;
+
+ for (EoBMonsterInPlay *m = _monsters; m < &_monsters[30]; m++) {
+ if (m->flags & 2) {
+ m->flags &= ~2;
+ updateShp = true;
+ if (m->hitPointsCur <= 0)
+ killMonster(m, true);
+ }
+ }
+
+ if (updateShp) {
+ _sceneUpdateRequired = true;
+ _flashShapeTimer = _system->getMillis() + _tickLength;
+ } else {
+ _sceneUpdateRequired = false;
+ }
+ _preventMonsterFlash = false;
+}
+
+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] << 1) - ((shp[2] << 3) >> 1);
+ 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];
+
+ if (_flags.gameID == GI_EOB1 && s == 0x85)
+ s = 0;
+
+ if (s >= _dscDoorShpIndexSize)
+ return;
+
+ 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;
+ setDoorShapeDim(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->capsFlags & 0x100) && !(_partyEffectFlags & 0x220) && !(d->flags & 2))
+ continue;
+
+ int f = (d->animStep << 4) + cDirOffs + d->dir;
+ f = (p->capsFlags & 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) {
+ int d = _dscDimMap[index];
+ assert(d < 3);
+ int dH = _wallOfForceDsNumH[d];
+ int dW = _wallOfForceDsNumW[d];
+ int y = _wallOfForceDsY[d];
+ int shpId = _wallOfForceShpId[d] + _teleporterPulse;
+ int h = _wallOfForceShapes[shpId][1];
+ int w = _wallOfForceShapes[shpId][2] << 3;
+
+ for (int i = 0; i < dH; i++) {
+ int x = _wallOfForceDsX[index];
+ for (int ii = 0; ii < dW; ii++) {
+ drawBlockObject(0, 2, _wallOfForceShapes[shpId], x, y, 5);
+ x += w;
+ }
+ y += h;
+ shpId ^= 1;
+ }
+}
+
+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 & 3)];
+ }
+
+ } else {
+ rstFade = true;
+ shp = (fo->objectType < _numThrownItemShapes) ? _thrownItemShapes[fo->objectType] : _spellShapes[fo->objectType - _numThrownItemShapes];
+ flipped = _flightObjFlipIndex[(fo->direction << 2) + (fo->curPos & 3)];
+
+ 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)
+ updateMonsterAttackMode(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:
+ updateMonstersSpellStatus(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::updateMonsterAttackMode(EoBMonsterInPlay *m) {
+ if (!(m->flags & 1) || m->mode == 10)
+ return;
+ if (m->mode == 8) {
+ turnFriendlyMonstersHostile();
+ return;
+ }
+ m->mode = 0;
+ m->dest = _currentBlock;
+}
+
+void EoBCoreEngine::updateAllMonsterDests() {
+ for (int i = 0; i < 30; i++)
+ updateMonsterDest(&_monsters[i]);
+}
+
+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)
+ setScriptFlags(0x40000);
+ else if (m->type == 12)
+ setScriptFlags(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 ((_flags.gameID == GI_EOB2) && (p->capsFlags & 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->capsFlags & 8)
+ updateMonsterTryCloseAttack(m, -1);
+}
+
+bool EoBCoreEngine::updateMonsterTryDistanceAttack(EoBMonsterInPlay *m) {
+ EoBMonsterProperty *p = &_monsterProps[m->type];
+ if (!m->numRemoteAttacks || ((_flags.gameID == GI_EOB1) && !(p->capsFlags & 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, _enemyMageSpellList[m->numRemoteAttacks], m->block, m->pos, m->dir);
+ snd_processEnvironmentalSoundEffect(_enemyMageSfx[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, _beholderSpellList[d], m->block, m->pos, m->dir);
+ snd_processEnvironmentalSoundEffect(_beholderSfx[d], 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 {
+ 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) {
+ // Interestingly, the fear spell in EOB 1 does not expire.
+ // I don't know whether this is intended or not.
+ if (_flags.gameID == GI_EOB1) {
+ d ^= 4;
+ } else if (m->spellStatusLeft > 0) {
+ if (--m->spellStatusLeft == 0)
+ m->flags &= ~8;
+ else
+ d ^= 4;
+ }
+ }
+
+ int d2 = (d - s) & 7;
+
+ if (_flags.gameID == GI_EOB1) {
+ if ((b + _monsterStepTable0[d >> 1] == _currentBlock) && !(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 (b + _monsterStepTable0[d] == destBlock) {
+ if (d & 1) {
+ int e = _monsterStepTable1[((d - 1) << 1) + m->dir];
+ if (e && (!(_monsterProps[m->type].capsFlags & 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->capsFlags & 0x1000) || _wllShapeMap[w] != -1)
+ return false;
+
+ if (_wllWallFlags[w] & 0x20) {
+ if (p->capsFlags & 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 > 0)
+ 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::updateMonstersSpellStatus(EoBMonsterInPlay *m) {
+ if (m->spellStatusLeft) {
+ if (!--m->spellStatusLeft)
+ 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..a07abd4580 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);
@@ -97,7 +97,7 @@ void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int animTy
uint8 *cl = (uint8 *)memchr(tmpPal1, tmpPal2[1 + ii], 64);
if (!cl)
continue;
- tmpPal3[ii] = (uint16) (cl - tmpPal1);
+ tmpPal3[ii] = (uint16)(cl - tmpPal1);
}
for (int ii = 0; ii < 8; ii++) {
@@ -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];
+ LoLMonster *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(LoLMonster *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(LoLMonster *monster) {
static const uint8 dims[] = { 0, 13, 9, 3 };
if (monster->properties->flags & 8)
return true;
@@ -248,10 +248,10 @@ bool LoLEngine::updateMonsterAdjustBlocks(MonsterInPlay *monster) {
int16 fx2 = 0;
setLevelShapesDim(x2 + dims[y2], fx1, fx2, 13);
- return (fx1 >= fx2) ? false : true;
+ return fx1 < fx2;
}
-void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) {
+void LoLEngine::placeMonster(LoLMonster *monster, uint16 x, uint16 y) {
bool cont = true;
int t = monster->block;
if (monster->block) {
@@ -273,7 +273,7 @@ void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) {
if (monster->block == 0)
return;
- assignMonsterToBlock(&_levelBlockProperties[monster->block].assignedObjects, ((uint16)monster->id) | 0x8000);
+ assignObjectToBlock(&_levelBlockProperties[monster->block].assignedObjects, ((uint16)monster->id) | 0x8000);
_levelBlockProperties[monster->block].direction = 5;
checkSceneUpdateNeed(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(LoLMonster *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(LoLMonster *monster) {
uint16 a = monster->assignedItems;
while (a) {
uint16 b = a;
@@ -347,46 +347,6 @@ void LoLEngine::monsterDropItems(MonsterInPlay *monster) {
}
}
-void LoLEngine::removeAssignedObjectFromBlock(LevelBlockProperty *l, uint16 id) {
- uint16 *blockItemIndex = &l->assignedObjects;
- ItemInPlay *i = 0;
-
- while (*blockItemIndex) {
- if (*blockItemIndex == id) {
- i = findObject(id);
- *blockItemIndex = i->nextAssignedObject;
- i->nextAssignedObject = 0;
- return;
- }
-
- i = findObject(*blockItemIndex);
- blockItemIndex = &i->nextAssignedObject;
- }
-}
-
-void LoLEngine::removeDrawObjectFromBlock(LevelBlockProperty *l, uint16 id) {
- uint16 *blockItemIndex = &l->drawObjects;
- ItemInPlay *i = 0;
-
- while (*blockItemIndex) {
- if (*blockItemIndex == id) {
- i = findObject(id);
- *blockItemIndex = i->nextDrawObject;
- i->nextDrawObject = 0;
- return;
- }
-
- i = findObject(*blockItemIndex);
- blockItemIndex = &i->nextDrawObject;
- }
-}
-
-void LoLEngine::assignMonsterToBlock(uint16 *assignedBlockObjects, uint16 id) {
- ItemInPlay *t = findObject(id);
- t->nextAssignedObject = *assignedBlockObjects;
- *assignedBlockObjects = id;
-}
-
int LoLEngine::checkBlockBeforeObjectPlacement(uint16 x, uint16 y, uint16 objectWidth, uint16 testFlag, uint16 wallFlag) {
_objectLastDirection = 0;
uint16 x2 = 0;
@@ -503,7 +463,7 @@ int LoLEngine::checkBlockForWallsAndSufficientSpace(int block, int x, int y, int
uint16 b = _levelBlockProperties[block].assignedObjects;
while (b & 0x8000) {
- MonsterInPlay *monster = &_monsters[b & 0x7fff];
+ LoLMonster *monster = &_monsters[b & 0x7fff];
if (monster->mode < 13) {
int r = checkDrawObjectSpace(x, y, monster->x, monster->y);
@@ -554,7 +514,7 @@ int LoLEngine::checkBlockOccupiedByParty(int x, int y, int testFlag) {
void LoLEngine::drawBlockObjects(int blockArrayIndex) {
LevelBlockProperty *l = _visibleBlocks[blockArrayIndex];
uint16 s = l->assignedObjects;
- ItemInPlay *i = findObject(s);
+ LoLObject *obj = findObject(s);
if (l->direction != _currentDirection) {
l->drawObjects = 0;
@@ -562,8 +522,8 @@ void LoLEngine::drawBlockObjects(int blockArrayIndex) {
while (s) {
reassignDrawObjects(_currentDirection, s, l, true);
- i = findObject(s);
- s = i->nextAssignedObject;
+ obj = findObject(s);
+ s = obj->nextAssignedObject;
}
}
@@ -575,7 +535,7 @@ void LoLEngine::drawBlockObjects(int blockArrayIndex) {
drawMonster(s);
s = _monsters[s].nextDrawObject;
} else {
- i = &_itemsInPlay[s];
+ LoLItem *i = &_itemsInPlay[s];
int fx = _sceneItemOffs[s & 7] << 1;
int fy = _sceneItemOffs[(s >> 1) & 7] + 5;
@@ -634,7 +594,7 @@ void LoLEngine::drawBlockObjects(int blockArrayIndex) {
} else {
shp = (_itemProperties[i->itemPropertyIndex].flags & 0x40) ? _gameShapes[_itemProperties[i->itemPropertyIndex].shpIndex] :
- _itemShapes[_gameShapeMap[_itemProperties[i->itemPropertyIndex].shpIndex << 1]];
+ _itemShapes[_gameShapeMap[_itemProperties[i->itemPropertyIndex].shpIndex << 1]];
}
if (shp)
@@ -645,7 +605,7 @@ void LoLEngine::drawBlockObjects(int blockArrayIndex) {
}
void LoLEngine::drawMonster(uint16 id) {
- MonsterInPlay *m = &_monsters[id];
+ LoLMonster *m = &_monsters[id];
int16 flg = _monsterDirFlags[(_currentDirection << 2) + m->facing];
int curFrm = getMonsterCurFrame(m, flg & 0xffef);
uint8 *shp = 0;
@@ -665,12 +625,12 @@ void LoLEngine::drawMonster(uint16 id) {
uint8 *monsterPalette = d ? _monsterPalettes[(m->properties->shapeIndex << 4) + (curFrm & 0x0f)] + (shp[10] * (d - 1)) : 0;
uint8 *brightnessOverlay = drawItemOrMonster(shp, monsterPalette, m->x + _monsterShiftOffs[m->shiftStep << 1], m->y + _monsterShiftOffs[(m->shiftStep << 1) + 1], 0, 0, flg | 1, -1, flip);
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 4; i++) {
int v = m->equipmentShapes[i] - 1;
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 +681,7 @@ void LoLEngine::drawMonster(uint16 id) {
delete[] tbl;
}
-int LoLEngine::getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags) {
+int LoLEngine::getMonsterCurFrame(LoLMonster *m, uint16 dirFlags) {
int tmp = 0;
switch (_monsterAnimType[m->properties->shapeIndex]) {
case 0:
@@ -796,19 +756,19 @@ void LoLEngine::reassignDrawObjects(uint16 direction, uint16 itemIndex, LevelBlo
return;
}
- ItemInPlay *newObject = findObject(itemIndex);
- int r = calcItemMonsterPosition(newObject, direction);
+ LoLObject *newObject = findObject(itemIndex);
+ int r = calcObjectPosition(newObject, direction);
uint16 *b = &l->drawObjects;
- ItemInPlay *lastObject = 0;
+ LoLObject *lastObject = 0;
while (*b) {
lastObject = findObject(*b);
if (flag) {
- if (calcItemMonsterPosition(lastObject, direction) >= r)
+ if (calcObjectPosition(lastObject, direction) >= r)
break;
} else {
- if (calcItemMonsterPosition(lastObject, direction) > r)
+ if (calcObjectPosition(lastObject, direction) > r)
break;
}
@@ -838,7 +798,7 @@ void LoLEngine::redrawSceneItem() {
if (s & 0x8000) {
s = _monsters[s & 0x7fff].nextDrawObject;
} else {
- ItemInPlay *item = &_itemsInPlay[s];
+ LoLItem *item = &_itemsInPlay[s];
if (item->shpCurFrame_flg & 0x4000) {
if (checkDrawObjectSpace(item->x, item->y, _partyPosX, _partyPosY) < 320) {
@@ -848,7 +808,7 @@ void LoLEngine::redrawSceneItem() {
fy -= ((item->flyingHeight - 1) * 6);
uint8 *shp = (_itemProperties[item->itemPropertyIndex].flags & 0x40) ? _gameShapes[_itemProperties[item->itemPropertyIndex].shpIndex] :
- _itemShapes[_gameShapeMap[_itemProperties[item->itemPropertyIndex].shpIndex << 1]];
+ _itemShapes[_gameShapeMap[_itemProperties[item->itemPropertyIndex].shpIndex << 1]];
drawItemOrMonster(shp, 0, item->x, item->y, fx, fy, 0, t, 0);
_screen->updateScreen();
@@ -862,21 +822,6 @@ void LoLEngine::redrawSceneItem() {
}
}
-int LoLEngine::calcItemMonsterPosition(ItemInPlay *i, uint16 direction) {
- int x = i->x;
- int y = i->y;
-
- calcSpriteRelPosition(_partyPosX, _partyPosY, x, y, direction);
-
- if (y < 0)
- y = 0;
-
- int res = (i->flyingHeight << 12);
- res |= (4095 - y);
-
- return res;
-}
-
void LoLEngine::calcSpriteRelPosition(uint16 x1, uint16 y1, int &x2, int &y2, uint16 direction) {
int a = x2 - x1;
int b = y1 - y2;
@@ -901,7 +846,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;
@@ -910,7 +855,7 @@ void LoLEngine::drawDoor(uint8 *shape, uint8 *doorPalette, int index, int unk2,
if (flags & 1) {
// TODO / UNUSED
- flags |=1;
+ flags |= 1;
}
int u = 0;
@@ -1080,7 +1025,7 @@ int LoLEngine::calcDrawingLayerParameters(int x1, int y1, int &x2, int &y2, uint
return l;
}
-void LoLEngine::updateMonster(MonsterInPlay *monster) {
+void LoLEngine::updateMonster(LoLMonster *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;
@@ -1182,7 +1127,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) {
// first recovery phase after delivering an attack
if (++monster->fightCurTick > 2) {
setMonsterMode(monster, 5);
- monster->fightCurTick = (int8) ((((8 << 8) / monster->properties->fightingStats[4]) * _monsterModifiers[6 + _monsterDifficulty]) >> 8);
+ monster->fightCurTick = (int8)((((8 << 8) / monster->properties->fightingStats[4]) * _monsterModifiers[6 + _monsterDifficulty]) >> 8);
}
checkSceneUpdateNeed(monster->block);
break;
@@ -1228,7 +1173,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) {
monster->flags &= 0xffef;
}
-void LoLEngine::moveMonster(MonsterInPlay *monster) {
+void LoLEngine::moveMonster(LoLMonster *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 +1183,7 @@ void LoLEngine::moveMonster(MonsterInPlay *monster) {
}
}
-void LoLEngine::walkMonster(MonsterInPlay *monster) {
+void LoLEngine::walkMonster(LoLMonster *monster) {
if (monster->properties->flags & 0x400)
return;
@@ -1253,7 +1198,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 +1214,7 @@ void LoLEngine::walkMonster(MonsterInPlay *monster) {
placeMonster(monster, fx, fy);
}
-bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) {
+bool LoLEngine::chasePartyWithDistanceAttacks(LoLMonster *monster) {
if (!monster->numDistAttacks)
return false;
@@ -1295,7 +1240,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 +1250,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 +1271,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 +1292,7 @@ bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) {
return true;
}
-void LoLEngine::chasePartyWithCloseAttacks(MonsterInPlay *monster) {
+void LoLEngine::chasePartyWithCloseAttacks(LoLMonster *monster) {
if (!(monster->flags & 8)) {
int dir = calcMonsterDirection(monster->x & 0xff00, monster->y & 0xff00, _partyPosX & 0xff00, _partyPosY & 0xff00);
int x1 = _partyPosX;
@@ -1365,7 +1310,7 @@ void LoLEngine::chasePartyWithCloseAttacks(MonsterInPlay *monster) {
if (hit) {
int mx = calcInflictableDamage(m, dst, hit);
- int dmg = rollDice(2, mx );
+ int dmg = rollDice(2, mx);
inflictDamage(dst, dmg, m, 0, 0);
applyMonsterAttackSkill(monster, dst, dmg);
}
@@ -1389,7 +1334,7 @@ void LoLEngine::chasePartyWithCloseAttacks(MonsterInPlay *monster) {
}
}
-int LoLEngine::walkMonsterCalcNextStep(MonsterInPlay *monster) {
+int LoLEngine::walkMonsterCalcNextStep(LoLMonster *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 +1390,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 +1424,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, LoLMonster *monster, int unk) {
uint8 m = monster->mode;
monster->mode = 15;
@@ -1512,12 +1442,12 @@ void LoLEngine::getNextStepCoords(int16 srcX, int16 srcY, int &newX, int &newY,
newY = (srcY + shiftTableY[direction]) & 0x1fff;
}
-void LoLEngine::rearrangeAttackingMonster(MonsterInPlay *monster) {
+void LoLEngine::rearrangeAttackingMonster(LoLMonster *monster) {
int t = (monster->direction >> 1);
uint16 mx = monster->x;
uint16 my = monster->y;
uint16 *c = (t & 1) ? &my : &mx;
- bool centered = (*c & 0x7f) ? false : true;
+ bool centered = (*c & 0x7f) == 0;
bool posFlag = true;
if (monster->properties->maxWidth <= 63) {
@@ -1579,7 +1509,7 @@ void LoLEngine::rearrangeAttackingMonster(MonsterInPlay *monster) {
placeMonster(monster, mx, my);
}
-void LoLEngine::moveStrayingMonster(MonsterInPlay *monster) {
+void LoLEngine::moveStrayingMonster(LoLMonster *monster) {
int x = 0;
int y = 0;
@@ -1616,13 +1546,13 @@ void LoLEngine::moveStrayingMonster(MonsterInPlay *monster) {
}
}
-void LoLEngine::killMonster(MonsterInPlay *monster) {
+void LoLEngine::killMonster(LoLMonster *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/sprites_rpg.cpp b/engines/kyra/sprites_rpg.cpp
new file mode 100644
index 0000000000..0c4fcb09ab
--- /dev/null
+++ b/engines/kyra/sprites_rpg.cpp
@@ -0,0 +1,46 @@
+/* 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/kyra_rpg.h"
+
+namespace Kyra {
+
+int KyraRpgEngine::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
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index e03369f700..423b827092 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -38,7 +38,7 @@
namespace Kyra {
-#define RESFILE_VERSION 78
+#define RESFILE_VERSION 82
namespace {
bool checkKyraDat(Common::SeekableReadStream *file) {
@@ -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 }
};
@@ -245,17 +247,34 @@ bool StaticResource::init() {
{ k2SeqData, proc(loadHofSequenceData), proc(freeHofSequenceData) },
{ k2ShpAnimDataV1, proc(loadShapeAnimData_v1), proc(freeHofShapeAnimDataV1) },
- { k2ShpAnimDataV2, proc(loadShapeAnimData_v2), proc(freeHofShapeAnimDataV2) },
+ { k2ItemAnimDefinition, proc(loadItemAnimDefinition), proc(freeItemAnimDefinition) },
#ifdef ENABLE_LOL
- { kLolCharData, proc(loadCharData), proc(freeCharData) },
- { kLolSpellData, proc(loadSpellData), proc(freeSpellData) },
- { kLolCompassData, proc(loadCompassData), proc(freeCompassData) },
- { kLolFlightShpData, proc(loadFlyingObjectData), proc(freeFlyingObjectData) },
- { kLolRawDataBe16, proc(loadRawDataBe16), proc(freeRawDataBe16) },
- { kLolRawDataBe32, proc(loadRawDataBe32), proc(freeRawDataBe32) },
- { kLolButtonData, proc(loadButtonDefs), proc(freeButtonDefs) },
-#endif // ENABLE_LOL
+ { kLoLCharData, proc(loadCharData), proc(freeCharData) },
+ { kLoLSpellData, proc(loadSpellData), proc(freeSpellData) },
+ { kLoLCompassData, proc(loadCompassData), proc(freeCompassData) },
+ { kLoLFlightShpData, proc(loadFlyingObjectData), proc(freeFlyingObjectData) },
+#else
+ { kLoLCharData, proc(loadDummy), proc(freeDummy) },
+ { kLoLSpellData, proc(loadDummy), proc(freeDummy) },
+ { kLoLCompassData, proc(loadDummy), proc(freeDummy) },
+ { kLoLFlightShpData, proc(loadDummy), proc(freeDummy) },
+#endif
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+ { kRawDataBe16, proc(loadRawDataBe16), proc(freeRawDataBe16) },
+ { kRawDataBe32, proc(loadRawDataBe32), proc(freeRawDataBe32) },
+#endif
+#ifdef ENABLE_LOL
+ { kLoLButtonData, proc(loadButtonDefs), proc(freeButtonDefs) },
+#else
+ { kLoLButtonData, proc(loadDummy), proc(freeDummy) },
+#endif
+
+#ifdef ENABLE_EOB
+ { kEoB2SequenceData, proc(loadEoB2SeqData), proc(freeEoB2SeqData) },
+ { kEoB2ShapeData, proc(loadEoB2ShapeData), proc(freeEoB2ShapeData) },
+ { kEoBNpcData, proc(loadEoBNpcData), proc(freeEoBNpcData) },
+#endif
{ 0, 0, 0 }
};
@@ -269,7 +288,7 @@ void StaticResource::deinit() {
unloadId(-1);
}
-const char * const *StaticResource::loadStrings(int id, int &strings) {
+const char *const *StaticResource::loadStrings(int id, int &strings) {
return (const char * const *)getData(id, kStringList, strings);
}
@@ -297,8 +316,8 @@ const ItemAnimData_v1 *StaticResource::loadShapeAnimData_v1(int id, int &entries
return (const ItemAnimData_v1 *)getData(id, k2ShpAnimDataV1, entries);
}
-const ItemAnimData_v2 *StaticResource::loadShapeAnimData_v2(int id, int &entries) {
- return (const ItemAnimData_v2 *)getData(id, k2ShpAnimDataV2, entries);
+const ItemAnimDefinition *StaticResource::loadItemAnimDefinition(int id, int &entries) {
+ return (const ItemAnimDefinition *)getData(id, k2ItemAnimDefinition, entries);
}
bool StaticResource::prefetchId(int id) {
@@ -403,6 +422,10 @@ const void *StaticResource::getData(int id, int requesttype, int &size) {
return 0;
}
+bool StaticResource::loadDummy(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ return true;
+}
+
bool StaticResource::loadStringTable(Common::SeekableReadStream &stream, void *&ptr, int &size) {
uint32 count = stream.readUint32BE();
size = count;
@@ -415,7 +438,7 @@ bool StaticResource::loadStringTable(Common::SeekableReadStream &stream, void *&
while ((c = (char)stream.readByte()) != 0)
string += c;
- output[i] = new char[string.size()+1];
+ output[i] = new char[string.size() + 1];
strcpy(output[i], string.c_str());
}
@@ -479,10 +502,10 @@ bool StaticResource::loadRoomTable(Common::SeekableReadStream &stream, void *&pt
loadTo[i].eastExit = stream.readUint16BE();
loadTo[i].southExit = stream.readUint16BE();
loadTo[i].westExit = stream.readUint16BE();
- memset(&loadTo[i].itemsTable[0], 0xFF, sizeof(byte)*6);
- memset(&loadTo[i].itemsTable[6], 0, sizeof(byte)*6);
- memset(loadTo[i].itemsXPos, 0, sizeof(uint16)*12);
- memset(loadTo[i].itemsYPos, 0, sizeof(uint8)*12);
+ memset(&loadTo[i].itemsTable[0], 0xFF, sizeof(byte) * 6);
+ memset(&loadTo[i].itemsTable[6], 0, sizeof(byte) * 6);
+ memset(loadTo[i].itemsXPos, 0, sizeof(uint16) * 12);
+ memset(loadTo[i].itemsYPos, 0, sizeof(uint8) * 12);
memset(loadTo[i].needInit, 0, sizeof(loadTo[i].needInit));
}
@@ -587,9 +610,9 @@ bool StaticResource::loadShapeAnimData_v1(Common::SeekableReadStream &stream, vo
return true;
}
-bool StaticResource::loadShapeAnimData_v2(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+bool StaticResource::loadItemAnimDefinition(Common::SeekableReadStream &stream, void *&ptr, int &size) {
size = stream.readByte();
- ItemAnimData_v2 *loadTo = new ItemAnimData_v2[size];
+ ItemAnimDefinition *loadTo = new ItemAnimDefinition[size];
assert(loadTo);
for (int i = 0; i < size; i++) {
@@ -607,6 +630,9 @@ bool StaticResource::loadShapeAnimData_v2(Common::SeekableReadStream &stream, vo
return true;
}
+void StaticResource::freeDummy(void *&ptr, int &size) {
+}
+
void StaticResource::freeRawData(void *&ptr, int &size) {
uint8 *data = (uint8 *)ptr;
delete[] data;
@@ -665,7 +691,7 @@ void StaticResource::freeHofSequenceData(void *&ptr, int &size) {
}
void StaticResource::freeHofShapeAnimDataV1(void *&ptr, int &size) {
- ItemAnimData_v1 *d= (ItemAnimData_v1 *)ptr;
+ ItemAnimData_v1 *d = (ItemAnimData_v1 *)ptr;
for (int i = 0; i < size; i++)
delete[] d[i].frames;
delete[] d;
@@ -673,8 +699,8 @@ void StaticResource::freeHofShapeAnimDataV1(void *&ptr, int &size) {
size = 0;
}
-void StaticResource::freeHofShapeAnimDataV2(void *&ptr, int &size) {
- ItemAnimData_v2 *d= (ItemAnimData_v2 *)ptr;
+void StaticResource::freeItemAnimDefinition(void *&ptr, int &size) {
+ ItemAnimDefinition *d = (ItemAnimDefinition *)ptr;
for (int i = 0; i < size; i++)
delete[] d[i].frames;
delete[] d;
@@ -774,7 +800,7 @@ void KyraEngine_LoK::initStaticResource() {
_roomTable = new Room[_roomTableSize];
assert(_roomTable);
- memcpy(_roomTable, tempRoomList, _roomTableSize*sizeof(Room));
+ memcpy(_roomTable, tempRoomList, _roomTableSize * sizeof(Room));
tempRoomList = 0;
_staticres->unloadId(k1RoomList);
@@ -787,7 +813,7 @@ void KyraEngine_LoK::initStaticResource() {
_defaultShapeTable = new Shape[_defaultShapeTableSize];
assert(_defaultShapeTable);
- memcpy(_defaultShapeTable, tempShapeTable, _defaultShapeTableSize*sizeof(Shape));
+ memcpy(_defaultShapeTable, tempShapeTable, _defaultShapeTableSize * sizeof(Shape));
tempShapeTable = 0;
_staticres->unloadId(k1DefaultShapes);
@@ -848,7 +874,7 @@ void KyraEngine_LoK::loadCharacterShapes() {
assert(i < _defaultShapeTableSize);
Shape *shape = &_defaultShapeTable[i];
if (shape->imageIndex == 0xFF) {
- _shapes[i+7] = 0;
+ _shapes[i + 7] = 0;
continue;
}
if (shape->imageIndex != curImage) {
@@ -856,7 +882,7 @@ void KyraEngine_LoK::loadCharacterShapes() {
_screen->loadBitmap(_characterImageTable[shape->imageIndex], 3, 3, 0);
curImage = shape->imageIndex;
}
- _shapes[i+7] = _screen->encodeShape(shape->x<<3, shape->y, shape->w<<3, shape->h, 1);
+ _shapes[i + 7] = _screen->encodeShape(shape->x << 3, shape->y, shape->w << 3, shape->h, 1);
}
_screen->_curPage = videoPage;
}
@@ -867,16 +893,16 @@ void KyraEngine_LoK::loadSpecialEffectShapes() {
int currShape;
for (currShape = 173; currShape < 183; currShape++)
- _shapes[currShape] = _screen->encodeShape((currShape-173) * 24, 0, 24, 24, 1);
+ _shapes[currShape] = _screen->encodeShape((currShape - 173) * 24, 0, 24, 24, 1);
for (currShape = 183; currShape < 190; currShape++)
- _shapes[currShape] = _screen->encodeShape((currShape-183) * 24, 24, 24, 24, 1);
+ _shapes[currShape] = _screen->encodeShape((currShape - 183) * 24, 24, 24, 24, 1);
for (currShape = 190; currShape < 201; currShape++)
- _shapes[currShape] = _screen->encodeShape((currShape-190) * 24, 48, 24, 24, 1);
+ _shapes[currShape] = _screen->encodeShape((currShape - 190) * 24, 48, 24, 24, 1);
for (currShape = 201; currShape < 206; currShape++)
- _shapes[currShape] = _screen->encodeShape((currShape-201) * 16, 106, 16, 16, 1);
+ _shapes[currShape] = _screen->encodeShape((currShape - 201) * 16, 106, 16, 16, 1);
}
void KyraEngine_LoK::loadItems() {
@@ -891,22 +917,22 @@ void KyraEngine_LoK::loadItems() {
_shapes[323 + shape] = _screen->encodeShape((shape - 1) * 32, 0, 32, 17, 0);
for (shape = 330; shape <= 334; shape++)
- _shapes[shape] = _screen->encodeShape((shape-330) * 32, 102, 32, 17, 0);
+ _shapes[shape] = _screen->encodeShape((shape - 330) * 32, 102, 32, 17, 0);
for (shape = 335; shape <= 339; shape++)
- _shapes[shape] = _screen->encodeShape((shape-335) * 32, 17, 32, 17, 0);
+ _shapes[shape] = _screen->encodeShape((shape - 335) * 32, 17, 32, 17, 0);
for (shape = 340; shape <= 344; shape++)
- _shapes[shape] = _screen->encodeShape((shape-340) * 32, 34, 32, 17, 0);
+ _shapes[shape] = _screen->encodeShape((shape - 340) * 32, 34, 32, 17, 0);
for (shape = 345; shape <= 349; shape++)
- _shapes[shape] = _screen->encodeShape((shape-345) * 32, 51, 32, 17, 0);
+ _shapes[shape] = _screen->encodeShape((shape - 345) * 32, 51, 32, 17, 0);
for (shape = 350; shape <= 354; shape++)
- _shapes[shape] = _screen->encodeShape((shape-350) * 32, 68, 32, 17, 0);
+ _shapes[shape] = _screen->encodeShape((shape - 350) * 32, 68, 32, 17, 0);
for (shape = 355; shape <= 359; shape++)
- _shapes[shape] = _screen->encodeShape((shape-355) * 32, 85, 32, 17, 0);
+ _shapes[shape] = _screen->encodeShape((shape - 355) * 32, 85, 32, 17, 0);
_screen->loadBitmap("ITEMS.CPS", 3, 3, 0);
@@ -918,7 +944,7 @@ void KyraEngine_LoK::loadItems() {
if (shape != -1)
_shapes[216 + i] = _shapes[216 + shape];
else
- _shapes[216 + i] = _screen->encodeShape( (i % 20) * 16, i/20 * 16, 16, 16, 0);
+ _shapes[216 + i] = _screen->encodeShape((i % 20) * 16, i / 20 * 16, 16, 16, 0);
}
_res->loadFileToBuf("_ITEM_HT.DAT", &_itemHtDat, sizeof(_itemHtDat));
@@ -981,7 +1007,7 @@ void KyraEngine_HoF::initStaticResource() {
_cdaTrackTableFinale = _staticres->loadRawData(k2SeqplayFinaleCDA, _cdaTrackTableFinaleSize);
_ingameTalkObjIndex = (const uint16 *)_staticres->loadRawData(k2IngameTalkObjIndex, _ingameTalkObjIndexSize);
_ingameTimJpStr = _staticres->loadStrings(k2IngameTimJpStrings, _ingameTimJpStrSize);
- _itemAnimData = _staticres->loadShapeAnimData_v2(k2IngameShapeAnimData, _itemAnimDataSize);
+ _itemAnimDefinition = _staticres->loadItemAnimDefinition(k2IngameShapeAnimData, _itemAnimDefinitionSize);
// replace sequence talkie files with localized versions
const char *const *seqSoundList = _staticres->loadStrings(k2SeqplaySfxFiles, _sequenceSoundListSize);
@@ -997,7 +1023,7 @@ void KyraEngine_HoF::initStaticResource() {
if (tlkfiles && len > 1) {
for (int ii = 0; ii < tmpSize; ii++) {
if (strlen(tlkfiles[ii]) > 1 && !scumm_stricmp(&seqSoundList[i][1], &tlkfiles[ii][1]))
- strcpy(tmpSndLst[i], tlkfiles[ii]);
+ strcpy(tmpSndLst[i], tlkfiles[ii]);
}
}
@@ -1052,8 +1078,8 @@ void KyraEngine_HoF::initStaticResource() {
// setup sequence data
_sequences = _staticres->loadHofSequenceData(k2SeqplaySeqData, tmpSize);
- static const SeqProc hofSequenceCallbacks[] = { 0,
- &KyraEngine_HoF::seq_introWestwood,
+ static const SeqProc hofSequenceCallbacks[] = {
+ 0, &KyraEngine_HoF::seq_introWestwood,
&KyraEngine_HoF::seq_introTitle, &KyraEngine_HoF::seq_introOverview,
&KyraEngine_HoF::seq_introLibrary, &KyraEngine_HoF::seq_introHand,
&KyraEngine_HoF::seq_introPoint, &KyraEngine_HoF::seq_introZanfaun,
@@ -1087,26 +1113,27 @@ void KyraEngine_HoF::initStaticResource() {
};
#ifdef ENABLE_LOL
- static const SeqProc kLolDemoSequenceCallbacks[] = {
+ static const SeqProc kLoLDemoSequenceCallbacks[] = {
&KyraEngine_HoF::seq_lolDemoScene1, 0, &KyraEngine_HoF::seq_lolDemoScene2, 0,
&KyraEngine_HoF::seq_lolDemoScene3, 0, &KyraEngine_HoF::seq_lolDemoScene4, 0,
&KyraEngine_HoF::seq_lolDemoScene5, &KyraEngine_HoF::seq_lolDemoText5,
&KyraEngine_HoF::seq_lolDemoScene6, 0
};
- static const SeqProc kLolDemoNestedSequenceCallbacks[] = { 0 };
+ static const SeqProc kLoLDemoNestedSequenceCallbacks[] = { 0 };
#endif // ENABLE_LOL
_callbackS =
#ifdef ENABLE_LOL
- _flags.gameID == GI_LOL ? kLolDemoSequenceCallbacks :
+ _flags.gameID == GI_LOL ? kLoLDemoSequenceCallbacks :
#endif // ENABLE_LOL
- ((_flags.isDemo && !_flags.isTalkie) ? hofDemoSequenceCallbacks : hofSequenceCallbacks);
+ ((_flags.isDemo && !_flags.isTalkie) ? hofDemoSequenceCallbacks : hofSequenceCallbacks);
+
_callbackN =
#ifdef ENABLE_LOL
- _flags.gameID == GI_LOL ? kLolDemoNestedSequenceCallbacks :
+ _flags.gameID == GI_LOL ? kLoLDemoNestedSequenceCallbacks :
#endif // ENABLE_LOL
- ((_flags.isDemo && !_flags.isTalkie) ? hofDemoNestedSequenceCallbacks : hofNestedSequenceCallbacks);
+ ((_flags.isDemo && !_flags.isTalkie) ? hofDemoNestedSequenceCallbacks : hofNestedSequenceCallbacks);
}
void KyraEngine_MR::initStaticResource() {
@@ -1116,7 +1143,7 @@ void KyraEngine_MR::initStaticResource() {
_scoreTable = _staticres->loadRawData(k3ScoreTable, _scoreTableSize);
_sfxFileList = _staticres->loadStrings(k3SfxFiles, _sfxFileListSize);
_sfxFileMap = _staticres->loadRawData(k3SfxMap, _sfxFileMapSize);
- _itemAnimData = _staticres->loadShapeAnimData_v2(k3ItemAnimData, tmp);
+ _itemAnimDefinition = _staticres->loadItemAnimDefinition(k3ItemAnimData, tmp);
_itemMagicTable = _staticres->loadRawData(k3ItemMagicTable, tmp);
_itemStringMap = _staticres->loadRawData(k3ItemStringMap, _itemStringMapSize);
}
@@ -1158,7 +1185,7 @@ const ScreenDim Screen_HoF::_screenDimTable[] = {
{ 0x00, 0x00, 0x28, 0x88, 0xC7, 0xCF, 0x00, 0x00 },
{ 0x00, 0x08, 0x28, 0xB8, 0xC7, 0xCF, 0x00, 0x00 },
{ 0x01, 0x28, 0x26, 0x46, 0xC7, 0xCC, 0x00, 0x00 },
- { 0x0A, 0x96, 0x14, 0x30, 0x19, 0xF0, 0x00, 0x00 } // menu, just present for current menu code
+ { 0x0A, 0x96, 0x14, 0x30, 0x19, 0xF0, 0x00, 0x00 } // menu, just present for current menu code
};
const int Screen_HoF::_screenDimTableCount = ARRAYSIZE(Screen_HoF::_screenDimTable);
@@ -1227,7 +1254,7 @@ void GUI_LoK::initStaticResource() {
_menu[0].item[3].callback = quitPlayingFunctor;
_menu[0].item[4].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::resumeGame);
- GUI_V1_MENU(_menu[1], -1, -1, 0x140, 0x38, 248, 249, 250, 0, 254,-1, 8, 0, 2, -1, -1, -1, -1);
+ GUI_V1_MENU(_menu[1], -1, -1, 0x140, 0x38, 248, 249, 250, 0, 254, -1, 8, 0, 2, -1, -1, -1, -1);
GUI_V1_MENU_ITEM(_menu[1].item[0], 1, 0, 0, 0, 0x18, 0, 0x1E, 0x48, 0x0F, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0);
GUI_V1_MENU_ITEM(_menu[1].item[1], 1, 0, 0, 0, 0xD8, 0, 0x1E, 0x48, 0x0F, 252, 253, -1, 255, 248, 249, 250, -1, 0, 0, 0, 0, 0);
_menu[1].item[0].callback = BUTTON_FUNCTOR(GUI_LoK, this, &GUI_LoK::quitConfirmYes);
@@ -1320,7 +1347,7 @@ void KyraEngine_LoK::setupButtonData() {
_buttonData[i].buttonCallback = amuletFunctor;
for (int i = 1; i < 15; ++i)
- _buttonDataListPtr[i-1] = &_buttonData[i];
+ _buttonDataListPtr[i - 1] = &_buttonData[i];
_buttonDataListPtr[14] = 0;
}
@@ -1391,7 +1418,7 @@ const char *const KyraEngine_HoF::_languageExtension[] = {
"ENG",
"FRE",
"GER",/*,
- "ITA", Italian and Spanish were never included
+ "ITA", Italian and Spanish were never included
"SPA"*/
"JPN",
};
@@ -1400,7 +1427,7 @@ const char *const KyraEngine_HoF::_scriptLangExt[] = {
"EMC",
"FMC",
"GMC",/*,
- "IMC", Italian and Spanish were never included
+ "IMC", Italian and Spanish were never included
"SMC"*/
"JMC"
};
@@ -1579,7 +1606,7 @@ void KyraEngine_HoF::initInventoryButtonList() {
GUI_V2_BUTTON(_inventoryButtons[1], 0x2, 0x00, 0, 1, 1, 1, 0x4487, 0, 0x104, 0x90, 0x3C, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
_inventoryButtons[1].buttonCallback = BUTTON_FUNCTOR(KyraEngine_HoF, this, &KyraEngine_HoF::cauldronButton);
- GUI_V2_BUTTON(_inventoryButtons[2], 0x5, 0x00, 0, 1, 1, 1, 0x4487, 0, 0x0FA, 0x90, 0x0A, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_inventoryButtons[2], 0x5, 0x00, 0, 1, 1, 1, 0x4487, 0, 0x0FA, 0x90, 0x0A, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
_inventoryButtons[2].buttonCallback = BUTTON_FUNCTOR(KyraEngine_HoF, this, &KyraEngine_HoF::cauldronClearButton);
GUI_V2_BUTTON(_inventoryButtons[3], 0x3, 0x00, 0, 1, 1, 1, 0x4487, 0, 0x0CE, 0x90, 0x2C, 0x2C, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
@@ -1613,14 +1640,14 @@ void GUI_HoF::initStaticData() {
GUI_V2_BUTTON(_scrollDownButton, 0x18, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x18, 0x0F, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
for (int i = 0; i < 4; ++i)
- GUI_V2_BUTTON(_sliderButtons[0][i], 0x18+i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_sliderButtons[0][i], 0x18 + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
for (int i = 0; i < 4; ++i)
- GUI_V2_BUTTON(_sliderButtons[1][i], 0x1C+i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_sliderButtons[1][i], 0x1C + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
for (int i = 0; i < 4; ++i)
- GUI_V2_BUTTON(_sliderButtons[2][i], 0x20+i, 0, 0, 0, 0, 0, 0x2200, 0, 0, 0, 0x6E, 0x0E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_sliderButtons[2][i], 0x20 + i, 0, 0, 0, 0, 0, 0x2200, 0, 0, 0, 0x6E, 0x0E, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
for (uint i = 0; i < ARRAYSIZE(_menuButtons); ++i)
- GUI_V2_BUTTON(_menuButtons[i], 0x10+i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
+ GUI_V2_BUTTON(_menuButtons[i], 0x10 + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0, 0xC7, 0xCF, 0xC7, 0xCF, 0xC7, 0xCF, 0);
Button::Callback clickLoadSlotFunctor = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::clickLoadSlot);
Button::Callback clickSaveSlotFunctor = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::clickSaveSlot);
@@ -1653,7 +1680,7 @@ void GUI_HoF::initStaticData() {
_mainMenu.numberOfItems = 6;
_mainMenu.item[6].enabled = false;
for (int i = 4; i < 6; ++i)
- _mainMenu.item[i].callback = _mainMenu.item[i+1].callback;
+ _mainMenu.item[i].callback = _mainMenu.item[i + 1].callback;
_mainMenu.item[3].callback = BUTTON_FUNCTOR(GUI_HoF, this, &GUI_HoF::gameOptions);
_mainMenu.item[6].callback = Button::Callback();
_mainMenu.item[5].y = 0x7F;
@@ -1755,25 +1782,25 @@ void GUI_HoF::initStaticData() {
}
const uint16 GUI_HoF::_menuStringsTalkie[] = {
- 0x001, 0x002, 0x003, 0x023, 0x004, 0x025, 0x005, 0x006, // Main Menu String IDs
- 0x025, 0x000, 0x000, 0x000, 0x010, 0x000, 0x000, 0x000, // Options Menu String IDs
- 0x007, 0x000, 0x000, 0x000, 0x010, 0x000, 0x000, 0x000, // Audio Menu String IDs
- 0x000, 0x014, 0x013, 0x000, 0x000, 0x000, 0x000, 0x000, // Menu3 Menu String IDs
- 0x008, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x00B, 0x000, // Load Menu String IDs
- 0x009, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x00B, 0x000, // Save Menu String IDs
- 0x00C, 0x00D, 0x00B, 0x000, 0x000, 0x000, 0x000, 0x000, // Menu6 Menu String IDs
- 0x00E, 0x002, 0x005, 0x000, 0x000, 0x000, 0x000, 0x000 // Death Menu String IDs
+ 0x001, 0x002, 0x003, 0x023, 0x004, 0x025, 0x005, 0x006, // Main Menu String IDs
+ 0x025, 0x000, 0x000, 0x000, 0x010, 0x000, 0x000, 0x000, // Options Menu String IDs
+ 0x007, 0x000, 0x000, 0x000, 0x010, 0x000, 0x000, 0x000, // Audio Menu String IDs
+ 0x000, 0x014, 0x013, 0x000, 0x000, 0x000, 0x000, 0x000, // Menu3 Menu String IDs
+ 0x008, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x00B, 0x000, // Load Menu String IDs
+ 0x009, 0x029, 0x02A, 0x02B, 0x02C, 0x02D, 0x00B, 0x000, // Save Menu String IDs
+ 0x00C, 0x00D, 0x00B, 0x000, 0x000, 0x000, 0x000, 0x000, // Menu6 Menu String IDs
+ 0x00E, 0x002, 0x005, 0x000, 0x000, 0x000, 0x000, 0x000 // Death Menu String IDs
};
const uint16 GUI_HoF::_menuStringsOther[] = {
- 0x009, 0x00A, 0x00B, 0x001, 0x00C, 0x00D, 0x00E, 0x000, // Main Menu String IDs
- 0x00F, 0x02B, 0x02C, 0x02D, 0x02E, 0x018, 0x000, 0x000, // Options Menu String IDs
- 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // Dummy
- 0x000, 0x01C, 0x01B, 0x000, 0x000, 0x000, 0x000, 0x000, // Menu3 Menu String IDs
- 0x010, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x013, 0x000, // Load Menu String IDs
- 0x011, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x013, 0x000, // Save Menu String IDs
- 0x014, 0x015, 0x013, 0x3E8, 0x000, 0x000, 0x000, 0x000, // Menu6 String IDs
- 0x016, 0x00A, 0x00D, 0x000, 0x000, 0x000, 0x000, 0x000 // Death Menu String IDs
+ 0x009, 0x00A, 0x00B, 0x001, 0x00C, 0x00D, 0x00E, 0x000, // Main Menu String IDs
+ 0x00F, 0x02B, 0x02C, 0x02D, 0x02E, 0x018, 0x000, 0x000, // Options Menu String IDs
+ 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, // Dummy
+ 0x000, 0x01C, 0x01B, 0x000, 0x000, 0x000, 0x000, 0x000, // Menu3 Menu String IDs
+ 0x010, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x013, 0x000, // Load Menu String IDs
+ 0x011, 0x02F, 0x030, 0x031, 0x032, 0x033, 0x013, 0x000, // Save Menu String IDs
+ 0x014, 0x015, 0x013, 0x3E8, 0x000, 0x000, 0x000, 0x000, // Menu6 String IDs
+ 0x016, 0x00A, 0x00D, 0x000, 0x000, 0x000, 0x000, 0x000 // Death Menu String IDs
};
const uint16 KyraEngine_HoF::_itemMagicTable[] = {
@@ -1889,20 +1916,20 @@ const char *const KyraEngine_MR::_languageExtension[] = {
"TRE",
"TRF",
"TRG"/*,
- "TRI", Italian and Spanish were never included, the supported fan translations are using
- "TRS" English/French extensions thus overwriting these languages */
+ "TRI", Italian and Spanish were never included, the supported fan translations are using
+ "TRS" English/French extensions thus overwriting these languages */
};
const int KyraEngine_MR::_languageExtensionSize = ARRAYSIZE(KyraEngine_MR::_languageExtension);
-const char * const KyraEngine_MR::_mainMenuSpanishFan[] = {
+const char *const KyraEngine_MR::_mainMenuSpanishFan[] = {
"Nueva Partida",
"Ver Intro",
"Restaurar",
"Finalizar"
};
-const char * const KyraEngine_MR::_mainMenuItalianFan[] = {
+const char *const KyraEngine_MR::_mainMenuItalianFan[] = {
"Nuova Partita",
"Introduzione",
"Carica una partita",
@@ -1998,13 +2025,13 @@ void KyraEngine_MR::initMainButtonList(bool disable) {
Button::Callback buttonInventoryFunctor = BUTTON_FUNCTOR(KyraEngine_MR, this, &KyraEngine_MR::buttonInventory);
for (int i = 0; i < 5; ++i) {
- GUI_V2_BUTTON(_mainButtonData[i+4], i+5, 0, 0, 0, 0, 0, 0x1100, 0, 67+i*28, 155, 27, 21, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
- _mainButtonData[i+4].buttonCallback = buttonInventoryFunctor;
+ GUI_V2_BUTTON(_mainButtonData[i + 4], i + 5, 0, 0, 0, 0, 0, 0x1100, 0, 67 + i * 28, 155, 27, 21, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ _mainButtonData[i + 4].buttonCallback = buttonInventoryFunctor;
}
for (int i = 0; i < 5; ++i) {
- GUI_V2_BUTTON(_mainButtonData[i+9], i+10, 0, 0, 0, 0, 0, 0x1100, 0, 67+i*28, 177, 27, 21, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
- _mainButtonData[i+9].buttonCallback = buttonInventoryFunctor;
+ GUI_V2_BUTTON(_mainButtonData[i + 9], i + 10, 0, 0, 0, 0, 0, 0x1100, 0, 67 + i * 28, 177, 27, 21, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ _mainButtonData[i + 9].buttonCallback = buttonInventoryFunctor;
}
for (int i = 0; i < 14; ++i)
@@ -2026,14 +2053,14 @@ void GUI_MR::initStaticData() {
GUI_V2_BUTTON(_scrollDownButton, 23, 0, 0, 4, 4, 4, 0x4487, 0, 0, 0, 0x18, 0x0F, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
for (int i = 0; i < 4; ++i)
- GUI_V2_BUTTON(_sliderButtons[0][i], 0x18+i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ GUI_V2_BUTTON(_sliderButtons[0][i], 0x18 + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
for (int i = 0; i < 4; ++i)
- GUI_V2_BUTTON(_sliderButtons[1][i], 0x1C+i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ GUI_V2_BUTTON(_sliderButtons[1][i], 0x1C + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0x0A, 0x0E, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
for (int i = 0; i < 4; ++i)
- GUI_V2_BUTTON(_sliderButtons[2][i], 0x20+i, 0, 0, 0, 0, 0, 0x2200, 0, 0, 0, 0x6E, 0x0E, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ GUI_V2_BUTTON(_sliderButtons[2][i], 0x20 + i, 0, 0, 0, 0, 0, 0x2200, 0, 0, 0, 0x6E, 0x0E, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
for (uint i = 0; i < ARRAYSIZE(_menuButtons); ++i)
- GUI_V2_BUTTON(_menuButtons[i], 0x0F+i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
+ GUI_V2_BUTTON(_menuButtons[i], 0x0F + i, 0, 0, 1, 1, 1, 0x4487, 0, 0, 0, 0, 0, 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF0, 0);
Button::Callback clickLoadSlotFunctor = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::clickLoadSlot);
Button::Callback clickSaveSlotFunctor = BUTTON_FUNCTOR(GUI_MR, this, &GUI_MR::clickSaveSlot);
@@ -2132,7 +2159,7 @@ void GUI_MR::initStaticData() {
}
const int8 KyraEngine_MR::_albumWSAX[] = {
- 0, 77, -50, 99, -61, 82, -58, 85,
+ 0, 77, -50, 99, -61, 82, -58, 85,
-64, 80, -63, 88, -63, 88, -64, 0
};
diff --git a/engines/kyra/staticres_eob.cpp b/engines/kyra/staticres_eob.cpp
new file mode 100644
index 0000000000..7a5012f117
--- /dev/null
+++ b/engines/kyra/staticres_eob.cpp
@@ -0,0 +1,1356 @@
+/* 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/eob.h"
+#include "kyra/resource.h"
+
+
+namespace Kyra {
+
+#ifdef ENABLE_EOB
+const DarkMoonAnimCommand *StaticResource::loadEoB2SeqData(int id, int &entries) {
+ return (const DarkMoonAnimCommand *)getData(id, kEoB2SequenceData, entries);
+}
+
+const DarkMoonShapeDef *StaticResource::loadEoB2ShapeData(int id, int &entries) {
+ return (const DarkMoonShapeDef *)getData(id, kEoB2ShapeData, entries);
+}
+
+const EoBCharacter *StaticResource::loadEoBNpcData(int id, int &entries) {
+ return (const EoBCharacter *)getData(id, kEoBNpcData, entries);
+}
+
+bool StaticResource::loadEoB2SeqData(Common::SeekableReadStream &stream, void *&ptr, int &size) {
+ size = stream.size() / 11;
+
+ DarkMoonAnimCommand *s = new DarkMoonAnimCommand[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;
+
+ DarkMoonShapeDef *s = new DarkMoonShapeDef[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.readSByte();
+ 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->mageSpellsAvailableFlags = stream.readUint32BE();
+ for (int ii = 0; ii < 27; ii++)
+ s->inventory[ii] = stream.readSint16BE();
+ }
+
+ ptr = e;
+ return true;
+}
+
+void StaticResource::freeEoB2SeqData(void *&ptr, int &size) {
+ DarkMoonAnimCommand *d = (DarkMoonAnimCommand *)ptr;
+ delete[] d;
+ ptr = 0;
+ size = 0;
+}
+
+void StaticResource::freeEoB2ShapeData(void *&ptr, int &size) {
+ DarkMoonShapeDef *d = (DarkMoonShapeDef *)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);
+
+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::_characterClassType[] = {
+ 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::_charClassModifier[] = {
+ 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02,
+ 0x00, 0x00, 0x02
+};
+
+const uint8 EoBCoreEngine::_itemsOverlayCGA[] = {
+ 0x00, 0x55, 0x55, 0xFF
+};
+
+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);
+
+ _suffixStringsRings = _staticres->loadStrings(kEoBBaseItemSuffixStringsRings, temp);
+ _suffixStringsPotions = _staticres->loadStrings(kEoBBaseItemSuffixStringsPotions, temp);
+ _suffixStringsWands = _staticres->loadStrings(kEoBBaseItemSuffixStringsWands, temp);
+
+ _ripItemStrings = _staticres->loadStrings(kEoBBaseRipItemStrings, temp);
+ _cursedString = _staticres->loadStrings(kEoBBaseCursedString, temp);
+ _enchantedString = _staticres->loadStrings(kEoBBaseEnchantedString, temp);
+ _magicObjectStrings = _staticres->loadStrings(kEoBBaseMagicObjectStrings, temp);
+ _magicObjectString5 = _staticres->loadStrings(kEoBBaseMagicObjectString5, temp);
+ _patternSuffix = _staticres->loadStrings(kEoBBasePatternSuffix, temp);
+ _patternGrFix1 = _staticres->loadStrings(kEoBBasePatternGrFix1, temp);
+ _patternGrFix2 = _staticres->loadStrings(kEoBBasePatternGrFix2, temp);
+ _validateArmorString = _staticres->loadStrings(kEoBBaseValidateArmorString, temp);
+ _validateCursedString = _staticres->loadStrings(kEoBBaseValidateCursedString, temp);
+ _validateNoDropString = _staticres->loadStrings(kEoBBaseValidateNoDropString, temp);
+ _potionStrings = _staticres->loadStrings(kEoBBasePotionStrings, temp);
+ _wandStrings = _staticres->loadStrings(kEoBBaseWandStrings, temp);
+ _itemMisuseStrings = _staticres->loadStrings(kEoBBaseItemMisuseStrings, 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 : kRpgCommonMoreStrings, temp);
+ _npcJoinStrings = _staticres->loadStrings(kEoBBaseNpcJoinStrings, temp);
+ _cancelStrings = _staticres->loadStrings(kEoBBaseCancelStrings, temp);
+ _abortStrings = _staticres->loadStrings(_flags.gameID == GI_EOB2 ? kEoBBaseAbortStrings : kEoBBaseCancelStrings, temp);
+
+ _menuStringsMain = _staticres->loadStrings(kEoBBaseMenuStringsMain, temp);
+ _menuStringsSaveLoad = _staticres->loadStrings(kEoBBaseMenuStringsSaveLoad, temp);
+ _menuStringsOnOff = _staticres->loadStrings(kEoBBaseMenuStringsOnOff, temp);
+ _menuStringsSpells = _staticres->loadStrings(kEoBBaseMenuStringsSpells, temp);
+ _menuStringsRest = _staticres->loadStrings(kEoBBaseMenuStringsRest, temp);
+ _menuStringsDrop = _staticres->loadStrings(kEoBBaseMenuStringsDrop, temp);
+ _menuStringsExit = _staticres->loadStrings(kEoBBaseMenuStringsExit, temp);
+ _menuStringsStarve = _staticres->loadStrings(kEoBBaseMenuStringsStarve, temp);
+ _menuStringsScribe = _staticres->loadStrings(kEoBBaseMenuStringsScribe, temp);
+ _menuStringsDrop2 = _staticres->loadStrings(kEoBBaseMenuStringsDrop2, temp);
+ _menuStringsHead = _staticres->loadStrings(kEoBBaseMenuStringsHead, temp);
+ _menuStringsPoison = _staticres->loadStrings(kEoBBaseMenuStringsPoison, temp);
+ _menuStringsMgc = _staticres->loadStrings(kEoBBaseMenuStringsMgc, temp);
+ _menuStringsPrefs = _staticres->loadStrings(kEoBBaseMenuStringsPrefs, temp);
+ _menuStringsRest2 = _staticres->loadStrings(kEoBBaseMenuStringsRest2, temp);
+ _menuStringsRest3 = _staticres->loadStrings(kEoBBaseMenuStringsRest3, temp);
+ _menuStringsRest4 = _staticres->loadStrings(kEoBBaseMenuStringsRest4, temp);
+ _menuStringsDefeat = _staticres->loadStrings(kEoBBaseMenuStringsDefeat, temp);
+ _menuStringsTransfer = _staticres->loadStrings(kEoBBaseMenuStringsTransfer, temp);
+ _menuStringsSpec = _staticres->loadStrings(kEoBBaseMenuStringsSpec, temp);
+ _menuStringsSpellNo = _staticres->loadStrings(kEoBBaseMenuStringsSpellNo, temp);
+ _menuYesNoStrings = _staticres->loadStrings(kEoBBaseMenuYesNoStrings, temp);
+
+ _spellLevelsMage = _staticres->loadRawData(kEoBBaseSpellLevelsMage, _spellLevelsMageSize);
+ _spellLevelsCleric = _staticres->loadRawData(kEoBBaseSpellLevelsCleric, _spellLevelsClericSize);
+ _numSpellsCleric = _staticres->loadRawData(kEoBBaseNumSpellsCleric, temp);
+ _numSpellsWisAdj = _staticres->loadRawData(kEoBBaseNumSpellsWisAdj, temp);
+ _numSpellsPal = _staticres->loadRawData(kEoBBaseNumSpellsPal, temp);
+ _numSpellsMage = _staticres->loadRawData(kEoBBaseNumSpellsMage, 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);
+ for (int i = 0; i < 5; i++)
+ _expRequirementTables[i] = _staticres->loadRawDataBe32(kEoBBaseExperienceTable0 + i, temp);
+ _expRequirementTables[5] = _staticres->loadRawDataBe32(kEoBBaseExperienceTable4, temp);
+
+ _classModifierFlags = _staticres->loadRawData(kEoBBaseClassModifierFlags, temp);
+
+ _saveThrowTables[0] = _saveThrowTables[4] = _saveThrowTables[5] = _staticres->loadRawData(kEoBBaseSaveThrowTable1, temp);
+ _saveThrowTables[1] = _staticres->loadRawData(kEoBBaseSaveThrowTable2, temp);
+ _saveThrowTables[2] = _staticres->loadRawData(kEoBBaseSaveThrowTable3, temp);
+ _saveThrowTables[3] = _staticres->loadRawData(kEoBBaseSaveThrowTable4, temp);
+ _saveThrowLevelIndex = _staticres->loadRawData(kEoBBaseSaveThrwLvlIndex, temp);
+ _saveThrowModDiv = _staticres->loadRawData(kEoBBaseSaveThrwModDiv, temp);
+ _saveThrowModExt = _staticres->loadRawData(kEoBBaseSaveThrwModExt, temp);
+
+ _encodeMonsterShpTable = _staticres->loadRawDataBe16(kEoBBaseEncodeMonsterDefs, temp);
+ _npcPreset = _staticres->loadEoBNpcData(kEoBBaseNpcPresets, temp);
+
+ _teleporterShapeCoords = _staticres->loadRawData(kEoBBaseDscTelptrShpCoords, temp);
+ _portalSeq = (const int8 *)_staticres->loadRawData(kEoBBasePortalSeqData, temp);
+ _mnDef = _staticres->loadRawData(kEoBBaseManDef, temp);
+ _mnWord = _staticres->loadStrings(kEoBBaseManWord, _mnNumWord);
+ _mnPrompt = _staticres->loadStrings(kEoBBaseManPrompt, temp);
+
+ _monsterStepTable0 = (const int8 *)_staticres->loadRawData(_flags.gameID == GI_EOB2 ? kEoBBaseMonsterStepTable02 : kEoBBaseMonsterStepTable01, temp);
+ _monsterStepTable1 = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterStepTable1, temp);
+ _monsterStepTable2 = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterStepTable2, temp);
+ _monsterStepTable3 = (const int8 *)_staticres->loadRawData(kEoBBaseMonsterStepTable3, temp);
+ _monsterCloseAttPosTable1 = _staticres->loadRawData(kEoBBaseMonsterCloseAttPosTable1, temp);
+ _monsterCloseAttPosTable2 = _staticres->loadRawData(_flags.gameID == GI_EOB2 ? kEoBBaseMonsterCloseAttPosTable22 : kEoBBaseMonsterCloseAttPosTable21, temp);
+ _monsterCloseAttUnkTable = (const 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);
+
+ _projectileWeaponAmmoTypes = (const int8 *)_staticres->loadRawData(kEoBBaseProjectileWeaponTypes, temp);
+ _wandTypes = _staticres->loadRawData(kEoBBaseWandTypes, 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);
+ _dscDoorXE = _staticres->loadRawData(kEoBBaseDscDoorXE, 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);
+ _magicStrings6 = _staticres->loadStrings(kEoBBaseMagicStrings6, temp);
+ _magicStrings7 = _staticres->loadStrings(kEoBBaseMagicStrings7, temp);
+ _magicStrings8 = _staticres->loadStrings(kEoBBaseMagicStrings8, temp);
+
+ _expObjectTlMode = _staticres->loadRawData(kEoBBaseExpObjectTlMode, temp);
+ _expObjectTblIndex = _staticres->loadRawData(kEoBBaseExpObjectTblIndex, temp);
+ _expObjectShpStart = _staticres->loadRawData(kEoBBaseExpObjectShpStart, temp);
+ _expObjectAnimTbl1 = _staticres->loadRawData(kEoBBaseExpObjectTbl1, _expObjectAnimTbl1Size);
+ _expObjectAnimTbl2 = _staticres->loadRawData(kEoBBaseExpObjectTbl2, _expObjectAnimTbl2Size);
+ _expObjectAnimTbl3 = _staticres->loadRawData(kEoBBaseExpObjectTbl3, _expObjectAnimTbl3Size);
+
+ _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);
+ _turnUndeadEffect = _staticres->loadRawData(kEoBBaseTurnUndeadEffect, temp);
+ _burningHandsDest = _staticres->loadRawData(kEoBBaseBurningHandsDest, temp);
+ _coneOfColdDest1 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest1, temp);
+ _coneOfColdDest2 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest2, temp);
+ _coneOfColdDest3 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest3, temp);
+ _coneOfColdDest4 = (const int8 *)_staticres->loadRawData(kEoBBaseConeOfColdDest4, temp);
+ _coneOfColdGfxTbl = _staticres->loadRawData(kEoBBaseConeOfColdGfxTbl, _coneOfColdGfxTblSize);
+
+ // Hard code the following strings, since EOB I doesn't have them in the original.
+ // EOB I doesn't have load and save menus, because there is only one single
+ // save slot. Instead of emulating this we provide a menu similiar to EOB II.
+
+ static const char *saveLoadStrings[3][4] = {
+ { "Cancel", "Empty Slot", "Save Game", "Load Game" },
+ { "Abbr.", "Leerer Slot", "Speichern", " Laden" },
+ { 0, 0, 0, 0 }
+ };
+
+ static const char *errorSlotEmptyString[3] = {
+ "There is no game\rsaved in that slot!",
+ "Hier ist noch kein\rSpiel gespeichert!",
+ 0
+ };
+
+ _saveLoadStrings = saveLoadStrings[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
+ _errorSlotEmptyString = errorSlotEmptyString[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
+ _menuOkString = "OK";
+}
+
+void EoBCoreEngine::initButtonData() {
+ static const EoBGuiButtonDef buttonDefs[] = {
+ { 112, 0, 0x1100, 184, 2, 63, 50, 0 },
+ { 113, 0, 0x1100, 256, 2, 63, 50, 1 },
+ { 114, 0, 0x1100, 184, 54, 63, 50, 2 },
+ { 115, 0, 0x1100, 256, 54, 63, 50, 3 },
+ { 48, 110, 0x1100, 289, 177, 31, 21, 0 },
+ { 0, 0, 0x1100, 0, 102, 88, 18, 0 },
+ { 0, 0, 0x1100, 89, 102, 88, 18, 1 },
+ { 0, 0, 0x1100, 0, 72, 88, 29, 2 },
+ { 0, 0, 0x1100, 89, 72, 88, 29, 3 },
+ { 24, 0, 0x1100, 184, 10, 33, 33, 0 },
+ { 0, 0, 0x1100, 256, 10, 33, 33, 1 },
+ { 0, 0, 0x1100, 184, 62, 33, 33, 2 },
+ { 0, 0, 0x1100, 256, 62, 33, 33, 3 },
+ { 0, 0, 0x1100, 216, 10, 31, 33, 0 },
+ { 0, 0, 0x1100, 288, 10, 31, 33, 1 },
+ { 0, 0, 0x1100, 216, 62, 31, 33, 2 },
+ { 0, 0, 0x1100, 288, 62, 31, 33, 3 },
+ { 368, 0, 0x1000, 184, 2, 63, 8, 0 },
+ { 369, 0, 0x1000, 256, 2, 63, 8, 1 },
+ { 370, 0, 0x1000, 184, 54, 63, 8, 2 },
+ { 371, 0, 0x1000, 256, 54, 63, 8, 3 },
+ { 0, 0, 0x1100, 230, 116, 16, 16, 0 },
+ { 0, 0, 0x1100, 278, 116, 16, 16, 1 },
+ { 0, 0, 0x1100, 181, 40, 16, 16, 2 },
+ { 0, 0, 0x1100, 199, 40, 16, 16, 3 },
+ { 0, 0, 0x1100, 181, 58, 16, 16, 4 },
+ { 0, 0, 0x1100, 199, 58, 16, 16, 5 },
+ { 0, 0, 0x1100, 181, 76, 16, 16, 6 },
+ { 0, 0, 0x1100, 199, 76, 16, 16, 7 },
+ { 0, 0, 0x1100, 181, 94, 16, 16, 8 },
+ { 0, 0, 0x1100, 199, 94, 16, 16, 9 },
+ { 0, 0, 0x1100, 181, 112, 16, 16, 10 },
+ { 0, 0, 0x1100, 199, 112, 16, 16, 11 },
+ { 0, 0, 0x1100, 181, 130, 16, 16, 12 },
+ { 0, 0, 0x1100, 199, 130, 16, 16, 13 },
+ { 0, 0, 0x1100, 181, 148, 16, 16, 14 },
+ { 0, 0, 0x1100, 199, 148, 16, 16, 15 },
+ { 0, 0, 0x1100, 225, 55, 16, 16, 16 },
+ { 0, 0, 0x1100, 224, 76, 16, 16, 17 },
+ { 0, 0, 0x1100, 225, 96, 16, 16, 18 },
+ { 0, 0, 0x1100, 298, 55, 16, 16, 19 },
+ { 0, 0, 0x1100, 287, 75, 16, 16, 20 },
+ { 0, 0, 0x1100, 277, 137, 16, 16, 21 },
+ { 0, 0, 0x1100, 300, 94, 16, 16, 22 },
+ { 0, 0, 0x1100, 300, 112, 16, 16, 23 },
+ { 0, 0, 0x1100, 300, 130, 16, 16, 24 },
+ { 0, 0, 0x1100, 236, 37, 31, 16, 25 },
+ { 26, 0, 0x1100, 291, 149, 25, 17, 25 },
+ { 110, 24, 0x1100, 181, 3, 32, 32, 25 },
+ { 96, 352, 0x1100, 24, 128, 21, 16, 25 },
+ { 98, 97, 0x1100, 24, 144, 21, 16, 25 },
+ { 92, 348, 0x1100, 3, 144, 21, 16, 25 },
+ { 102, 358, 0x1100, 45, 144, 21, 16, 25 },
+ { 91, 0, 0x1100, 3, 128, 21, 16, 25 },
+ { 101, 0, 0x1100, 45, 128, 21, 16, 25 },
+ { 110, 0, 0x1100, 184, 0, 136, 120, 0 },
+ { 0, 0, 0x1100, 0, 8, 88, 48, 0 },
+ { 0, 0, 0x1100, 88, 8, 88, 48, 1 },
+ { 0, 0, 0x1100, 24, 8, 128, 96, 1 },
+ { 112, 113, 0x1100, 274, 35, 20, 15, 1 },
+ { 114, 115, 0x1100, 297, 35, 20, 15, 1 },
+ { 2, 0, 0x1100, 68, 121, 18, 10, 0 },
+ { 3, 0, 0x1100, 86, 121, 18, 10, 1 },
+ { 4, 0, 0x1100, 104, 121, 15, 10, 2 },
+ { 5, 0, 0x1100, 122, 121, 15, 10, 3 },
+ { 6, 0, 0x1100, 140, 121, 15, 10, 4 },
+ { 0, 0, 0x1100, 75, 131, 97, 6, 0 },
+ { 0, 0, 0x1100, 75, 137, 97, 6, 1 },
+ { 0, 0, 0x1100, 75, 143, 97, 6, 2 },
+ { 0, 0, 0x1100, 75, 149, 97, 6, 3 },
+ { 0, 0, 0x1100, 75, 155, 97, 6, 4 },
+ { 0, 0, 0x1100, 75, 161, 97, 6, 5 },
+ { 112, 0, 0x1100, 184, 2, 63, 50, 0 },
+ { 113, 0, 0x1100, 256, 2, 63, 50, 1 },
+ { 114, 0, 0x1100, 184, 54, 63, 50, 2 },
+ { 115, 0, 0x1100, 256, 54, 63, 50, 3 },
+ { 53, 54, 0x1100, 320, 200, 0, 0, 6 },
+ { 61, 0, 0x1100, 320, 200, 0, 0, 7 },
+ { 0, 0, 0x1100, 184, 114, 33, 33, 4 },
+ { 0, 0, 0x1100, 256, 114, 33, 33, 5 },
+ { 0, 0, 0x1100, 216, 114, 31, 33, 4 },
+ { 0, 0, 0x1100, 288, 114, 31, 33, 5 },
+ { 372, 0, 0x1000, 184, 106, 63, 8, 4 },
+ { 373, 0, 0x1000, 256, 106, 63, 8, 5 },
+ { 0, 0, 0x1100, 227, 135, 10, 10, 25 },
+ { 0, 0, 0x1100, 239, 135, 10, 10, 26 },
+ { 116, 0, 0x1100, 184, 106, 63, 50, 4 },
+ { 117, 0, 0x1100, 256, 106, 63, 50, 5 },
+ { 110, 0, 0x1100, 68, 168, 78, 10, 0 },
+ { 110, 0, 0x1100, 68, 168, 78, 10, 65535 },
+ { 116, 0, 0x1100, 184, 106, 63, 50, 4 },
+ { 117, 0, 0x1100, 256, 106, 63, 50, 5 },
+ { 116, 117, 0x1100, 320, 200, 1, 1, 2 },
+ { 7, 0, 0x1100, 158, 121, 15, 10, 5 },
+ { 0, 0, 0x1100, 146, 168, 32, 10, 0 },
+
+ // EOB1 spellbook modifications
+ { 2, 0, 0x1100, 71, 122, 20, 8, 0 },
+ { 3, 0, 0x1100, 92, 122, 20, 8, 1 },
+ { 4, 0, 0x1100, 113, 122, 20, 8, 2 },
+ { 5, 0, 0x1100, 134, 122, 20, 8, 3 },
+ { 6, 0, 0x1100, 155, 122, 20, 8, 4 },
+ { 110, 0, 0x1100, 75, 168, 97, 6, 0 }
+ };
+
+ _buttonDefs = buttonDefs;
+ _buttonCallbacks.clear();
+ _buttonCallbacks.reserve(ARRAYSIZE(buttonDefs));
+
+#define EOB_CBN(x, y) _buttonCallbacks.push_back(BUTTON_FUNCTOR(EoBCoreEngine, this, &EoBCoreEngine::y)); for (int l = 0; l < (x - 1); l++) { _buttonCallbacks.push_back(_buttonCallbacks[_buttonCallbacks.size() - 1 - l]); }
+#define EOB_CBI(x, y) for (int l = x; l; l--) { _buttonCallbacks.push_back(_buttonCallbacks[y]); }
+ EOB_CBN(4, clickedCharPortraitDefault);
+ EOB_CBN(1, clickedCamp);
+ EOB_CBN(4, clickedSceneDropPickupItem);
+ EOB_CBN(4, clickedCharPortrait2);
+ EOB_CBN(4, clickedWeaponSlot);
+ EOB_CBN(4, clickedCharNameLabelRight);
+ EOB_CBN(25, clickedInventorySlot);
+ EOB_CBN(1, clickedEatItem);
+ EOB_CBN(1, clickedInventoryNextPage);
+ EOB_CBN(1, clickedPortraitRestore);
+ EOB_CBN(1, clickedUpArrow);
+ EOB_CBN(1, clickedDownArrow);
+ EOB_CBN(1, clickedLeftArrow);
+ EOB_CBN(1, clickedRightArrow);
+ EOB_CBN(1, clickedTurnLeftArrow);
+ EOB_CBN(1, clickedTurnRightArrow);
+ EOB_CBN(1, clickedAbortCharSwitch);
+ EOB_CBN(2, clickedSceneThrowItem);
+ EOB_CBN(1, clickedSceneSpecial);
+ EOB_CBN(1, clickedInventoryPrevChar);
+ EOB_CBN(1, clickedInventoryNextChar);
+ EOB_CBN(5, clickedSpellbookTab);
+ EOB_CBN(6, clickedSpellbookList);
+ EOB_CBN(4, clickedCastSpellOnCharacter);
+ EOB_CBI(2, 66);
+ EOB_CBI(2, 9);
+ EOB_CBI(2, 13);
+ EOB_CBI(2, 17);
+ EOB_CBI(2, 21);
+ EOB_CBI(2, 72);
+ EOB_CBN(1, clickedSpellbookAbort);
+ EOB_CBI(1, 72);
+ EOB_CBI(2, 0);
+ EOB_CBI(1, 60);
+ EOB_CBI(1, 61);
+ EOB_CBN(1, clickedSpellbookScroll);
+ EOB_CBI(5, 61);
+ EOB_CBI(1, 88);
+#undef EOB_CBI
+#undef EOB_CBN
+}
+
+void EoBCoreEngine::initMenus() {
+ static const EoBMenuButtonDef buttonDefs[] = {
+ { 2, 12, 20, 158, 14, 20, 3 },
+ { 3, 12, 37, 158, 14, 52, 3 },
+ { 4, 12, 54, 158, 14, 26, 3 },
+ { 5, 12, 71, 158, 14, 32, 3 },
+ { 6, 12, 88, 158, 14, 0, 3 },
+ { 7, 12, 105, 158, 14, 35, 3 },
+ { 8, 128, 122, 40, 14, 19, 7 },
+ { 9, 12, 20, 158, 14, 39, 3 },
+ { 10, 12, 37, 158, 14, 32, 3 },
+ { 11, 12, 54, 158, 14, 33, 3 },
+ { 12, 12, 71, 158, 14, 17, 3 },
+ { 8, 128, 122, 40, 14, 19, 7 },
+ { 18, 12, 20, 158, 14, 32, 3 },
+ { 19, 12, 37, 158, 14, 50, 3 },
+ { 8, 128, 122, 40, 14, 19, 7 },
+ { 8, 128, 122, 40, 14, 19, 5 },
+ { 0, 184, 0, 64, 48, 112, 0 },
+ { 0, 256, 0, 64, 48, 113, 0 },
+ { 0, 184, 56, 64, 48, 114, 0 },
+ { 0, 256, 56, 64, 48, 115, 0 },
+ { 0, 184, 112, 64, 48, 116, 0 },
+ { 0, 256, 112, 64, 48, 117, 0 },
+ { 36, 8, 126, 48, 14, 48, 5 },
+ { 8, 128, 126, 40, 14, 19, 5 },
+ { 0, 0, 50, 168, 72, 61, 0 },
+ { 31, 11, 16, 20, 18, 2, 5 },
+ { 32, 38, 16, 20, 18, 3, 5 },
+ { 33, 65, 16, 20, 18, 4, 5 },
+ { 34, 92, 16, 20, 18, 5, 5 },
+ { 35, 119, 16, 20, 18, 6, 5 },
+ { 60, 146, 16, 20, 18, 7, 5 },
+ { 61, 150, 16, 20, 18, 8, 5 },
+ { 38, 16, 57, 32, 14, 22, 7 },
+ { 39, 128, 57, 32, 14, 51, 7 },
+ { 8, 128, 126, 40, 14, 19, 7 },
+ { 0, 0, 50, 168, 72, 61, 0 },
+ // EOB 1 memorize/pray menu:
+ { 36, 8, 126, 48, 14, 48, 5 },
+ { 8, 128, 126, 40, 14, 19, 5 },
+ { 0, 0, 50, 168, 72, 61, 0 },
+ { 31, 8, 16, 24, 20, 2, 5 },
+ { 32, 40, 16, 24, 20, 3, 5 },
+ { 33, 72, 16, 24, 20, 4, 5 },
+ { 34, 104, 16, 24, 20, 5, 5 },
+ { 35, 136, 16, 24, 20, 6, 5 }
+ };
+
+ _menuButtonDefs = buttonDefs;
+
+ static const EoBMenuDef menuDefs[] = {
+ { 1, 10, 0, 7, 9 },
+ { 1, 10, 7, 5, 9 },
+ { 1, 10, 12, 3, 9 },
+ { 0, 10, 15, 7, 15 },
+ { 37, 10, 22, 9, 9 },
+ { 0, 11, 32, 2, 15 },
+ { 48, 10, 34, 2, 9 }
+ };
+
+ delete[] _menuDefs;
+ _menuDefs = new EoBMenuDef[ARRAYSIZE(menuDefs)];
+ memcpy(_menuDefs, menuDefs, sizeof(menuDefs));
+
+ if (_flags.gameID == GI_EOB1) {
+ // assign EOB 1 style memorize/pray menu
+ _menuDefs[4].numButtons = 8;
+ _menuDefs[4].firstButtonStrId = 36;
+ }
+}
+
+
+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
+ 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
+ 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; // Lightning Bolt (EOB1) / Fireball 1(EOB2) passive
+ mp2(10);// Mystic Defense
+ mp2n; // Fireball 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);
+ sc1(stoneSkin); // stone skin
+ sc2(empty); // 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);
+ 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);
+ ec1(monster_lightningBolt);
+ ec2(monster_fireball1);
+ ec2(empty);
+ ec2(monster_fireball2);
+ ec(monster_deathSpell);
+ ec(monster_disintegrate);
+ ec2(monster_causeCriticalWounds);
+ ec2(monster_fleshToStone);
+
+ _spells = new EoBSpell[_numSpells];
+ memset(_spells, 0, _numSpells * sizeof(EoBSpell));
+
+ for (int i = 0, n = 0; i < _numSpells; i++, n++) {
+ EoBSpell *s = &_spells[i];
+
+ // Fix EoB 1 spell names
+ bool skip = false;
+ if (i == 5 || i == 9) {
+ n--;
+ skip = true;
+ }
+
+ s->name = _flags.gameID == GI_EOB2 ? ((i == 0 || i == _mageSpellListSize) ? _mageSpellList[0] : ((i < (_mageSpellListSize + 1)) ? _spellNames[i - 1] : _spellNames[i - 2])) : (skip ? _spellNames[0] : _spellNames[n]);
+ 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);
+ _finBonusStrings = _staticres->loadStrings(kEoB1BonusStrings, 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);
+ _dscDoorY7 = _staticres->loadRawData(kEoBBaseDscDoorY7, temp);
+ _dscDoorCoordsExt = (const int16 *)_staticres->loadRawDataBe16(kEoBBaseDscDoorCoordsExt, temp);
+
+ _enemyMageSpellList = _staticres->loadRawData(kEoB1EnemyMageSpellList, temp);
+ _enemyMageSfx = _staticres->loadRawData(kEoB1EnemyMageSfx, temp);
+ _beholderSpellList = _staticres->loadRawData(kEoB1BeholderSpellList, temp);
+ _beholderSfx = _staticres->loadRawData(kEoB1BeholderSfx, temp);
+
+ _cgaMappingDefault = _staticres->loadRawData(kEoB1CgaMappingDefault, temp);
+ _cgaMappingAlt = _staticres->loadRawData(kEoB1CgaMappingAlt, temp);
+ _cgaMappingInv = _staticres->loadRawData(kEoB1CgaMappingInv, temp);
+ _cgaMappingItemsL = _staticres->loadRawData(kEoB1CgaMappingItemsL, temp);
+ _cgaMappingItemsS = _staticres->loadRawData(kEoB1CgaMappingItemsS, temp);
+ _cgaMappingThrown = _staticres->loadRawData(kEoB1CgaMappingThrown, temp);
+ _cgaMappingIcons = _staticres->loadRawData(kEoB1CgaMappingIcons, temp);
+ _cgaMappingDeco = _staticres->loadRawData(kEoB1CgaMappingDeco, temp);
+ _cgaLevelMappingIndex = _staticres->loadRawData(kEoB1CgaLevelMappingIndex, temp);
+ for (int i = 0; i < 5; i++)
+ _cgaMappingLevel[i] = _staticres->loadRawData(kEoB1CgaMappingLevel0 + i, temp);
+
+ _turnUndeadString = _staticres->loadStrings(kEoB1TurnUndeadString, temp);
+
+ _npcShpData = _staticres->loadRawData(kEoB1NpcShpData, temp);
+ _npcSubShpIndex1 = _staticres->loadRawData(kEoB1NpcSubShpIndex1, temp);
+ _npcSubShpIndex2 = _staticres->loadRawData(kEoB1NpcSubShpIndex2, temp);
+ _npcSubShpY = _staticres->loadRawData(kEoB1NpcSubShpY, temp);
+ for (int i = 0; i < 11; i++)
+ _npcStrings[i] = _staticres->loadStrings(kEoB1Npc0Strings + i, temp);
+
+ const uint8 *ps = _staticres->loadRawData(kEoB1MonsterProperties, temp);
+ temp /= 27;
+ _monsterProps = new EoBMonsterProperty[temp];
+ memset(_monsterProps, 0, temp * sizeof(EoBMonsterProperty));
+ // Convert EOB1 (hard coded) monster properties to EOB2 type monster properties.
+ for (int i = 0; i < temp; i++) {
+ EoBMonsterProperty *p = &_monsterProps[i];
+ p->armorClass = (int8)*ps++;
+ p->hitChance = (int8)*ps++;
+ p->level = (int8)*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->capsFlags = *ps++;
+ p->typeFlags = READ_LE_UINT16(ps);
+ ps += 2;
+ ps++;
+ ps++;
+ p->experience = READ_LE_UINT16(ps);
+ ps += 2;
+ p->u30 = *ps++;
+ p->sound1 = (int8)*ps++;
+ p->sound2 = (int8)*ps++;
+ p->numRemoteAttacks = *ps++;
+ p->tuResist = (int8)*ps++;
+ p->dmgModifierEvade = *ps++;
+ }
+
+ static const char *errorSlotNoNameString[3] = {
+ " You must specify\r a name for your\r save game!",
+ " Spielstaende mues-\r sen einen Namen\r haben!",
+ 0
+ };
+
+ _errorSlotNoNameString = errorSlotNoNameString[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
+}
+
+void EoBEngine::initSpells() {
+ EoBCoreEngine::initSpells();
+
+ struct FlagTableEntry {
+ uint16 typeFlag;
+ uint32 effectFlag;
+ uint8 damageFlag;
+ };
+
+ static const FlagTableEntry flagTable[] = {
+ { 0x0000, 0x000000, 0x00 }, // dummy
+ { 0x0033, 0x000001, 0x00 }, // armor
+ { 0x0100, 0x000000, 0x21 }, // burning hands
+ { 0x004c, 0x000002, 0x00 }, // detect magic
+ { 0x0100, 0x000000, 0x01 }, // magic missile
+ { 0x0000, 0x000000, 0x00 }, // dummy
+ { 0x008b, 0x000008, 0x00 }, // shield
+ { 0x0488, 0x000000, 0x03 }, // shocking grasp
+ { 0x0021, 0x000040, 0x00 }, // invisibility
+ { 0x0000, 0x000000, 0x00 }, // dummy
+ { 0x0100, 0x000000, 0x11 }, // melf's acid arrow
+ { 0x0000, 0x000000, 0x00 }, // STINKING CLOUD
+ { 0x1000, 0x000000, 0x00 }, // dispel magic
+ { 0x0100, 0x000000, 0x21 }, // fireball
+ { 0x0100, 0x000000, 0x11 }, // FLAME ARROW
+ { 0x0248, 0x010000, 0x00 }, // haste
+ { 0x0100, 0x000000, 0x00 }, // hold person
+ { 0x0240, 0x000040, 0x00 }, // inv 10'
+ { 0x0100, 0x000000, 0x03 }, // lightning bolt
+ { 0x0488, 0x000000, 0x01 }, // vampiric touch
+ { 0x0100, 0x000000, 0x00 }, // fear
+ { 0x0100, 0x000000, 0x41 }, // ice storm
+ { 0x0033, 0x000001, 0x00 }, // STONE SKIN
+ { 0x0000, 0x000000, 0x00 }, // CLOUD KILL
+ { 0x0100, 0x000000, 0x41 }, // cone of cold
+ { 0x0100, 0x000000, 0x00 }, // hold monster
+ { 0x005c, 0x000400, 0x00 }, // bless
+ { 0x0020, 0x000000, 0x00 }, // cure light wounds
+ { 0x0100, 0x000000, 0x01 }, // cause light wounds
+ { 0x004c, 0x000002, 0x00 }, // detect magic
+ { 0x0029, 0x000800, 0x00 }, // prot from evil
+ { 0x0039, 0x000000, 0x00 }, // aid
+ { 0x2408, 0x000000, 0x21 }, // flame blade
+ { 0x0100, 0x000000, 0x00 }, // hold person
+ { 0x0028, 0x002000, 0x00 }, // slow poison
+ { 0x0040, 0x000000, 0x00 }, // create food
+ { 0x1000, 0x000000, 0x00 }, // dispel magic
+ { 0x0099, 0x004000, 0x00 }, // magical vestment
+ { 0x004c, 0x008000, 0x00 }, // prayer
+ { 0x0040, 0x000000, 0x00 }, // remove paralysis
+ { 0x0020, 0x000000, 0x00 }, // cure serious
+ { 0x0100, 0x000000, 0x01 }, // cause serious
+ { 0x0020, 0x000000, 0x00 }, // neutralize poison
+ { 0x0248, 0x000800, 0x00 }, // prot from evil 10'
+ { 0x0000, 0x000000, 0x00 }, // PROT FROM LIGHTNING
+ { 0x0020, 0x000000, 0x00 }, // cure critical
+ { 0x0100, 0x000000, 0x01 }, // cause critical
+ { 0x0100, 0x000000, 0x21 }, // flame strike
+ { 0x0020, 0x000000, 0x00 }, // raise dead
+ { 0x0020, 0x000000, 0x00 }, // lay on hands
+ { 0x0000, 0x000000, 0x00 }, // obj hit passive
+ { 0x0000, 0x000000, 0x00 }, // disintegrate passive
+ { 0x0000, 0x000000, 0x00 } // death spell passive
+ };
+
+ int temp;
+ const uint8 *src = _staticres->loadRawData(kEoBBaseSpellProperties, temp);
+ _clericSpellOffset -= 1;
+
+ for (int i = 0; i < _numSpells; i++) {
+ EoBSpell *s = &_spells[i];
+ src += 4;
+ s->flags = flagTable[i].typeFlag;
+ s->damageFlags = flagTable[i].damageFlag;
+ s->effectFlags = flagTable[i].effectFlag;
+ s->sound = src[13];
+ src += 15;
+ }
+}
+
+const KyraRpgGUISettings EoBEngine::_guiSettingsVGA = {
+ { 9, 15, 95, 9, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
+ { 135, 130, 132, 133, 133, 17, 23, 20, 184, 177, 180, 184, 177, 180 }
+};
+
+const KyraRpgGUISettings EoBEngine::_guiSettingsEGA = {
+ { 9, 15, 95, 9, 7, { 285, 139 }, { 189, 162 }, { 31, 31 } },
+ { 13, 9, 2, 133, 2, 6, 13, 8, 13, 15, 14, 13, 15, 14 }
+};
+
+const uint8 EoBEngine::_egaDefaultPalette[] = {
+ 0, 5, 3, 2, 10, 14, 12, 6, 4, 11, 9, 1, 0, 8, 7, 15
+};
+
+void DarkMoonEngine::initStaticResource() {
+ int temp;
+ _mainMenuStrings = _staticres->loadStrings(kEoB2MainMenuStrings, temp);
+ _introStrings = _staticres->loadStrings(kEoB2IntroStrings, temp);
+ _cpsFilesIntro = _staticres->loadStrings(kEoB2IntroCPSFiles, temp);
+
+ _animIntro = new const DarkMoonAnimCommand*[44];
+ for (int i = 0; i < 44; i++)
+ _animIntro[i] = _staticres->loadEoB2SeqData(kEob2IntroAnimData00 + i, temp);
+
+ _shapesIntro = new const DarkMoonShapeDef*[13];
+ memset(_shapesIntro, 0, sizeof(DarkMoonShapeDef*) * 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);
+
+ _animFinale = new const DarkMoonAnimCommand*[21];
+ for (int i = 0; i < 21; i++)
+ _animFinale[i] = _staticres->loadEoB2SeqData(kEob2FinaleAnimData00 + i, temp);
+
+ _shapesFinale = new const DarkMoonShapeDef*[13];
+ memset(_shapesFinale, 0, sizeof(DarkMoonShapeDef*) * 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);
+ _npcStrings[0] = _staticres->loadStrings(kEoB2Npc1Strings, temp);
+ _npcStrings[1] = _staticres->loadStrings(kEoB2Npc2Strings, temp);
+ _monsterDustStrings = _staticres->loadStrings(kEoB2MonsterDustStrings, temp);
+ _dreamSteps = (const int8 *)_staticres->loadRawData(kEoB2DreamSteps, temp);
+ _kheldranStrings = _staticres->loadStrings(kEoB2KheldranStrings, temp);
+ _hornStrings = _staticres->loadStrings(kEoB2HornStrings, temp);
+ _hornSounds = _staticres->loadRawData(kEoB2HornSounds, temp);
+
+ _wallOfForceDsX = (const int16 *)_staticres->loadRawDataBe16(kEoB2WallOfForceDsX, temp);
+ _wallOfForceDsY = _staticres->loadRawData(kEoB2WallOfForceDsY, temp);
+ _wallOfForceDsNumW = _staticres->loadRawData(kEoB2WallOfForceNumW, temp);
+ _wallOfForceDsNumH = _staticres->loadRawData(kEoB2WallOfForceNumH, temp);
+ _wallOfForceShpId = _staticres->loadRawData(kEoB2WallOfForceShpId, temp);
+
+ static const char *errorSlotNoNameString[3] = {
+ " You must specify\r a name for your\r save game!",
+ " Spielst[nde m]ssen\r einen Namen haben!",
+ 0
+ };
+
+ _errorSlotNoNameString = errorSlotNoNameString[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
+
+ // ScummVM specific
+ static const char *transferStringsScummVM[3][5] = {
+ {
+ "\r We cannot find any EOB save game\r file. Please make sure that the\r save game file with the party\r you wish to transfer is located\r in your ScummVM save game\r directory. If you have set up\r multiple save directories you\r have to copy the EOB save file\r into your EOB II save directory.\r Do you wish to try again?",
+ "Game ID",
+ "\r It seems that you have already\r defeated Xanathar here. Do you\r wish to transfer the party that\r finished the game? If not, you\r will be able to select a save\r game from the save game\r dialogue.",
+ "Select File",
+ "\r\r Please wait..."
+ },
+ {
+ "\r Kein EOB-Spielstand zu finden.\r Bitte Spielstandsdatei mit der\r zu ]bernehmenden Gruppe in das\r ScummVM Spielstands-Verzeichnis\r kopieren. Bei mehreren Spiel-\r stands-Verzeichnissen bitte\r den EOB-Spielstand in das\r EOB II-Spielstands-Verzeichnis\r kopieren. Nochmal versuchen?",
+ "Game ID",
+ "\r Wie es scheint, wurde Xanathar\r hier bereits besiegt. Soll die\r Gruppe, mit der das Spiel be-\r endet wurde, ]bernommen werden?\r Falls nicht, kann ein Spielstand\r aus der Spielstandsliste gew[hlt\r werden.",
+ "Spiel W[hlen",
+ "\r\r Bitte warten..."
+ },
+ {
+ 0, 0, 0, 0
+ }
+ };
+
+ _transferStringsScummVM = transferStringsScummVM[(_flags.lang == Common::EN_ANY) ? 0 : ((_flags.lang == Common::DE_DEU) ? 1 : 2)];
+}
+
+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::_palFilesIntroVGA[] = {
+ "PALETTE1.PAL",
+ "PALETTE3.PAL",
+ "PALETTE2.PAL",
+ "PALETTE4.PAL",
+ 0
+};
+
+const char *DarkMoonEngine::_palFilesIntroEGA[] = {
+ "PALETTE0.PAL",
+ "PALETTE3.PAL",
+ "PALETTE2.PAL",
+ "PALETTE4.PAL",
+ 0
+};
+
+const char *DarkMoonEngine::_palFilesFinaleVGA[] = {
+ "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
+};
+
+const char *DarkMoonEngine::_palFilesFinaleEGA[] = {
+ "FINALE_0.PAL",
+ "FINALE_0.PAL",
+ "FINALE_1.PAL",
+ "FINALE_2.PAL",
+ "FINALE_3.PAL",
+ "FINALE_4.PAL",
+ "FINALE_5.PAL",
+ "FINALE_0.PAL",
+ "FINALE_0.PAL",
+ 0
+};
+
+const KyraRpgGUISettings DarkMoonEngine::_guiSettings = {
+ { 9, 15, 95, 9, 7, { 221, 76 }, { 189, 162 }, { 95, 95 } },
+ { 186, 181, 183, 133, 184, 17, 23, 20, 186, 181, 183, 182, 177, 180 }
+};
+
+const uint8 DarkMoonEngine::_egaDefaultPalette[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+#endif // ENABLE_EOB
+
+} // End of namespace Kyra
diff --git a/engines/kyra/staticres_lol.cpp b/engines/kyra/staticres_lol.cpp
index bf838cd572..63bc7fa99b 100644
--- a/engines/kyra/staticres_lol.cpp
+++ b/engines/kyra/staticres_lol.cpp
@@ -30,31 +30,23 @@
namespace Kyra {
const LoLCharacter *StaticResource::loadCharData(int id, int &entries) {
- return (const LoLCharacter *)getData(id, kLolCharData, entries);
+ return (const LoLCharacter *)getData(id, kLoLCharData, entries);
}
const SpellProperty *StaticResource::loadSpellData(int id, int &entries) {
- return (const SpellProperty *)getData(id, kLolSpellData, entries);
+ return (const SpellProperty *)getData(id, kLoLSpellData, entries);
}
const CompassDef *StaticResource::loadCompassData(int id, int &entries) {
- return (const CompassDef *)getData(id, kLolCompassData, entries);
+ return (const CompassDef *)getData(id, kLoLCompassData, entries);
}
const FlyingObjectShape *StaticResource::loadFlyingObjectData(int id, int &entries) {
- return (const FlyingObjectShape *)getData(id, kLolFlightShpData, entries);
+ 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,88 +242,79 @@ void LoLEngine::initStaticResource() {
if (_flags.isDemo)
return;
- _pakFileList = _staticres->loadStrings(kLolIngamePakFiles, _pakFileListSize);
- _charDefaults = _staticres->loadCharData(kLolCharacterDefs, _charDefaultsSize);
- _ingameSoundIndex = (const uint16 *)_staticres->loadRawData(kLolIngameSfxIndex, _ingameSoundIndexSize);
- _musicTrackMap = _staticres->loadRawData(kLolMusicTrackMap, _musicTrackMapSize);
- _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);
-
- const char *const *tmpSndList = _staticres->loadStrings(kLolIngameSfxFiles, _ingameSoundListSize);
+ int tempSize;
+ _pakFileList = _staticres->loadStrings(kLoLIngamePakFiles, _pakFileListSize);
+ _charDefaults = _staticres->loadCharData(kLoLCharacterDefs, _charDefaultsSize);
+ _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, 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]);
}
- _staticres->unloadId(kLolIngameSfxFiles);
+ _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);
+ const uint8 *tmp = _staticres->loadRawData(kLoLLegendData, tempSize);
uint8 entrySize = tempSize / 12;
tempSize /= entrySize;
if (tempSize) {
@@ -382,19 +326,21 @@ void LoLEngine::initStaticResource() {
_defaultLegendData[i].stringId = READ_LE_UINT16(tmp);
tmp += 2;
}
- _staticres->unloadId(kLolLegendData);
+ _staticres->unloadId(kLoLLegendData);
}
- tmp = _staticres->loadRawData(kLolMapCursorOvl, tempSize);
- _mapCursorOverlay = new uint8[tempSize];
- memcpy(_mapCursorOverlay, tmp, tempSize);
- _staticres->unloadId(kLolMapCursorOvl);
+ tmp = _staticres->loadRawData(kLoLMapCursorOvl, tempSize);
+ 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);
+ tmp = _staticres->loadRawData(kLoLLightningDefs, tempSize);
if (tmp) {
_lightningProps = new LightningProperty[5];
for (int i = 0; i < 5; i++) {
@@ -402,10 +348,10 @@ void LoLEngine::initStaticResource() {
_lightningProps[i].frameDiv = tmp[(i << 2) + 1];
_lightningProps[i].sfxId = READ_LE_UINT16(&tmp[(i << 2) + 2]);
}
- _staticres->unloadId(kLolLightningDefs);
+ _staticres->unloadId(kLoLLightningDefs);
}
- _fireBallCoords = (const int16 *)_staticres->loadRawDataBe16(kLolFireballCoords, _fireBallCoordsSize);
+ _fireBallCoords = (const int16 *)_staticres->loadRawDataBe16(kLoLFireballCoords, tempSize);
_buttonCallbacks.clear();
_buttonCallbacks.reserve(95);
@@ -519,7 +465,7 @@ void GUI_LoL::initStaticData() {
if (_vm->gameFlags().isTalkie)
GUI_LOL_MENU(_mainMenu, 9, 0x4000, 0, 7, -1, -1, -1, -1);
- else
+ else
GUI_LOL_MENU(_mainMenu, 17, 0x4000, 0, 6, -1, -1, -1, -1);
GUI_LOL_MENU_ITEM(_mainMenu.item[0], 0x4001, 16, 23, 176, 15, 0, 0);
@@ -681,7 +627,7 @@ const ScreenDim Screen_LoL::_screenDimTable16C[] = {
const int Screen_LoL::_screenDimTableCount = ARRAYSIZE(Screen_LoL::_screenDimTable256C);
-const char * const LoLEngine::_languageExt[] = {
+const char *const LoLEngine::_languageExt[] = {
"ENG",
"FRE",
"GER"
@@ -818,6 +764,11 @@ const int8 LoLEngine::_mapCoords[12][4] = {
{ 3, 1, 3, 1 }, { -1, 6, -1, -8 }, { -7, -1, 5, -1 }
};
+const KyraRpgGUISettings LoLEngine::_guiSettings = {
+ { 144, 254, 74, 9, 80, { 0, 0 }, { 0, 0 }, { 0, 0 } },
+ { 136, 251, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
const MistOfDoomAnimData LoLEngine::_mistAnimData[] = {
{ 0, 7, 7, 13, 155 },
{ 0, 16, 16, 17, 155 },
@@ -826,7 +777,7 @@ const MistOfDoomAnimData LoLEngine::_mistAnimData[] = {
{ 0, 16, 16, 17, 175 },
};
-const char * const LoLEngine::_outroShapeFileTable[] = {
+const char *const LoLEngine::_outroShapeFileTable[] = {
"AMAZON.SHP", "ARCHRSLG.SHP", "AVIANWRM.SHP", "BANDIT.SHP", "BOAR.SHP", "CABAL.SHP",
"GUARD.SHP", "HAG.SHP", "HORNET.SHP", "HURZELL.SHP", "IRONGRZR.SHP", "KNOWLES.SHP",
"LIZARD.SHP", "MANTHA.SHP", "MINOTAUR.SHP", "MORIBUND.SHP", "ORC.SHP", "ORCLDR.SHP",
diff --git a/engines/kyra/staticres_rpg.cpp b/engines/kyra/staticres_rpg.cpp
new file mode 100644
index 0000000000..a30cbf7d05
--- /dev/null
+++ b/engines/kyra/staticres_rpg.cpp
@@ -0,0 +1,100 @@
+/* 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/resource.h"
+
+
+namespace Kyra {
+
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+const uint16 *StaticResource::loadRawDataBe16(int id, int &entries) {
+ return (const uint16 *)getData(id, kRawDataBe16, entries);
+}
+
+const uint32 *StaticResource::loadRawDataBe32(int id, int &entries) {
+ return (const uint32 *)getData(id, kRawDataBe32, entries);
+}
+
+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;
+}
+
+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;
+}
+
+const uint8 KyraRpgEngine::_dropItemDirIndex[] = { 0, 1, 2, 3, 1, 3, 0, 2, 3, 2, 1, 0, 2, 0, 3, 1 };
+
+void KyraRpgEngine::initStaticResource() {
+ int temp;
+ _dscShapeX = (const int16 *)_staticres->loadRawDataBe16(kRpgCommonDscX, temp);
+ _dscShapeIndex = (const int8 *)_staticres->loadRawData(kRpgCommonDscShapeIndex, temp);
+ _dscTileIndex = _staticres->loadRawData(kRpgCommonDscTileIndex, temp);
+ _dscDim1 = (const int8 *)_staticres->loadRawData(kRpgCommonDscDimData1, temp);
+ _dscDim2 = (const int8 *)_staticres->loadRawData(kRpgCommonDscDimData2, temp);
+ _dscUnk2 = _staticres->loadRawData(kRpgCommonDscUnk2, temp);
+ _dscBlockMap = _staticres->loadRawData(kRpgCommonDscBlockMap, temp);
+ _dscBlockIndex = (const int8 *)_staticres->loadRawData(kRpgCommonDscBlockIndex, temp);
+ _dscDimMap = _staticres->loadRawData(kRpgCommonDscDimMap, temp);
+ _dscDoorShpIndex = _staticres->loadRawData(kRpgCommonDscDoorShapeIndex, _dscDoorShpIndexSize);
+ _dscDoorY2 = _staticres->loadRawData(kRpgCommonDscDoorY2, temp);
+ _dscDoorFrameY1 = _staticres->loadRawData(kRpgCommonDscDoorFrameY1, temp);
+ _dscDoorFrameY2 = _staticres->loadRawData(kRpgCommonDscDoorFrameY2, temp);
+ _dscDoorFrameIndex1 = _staticres->loadRawData(kRpgCommonDscDoorFrameIndex1, temp);
+ _dscDoorFrameIndex2 = _staticres->loadRawData(kRpgCommonDscDoorFrameIndex2, temp);
+ _moreStrings = _staticres->loadStrings(kRpgCommonMoreStrings, temp);
+}
+
+#endif // (ENABLE_EOB || ENABLE_LOL)
+
+} // End of namespace Kyra
diff --git a/engines/kyra/text_lok.cpp b/engines/kyra/text_lok.cpp
index 0ee3574903..62bdf18816 100644
--- a/engines/kyra/text_lok.cpp
+++ b/engines/kyra/text_lok.cpp
@@ -188,7 +188,7 @@ int8 KyraEngine_LoK::getChatPartnerNum() {
for (int i = 1; i < 6; i++) {
if (_currentCharacter->sceneId == sceneTable[pos]) {
- partner = sceneTable[pos+1];
+ partner = sceneTable[pos + 1];
break;
}
pos += 2;
@@ -342,12 +342,12 @@ void KyraEngine_LoK::drawSentenceCommand(const char *sentence, int color) {
_currSentenceColor[2] = 0x3F;
_screen->setInterfacePalette(_screen->getPalette(1),
- _currSentenceColor[0], _currSentenceColor[1], _currSentenceColor[2]);
+ _currSentenceColor[0], _currSentenceColor[1], _currSentenceColor[2]);
}
} else if (_startSentencePalIndex != color || _fadeText != false) {
- _currSentenceColor[0] = _screen->getPalette(0)[765] = _screen->getPalette(0)[color*3+0];
- _currSentenceColor[1] = _screen->getPalette(0)[766] = _screen->getPalette(0)[color*3+1];
- _currSentenceColor[2] = _screen->getPalette(0)[767] = _screen->getPalette(0)[color*3+2];
+ _currSentenceColor[0] = _screen->getPalette(0)[765] = _screen->getPalette(0)[color * 3 + 0];
+ _currSentenceColor[1] = _screen->getPalette(0)[766] = _screen->getPalette(0)[color * 3 + 1];
+ _currSentenceColor[2] = _screen->getPalette(0)[767] = _screen->getPalette(0)[color * 3 + 2];
_screen->setScreenPalette(_screen->getPalette(0));
_startSentencePalIndex = color;
@@ -377,16 +377,15 @@ void KyraEngine_LoK::updateTextFade() {
for (int i = 0; i < 3; i++) {
if (_currSentenceColor[i] > 4)
_currSentenceColor[i] -= 4;
- else
- if (_currSentenceColor[i]) {
- _currSentenceColor[i] = 0;
- finished = true;
- }
+ else if (_currSentenceColor[i]) {
+ _currSentenceColor[i] = 0;
+ finished = true;
+ }
}
if (_flags.platform == Common::kPlatformAmiga) {
_screen->setInterfacePalette(_screen->getPalette(1),
- _currSentenceColor[0], _currSentenceColor[1], _currSentenceColor[2]);
+ _currSentenceColor[0], _currSentenceColor[1], _currSentenceColor[2]);
} else {
_screen->getPalette(0)[765] = _currSentenceColor[0];
_screen->getPalette(0)[766] = _currSentenceColor[1];
diff --git a/engines/kyra/text_lol.cpp b/engines/kyra/text_lol.cpp
index 1c2167b892..ee42d6db92 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_rpg(engine, screenLoL),
+ _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;
}
@@ -336,7 +303,7 @@ void TextDisplayer_LoL::preprocessString(char *str, EMCState *script, const uint
switch (para) {
case 'a':
- snprintf(dst, 7, "%d", _scriptTextParameter);
+ strcpy(dst, Common::String::format("%d", _scriptTextParameter).c_str());
dst += strlen(dst);
break;
@@ -354,7 +321,7 @@ void TextDisplayer_LoL::preprocessString(char *str, EMCState *script, const uint
case 'd':
case 'u':
case 'x':
- snprintf(dst, 7, "%d", script ? script->stack[script->sp + paramIndex] : paramList[paramIndex]);
+ strcpy(dst, Common::String::format("%d", script ? script->stack[script->sp + paramIndex] : paramList[paramIndex]).c_str());
dst += strlen(dst);
break;
@@ -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;
+KyraRpgEngine *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_rpg::textPageBreak();
}
} // End of namespace Kyra
diff --git a/engines/kyra/text_lol.h b/engines/kyra/text_lol.h
index 3e59bc90fe..e2b10e8d4d 100644
--- a/engines/kyra/text_lol.h
+++ b/engines/kyra/text_lol.h
@@ -20,80 +20,51 @@
*
*/
-#ifdef ENABLE_LOL
-
#ifndef KYRA_TEXT_LOL_H
#define KYRA_TEXT_LOL_H
+#if defined(ENABLE_EOB) || defined(ENABLE_LOL)
+#include "kyra/text_rpg.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_rpg {
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);
+ virtual KyraRpgEngine *vm();
+ virtual 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
-
#endif // ENABLE_LOL
+
+#endif
diff --git a/engines/kyra/text_rpg.cpp b/engines/kyra/text_rpg.cpp
new file mode 100644
index 0000000000..52c14c7223
--- /dev/null
+++ b/engines/kyra/text_rpg.cpp
@@ -0,0 +1,671 @@
+/* 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/kyra_rpg.h"
+#include "kyra/timer.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+enum {
+ kEoBTextBufferSize = 2048
+};
+
+TextDisplayer_rpg::TextDisplayer_rpg(KyraRpgEngine *engine, Screen *scr) : _vm(engine), _screen(scr),
+ _lineCount(0), _printFlag(false), _lineWidth(0), _numCharsTotal(0), _allowPageBreak(true),
+ _numCharsLeft(0), _numCharsPrinted(0), _sjisLineBreakFlag(false), _waitButtonMode(1) {
+
+ _dialogueBuffer = new char[kEoBTextBufferSize];
+ memset(_dialogueBuffer, 0, kEoBTextBufferSize);
+
+ _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;
+ }
+
+ _table1 = new char[128];
+ memset(_table1, 0, 128);
+ _table2 = new char[16];
+ memset(_table2, 0, 16);
+
+ _waitButtonSpace = 0;
+}
+
+TextDisplayer_rpg::~TextDisplayer_rpg() {
+ delete[] _dialogueBuffer;
+ delete[] _currentLine;
+ delete[] _textDimData;
+ delete[] _table1;
+ delete[] _table2;
+}
+
+void TextDisplayer_rpg::setupField(int dim, bool mode) {
+ setPageBreakFlag();
+
+ _textDimData[dim].color2 = _vm->guiSettings()->colors.fill;
+ _screen->setScreenDim(dim);
+
+ if (mode)
+ clearCurDim();
+ else
+ resetDimTextPositions(dim);
+}
+
+void TextDisplayer_rpg::resetDimTextPositions(int dim) {
+ _textDimData[dim].column = 0;
+ _textDimData[dim].line = 0;
+}
+
+void TextDisplayer_rpg::resetPageBreakString() {
+ if (vm()->_moreStrings)
+ strcpy(_pageBreakString, vm()->_moreStrings[0]);
+}
+
+void TextDisplayer_rpg::setPageBreakFlag() {
+ _allowPageBreak = true;
+ _lineCount = 0;
+}
+
+void TextDisplayer_rpg::removePageBreakFlag() {
+ _allowPageBreak = false;
+}
+
+void TextDisplayer_rpg::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') {
+ strcpy(_scriptParaString, Common::String::format("%d", va_arg(args, int)).c_str());
+ _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 12:
+ if (isPc98)
+ _sjisLineBreakFlag = true;
+ printLine(_currentLine);
+ _sjisLineBreakFlag = false;
+ _lineCount++;
+ _textDimData[sdx].column = 0;
+ _textDimData[sdx].line++;
+ break;
+
+ case 11: case 18: case 23:
+ case 24: case 26: case 28:
+ // These are at the time of writing this comment not known to be
+ // used. In case there is some use of them in some odd version
+ // we display this warning here.
+ warning("TextDisplayer_rpg::displayText: Triggered stub function %d", c - 1);
+ break;
+
+ default:
+ if (_vm->game() == GI_LOL || (unsigned char)c > 30) {
+ _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_rpg::parseCommand() {
+ if (!_ctrl[1])
+ readNextPara();
+
+ char res = _ctrl[1];
+ _ctrl[1] = _ctrl[2];
+ _ctrl[2] = 0;
+
+ if (!_ctrl[1])
+ readNextPara();
+
+ return res;
+}
+
+void TextDisplayer_rpg::readNextPara() {
+ char c = 0;
+ 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;
+ }
+
+ // This seems to be some sort of character conversion mechanism. The original doesn't make any use of it, however.
+ // All necessary conversions take place somewhere else. This code actually causes issues if the character conversions
+ // don't take place before calling displayText(). So we disable it for now. If some (not yet supported) localized
+ // versions depend on this code we'll have to look at this again.
+#if 0
+ if ((_vm->game() != GI_LOL) && (d & 0x80)) {
+ d &= 0x7f;
+ c = d & 7;
+ d = (d & 0x78) >> 3;
+ uint8 l = d;
+ c = _table1[(l << 3) + c];
+ d = _table2[l];
+ }
+#endif
+
+ _ctrl[1] = d;
+ _ctrl[2] = c;
+}
+
+void TextDisplayer_rpg::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 -= vm()->guiSettings()->buttons.waitReserve;
+ } else {
+ if (!_sjisLineBreakFlag || (_lineCount + 1 < lines - 1))
+ ct = false;
+ else
+ // cut off line to leave space for "MORE" button
+ w -= vm()->guiSettings()->buttons.waitReserve;
+ }
+
+ 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 -= vm()->guiSettings()->buttons.waitReserve;
+
+ 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_rpg::printDialogueText(int stringId, const char *pageBreakString) {
+ const char *str = (const char *)(_screen->getCPagePtr(5) + READ_LE_UINT16(&_screen->getCPagePtr(5)[(stringId - 1) << 1]));
+ assert(strlen(str) < kEoBTextBufferSize);
+ Common::strlcpy(_dialogueBuffer, str, kEoBTextBufferSize);
+
+ displayText(_dialogueBuffer);
+
+ if (pageBreakString) {
+ if (pageBreakString[0]) {
+ strcpy(_pageBreakString, pageBreakString);
+ displayWaitButton();
+ resetPageBreakString();
+ }
+ }
+}
+
+void TextDisplayer_rpg::printDialogueText(const char *str, bool wait) {
+ assert(strlen(str) < kEoBTextBufferSize);
+ Common::strlcpy(_dialogueBuffer, str, kEoBTextBufferSize);
+
+ strcpy(_dialogueBuffer, str);
+ displayText(_dialogueBuffer);
+ if (wait)
+ displayWaitButton();
+}
+
+void TextDisplayer_rpg::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, kEoBTextBufferSize - 1, str, args);
+ va_end(args);
+
+ displayText(_dialogueBuffer);
+
+ if (vm()->game() != GI_EOB1)
+ _textDimData[_screen->curDimIndex()].color1 = tc;
+
+ if (!_screen->_curPage)
+ _screen->updateScreen();
+}
+
+int TextDisplayer_rpg::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()->guiSettings()->colors.fill;
+ clearCurDim();
+ return res;
+}
+
+void TextDisplayer_rpg::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_rpg::textPageBreak() {
+ if (vm()->game() != GI_LOL)
+ SWAP(vm()->_dialogueButtonLabelColor1, vm()->_dialogueButtonLabelColor2);
+
+ int cp = _screen->setCurPage(0);
+ Screen::FontId cf = _screen->setFont(vm()->gameFlags().use16ColorMode ? Screen::FID_SJIS_FNT : Screen::FID_6_FNT);
+
+ if (vm()->game() == GI_LOL)
+ 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->_dialogueButtonWidth + 3);
+ int y = 0;
+ int w = vm()->_dialogueButtonWidth;
+
+ if (vm()->game() == GI_LOL) {
+ 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;
+ }
+ } else {
+ y = vm()->guiSettings()->buttons.waitY[_waitButtonMode];
+ x = vm()->guiSettings()->buttons.waitX[_waitButtonMode];
+ w = vm()->guiSettings()->buttons.waitWidth[_waitButtonMode];
+ }
+
+ 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, w, vm()->guiSettings()->buttons.height, vm()->guiSettings()->colors.frame1, vm()->guiSettings()->colors.frame2, vm()->guiSettings()->colors.fill);
+ _screen->printText(_pageBreakString, x + (w >> 1) - (vm()->screen()->getTextWidth(_pageBreakString) >> 1), y + 2, vm()->_dialogueButtonLabelColor1, 0);
+ }
+
+ vm()->removeInputTop();
+
+ bool loop = true;
+ bool target = false;
+
+ do {
+ int inputFlag = vm()->checkInput(0, false) & 0xFF;
+ vm()->removeInputTop();
+
+ while (!inputFlag && !_vm->shouldQuit()) {
+ 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 + w, y + 9)) {
+ if (_vm->game() == GI_LOL)
+ target = true;
+ else
+ loop = false;
+ }
+ } else if (inputFlag == 200 || inputFlag == 202) {
+ if (target)
+ loop = false;
+ }
+ } while (loop && !_vm->shouldQuit());
+
+ if (vm()->gameFlags().use16ColorMode)
+ _screen->fillRect(x + 8, y, x + 57, y + 9, _textDimData[_screen->curDimIndex()].color2);
+ else
+ _screen->fillRect(x, y, x + w - 1, y + 8, _textDimData[_screen->curDimIndex()].color2);
+
+ clearCurDim();
+ _screen->updateScreen();
+
+ if (vm()->game() == GI_LOL)
+ 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()->_dialogueButtonLabelColor1, vm()->_dialogueButtonLabelColor2);
+
+ vm()->removeInputTop();
+}
+
+void TextDisplayer_rpg::displayWaitButton() {
+ vm()->_dialogueNumButtons = 1;
+ vm()->_dialogueButtonString[0] = _pageBreakString;
+ vm()->_dialogueButtonString[1] = 0;
+ vm()->_dialogueButtonString[2] = 0;
+ vm()->_dialogueHighlightedButton = 0;
+
+ vm()->_dialogueButtonPosX = &vm()->guiSettings()->buttons.waitX[_waitButtonMode];
+ vm()->_dialogueButtonPosY = &vm()->guiSettings()->buttons.waitY[_waitButtonMode];
+ vm()->_dialogueButtonWidth = vm()->guiSettings()->buttons.waitWidth[_waitButtonMode];
+ vm()->_dialogueButtonYoffs = 0;
+
+ SWAP(vm()->_dialogueButtonLabelColor1, vm()->_dialogueButtonLabelColor2);
+ vm()->drawDialogueButtons();
+
+ if (!vm()->shouldQuit())
+ vm()->removeInputTop();
+
+ while (!vm()->processDialogue() && !vm()->shouldQuit()) {}
+
+ _screen->fillRect(vm()->_dialogueButtonPosX[0], vm()->_dialogueButtonPosY[0], vm()->_dialogueButtonPosX[0] + vm()->_dialogueButtonWidth - 1, vm()->_dialogueButtonPosY[0] + vm()->guiSettings()->buttons.height - 1, vm()->guiSettings()->colors.fill);
+ _screen->updateScreen();
+ vm()->_dialogueButtonWidth = 95;
+ SWAP(vm()->_dialogueButtonLabelColor1, vm()->_dialogueButtonLabelColor2);
+ clearCurDim();
+}
+
+} // End of namespace Kyra
+
+#endif // (ENABLE_EOB || ENABLE_LOL)
diff --git a/engines/kyra/text_rpg.h b/engines/kyra/text_rpg.h
new file mode 100644
index 0000000000..5ad8899484
--- /dev/null
+++ b/engines/kyra/text_rpg.h
@@ -0,0 +1,115 @@
+/* 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 KyraRpgEngine;
+
+class TextDisplayer_rpg {
+public:
+ TextDisplayer_rpg(KyraRpgEngine *engine, Screen *scr);
+ virtual ~TextDisplayer_rpg();
+
+ 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 KyraRpgEngine *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:
+ KyraRpgEngine *_vm;
+ Screen *_screen;
+
+ char *_table1;
+ char *_table2;
+};
+
+} // End of namespace Kyra
+
+#endif
+
+#endif // ENABLE_EOB || ENABLE_LOL
diff --git a/engines/kyra/timer.cpp b/engines/kyra/timer.cpp
index 9834646a45..95c283f063 100644
--- a/engines/kyra/timer.cpp
+++ b/engines/kyra/timer.cpp
@@ -149,6 +149,8 @@ void TimerManager::setCountdown(uint8 id, int32 countdown) {
uint32 curTime = _system->getMillis();
timer->lastUpdate = curTime;
timer->nextRun = curTime + countdown * _vm->tickLength();
+ if (timer->enabled & 2)
+ timer->pauseStartTime = curTime;
_nextRun = MIN(_nextRun, timer->nextRun);
}
@@ -177,6 +179,8 @@ int32 TimerManager::getDelay(uint8 id) const {
void TimerManager::setNextRun(uint8 id, uint32 nextRun) {
Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id));
if (timer != _timers.end()) {
+ if (timer->enabled & 2)
+ timer->pauseStartTime = _system->getMillis();
timer->nextRun = nextRun;
return;
}
@@ -217,7 +221,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..766fe453ab
--- /dev/null
+++ b/engines/kyra/timer_eob.cpp
@@ -0,0 +1,360 @@
+/* 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/eobcommon.h"
+#include "kyra/timer.h"
+
+#include "common/system.h"
+
+#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(0x20, _system->getMillis());
+ _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);
+ _timer->resetNextRun();
+}
+
+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);
+ _timer->resetNextRun();
+
+ if (updateExistingTimer) {
+ bool updated = false;
+ int d = -1;
+
+ for (int i = 0; i < 10 && updated == false; i++) {
+ if (d == -1 && !c->timers[i])
+ d = i;
+
+ if (!updated && c->events[i] == evnt) {
+ d = i;
+ updated = true;
+ }
+ }
+
+ assert(d != -1);
+
+ 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] && 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);
+ }
+ }
+ _timer->resetNextRun();
+}
+
+void EoBCoreEngine::advanceTimers(uint32 millis) {
+ uint32 ct = _system->getMillis();
+ for (int i = 0; i < 6; i++) {
+ EoBCharacter *c = &_characters[i];
+ for (int ii = 0; ii < 10; ii++) {
+ if (c->timers[ii] > ct) {
+ uint32 chrt = c->timers[ii] - ct;
+ c->timers[ii] = chrt > millis ? ct + chrt - millis : ct;
+ }
+ }
+ }
+
+ setupCharacterTimers();
+
+ if (_scriptTimersMode & 1) {
+ for (int i = 0; i < _scriptTimersCount; i++) {
+ if (_scriptTimers[i].next > ct) {
+ uint32 chrt = _scriptTimers[i].next - ct;
+ _scriptTimers[i].next = chrt > millis ? ct + chrt - millis : ct;
+ }
+ }
+ }
+
+ for (int i = 0; i < 5; i++) {
+ if (_wallsOfForce[i].duration > ct) {
+ uint32 chrt = _wallsOfForce[i].duration - ct;
+ _wallsOfForce[i].duration = chrt > millis ? ct + chrt - millis : ct;
+ }
+ }
+}
+
+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 == 0;
+
+ 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->starting = 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))
+ explodeObject(fo, fo->curBlock, fo->item);
+ }
+ 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;
+ }
+
+ int od = _screen->curDimIndex();
+ Screen::FontId of = _screen->setFont(Screen::FID_6_FNT);
+ _screen->setScreenDim(7);
+
+ 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 &= ~2;
+ gui_drawCharPortraitWithStats(charIndex);
+ }
+ break;
+
+ case 9:
+ if (c->flags & 4) {
+ _txt->printMessage(_characterStatusStrings9[0], -1, c->name);
+ c->flags &= ~4;
+ gui_drawCharPortraitWithStats(charIndex);
+ }
+ break;
+
+ case 11:
+ if (c->disabledSlots & 4) {
+ c->disabledSlots &= ~4;
+ if (_openBookChar == charIndex && _updateFlags)
+ gui_drawSpellbook();
+ }
+ break;
+
+ case 12:
+ c->effectFlags &= ~0x1000;
+ if (_characterStatusStrings12)
+ _txt->printMessage(_characterStatusStrings12[0], -1, c->name);
+ break;
+
+ default:
+ break;
+ }
+
+ _screen->setScreenDim(od);
+ _screen->setFont(of);
+ }
+
+ uint32 nextTimer = 0xffffffff;
+ for (int i = 0; i < 10; i++) {
+ if (c->timers[i] && c->timers[i] < nextTimer)
+ nextTimer = c->timers[i];
+ }
+
+ if (nextTimer == 0xffffffff)
+ _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 == _teleporterWallId) || (_flags.gameID == GI_EOB2 && w == 74)) {
+ _sceneUpdateRequired = true;
+ return;
+ }
+ }
+}
+
+void EoBCoreEngine::timerUpdateFoodStatus(int timerNum) {
+ for (int i = 0; i < 6; i++) {
+ // Ring of Sustenance check
+ 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_lok.cpp b/engines/kyra/timer_lok.cpp
index 555b3680e2..13f5403618 100644
--- a/engines/kyra/timer_lok.cpp
+++ b/engines/kyra/timer_lok.cpp
@@ -155,7 +155,7 @@ void KyraEngine_LoK::setTextFadeTimerCountdown(int16 countdown) {
if (countdown == -1)
countdown = 32000;
- _timer->setCountdown(31, countdown*60);
+ _timer->setCountdown(31, countdown * 60);
}
void KyraEngine_LoK::timerAsInvisibleTimeout(int timerNum) {
diff --git a/engines/kyra/timer_lol.cpp b/engines/kyra/timer_lol.cpp
index 3221556e6d..a3df8dbe00 100644
--- a/engines/kyra/timer_lol.cpp
+++ b/engines/kyra/timer_lol.cpp
@@ -45,58 +45,7 @@ void LoLEngine::setupTimers() {
_timer->addTimer(9, TimerV2(timerUpdatePortraitAnimations), 10, true);
_timer->addTimer(10, TimerV2(timerUpdateLampState), 360, true);
_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;
- }
+ _timer->resetNextRun();
}
void LoLEngine::timerProcessMonsters(int timerNum) {
@@ -209,7 +158,7 @@ void LoLEngine::timerRegeneratePoints(int timerNum) {
int hInc = (_characters[i].flags & 8) ? 0 : (itemEquipped(i, 228) ? 4 : 1);
// check for Talba ring
int mInc = _drainMagic ? ((_characters[i].magicPointsMax >> 5) * -1) :
- ((_characters[i].flags & 8) ? 0 : (itemEquipped(i, 227) ? (_characters[i].magicPointsMax / 10) : 1));
+ ((_characters[i].flags & 8) ? 0 : (itemEquipped(i, 227) ? (_characters[i].magicPointsMax / 10) : 1));
_characters[i].magicPointsCur = CLIP<int16>(_characters[i].magicPointsCur + mInc, 0, _characters[i].magicPointsMax);
diff --git a/engines/kyra/timer_rpg.cpp b/engines/kyra/timer_rpg.cpp
new file mode 100644
index 0000000000..02c2669436
--- /dev/null
+++ b/engines/kyra/timer_rpg.cpp
@@ -0,0 +1,90 @@
+/* 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/kyra_rpg.h"
+#include "kyra/timer.h"
+
+#include "common/system.h"
+
+namespace Kyra {
+
+void KyraRpgEngine::enableSysTimer(int sysTimer) {
+ if (sysTimer != 2)
+ return;
+
+ for (int i = 0; i < getNumClock2Timers(); i++)
+ _timer->pauseSingleTimer(getClock2Timer(i), false);
+}
+
+void KyraRpgEngine::disableSysTimer(int sysTimer) {
+ if (sysTimer != 2)
+ return;
+
+ for (int i = 0; i < getNumClock2Timers(); i++)
+ _timer->pauseSingleTimer(getClock2Timer(i), true);
+}
+
+void KyraRpgEngine::enableTimer(int id) {
+ _timer->enable(id);
+ _timer->setCountdown(id, _timer->getDelay(id));
+}
+
+void KyraRpgEngine::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
diff --git a/engines/kyra/vqa.cpp b/engines/kyra/vqa.cpp
index 04455ae307..471e83c9ed 100644
--- a/engines/kyra/vqa.cpp
+++ b/engines/kyra/vqa.cpp
@@ -395,7 +395,7 @@ void VQAMovie::displayFrame(uint frameNum) {
if (frameNum >= _header.numFrames || !_opened)
return;
- bool foundSound = _stream ? false : true;
+ bool foundSound = !_stream;
bool foundFrame = false;
uint i;
diff --git a/engines/kyra/wsamovie.cpp b/engines/kyra/wsamovie.cpp
index 21ff80f033..f6aca2bb82 100644
--- a/engines/kyra/wsamovie.cpp
+++ b/engines/kyra/wsamovie.cpp
@@ -28,10 +28,12 @@
namespace Kyra {
WSAMovie_v1::WSAMovie_v1(KyraEngine_v1 *vm)
- : Movie(vm), _frameData(0), _frameOffsTable(0), _offscreenBuffer(0), _deltaBuffer(0) {
+ : Movie(vm), _frameData(0), _frameOffsTable(0), _offscreenBuffer(0), _deltaBuffer(0) {
}
-WSAMovie_v1::~WSAMovie_v1() { close(); }
+WSAMovie_v1::~WSAMovie_v1() {
+ close();
+}
int WSAMovie_v1::open(const char *filename, int offscreenDecode, Palette *palBuf) {
close();
@@ -95,7 +97,7 @@ int WSAMovie_v1::open(const char *filename, int offscreenDecode, Palette *palBuf
for (int i = 1; i < _numFrames + 2; ++i) {
_frameOffsTable[i] = READ_LE_UINT32(wsaData);
- if (_frameOffsTable[i])
+ if (_frameOffsTable[i])
_frameOffsTable[i] -= frameDataOffs;
wsaData += 4;
}
@@ -251,7 +253,7 @@ void WSAMovieAmiga::displayFrame(int frameNum, int pageNum, int x, int y, uint16
uint8 *dst;
dst = _buffer;
- memset(_buffer, 0, _width*_height);
+ memset(_buffer, 0, _width * _height);
if (_currentFrame == _numFrames) {
if (!(_flags & WF_NO_FIRST_FRAME)) {
@@ -330,7 +332,7 @@ void WSAMovieAmiga::processFrame(int frameNum, uint8 *dst) {
return;
assert(frameNum <= _numFrames);
- memset(dst, 0, _width*_height);
+ memset(dst, 0, _width * _height);
const uint8 *src = _frameData + _frameOffsTable[frameNum];
Screen::decodeFrame4(src, _deltaBuffer, _deltaBufferSize);