From ccb64ad81e6c56eaa2350197f964d470d8610ed9 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sat, 25 Apr 2009 13:15:05 +0000 Subject: LOL: - Started implementing the fighting system. The damage inflicted is wrong, however (at least the damage inflicted by the monsters). I'm sowewhat clueless about that bug atm. - added support for monsters with distance attacks (like those orcs in front of roland's house) - lots of small bug fixes - Some startup support for the pc-98 16 color version. The intro will run, but the font drawing/coloring is still wrong. svn-id: r40144 --- engines/kyra/detection.cpp | 80 ++-- engines/kyra/gui_lok.cpp | 2 +- engines/kyra/gui_lol.cpp | 67 +++- engines/kyra/items_lol.cpp | 70 ++-- engines/kyra/kyra_v1.h | 10 +- engines/kyra/lol.cpp | 891 +++++++++++++++++++++++++++++++++++++---- engines/kyra/lol.h | 185 +++++---- engines/kyra/resource.h | 2 + engines/kyra/saveload_lok.cpp | 2 +- engines/kyra/scene_lol.cpp | 20 +- engines/kyra/screen.cpp | 58 ++- engines/kyra/screen.h | 2 + engines/kyra/screen_lol.cpp | 127 ++++-- engines/kyra/screen_lol.h | 39 +- engines/kyra/screen_v2.cpp | 3 +- engines/kyra/script_lol.cpp | 187 ++++++--- engines/kyra/script_tim.cpp | 4 +- engines/kyra/script_tim.h | 4 +- engines/kyra/sequences_lol.cpp | 61 ++- engines/kyra/sound.h | 8 +- engines/kyra/sound_towns.cpp | 59 ++- engines/kyra/sprites_lol.cpp | 226 +++++++---- engines/kyra/staticres.cpp | 193 ++++----- engines/kyra/timer.cpp | 2 +- engines/kyra/timer_lol.cpp | 111 ++++- engines/kyra/wsamovie.cpp | 13 +- 26 files changed, 1851 insertions(+), 575 deletions(-) (limited to 'engines') diff --git a/engines/kyra/detection.cpp b/engines/kyra/detection.cpp index c84dbb9434..dd5162e56e 100644 --- a/engines/kyra/detection.cpp +++ b/engines/kyra/detection.cpp @@ -43,36 +43,35 @@ struct KYRAGameDescription { namespace { -#define FLAGS(x, y, z, a, b, c, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, id } -#define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, id } - -#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA1) -#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, false, Kyra::GI_KYRA1) -#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, false, Kyra::GI_KYRA1) -#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA1) - -#define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_KYRA2) -#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_KYRA2) -#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, false, Kyra::GI_KYRA2) - -#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, true, true, Kyra::GI_KYRA3) -#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, true, false, Kyra::GI_KYRA3) -#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, true, false, Kyra::GI_KYRA3) - -#define LOL_CD_FLAGS FLAGS(false, false, true, false, false, false, Kyra::GI_LOL) -#define LOL_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_LOL) -#define LOL_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, true, Kyra::GI_LOL) -#define LOL_PC98_FLAGS FLAGS(false, false, false, false, false, false, Kyra::GI_LOL) -#define LOL_PC98_SJIS_FLAGS FLAGS(false, false, false, true, false, false, Kyra::GI_LOL) -#define LOL_DEMO_FLAGS FLAGS(true, false, false, false, false, false, Kyra::GI_KYRA2) +#define FLAGS(x, y, z, a, b, c, d, id) { Common::UNK_LANG, Common::UNK_LANG, Common::UNK_LANG, Common::kPlatformUnknown, x, y, z, a, b, c, d, id } +#define FLAGS_FAN(fanLang, repLang, x, y, z, a, b, c, d, id) { Common::UNK_LANG, fanLang, repLang, Common::kPlatformUnknown, x, y, z, a, b, c, d, id } + +#define KYRA1_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, true, Kyra::GI_KYRA1) +#define KYRA1_AMIGA_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_TOWNS_FLAGS FLAGS(false, true, false, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_TOWNS_SJIS_FLAGS FLAGS(false, true, false, true, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_CD_FLAGS FLAGS(false, true, true, false, false, false, false, Kyra::GI_KYRA1) +#define KYRA1_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, Kyra::GI_KYRA1) + +#define KYRA2_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, true, Kyra::GI_KYRA2) +#define KYRA2_CD_FLAGS FLAGS(false, false, true, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_CD_DEMO_FLAGS FLAGS(true, false, true, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_KYRA2) +#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, false, false, false, Kyra::GI_KYRA2) + +#define KYRA3_CD_FLAGS FLAGS(false, false, true, false, false, true, true, Kyra::GI_KYRA3) +#define KYRA3_CD_INS_FLAGS FLAGS(false, false, true, false, false, true, false, Kyra::GI_KYRA3) +#define KYRA3_CD_FAN_FLAGS(x, y) FLAGS_FAN(x, y, false, false, true, false, false, true, false, Kyra::GI_KYRA3) + +#define LOL_CD_FLAGS FLAGS(false, false, true, false, false, false, false, Kyra::GI_LOL) +#define LOL_FLOPPY_FLAGS FLAGS(false, false, false, false, false, false, false, Kyra::GI_LOL) +#define LOL_FLOPPY_CMP_FLAGS FLAGS(false, false, false, false, false, false, true, Kyra::GI_LOL) +#define LOL_PC98_SJIS_FLAGS FLAGS(false, false, false, true, true, false, false, Kyra::GI_LOL) +#define LOL_DEMO_FLAGS FLAGS(true, false, false, false, false, false, false, Kyra::GI_KYRA2) const KYRAGameDescription adGameDescs[] = { /* disable these targets until they get supported @@ -1020,23 +1019,6 @@ const KYRAGameDescription adGameDescs[] = { LOL_FLOPPY_FLAGS }, - /* disable these targets until they get supported - { - { - "lol", - 0, - { - { "GENERAL.PAK", 0, "3fe6539b9b09084c0984eaf7170464e9", -1 }, - { "MUS.PAK", 0, "008dc69d8cbcdb6bae30e270fab26e76", -1 }, - { 0, 0, 0, 0 } - }, - Common::EN_ANY, - Common::kPlatformPC98, - ADGF_NO_FLAGS - }, - LOL_PC98_FLAGS - }, - { { "lol", @@ -1051,7 +1033,7 @@ const KYRAGameDescription adGameDescs[] = { ADGF_NO_FLAGS }, LOL_PC98_SJIS_FLAGS - },*/ + }, { { @@ -1069,7 +1051,7 @@ const KYRAGameDescription adGameDescs[] = { }, #endif // ENABLE_LOL - { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0) } + { AD_TABLE_END_MARKER, FLAGS(0, 0, 0, 0, 0, 0, 0, 0) } }; const PlainGameDescriptor gameList[] = { diff --git a/engines/kyra/gui_lok.cpp b/engines/kyra/gui_lok.cpp index 665c38115b..baf39c0954 100644 --- a/engines/kyra/gui_lok.cpp +++ b/engines/kyra/gui_lok.cpp @@ -962,7 +962,7 @@ int GUI_LoK::controlsChangeMusic(Button *button) { debugC(9, kDebugLevelGUI, "GUI_LoK::controlsChangeMusic()"); updateMenuButton(button); - _vm->_configMusic = ++_vm->_configMusic % ((_vm->gameFlags().platform == Common::kPlatformFMTowns || _vm->gameFlags().platform == Common::kPlatformPC98) ? 3 : 2); + _vm->_configMusic = ++_vm->_configMusic % (_vm->gameFlags().platform == Common::kPlatformFMTowns ? 3 : 2); setupControls(_menu[5]); return 0; } diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp index 30e0ec7c15..2769692a65 100644 --- a/engines/kyra/gui_lol.cpp +++ b/engines/kyra/gui_lol.cpp @@ -473,7 +473,7 @@ void LoLEngine::gui_drawLiveMagicBar(int x, int y, int curPoints, int unk, int m int barHeight = (curPoints * h) / maxPoints; - if (barHeight < 1 && curPoints < 1) + if (barHeight < 1 && curPoints > 0) barHeight = 1; _screen->drawClippedLine(x - 1, y - h, x - 1, y, 1); @@ -1037,6 +1037,46 @@ int LoLEngine::clickedTurnRightArrow(Button *button) { } int LoLEngine::clickedAttackButton(Button *button) { + int c = button->data2Val2; + + if (_characters[c].flags & 0x314C) + return 1; + + int bl = calcNewBlockPosition(_currentBlock, _currentDirection); + + if (_levelBlockProperties[bl].flags & 0x10) { + attackWall(0, 0); + return 1; + } + + uint16 target = getNearestMonsterFromCharacter(c); + int s = 0; + + for (int i = 0; i < 4; i++) { + if (!_characters[c].items[i]) + continue; + + runItemScript(c, _characters[c].items[i], 0x400, target, s); + runLevelScriptCustom(_currentBlock, 0x400, c, _characters[c].items[i], target, s); + s -= 10; + } + + if (!s) { + runItemScript(c, 0, 0x400, target, s); + runLevelScriptCustom(_currentBlock, 0x400, c, 0, target, s); + } + + s = _characters[c].weaponHit ? 4 : calcMonsterSkillLevel(c, 8) + 4; + + // check for Zephyr ring + if (itemEquipped(c, 230)) + s >>= 1; + + _characters[c].flags |= 4; + gui_highlightPortraitFrame(c); + + setCharacterUpdateEvent(c, 1, s, 1); + return 1; } @@ -1074,7 +1114,7 @@ int LoLEngine::clickedMagicSubmenu(Button *button) { // TODO /// /*if (processSpellcast(c, _availableSpells[_selectedSpell], spellLevel)) { - setFaceFramesUnkArrays(c, 1, 8, 1); + setCharacterUpdateEvent(c, 1, 8, 1); sub_718F(c, 2, spellLevel * spellLevel); } else {*/ _characters[c].flags &= 0xfffb; @@ -1130,6 +1170,23 @@ int LoLEngine::clickedLiveMagicBarsLeft(Button *button) { } int LoLEngine::clickedPortraitEtcRight(Button *button) { + if (!_itemInHand) + return 1; + + int flg = _itemProperties[_itemsInPlay[_itemInHand].itemPropertyIndex].flags; + int c = button->data2Val2; + + if (flg & 1) { + if (!(_characters[c].flags & 8) || (flg & 0x20)) { + runItemScript(c, _itemInHand, 0x400, 0, 0); + runLevelScriptCustom(_currentBlock, 0x400, c, _itemInHand, 0, 0); + } else { + _txt->printMessage(2, getLangString(0x402c), _characters[c].name); + } + return 1; + } + + _txt->printMessage(2, getLangString((flg & 8) ? 0x4029 : ((flg & 0x10) ? 0x402a : 0x402b))); return 1; } @@ -1389,8 +1446,10 @@ int LoLEngine::clickedWall(Button *button) { int LoLEngine::clickedSequenceWindow(Button *button) { runLevelScript(calcNewBlockPosition(_currentBlock, _currentDirection), 0x40); - if (!_seqTrigger || !posWithinRect(_mouseX, _mouseY, _seqWindowX1, _seqWindowY1, _seqWindowX2, _seqWindowY2)) + if (!_seqTrigger || !posWithinRect(_mouseX, _mouseY, _seqWindowX1, _seqWindowY1, _seqWindowX2, _seqWindowY2)) { _seqTrigger = 0; + removeInputTop(); + } return 1; } @@ -1418,7 +1477,7 @@ int LoLEngine::clickedSceneThrowItem(Button *button) { uint16 y = 0; calcCoordinates(x, y, _currentBlock, 0x80, 0x80); - if (throwItem(0, _itemInHand, x, y, 12, _currentDirection << 1, 6, _selectedCharacter, 0x3f)) { + if (launchObject(0, _itemInHand, x, y, 12, _currentDirection << 1, 6, _selectedCharacter, 0x3f)) { snd_playSoundEffect(18, -1); setHandItem(0); } diff --git a/engines/kyra/items_lol.cpp b/engines/kyra/items_lol.cpp index 64a6850fcb..02c8e50410 100644 --- a/engines/kyra/items_lol.cpp +++ b/engines/kyra/items_lol.cpp @@ -181,14 +181,14 @@ int LoLEngine::makeItem(int itemType, int curFrame, int flags) { void LoLEngine::placeMoveLevelItem(int itemIndex, int level, int block, int xOffs, int yOffs, int flyingHeight) { calcCoordinates(_itemsInPlay[itemIndex].x, _itemsInPlay[itemIndex].y, block, xOffs, yOffs); - if (_itemsInPlay[itemIndex].blockPropertyIndex) - removeLevelItem(itemIndex, _itemsInPlay[itemIndex].blockPropertyIndex); + if (_itemsInPlay[itemIndex].block) + removeLevelItem(itemIndex, _itemsInPlay[itemIndex].block); if (_currentLevel == level) { setItemPosition(itemIndex, _itemsInPlay[itemIndex].x, _itemsInPlay[itemIndex].y, flyingHeight, 1); } else { _itemsInPlay[itemIndex].level = level; - _itemsInPlay[itemIndex].blockPropertyIndex = block; + _itemsInPlay[itemIndex].block = block; _itemsInPlay[itemIndex].flyingHeight = flyingHeight; _itemsInPlay[itemIndex].shpCurFrame_flg |= 0x4000; } @@ -289,6 +289,24 @@ void LoLEngine::setHandItem(uint16 itemIndex) { _screen->setMouseCursor(mouseOffs, mouseOffs, getItemIconShapePtr(itemIndex)); } +bool LoLEngine::itemEquipped(int charNum, uint16 itemType) { + if (charNum < 0 || charNum > 3) + return false; + + if (!(_characters[charNum].flags & 1)) + return false; + + for (int i = 0; i < 11; i++) { + if (!_characters[charNum].items[i]) + continue; + + if (_itemsInPlay[_characters[charNum].items[i]].itemPropertyIndex == itemType) + return true; + } + + return false; +} + void LoLEngine::setItemPosition(int item, uint16 x, uint16 y, int flyingHeight, int b) { if (!flyingHeight) { x = (x & 0xffc0) | 0x40; @@ -298,7 +316,7 @@ void LoLEngine::setItemPosition(int item, uint16 x, uint16 y, int flyingHeight, uint16 block = calcBlockIndex(x, y); _itemsInPlay[item].x = x; _itemsInPlay[item].y = y; - _itemsInPlay[item].blockPropertyIndex = block; + _itemsInPlay[item].block = block; _itemsInPlay[item].flyingHeight = flyingHeight; if (b) @@ -320,12 +338,12 @@ void LoLEngine::removeLevelItem(int item, int block) { removeAssignedObjectFromBlock(&_levelBlockProperties[block], item); removeDrawObjectFromBlock(&_levelBlockProperties[block], item); runLevelScriptCustom(block, 0x100, -1, item, 0, 0); - _itemsInPlay[item].blockPropertyIndex = 0; + _itemsInPlay[item].block = 0; _itemsInPlay[item].level = 0; } -bool LoLEngine::throwItem(int a, int item, int x, int y, int flyingHeight, int direction, int, int charNum, int c) { - int sp = checkDrawObjectSpace(_partyPosX, _partyPosX, x, y); +bool LoLEngine::launchObject(int objectType, int item, int startX, int startY, int flyingHeight, int direction, int, int attackerId, int c) { + int sp = checkDrawObjectSpace(_partyPosX, _partyPosX, startX, startY); FlyingObject *t = _flyingObjects; int slot = -1; int i = 0; @@ -348,31 +366,31 @@ bool LoLEngine::throwItem(int a, int item, int x, int y, int flyingHeight, int d i = slot; t = &_flyingObjects[i]; - endObjectFlight(t, x, y, 8); + endObjectFlight(t, startX, startY, 8); } if (i == 8) return false; t->enable = 1; - t->a = a; + t->objectType = objectType; t->item = item; - t->x = x; - t->y = y; + t->x = startX; + t->y = startY; t->flyingHeight = flyingHeight; t->direction = direction; t->distance = 255; - t->charNum = charNum; + t->attackerId = attackerId; t->flags = 7; t->wallFlags = 2; t->c = c; - if (charNum != -1) { - if (charNum & 0x8000) { + if (attackerId != -1) { + if (attackerId & 0x8000) { t->flags &= 0xfd; } else { t->flags &= 0xfb; - increaseExperience(charNum, 1, 2); + increaseExperience(attackerId, 1, 2); } } @@ -393,7 +411,7 @@ void LoLEngine::endObjectFlight(FlyingObject *t, int x, int y, int objectOnNextB cy = t->y; } - if (t->a == 0 || t->a == 1) { + if (t->objectType == 0 || t->objectType == 1) { objectFlightProcessHits(t, cx, cy, objectOnNextBlock); t->x = (cx & 0xffc0) | 0x40; t->y = (cy & 0xffc0) | 0x40; @@ -416,9 +434,9 @@ void LoLEngine::processObjectFlight(FlyingObject *t, int x, int y) { } void LoLEngine::updateObjectFlightPosition(FlyingObject *t) { - if (t->a == 0) { + if (t->objectType == 0) { setItemPosition(t->item, t->x, t->y, t->flyingHeight, (t->flyingHeight == 0) ? 1 : 0); - } else if (t->a == 1) { + } else if (t->objectType == 1) { if (t->flyingHeight == 0) { deleteItem(t->item); checkSceneUpdateNeed(calcBlockIndex(t->x, t->y)); @@ -432,23 +450,23 @@ void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int objec uint16 r = 0; if (objectOnNextBlock == 1) { - runLevelScriptCustom(calcNewBlockPosition(_itemsInPlay[t->item].blockPropertyIndex, t->direction >> 1), 0x8000, -1, t->item, 0, 0); + runLevelScriptCustom(calcNewBlockPosition(_itemsInPlay[t->item].block, t->direction >> 1), 0x8000, -1, t->item, 0, 0); return; } else if (objectOnNextBlock == 2) { if (_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000) { - int o = _levelBlockProperties[_itemsInPlay[t->item].blockPropertyIndex].assignedObjects; + int o = _levelBlockProperties[_itemsInPlay[t->item].block].assignedObjects; while (o & 0x8000) { ItemInPlay *i = findObject(o); o = i->nextAssignedObject; - runItemScript(t->charNum, t->item, 0x8000, o, 0); + runItemScript(t->attackerId, t->item, 0x8000, o, 0); } return; } else { - r = getClosestMonster(x, y); + r = getNearestMonsterFromPos(x, y); } } else if (objectOnNextBlock == 4) { @@ -456,19 +474,19 @@ void LoLEngine::objectFlightProcessHits(FlyingObject *t, int x, int y, int objec if (_itemProperties[_itemsInPlay[t->item].itemPropertyIndex].flags & 0x4000) { for (int i = 0; i < 4; i++) { if (_characters[i].flags & 1) - runItemScript(t->charNum, t->item, 0x8000, i, 0); + runItemScript(t->attackerId, t->item, 0x8000, i, 0); } return; } else { - r = getClosestPartyMember(x, y); + r = getNearestPartyMemberFromPos(x, y); } } - runItemScript(t->charNum, t->item, 0x8000, r, 0); + runItemScript(t->attackerId, t->item, 0x8000, r, 0); } -void LoLEngine::updateFlyingObjects(FlyingObject *t) { +void LoLEngine::updateFlyingObject(FlyingObject *t) { int x = 0; int y = 0; getNextStepCoords(t->x, t->y, x, y, t->direction); diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 527739f19f..148da506c4 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -56,6 +56,7 @@ struct GameFlags { bool useAltShapeHeader : 1; // alternative shape header (uses 2 bytes more, those are unused though) bool isTalkie : 1; bool useHiResOverlay : 1; + bool use16ColorMode : 1; bool useDigSound : 1; bool useInstallerPackage : 1; @@ -70,10 +71,11 @@ enum { }; struct AudioDataStruct { - const char * const *_fileList; - int _fileListLen; - const void * _cdaTracks; - int _cdaNumTracks; + const char *const *fileList; + int fileListLen; + const void *cdaTracks; + int cdaNumTracks; + int extraOffset; }; // TODO: this is just the start of makeing the debug output of the kyra engine a bit more useable diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 9093c63dc9..a05003ffbd 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -63,6 +63,9 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _lang = 2; break; + case Common::JA_JPN: + _lang = 0; + default: warning("unsupported language, switching back to English"); _lang = 0; @@ -91,13 +94,14 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _specialSceneFlag = 0; _lastCharInventory = -1; - _itemIconShapes = _itemShapes = _gameShapes = _thrownShapes = _effectShapes = _fireballShapes = 0; + _itemIconShapes = _itemShapes = _gameShapes = _thrownShapes = _effectShapes = _fireballShapes = _healShapes = _healiShapes = 0; _levelShpList = _levelDatList = 0; _monsterShapes = _monsterPalettes = 0; _monsterShapesEx = 0; _gameShapeMap = 0; memset(_monsterUnk, 0, 3); _pageSavedFlag = false; + _healOverlay = 0; _ingameMT32SoundIndex = _ingameGMSoundIndex = /*_ingameADLSoundIndex =*/ 0; @@ -181,7 +185,11 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _curMusicTheme = -1; _curMusicFileExt = 0; _curMusicFileIndex = -1; - _environmentSfx = _environmentSfxVol = _environmentSfxDistThreshold = 0; + _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; @@ -198,7 +206,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy memset(_charStatsTemp, 0, sizeof(_charStatsTemp)); - _compassBroken = _unkBt2 = 0; + _compassBroken = _drainMagic = 0; _dialogueField = false; _rndSpecial = 0x12349876; @@ -220,6 +228,8 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _defaultLegendData = 0; _compassTimer = 0; + _timer3Para = 0; + _partyDeathFlag = -1; } LoLEngine::~LoLEngine() { @@ -250,32 +260,49 @@ LoLEngine::~LoLEngine() { delete[] _itemIconShapes[i]; delete[] _itemIconShapes; } + if (_itemShapes) { for (int i = 0; i < _numItemShapes; i++) delete[] _itemShapes[i]; delete[] _itemShapes; } + if (_gameShapes) { for (int i = 0; i < _numGameShapes; i++) delete[] _gameShapes[i]; delete[] _gameShapes; } + if (_thrownShapes) { for (int i = 0; i < _numThrownShapes; i++) delete[] _thrownShapes[i]; delete[] _thrownShapes; } + if (_effectShapes) { for (int i = 0; i < _numEffectShapes; i++) delete[] _effectShapes[i]; delete[] _effectShapes; } + if (_fireballShapes) { for (int i = 0; i < _numFireballShapes; i++) delete[] _fireballShapes[i]; delete[] _fireballShapes; } + if (_healShapes) { + for (int i = 0; i < _numHealShapes; i++) + delete[] _healShapes[i]; + delete[] _healShapes; + } + + if (_healiShapes) { + for (int i = 0; i < _numHealiShapes; i++) + delete[] _healiShapes[i]; + delete[] _healiShapes; + } + if (_monsterShapes) { for (int i = 0; i < 48; i++) delete[] _monsterShapes[i]; @@ -357,6 +384,8 @@ LoLEngine::~LoLEngine() { } } + delete[] _healOverlay; + delete[] _defaultLegendData; delete[] _mapCursorOverlay; delete[] _mapOverlay; @@ -378,7 +407,7 @@ Common::Error LoLEngine::init() { KyraEngine_v1::init(); initStaticResource(); - _environmentSfxDistThreshold = (MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB) == MD_ADLIB || ConfMan.getBool("multi_midi")) ? 15 : 3; + _envSfxDistThreshold = (MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB) == MD_ADLIB || ConfMan.getBool("multi_midi")) ? 15 : 3; _gui = new GUI_LoL(this); assert(_gui); @@ -475,6 +504,7 @@ Common::Error LoLEngine::init() { Common::Error LoLEngine::go() { setupPrologueData(true); + _sound->setSoundList(&_soundData[kMusicIntro]); if (!saveFileLoadable(0)) showIntro(); @@ -532,7 +562,7 @@ Common::Error LoLEngine::go() { return Common::kNoError; if (processSelection == 0) { - _sound->loadSoundFile("LOREINTR"); + _sound->loadSoundFile(0); _sound->playTrack(6); chooseCharacter(); _sound->playTrack(1); @@ -541,6 +571,9 @@ Common::Error LoLEngine::go() { setupPrologueData(false); + _sound->setSoundList(&_soundData[kMusicIngame]); + _sound->loadSoundFile(0); + _tim = new TIMInterpreter_LoL(this, _screen, _system); assert(_tim); @@ -637,15 +670,27 @@ int LoLEngine::mainMenu() { bool hasSave = saveFileLoadable(0); - MainMenu::StaticData data = { - { 0, 0, 0, 0, 0 }, - { 0x01, 0x04, 0x0C, 0x04, 0x00, 0x3D, 0x9F }, - { 0x2C, 0x19, 0x48, 0x2C }, - Screen::FID_9_FNT, 1 + MainMenu::StaticData data[] = { + // 256 color mode + { + { 0, 0, 0, 0, 0 }, + { 0x01, 0x04, 0x0C, 0x04, 0x00, 0x3D, 0x9F }, + { 0x2C, 0x19, 0x48, 0x2C }, + Screen::FID_9_FNT, 1 + }, + // 16 color mode + { + { 0, 0, 0, 0, 0 }, + { 0x01, 0x04, 0x0C, 0x03, 0x00, 0xC1, 0xE1 }, + { 0xCC, 0xDD, 0xDD, 0xDD }, + Screen::FID_9_FNT, 1 + } }; + int dataIndex = _flags.use16ColorMode ? 1 : 0; + if (hasSave) - ++data.menuTable[3]; + ++data[dataIndex].menuTable[3]; static const uint16 mainMenuStrings[4][5] = { { 0x4248, 0x4249, 0x42DD, 0x424A, 0x0000 }, @@ -658,14 +703,14 @@ int LoLEngine::mainMenu() { for (int i = 0; i < 5; ++i) { if (hasSave) - data.strings[i] = getLangString(mainMenuStrings[1 + tableOffs][i]); + data[dataIndex].strings[i] = getLangString(mainMenuStrings[1 + tableOffs][i]); else - data.strings[i] = getLangString(mainMenuStrings[tableOffs][i]); + data[dataIndex].strings[i] = getLangString(mainMenuStrings[tableOffs][i]); } MainMenu *menu = new MainMenu(this); assert(menu); - menu->init(data, MainMenu::Animation()); + menu->init(data[dataIndex], MainMenu::Animation()); int selection = menu->handle(_flags.isTalkie ? (hasSave ? 12 : 6) : (hasSave ? 6 : 13)); delete menu; @@ -735,6 +780,20 @@ void LoLEngine::startup() { 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]; + 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]; + for (int i = 0; i < _numHealiShapes; i++) + _healiShapes[i] = _screen->makeShapeCopy(shp, i); + memset(_itemsInPlay, 0, 400 * sizeof(ItemInPlay)); for (int i = 0; i < 400; i++) _itemsInPlay[i].shpCurFrame_flg |= 0x8000; @@ -814,10 +873,10 @@ void LoLEngine::runLoop() { else updateEnvironmentalSfx(0); - /*if (_partyDeathFlag != -1) { - checkForPartyDeath(_partyDeathFlag); + if (_partyDeathFlag != -1) { + checkForPartyDeath(); _partyDeathFlag = -1; - }*/ + } delay(_tickLength); } @@ -864,8 +923,12 @@ char *LoLEngine::getLangString(uint16 id) { char *string = (char *)getTableEntry(buffer, realId); char *srcBuffer = _stringBuffer[_lastUsedStringBuffer]; - Util::decodeString1(string, srcBuffer); - Util::decodeString2(srcBuffer, srcBuffer); + if (_flags.lang != Common::JA_JPN) { + Util::decodeString1(string, srcBuffer); + Util::decodeString2(srcBuffer, srcBuffer); + } else { + decodeSjis(string, srcBuffer); + } ++_lastUsedStringBuffer; _lastUsedStringBuffer %= ARRAYSIZE(_stringBuffer); @@ -881,6 +944,36 @@ uint8 *LoLEngine::getTableEntry(uint8 *buffer, uint16 id) { return buffer + READ_LE_UINT16(buffer + (id<<1)); } +void LoLEngine::decodeSjis(const char *src, char *dst) { + char s[2]; + char d[3]; + s[1] = 0; + + uint8 cmd = *src++; + + while (cmd) { + if (cmd == 27) { + cmd = *src & 0x7f; + src++; + + for (int i = 0; i < cmd; i ++) { + *dst++ = *src++; + *dst++ = *src++; + } + cmd = *src++; + + } else { + s[0] = *src++; + Util::decodeString1(s, d); + *dst++ = d[0]; + cmd = *src++; + } + } + + if (!cmd) + *dst = 0; +} + bool LoLEngine::addCharacter(int id) { const uint16 *cdf[] = { _charDefsMan, _charDefsMan, _charDefsMan, _charDefsWoman, _charDefsMan, _charDefsMan, _charDefsWoman, _charDefsKieran, _charDefsAkshel }; @@ -913,29 +1006,30 @@ bool LoLEngine::addCharacter(int id) { calcCharPortraitXpos(); if (numChars > 0) - setFaceFrames(numChars, 2, 6, 0); + setTemporaryFaceFrame(numChars, 2, 6, 0); return true; } -void LoLEngine::setFaceFrames(int charNum, int defaultFrame, int unk2, int redraw) { - _characters[charNum].defaultFaceFrame = defaultFrame; - if (defaultFrame || unk2) - setFaceFramesUnkArrays(charNum, 6, unk2, 1); +void LoLEngine::setTemporaryFaceFrame(int charNum, int frame, int updateDelay, int redraw) { + _characters[charNum].defaultFaceFrame = frame; + if (frame || updateDelay) + setCharacterUpdateEvent(charNum, 6, updateDelay, 1); if (redraw) gui_drawCharPortraitWithStats(charNum); } -void LoLEngine::setFaceFramesUnkArrays(int charNum, int unk1, int unk2, int unk3) { +void LoLEngine::setCharacterUpdateEvent(int charNum, int updateType, int updateDelay, int overwrite) { LoLCharacter *l = &_characters[charNum]; for (int i = 0; i < 5; i++) { - if (l->arrayUnk2[i] && (!unk3 || l->arrayUnk2[i] != unk1)) + if (l->characterUpdateEvents[i] && (!overwrite || l->characterUpdateEvents[i] != updateType)) continue; - l->arrayUnk2[i] = unk1; - l->arrayUnk1[i] = unk2; + l->characterUpdateEvents[i] = updateType; + l->characterUpdateDelay[i] = updateDelay; _timer->setNextRun(3, _system->getMillis()); _timer->enable(3); + break; } } @@ -1057,10 +1151,10 @@ void LoLEngine::setCharFaceFrame(int charNum, int frameNum) { void LoLEngine::faceFrameRefresh(int charNum) { if (_characters[charNum].curFaceFrame == 1) - setFaceFrames(charNum, 0, 0, 0); + setTemporaryFaceFrame(charNum, 0, 0, 0); else if (_characters[charNum].curFaceFrame == 6) if (_characters[charNum].defaultFaceFrame != 5) - setFaceFrames(charNum, 0, 0, 0); + setTemporaryFaceFrame(charNum, 0, 0, 0); else _characters[charNum].curFaceFrame = 5; else @@ -1114,7 +1208,7 @@ int LoLEngine::calculateProtection(int index) { c = (_monsters[index].properties->itemProtection * _monsters[index].properties->fightingStats[2]) >> 8; } else { // Character - c = _characters[index].itemsProtection + _characters[index].protection; + c = _characters[index].itemProtection + _characters[index].protection; c = (c * _characters[index].defaultModifiers[2]) >> 8; c = (c * _characters[index].totalProtectionModifier) >> 8; } @@ -1122,6 +1216,74 @@ int LoLEngine::calculateProtection(int index) { return c; } +void LoLEngine::setCharacterMagicOrHitPoints(int charNum, int type, int points, int mode) { + static const uint16 barData[2][5] = { + // xPos, bar color, text color, flag, string id + { 0x27, 0x9A, 0x98, 0x01, 0x4254 }, + { 0x21, 0xA2, 0xA0, 0x00, 0x4253 } + }; + + LoLCharacter *c = &_characters[charNum]; + if (!(c->flags & 1)) + return; + + int pointsMax = type ? c->magicPointsMax : c->hitPointsMax; + int pointsCur = type ? c->magicPointsCur : c->hitPointsCur; + + int newVal = (mode == 2) ? (pointsMax + points) : (mode ? (pointsCur + points) : points); + newVal = CLIP(newVal, 0, pointsMax); + + if (type) { + c->magicPointsCur = newVal; + } else { + c->hitPointsCur = newVal; + if (c->hitPointsCur < 1) + c->flags |= 8; + } + + if (_updateFlags & 2) + return; + + Screen::FontId cf = _screen->setFont(Screen::FID_6_FNT); + int cp = _screen->setCurPage(0); + + int s = 8192 / pointsMax; + pointsMax = (s * pointsMax) >> 8; + pointsCur = (s * pointsCur) >> 8; + newVal = (s * newVal) >> 8; + int newValScl = CLIP(newVal, 0, pointsMax); + + int step = (newVal > pointsCur) ? 2 : -2; + newVal = CLIP(newVal + step, 0, pointsMax); + + if (newVal != pointsCur) { + step = (newVal >= pointsCur) ? 2 : -2; + + for (int i = pointsCur; i != newVal || newVal != newValScl;) { + if (ABS(i - newVal) < ABS(step)) + step >>= 1; + + i += step; + + _smoothScrollTimer = _system->getMillis() + _tickLength; + + gui_drawLiveMagicBar(barData[type][0] + _activeCharsXpos[charNum], 175, i, 0, pointsMax, 5, 32, barData[type][1], 1, barData[type][3]); + _screen->printText(getLangString(barData[type][4]), barData[type][0] + _activeCharsXpos[charNum], 144, barData[type][2], 0); + _screen->updateScreen(); + + if (i == newVal) { + newVal = newValScl; + step = -step; + } + + delayUntil(_smoothScrollTimer); + } + } + + _screen->setFont(cf); + _screen->setCurPage(cp); +} + void LoLEngine::increaseExperience(int charNum, int skill, uint32 points) { if (charNum & 0x8000) return; @@ -1174,6 +1336,17 @@ void LoLEngine::increaseExperience(int charNum, int skill, uint32 points) { } } +void LoLEngine::increaseCharacterHitpoints(int charNum, int points, bool ignoreDeath) { + if (_characters[charNum].hitPointsCur <= 0 && !ignoreDeath) + return; + + if (points <= 1) + points = 1; + + _characters[charNum].hitPointsCur = CLIP(_characters[charNum].hitPointsCur + points, 1, _characters[charNum].hitPointsMax); + _characters[charNum].flags &= 0xfff7; +} + void LoLEngine::setupScreenDims() { if (textEnabled()) { _screen->modifyScreenDim(4, 11, 124, 28, 45); @@ -1590,7 +1763,7 @@ void LoLEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) { int dist = 0; if (block) { dist = getMonsterDistance(_currentBlock, block); - if (dist > _environmentSfxDistThreshold) { + if (dist > _envSfxDistThreshold) { _environmentSfx = 0; return; } @@ -1619,6 +1792,16 @@ void LoLEngine::snd_processEnvironmentalSoundEffect(int soundId, int block) { snd_processEnvironmentalSoundEffect(0, 0); } +void LoLEngine::snd_queueEnvironmentalSoundEffect(int soundId, int block) { + if (_envSfxUseQueue && _envSfxNumTracksInQueue < 10) { + _envSfxQueuedTracks[_envSfxNumTracksInQueue] = soundId; + _envSfxQueuedBlocks[_envSfxNumTracksInQueue] = block; + _envSfxNumTracksInQueue++; + } else { + snd_processEnvironmentalSoundEffect(soundId, block); + } +} + void LoLEngine::snd_loadSoundFile(int track) { if (_sound->musicEnabled()) { char filename[13]; @@ -1781,6 +1964,14 @@ const uint16 *LoLEngine::getCharacterOrMonsterStats(int id) { return (id & 0x8000) ? (const uint16*)_monsters[id & 0x7fff].properties->fightingStats : _characters[id].defaultModifiers; } +uint16 *LoLEngine::getCharacterOrMonsterItemsMight(int id) { + return (id & 0x8000) ? _monsters[id & 0x7fff].properties->itemsMight : _characters[id].itemsMight; +} + +uint16 *LoLEngine::getCharacterOrMonsterProtectionAgainstItems(int id) { + return (id & 0x8000) ? _monsters[id & 0x7fff].properties->protectionAgainstItems : _characters[id].protectionAgainstItems; +} + void LoLEngine::delay(uint32 millis, bool cUpdate, bool isMainLoop) { uint32 endTime = _system->getMillis() + millis; while (endTime > _system->getMillis()) { @@ -1820,6 +2011,120 @@ void LoLEngine::updateEnvironmentalSfx(int soundId) { snd_processEnvironmentalSoundEffect(soundId, _currentBlock); } +void LoLEngine::processMagicHeal(int charNum, int points) { + if (!_healOverlay) { + _healOverlay = new uint8[256]; + _screen->generateGrayOverlay(_screen->getPalette(1), _healOverlay, 52, 22, 20, 0, 256, true); + } + + const uint8 *healShpFrames = 0; + const uint8 *healiShpFrames = 0; + bool resetFlag = false; + int maxDiff = 0; + + if (points == 0) { + maxDiff = 25; + healShpFrames = _healShapeFrames; + healiShpFrames = _healShapeFrames + 32; + + } else if (points == 1) { + maxDiff = 45; + healShpFrames = _healShapeFrames + 16; + healiShpFrames = _healShapeFrames + 48; + + } else if (points > 3) { + resetFlag = true; + maxDiff = points; + healShpFrames = _healShapeFrames + 16; + healiShpFrames = _healShapeFrames + 64; + + } else { + resetFlag = true; + maxDiff = 10000; + healShpFrames = _healShapeFrames + 16; + healiShpFrames = _healShapeFrames + 64; + + } + + int ch = 0; + int n = 4; + + if (charNum != -1){ + ch = charNum; + n = charNum + 1; + } + + charNum = ch; + + uint16 pX[4]; + uint16 pY = 138; + uint16 diff[4]; + uint16 pts[4]; + memset(pts, 0, sizeof(pts)); + + while (charNum < n) { + if (!(_characters[charNum].flags & 1)) + continue; + + pX[charNum] = _activeCharsXpos[charNum] - 6; + _characters[charNum].damageSuffered = 0; + int dmg = _characters[charNum].hitPointsMax - _characters[charNum].hitPointsCur; + diff[charNum] = (dmg < maxDiff) ? dmg : maxDiff; + _screen->copyRegion(pX[charNum], pY, charNum * 77, 32, 77, 44, 0, 2, Screen::CR_NO_P_CHECK); + charNum++; + } + + int cp = _screen->setCurPage(2); + snd_playSoundEffect(68, -1); + + for (int i = 0; i < 16; i++) { + _smoothScrollTimer = _system->getMillis() + 4 * _tickLength; + + for (charNum = ch; charNum < n; charNum++) { + if (!(_characters[charNum].flags & 1)) + continue; + + _screen->copyRegion(charNum * 77, 32, pX[charNum], pY, 77, 44, 2, 2, Screen::CR_NO_P_CHECK); + + pts[charNum] &= 0xff; + pts[charNum] += ((diff[charNum] << 8) / 16); + increaseCharacterHitpoints(ch, pts[charNum] / 256, true); + gui_drawCharPortraitWithStats(charNum); + + _screen->drawShape(2, _healShapes[healShpFrames[i]], pX[charNum], pY, 0, 0x1000, _trueLightTable1, _trueLightTable2); + _screen->fillRect(0, 0, 31, 31, 0); + + _screen->drawShape(_screen->_curPage, _healiShapes[healiShpFrames[i]], 0, 0, 0, 0); + _screen->applyOverlaySpecial(_screen->_curPage, 0, 0, 2, pX[charNum] + 7, pY + 6, 32, 32, 0, 0, _healOverlay); + + _screen->copyRegion(pX[charNum], pY, pX[charNum], pY, 77, 44, 2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + } + + while ((int)(_smoothScrollTimer - _system->getMillis()) > 0) { + updateInput(); + delay(_tickLength); + } + } + + for (charNum = ch; charNum < n; charNum++) { + if (!(_characters[charNum].flags & 1)) + continue; + + _screen->copyRegion(charNum * 77, 32, pX[charNum], pY, 77, 44, 2, 2, Screen::CR_NO_P_CHECK); + + if (resetFlag) + resetCharacterState(&_characters[charNum], 4, 4); + + gui_drawCharPortraitWithStats(charNum); + _screen->copyRegion(pX[charNum], pY, pX[charNum], pY, 77, 44, 2, 0, Screen::CR_NO_P_CHECK); + _screen->updateScreen(); + } + + _screen->setCurPage(cp); + updateDrawPage2(); +} + bool LoLEngine::notEnoughMagic(int charNum, int spellNum, int spellLevel) { if (_spellProperties[spellNum].mpRequired[spellLevel] > _characters[charNum].magicPointsCur) { if (characterSays(0x4043, _characters[charNum].id, true)) @@ -1833,6 +2138,8 @@ bool LoLEngine::notEnoughMagic(int charNum, int spellNum, int spellLevel) { return false; } +// fight + int LoLEngine::battleHitSkillTest(int16 attacker, int16 target, int skill) { if (target == -1) return 0; @@ -1879,28 +2186,440 @@ int LoLEngine::battleHitSkillTest(int16 attacker, int16 target, int skill) { } int LoLEngine::calcInflictableDamage(int16 attacker, int16 target, int hitType) { - const uint16 *s = getCharacterOrMonsterStats(attacker); + const uint16 *s = getCharacterOrMonsterItemsMight(attacker); - int res = 0; + // The original code looks somewhat like the commented out part of the next line. + // In the end the value is always set to zero. I do not know whether this is done on purpose or not. + // It might be a bug in the original code. + int res = 0/*attacker & 0x8000 ? 0 : _characters[attacker].might*/; for (int i = 0; i < 8; i++) - res += calcInflictableDamagePerStat(attacker, target, s[2 + i], i, hitType); + res += calcInflictableDamagePerItem(attacker, target, s[i], i, hitType); return res; } -void LoLEngine::battleHit_sub2(int16 target, int damageInflicted, int16 attacker, uint32 b) { +int LoLEngine::inflictDamage(int16 target, int damage, int16 attacker, int skill, int deathFlag) { + MonsterInPlay *m = 0; + LoLCharacter *c = 0; + + if (target & 0x8000) { + m = &_monsters[target & 0x7fff]; + if (m->mode >= 13) + return 0; + + if (damage > 0) { + m->hitPoints -= damage; + m->damageReceived = 0x8000 | damage; + m->flags |= 0x10; + m->hitOffsX = _rnd.getRandomNumberRng(1, 24); + m->hitOffsX -= 12; + m->hitOffsY = _rnd.getRandomNumberRng(1, 24); + m->hitOffsY -= 12; + m->hitPoints = CLIP(m->hitPoints, 0, m->properties->hitPoints); + + if (!(attacker & 0x8000)) + applyMonsterDefenseSkill(m, attacker, deathFlag, skill, damage); + + snd_queueEnvironmentalSoundEffect(m->properties->sounds[2], m->block); + checkSceneUpdateNeed(m->block); + + if (m->hitPoints <= 0) { + m->hitPoints = 0; + if (!(attacker & 0x8000)) + increaseExperience(attacker, skill, m->properties->hitPoints); + setMonsterMode(m, 13); + } + } else { + m->hitPoints -= damage; + m->hitPoints = CLIP(m->hitPoints, 1, m->properties->hitPoints); + } + + } else { + c = &_characters[target]; + if (!(c->flags & 1) || (c->flags & 8)) + return 0; + + if (!(c->flags & 0x1000)) + snd_playSoundEffect(c->screamSfx, -1); + + setTemporaryFaceFrame(target, 6, 4, 0); + + // check for equipped cloud ring + if (deathFlag == 4 && itemEquipped(target, 229)) + damage >>= 2; + + setCharacterMagicOrHitPoints(target, 0, -damage, 1); + + if (c->hitPointsCur <= 0) { + characterHitpointsZero(target, deathFlag); + } else { + _characters[target].damageSuffered = damage; + setCharacterUpdateEvent(target, 2, 4, 1); + } + gui_drawCharPortraitWithStats(target); + } + + if (!(attacker & 0x8000)) { + if (!skill) + _characters[attacker].weaponHit = damage; + increaseExperience(attacker, skill, damage); + } + + return damage; +} + +void LoLEngine::characterHitpointsZero(int16 charNum, int deathFlag) { + LoLCharacter *c = &_characters[charNum]; + c->hitPointsCur = 0; + c->flags |= 8; + resetCharacterState(c, 1, 5); + _partyDeathFlag = deathFlag; +} + +void LoLEngine::resetCharacterState(LoLCharacter *c, int first, int last) { + for (int i = first; i <= last; i++) { + switch (i - 1) { + case 0: + c->weaponHit = 0; + break; + + case 1: + c->damageSuffered = 0; + break; + + case 2: + c->flags &= 0xffbf; + break; + + case 3: + c->flags &= 0xff7f; + break; + + case 4: + c->flags &= 0xfeff; + break; + + case 6: + c->flags &= 0xefff; + break; + + default: + break; + } + + for (int ii = 0; ii < 5; ii++) { + if (i != c->characterUpdateEvents[ii]) + continue; + + c->characterUpdateEvents[ii] = 0; + c->characterUpdateDelay[ii] = 0; + } + } + _timer3Para = 1; + _timer->enable(3); } -void LoLEngine::battleHit_sub3(MonsterInPlay *monster, int16 target, int16 damageInflicted) { +int LoLEngine::calcInflictableDamagePerItem(int16 attacker, int16 target, uint16 itemMight, int index, int hitType) { + int dmg = (attacker == -1) ? 0x100 : getCharacterOrMonsterStats(attacker)[1]; + const uint16 *st_t = getCharacterOrMonsterProtectionAgainstItems(target); + + dmg = (dmg * itemMight) >> 8; + if (!dmg) + return 0; + + if (!(attacker & 0x8000)) { + dmg = (dmg * _characters[attacker].totalMightModifier) >> 8; + if (!dmg) + return 0; + } + + int d = (index & 0x80) ? st_t[7] : st_t[index]; + int r = (dmg * ABS(d)) >> 8; + dmg = d < 0 ? -r : r; + + if (hitType == 2 || !dmg) + return (dmg == 1) ? 2 : dmg; + + int p = (calculateProtection(target) << 7) / dmg; + if (p > 217) + p = 217; + + d = 256 - p; + r = (dmg * ABS(d)) >> 8; + dmg = d < 0 ? -r : r; + + return (dmg < 2) ? 2 : dmg; } -int LoLEngine::calcInflictableDamagePerStat(int16 attacker, int16 target, uint16 stat2m, int index, int hitType) { - return 1; +void LoLEngine::checkForPartyDeath() { + } -uint16 LoLEngine::getClosestMonster(int x, int y) { +void LoLEngine::applyMonsterAttackSkill(MonsterInPlay *monster, int16 target, int16 damage) { + if (_rnd.getRandomNumberRng(1, 100) > monster->properties->attackSkillChance) + return; + + int t = 0; + + switch (monster->properties->attackSkillType - 1) { + case 0: + t = removeCharacterItem(target, 0x7ff); + if (t) { + giveItemToMonster(monster, t); + if (characterSays(0x4019, _characters[target].id, true)) + _txt->printMessage(6, getLangString(0x4019)); + } + break; + + case 1: + // poison character + paralyzePoisonCharacter(target, 0x80, 0x88, 100, 1); + break; + + case 2: + t = removeCharacterItem(target, 0x20); + if (t) { + deleteItem(t); + if (characterSays(0x401b, _characters[target].id, true)) + _txt->printMessage(6, getLangString(0x401b)); + } + break; + + case 3: + t = removeCharacterItem(target, 0x0f); + if (t) { + if (characterSays(0x401e, _characters[target].id, true)) + _txt->printMessage(6, getLangString(0x401e), _characters[target].name); + setItemPosition(t, monster->x, monster->y, 0, 1); + } + break; + + case 5: + if (_characters[target].magicPointsCur <= 0) + return; + + monster->hitPoints += _characters[target].magicPointsCur; + _characters[target].magicPointsCur = 0; + gui_drawCharPortraitWithStats(target); + if (characterSays(0x4020, _characters[target].id, true)) + _txt->printMessage(6, getLangString(0x4020), _characters[target].name); + break; + + case 7: + stunCharacter(target); + break; + + case 8: + monster->hitPoints += damage; + if (monster->hitPoints > monster->properties->hitPoints) + monster->hitPoints = monster->properties->hitPoints; + + break; + + case 9: + // paralyze party (spider web) + paralyzePoisonAllCharacters(0x40, 0x48, 100); + break; + + default: + break; + } +} + +void LoLEngine::applyMonsterDefenseSkill(MonsterInPlay *monster, int16 attacker, int deathFlag, int skill, int damage) { + if (_rnd.getRandomNumberRng(1, 100) > monster->properties->defenseSkillChance) + return; + + int itm = 0; + + switch (monster->properties->defenseSkillType - 1) { + case 0: + case 1: + if ((deathFlag & 0x3f) == 2 || skill) + return; + + for (int i = 0; i < 3 ; i++) { + itm = _characters[attacker].items[i]; + if (!itm) + continue; + if ((_itemProperties[_itemsInPlay[itm].itemPropertyIndex].protection & 0x3f) != deathFlag) + continue; + + removeCharacterItem(attacker, 0x7fff); + + if (monster->properties->defenseSkillType == 1) { + deleteItem(itm); + if (characterSays(0x401d, _characters[attacker].id, true)) + _txt->printMessage(6, getLangString(0x401d)); + } else { + giveItemToMonster(monster, itm); + if (characterSays(0x401c, _characters[attacker].id, true)) + _txt->printMessage(6, getLangString(0x401c)); + } + } + break; + + case 2: + if (!(deathFlag & 0x80)) + return; + monster->flags |= 8; + monster->direction = calcMonsterDirection(monster->x, monster->y, _partyPosX, _partyPosY) ^ 4; + setMonsterMode(monster, 9); + monster->fightCurTick = 30; + break; + + case 3: + if (deathFlag != 3) + return; + monster->hitPoints += damage; + if (monster->hitPoints > monster->properties->hitPoints) + monster->hitPoints = monster->properties->hitPoints; + + + break; + + case 4: + if (!(deathFlag & 0x80)) + return; + monster->hitPoints += damage; + if (monster->hitPoints > monster->properties->hitPoints) + monster->hitPoints = monster->properties->hitPoints; + break; + + case 5: + if ((deathFlag & 0x84) == 0x84) + monster->numDistAttacks++; + break; + + default: + break; + } +} + +int LoLEngine::removeCharacterItem(int charNum, int itemFlags) { + for (int i = 0; i < 11; i++) { + int s = _characters[charNum].items[i]; + if (!((1 << i) & itemFlags) || !s) + continue; + + _characters[charNum].items[i] = 0; + runItemScript(charNum, s, 0x100, 0, 0); + + return s; + } + + return 0; +} + +bool LoLEngine::paralyzePoisonCharacter(int charNum, int typeFlag, int immunityFlags, int hitChance, int redraw) { + if (!(_characters[charNum].flags & 1) || (_characters[charNum].flags & immunityFlags)) + return 0; + + if ((int)_rnd.getRandomNumberRng(1, 100) > hitChance) + return 0; + + int r = false; + + if (typeFlag == 0x40) { + _characters[charNum].flags |= 0x40; + setCharacterUpdateEvent(charNum, 3, 3600, 1); + r = true; + + // check for bezel ring + } else if (typeFlag == 0x80 && !itemEquipped(charNum, 225)) { + _characters[charNum].flags |= 0x80; + setCharacterUpdateEvent(charNum, 4, 10, 1); + if (characterSays(0x4021, _characters[charNum].id, true)) + _txt->printMessage(6, getLangString(0x4021), _characters[charNum].name); + r = true; + + } else if (typeFlag == 0x1000) { + _characters[charNum].flags |= 0x1000; + setCharacterUpdateEvent(charNum, 7, 120, 1); + r = true; + } + + if (r && redraw) + gui_drawCharPortraitWithStats(charNum); + + return r; +} + +void LoLEngine::paralyzePoisonAllCharacters(int typeFlag, int immunityFlags, int hitChance) { + bool r = false; + for (int i = 0; i < 4; i++) { + if (paralyzePoisonCharacter(i, typeFlag, immunityFlags, hitChance, 0)) + r = true; + } + if (r) + gui_drawAllCharPortraitsWithStats(); +} + +void LoLEngine::stunCharacter(int charNum) { + if (!(_characters[charNum].flags & 1) || (_characters[charNum].flags & 0x108)) + return; + + _characters[charNum].flags |= 0x100; + + setCharacterUpdateEvent(charNum, 5, 20, 1); + gui_drawCharPortraitWithStats(charNum); + + _txt->printMessage(6, getLangString(0x4026), _characters[charNum].name); +} + +void LoLEngine::level11specialUnk() { + +} + +void LoLEngine::distObj1Sub(int a, int b, int c, int d) { + +} + +void LoLEngine::launchMagicViper() { + +} + +void LoLEngine::attackWall(int a, int b) { + +} + +uint16 LoLEngine::getNearestMonsterFromCharacter(int charNum) { + return getNearestMonsterFromCharacterForBlock(calcNewBlockPosition(_currentBlock, _currentDirection), charNum); +} + +uint16 LoLEngine::getNearestMonsterFromCharacterForBlock(int block, int charNum) { + uint16 cX = 0; + uint16 cY = 0; + + uint16 id = 0xffff; + int minDist = 0x7fff; + + calcCoordinatesForSingleCharacter(charNum, cX, cY); + + int o = _levelBlockProperties[block].assignedObjects; + + while (o & 0x8000) { + MonsterInPlay *m = &_monsters[o & 0x7fff]; + if (m->mode >= 13) { + o = m->nextAssignedObject; + continue; + } + + int d = ABS(cX - m->x) + ABS(cY - m->y); + if (d < minDist) { + minDist = d; + id = o; + } + + o = m->nextAssignedObject; + } + + return id; +} + +uint16 LoLEngine::getNearestMonsterFromPos(int x, int y) { uint16 id = 0xffff; int minDist = 0x7fff; @@ -1918,7 +2637,7 @@ uint16 LoLEngine::getClosestMonster(int x, int y) { return id; } -uint16 LoLEngine::getClosestPartyMember(int x, int y) { +uint16 LoLEngine::getNearestPartyMemberFromPos(int x, int y) { uint16 id = 0xffff; int minDist = 0x7fff; @@ -1940,50 +2659,6 @@ uint16 LoLEngine::getClosestPartyMember(int x, int y) { return id; } -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]; - - char filename[13]; - snprintf(filename, sizeof(filename), "LEVEL%d.CMZ", _currentLevel); - - _screen->loadBitmap(filename, 3, 3, 0); - const uint8 *p = _screen->getCPagePtr(2); - 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); -} - // magic atlas void LoLEngine::displayAutomap() { @@ -2056,7 +2731,7 @@ void LoLEngine::displayAutomap() { exitAutomap = true; } - delay (_tickLength); + delay(_tickLength); } _screen->loadFont(Screen::FID_9_FNT, "FONT9P.FNT"); @@ -2468,6 +3143,50 @@ 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]; + + char filename[13]; + snprintf(filename, sizeof(filename), "LEVEL%d.CMZ", _currentLevel); + + _screen->loadBitmap(filename, 3, 3, 0); + const uint8 *p = _screen->getCPagePtr(2); + 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 #endif // ENABLE_LOL diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index f578c22f57..ba97167ede 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -50,18 +50,11 @@ struct LoLCharacter { int16 id; uint8 curFaceFrame; uint8 defaultFaceFrame; - uint8 field_12; + uint8 screamSfx; const uint16 *defaultModifiers; uint16 itemsMight[8]; - uint16 field_27[2]; - uint8 field_2B; - uint16 field_2C; - uint16 field_2E; - uint16 field_30; - uint16 field_32; - uint16 field_34; - uint8 field_36; - uint16 itemsProtection; + uint16 protectionAgainstItems[8]; + uint16 itemProtection; int16 hitPointsCur; uint16 hitPointsMax; int16 magicPointsCur; @@ -78,8 +71,8 @@ struct LoLCharacter { uint8 skillLevels[3]; uint8 skillModifiers[3]; int32 experiencePts[3]; - uint8 arrayUnk2[5]; - uint8 arrayUnk1[5]; + uint8 characterUpdateEvents[5]; + uint8 characterUpdateDelay[5]; }; struct SpellProperty { @@ -100,17 +93,22 @@ struct LevelBlockProperty { struct MonsterProperty { uint8 shapeIndex; uint8 maxWidth; - uint16 fightingStats[10]; - uint16 unk2[8]; - uint16 unk3[8]; + uint16 fightingStats[9]; + uint16 itemsMight[8]; + uint16 protectionAgainstItems[8]; uint16 itemProtection; - uint16 might; + uint16 hitPoints; uint8 speedTotalWaitTicks; uint8 skillLevel; uint16 flags; uint16 unk5; - uint16 unk6[5]; - uint8 unk7[4]; + uint16 numDistAttacks; + uint16 numDistWeapons; + uint16 distWeapons[3]; + uint8 attackSkillChance; + uint8 attackSkillType; + uint8 defenseSkillChance; + uint8 defenseSkillType; uint8 sounds[3]; }; @@ -118,15 +116,15 @@ struct MonsterInPlay { uint16 nextAssignedObject; uint16 nextDrawObject; uint8 flyingHeight; - uint16 blockPropertyIndex; + uint16 block; uint16 x; uint16 y; int8 shiftStep; uint16 destX; uint16 destY; uint8 destDirection; - uint8 anon8; - uint8 anonh; + int8 hitOffsX; + int8 hitOffsY; uint8 currentSubFrame; uint8 mode; @@ -135,15 +133,15 @@ struct MonsterInPlay { uint8 direction; uint8 facing; uint16 flags; - uint8 field_1B; - uint8 field_1C; - int16 might; + uint16 damageReceived; + //uint8 field_1C; + int16 hitPoints; uint8 speedTick; uint8 type; MonsterProperty *properties; - uint8 field_25; - uint8 field_26; - uint8 field_27; + uint8 numDistAttacks; + uint8 curDistWeapon; + int8 distAttackTick; uint16 assignedItems; uint8 field_2A[4]; }; @@ -152,15 +150,15 @@ struct ItemInPlay { uint16 nextAssignedObject; uint16 nextDrawObject; uint8 flyingHeight; - uint16 blockPropertyIndex; + uint16 block; uint16 x; uint16 y; int8 level; uint16 itemPropertyIndex; uint16 shpCurFrame_flg; uint8 destDirection; - uint8 anon8; - uint8 anonh; + int8 hitOffsX; + int8 hitOffsY; uint8 currentSubFrame; }; @@ -213,8 +211,8 @@ struct OpenDoorState { struct FlyingObject { uint8 enable; - uint8 a; - uint16 charNum; + uint8 objectType; + uint16 attackerId; uint16 item; uint16 x; uint16 y; @@ -324,6 +322,8 @@ private: int getCharSelection(); int selectionCharAccept(); + + void showStarcraftLogo(); int _charSelection; int _charSelectionInfoResult; @@ -354,16 +354,17 @@ private: void timerProcessDoors(int timerNum); void timerProcessMonsters(int timerNum); - void timerSub3(int timerNum); + void timerSpecialCharacterUpdate(int timerNum); void timerProcessFlyingObjects(int timerNum); void timerRunSceneAnimScript(int timerNum); - void timerSub6(int timerNum); + void timerRegeneratePoints(int timerNum); void timerUpdatePortraitAnimations(int skipUpdate); void timerUpdateLampState(int timerNum); void timerFadeMessageText(int timerNum); static const uint8 _clock2Timers[]; static const uint8 _numClock2Timers; + int _timer3Para; // sound void loadTalkFile(int index); @@ -373,6 +374,7 @@ private: void snd_stopSpeech(bool setFlag); void snd_playSoundEffect(int track, int volume); void snd_processEnvironmentalSoundEffect(int soundId, int block); + void snd_queueEnvironmentalSoundEffect(int soundId, int block); void snd_loadSoundFile(int track); int snd_playTrack(int track); int snd_stopMusic(); @@ -387,7 +389,11 @@ private: char _curMusicFileExt; int _environmentSfx; int _environmentSfxVol; - int _environmentSfxDistThreshold; + int _envSfxDistThreshold; + bool _envSfxUseQueue; + int _envSfxNumTracksInQueue; + uint16 _envSfxQueuedTracks[10]; + uint16 _envSfxQueuedBlocks[10]; int _nextSpeechId; int _nextSpeaker; @@ -405,8 +411,8 @@ private: int _ingameGMSoundIndexSize; const uint8 *_ingameMT32SoundIndex; int _ingameMT32SoundIndexSize; - /*const uint8 *_ingameADLSoundIndex; - int _ingameADLSoundIndexSize;*/ + + AudioDataStruct _soundData[3]; // gui void gui_drawPlayField(); @@ -597,15 +603,18 @@ private: int olol_fadeSequencePalette(EMCState *script); int olol_redrawPlayfield(EMCState *script); int olol_loadNewLevel(EMCState *script); + int olol_getNearestMonsterFromCharacter(EMCState *script); int olol_dummy0(EMCState *script); int olol_loadMonsterProperties(EMCState *script); int olol_battleHitSkillTest(EMCState *script); + int olol_inflictDamage(EMCState *script); int olol_moveMonster(EMCState *script); int olol_dialogueBox(EMCState *script); int olol_giveTakeMoney(EMCState *script); int olol_checkMoney(EMCState *script); int olol_setScriptTimer(EMCState *script); int olol_createHandItem(EMCState *script); + int olol_playAttackSound(EMCState *script); int olol_characterJoinsParty(EMCState *script); int olol_loadTimScript(EMCState *script); int olol_runTimScript(EMCState *script); @@ -619,18 +628,23 @@ private: int olol_processDialogue(EMCState *script); int olol_stopTimScript(EMCState *script); int olol_getWallFlags(EMCState *script); - int olol_changeMonsterSettings(EMCState *script); + int olol_changeMonsterStat(EMCState *script); + int olol_getMonsterStat(EMCState *script); int olol_playCharacterScriptChat(EMCState *script); int olol_update(EMCState *script); + int olol_healCharacter(EMCState *script); int olol_drawExitButton(EMCState *script); int olol_loadSoundFile(EMCState *script); int olol_playMusicTrack(EMCState *script); int olol_countBlockItems(EMCState *script); int olol_stopCharacterSpeech(EMCState *script); int olol_setPaletteBrightness(EMCState *script); + int olol_calcInflictableDamage(EMCState *script); + int olol_getInflictedDamage(EMCState *script); int olol_checkForCertainPartyMember(EMCState *script); int olol_printMessage(EMCState *script); int olol_deleteLevelItem(EMCState *script); + int olol_calcInflictableDamagePerItem(EMCState *script); int olol_objectLeavesLevel(EMCState *script); int olol_playDialogueTalkText(EMCState *script); int olol_checkMonsterTypeHostility(EMCState *script); @@ -638,7 +652,7 @@ private: int olol_dummy1(EMCState *script); int olol_suspendMonster(EMCState *script); int olol_setDoorState(EMCState *script); - int olol_processButtonClick(EMCState *script); + int olol_resetTimDialogueState(EMCState *script); int olol_savePage5(EMCState *script); int olol_restorePage5(EMCState *script); int olol_initDialogueSequence(EMCState *script); @@ -699,6 +713,7 @@ private: // Maybe we can someday reduce the size. char *getLangString(uint16 id); uint8 *getTableEntry(uint8 *buffer, uint16 id); + void decodeSjis(const char *src, char *dst); static const char * const _languageExt[]; @@ -728,8 +743,6 @@ private: int _numThrownShapes; uint8 **_effectShapes; int _numEffectShapes; - uint8 **_fireballShapes; - int _numFireballShapes; const int8 *_gameShapeMap; int _gameShapeMapSize; @@ -740,8 +753,8 @@ private: // characters bool addCharacter(int id); - void setFaceFrames(int charNum, int defaultFrame, int unk2, int redraw); - void setFaceFramesUnkArrays(int charNum, int unk1, int unk2, int unk3); + void setTemporaryFaceFrame(int charNum, int frame, int updateDelay, int redraw); + void setCharacterUpdateEvent(int charNum, int updateType, int updateDelay, int overwrite); int countActiveCharacters(); void loadCharFaceShapes(int charNum, int id); void calcCharPortraitXpos(); @@ -756,7 +769,9 @@ private: int calculateCharacterStats(int charNum, int index); int calculateProtection(int index); + void setCharacterMagicOrHitPoints(int charNum, int type, int points, int mode); void increaseExperience(int charNum, int skill, uint32 points); + void increaseCharacterHitpoints(int charNum, int points, bool unk); LoLCharacter *_characters; uint16 _activeCharsXpos[3]; @@ -1023,15 +1038,16 @@ private: ItemInPlay *findObject(uint16 index); void runItemScript(int charNum, int item, int sub, int next, int reg4); void setHandItem(uint16 itemIndex); + bool itemEquipped(int charNum, uint16 itemType); void setItemPosition(int item, uint16 x, uint16 y, int flyingHeight, int b); void removeLevelItem(int item, int block); - bool throwItem(int a, int item, int x, int y, int flyingHeight, int direction, int, int charNum, int c); + bool launchObject(int objectType, int item, int startX, int startY, int flyingHeight, int direction, int, int attackerId, int c); void endObjectFlight(FlyingObject *t, int x, int y, int objectOnNextBlock); void processObjectFlight(FlyingObject *t, int x, int y); void updateObjectFlightPosition(FlyingObject *t); void objectFlightProcessHits(FlyingObject *t, int x, int y, int objectOnNextBlock); - void updateFlyingObjects(FlyingObject *t); + void updateFlyingObject(FlyingObject *t); void assignItemToBlock(uint16 *assignedBlockObjects, int id); int checkDrawObjectSpace(int itemX, int itemY, int partyX, int partyY); @@ -1088,6 +1104,9 @@ private: int calcMonsterSkillLevel(int id, int a); bool checkBlockOccupiedByParty(int x, int y, int testFlag); const uint16 *getCharacterOrMonsterStats(int id); + uint16 *getCharacterOrMonsterItemsMight(int id); + uint16 *getCharacterOrMonsterProtectionAgainstItems(int id); + void drawBlockObjects(int blockArrayIndex); void drawMonster(uint16 id); int getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags); @@ -1107,7 +1126,7 @@ private: void chasePartyWithCloseAttacks(MonsterInPlay *monster); int walkMonsterCalcNextStep(MonsterInPlay *monster); int getMonsterDistance(uint16 block1, uint16 block2); - int walkMonster_s3(uint16 monsterBlock, int direction, int distance, uint16 curBlock); + int checkForPossibleDistanceAttack(uint16 monsterBlock, int direction, int distance, uint16 curBlock); int walkMonsterCheckDest(int x, int y, MonsterInPlay *monster, int unk); void getNextStepCoords(int16 monsterX, int16 monsterY, int &newX, int &newY, uint16 direction); void rearrangeAttackingMonster(MonsterInPlay *monster); @@ -1143,25 +1162,16 @@ private: uint8 getRandomNumberSpecial(); uint8 _compassBroken; - uint8 _unkBt2; + uint8 _drainMagic; uint16 _unkWordArraySize8[8]; uint8 *_pageBuffer1; uint8 *_pageBuffer2; uint32 _rndSpecial; - // fight - int battleHitSkillTest(int16 attacker, int16 target, int skill); - int calcInflictableDamage(int16 attacker, int16 target, int hitType); - void battleHit_sub2(int16 target, int damageInflicted, int16 attacker, uint32 b); - void battleHit_sub3(MonsterInPlay *monster, int16 target, int16 damageInflicted); - int calcInflictableDamagePerStat(int16 attacker, int16 target, uint16 stat2m, int index, int hitType); - - uint16 getClosestMonster(int x, int y); - uint16 getClosestPartyMember(int x, int y); - // spells - bool notEnoughMagic(int charNum, int spellNum, int spellLevel); + void processMagicHeal(int charNum, int points); + bool notEnoughMagic(int charNum, int spellNum, int spellLevel); int8 _availableSpells[7]; int _selectedSpell; @@ -1170,17 +1180,46 @@ private: int _subMenuIndex; uint16 _unkIceSHpFlag; - // unneeded - void setWalkspeed(uint8) {} - void removeHandItem() {} - bool lineIsPassable(int, int) { return false; } + uint8 *_healOverlay; - // save - Common::Error loadGameState(int slot) { return Common::kNoError; } - Common::Error saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail) { return Common::kNoError; } + uint8 **_fireballShapes; + int _numFireballShapes; + uint8 **_healShapes; + int _numHealShapes; + uint8 **_healiShapes; + int _numHealiShapes; - void generateTempData(); - LevelTempData *_lvlTempData[28]; + const uint8 *_healShapeFrames; + int _healShapeFramesSize; + + // fight + int battleHitSkillTest(int16 attacker, int16 target, int skill); + int calcInflictableDamage(int16 attacker, int16 target, int hitType); + int inflictDamage(int16 target, int damage, int16 attacker, int skill, int deathFlag); + void characterHitpointsZero(int16 charNum, int a); + void resetCharacterState(LoLCharacter *c, int first, int last); + 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 deathFlag, int skill, int damage); + int removeCharacterItem(int charNum, int itemFlags); + bool paralyzePoisonCharacter(int charNum, int typeFlag, int immunityFlags, int hitChance, int redraw); + void paralyzePoisonAllCharacters(int typeFlag, int immunityFlags, int hitChance); + void stunCharacter(int charNum); + void level11specialUnk(); + + void distObj1Sub(int a, int b, int c, int d); + void launchMagicViper(); + + void attackWall(int a, int b); + + uint16 getNearestMonsterFromCharacter(int charNum); + uint16 getNearestMonsterFromCharacterForBlock(int block, int charNum); + uint16 getNearestMonsterFromPos(int x, int y); + uint16 getNearestPartyMemberFromPos(int x, int y); + + int _partyDeathFlag; // magic atlas void displayAutomap(); @@ -1211,6 +1250,18 @@ private: uint8 _automapTopLeftY; static const int8 _mapCoords[12][4]; bool _mapUpdateNeeded; + + // unneeded + void setWalkspeed(uint8) {} + void removeHandItem() {} + bool lineIsPassable(int, int) { return false; } + + // save + Common::Error loadGameState(int slot) { return Common::kNoError; } + Common::Error saveGameState(int slot, const char *saveName, const Graphics::Surface *thumbnail) { return Common::kNoError; } + + void generateTempData(); + LevelTempData *_lvlTempData[28]; }; } // end of namespace Kyra diff --git a/engines/kyra/resource.h b/engines/kyra/resource.h index 4e97853490..9b858831a2 100644 --- a/engines/kyra/resource.h +++ b/engines/kyra/resource.h @@ -286,6 +286,8 @@ enum kKyraResources { lolMapCursorOvl, lolMapStringId, //lolMapPal, + + lolHealShapeFrames, #endif // ENABLE_LOL kMaxResIDs diff --git a/engines/kyra/saveload_lok.cpp b/engines/kyra/saveload_lok.cpp index 3548723610..d5ff36480c 100644 --- a/engines/kyra/saveload_lok.cpp +++ b/engines/kyra/saveload_lok.cpp @@ -163,7 +163,7 @@ Common::Error KyraEngine_LoK::loadGameState(int slot) { // it wasn't made sure that _curSfxFile was initialized // so if it's out of bounds we just set it to 0. if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) { - if (_curSfxFile >= _soundData->_fileListLen || _curSfxFile < 0) + if (_curSfxFile >= _soundData->fileListLen || _curSfxFile < 0) _curSfxFile = 0; _sound->loadSoundFile(_curSfxFile); } diff --git a/engines/kyra/scene_lol.cpp b/engines/kyra/scene_lol.cpp index e467749700..2508a3062a 100644 --- a/engines/kyra/scene_lol.cpp +++ b/engines/kyra/scene_lol.cpp @@ -105,9 +105,9 @@ void LoLEngine::addLevelItems() { if (_itemsInPlay[i].level != _currentLevel) continue; - assignBlockObject(&_levelBlockProperties[_itemsInPlay[i].blockPropertyIndex].assignedObjects, i); + assignBlockObject(&_levelBlockProperties[_itemsInPlay[i].block].assignedObjects, i); - _levelBlockProperties[_itemsInPlay[i].blockPropertyIndex].direction = 5; + _levelBlockProperties[_itemsInPlay[i].block].direction = 5; _itemsInPlay[i].nextDrawObject = 0; } } @@ -259,8 +259,8 @@ void LoLEngine::restoreBlockTempData(int index) { } for (int i = 0; i < 30; i++) { - if (_monsters[i].blockPropertyIndex) { - _monsters[i].blockPropertyIndex = 0; + if (_monsters[i].block) { + _monsters[i].block = 0; _monsters[i].properties = &_monsterProperties[_monsters[i].type]; placeMonster(&_monsters[i], _monsters[i].x, _monsters[i].y); } @@ -276,14 +276,14 @@ void LoLEngine::restoreTempDataAdjustMonsterStrength(int index) { uint16 d = (_monsterModifiers[_lvlTempData[index]->monsterDifficulty] << 8) / _monsterModifiers[_monsterDifficulty]; for (int i = 0; i < 30; i++) { - if (_monsters[i].mode >= 14 || _monsters[i].blockPropertyIndex == 0 || _monsters[i].might <= 0) + if (_monsters[i].mode >= 14 || _monsters[i].block == 0 || _monsters[i].hitPoints <= 0) continue; - _monsters[i].might = (d * _monsters[i].might) >> 8; + _monsters[i].hitPoints = (d * _monsters[i].hitPoints) >> 8; if (_monsterDifficulty < _lvlTempData[index]->monsterDifficulty) - _monsters[i].might++; - if (_monsters[i].might == 0) - _monsters[i].might = 1; + _monsters[i].hitPoints++; + if (_monsters[i].hitPoints == 0) + _monsters[i].hitPoints = 1; } } @@ -470,7 +470,7 @@ void LoLEngine::resetItems(int flag) { ItemInPlay *it = &_itemsInPlay[id]; it->level = _currentLevel; - it->blockPropertyIndex = i; + it->block = i; if (r) r->nextAssignedObject = 0; } diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index 26b8e3a922..c505152b11 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -73,6 +73,8 @@ bool Screen::init() { memset(_sjisOverlayPtrs, 0, sizeof(_sjisOverlayPtrs)); _useOverlays = false; _useSJIS = false; + _use16ColorMode = _vm->gameFlags().use16ColorMode; + _sjisTempPage = _sjisFontData = 0; if (_vm->gameFlags().useHiResOverlay) { @@ -432,11 +434,13 @@ void Screen::getFadeParams(const uint8 *palette, int delay, int &delayInc, int & int Screen::fadePalStep(const uint8 *palette, int diff) { debugC(9, kDebugLevelScreen, "Screen::fadePalStep(%p, %d)", (const void *)palette, diff); + const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : (_use16ColorMode ? 16 : 256)) * 3; + uint8 fadePal[768]; - memcpy(fadePal, _screenPalette, 768); + memcpy(fadePal, _screenPalette, colors); bool needRefresh = false; - const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256) * 3; + for (int i = 0; i < colors; ++i) { int c1 = palette[i]; int c2 = fadePal[i]; @@ -495,17 +499,35 @@ void Screen::setScreenPalette(const uint8 *palData) { debugC(9, kDebugLevelScreen, "Screen::setScreenPalette(%p)", (const void *)palData); const int colors = (_vm->gameFlags().platform == Common::kPlatformAmiga ? 32 : 256); + + uint8 screenPal[256 * 4]; if (palData != _screenPalette) memcpy(_screenPalette, palData, colors*3); - uint8 screenPal[256 * 4]; - for (int i = 0; i < colors; ++i) { - screenPal[4 * i + 0] = (palData[0] << 2) | (palData[0] & 3); - screenPal[4 * i + 1] = (palData[1] << 2) | (palData[1] & 3); - screenPal[4 * i + 2] = (palData[2] << 2) | (palData[2] & 3); - screenPal[4 * i + 3] = 0; - palData += 3; + if (_use16ColorMode && _vm->gameFlags().platform == Common::kPlatformPC98) { + for (int l = 0; l < 1024; l += 64) { + const uint8 *tp = palData; + for (int i = 0; i < 16; ++i) { + screenPal[l + 4 * i + 0] = palData[1]; + screenPal[l + 4 * i + 1] = palData[0]; + screenPal[l + 4 * i + 2] = palData[2]; + screenPal[l + 4 * i + 3] = 0; + palData += 3; + } + palData = tp; + } + } else { + if (palData != _screenPalette) + memcpy(_screenPalette, palData, colors*3); + for (int i = 0; i < colors; ++i) { + screenPal[4 * i + 0] = (palData[0] << 2) | (palData[0] & 3); + screenPal[4 * i + 1] = (palData[1] << 2) | (palData[1] & 3); + screenPal[4 * i + 2] = (palData[2] << 2) | (palData[2] & 3); + screenPal[4 * i + 3] = 0; + palData += 3; + } } + _system->setPalette(screenPal, 0, colors); } @@ -1242,7 +1264,9 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int &Screen::drawShapePlotType13, // used by Kyra 1 &Screen::drawShapePlotType14, // used by Kyra 1 (invisibility) &Screen::drawShapePlotType11_15, // used by Kyra 1 (invisibility) - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + &Screen::drawShapePlotType20, // used by LoL (heal spell effect) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &Screen::drawShapePlotType33, // used by LoL (blood spots on the floor) 0, 0, 0, @@ -1683,7 +1707,6 @@ void Screen::drawShapePlotType0(uint8 *dst, uint8 cmd) { } void Screen::drawShapePlotType1(uint8 *dst, uint8 cmd) { - // uint32 relOffs = dst - _dsDstPage; for (int i = 0; i < _dsTableLoopCount; ++i) cmd = _dsTable[cmd]; @@ -1705,7 +1728,6 @@ void Screen::drawShapePlotType4(uint8 *dst, uint8 cmd) { } void Screen::drawShapePlotType5(uint8 *dst, uint8 cmd) { - // uint32 relOffs = dst - _dsDstPage; cmd = _dsTable2[cmd]; for (int i = 0; i < _dsTableLoopCount; ++i) cmd = _dsTable[cmd]; @@ -1812,6 +1834,15 @@ void Screen::drawShapePlotType14(uint8 *dst, uint8 cmd) { *dst = cmd; } +void Screen::drawShapePlotType20(uint8 *dst, uint8 cmd) { + cmd = _dsTable2[cmd]; + uint8 tOffs = _dsTable3[cmd]; + if (!(tOffs & 0x80)) + cmd = _dsTable4[tOffs << 8 | *dst]; + + *dst = cmd; +} + void Screen::drawShapePlotType33(uint8 *dst, uint8 cmd) { if (cmd == 255) { *dst = _dsTable5[*dst]; @@ -2822,6 +2853,9 @@ void Screen::loadPalette(const byte *data, uint8 *palData, int bytes) { palData[0] = (col & 0xF) << 2; col >>= 4; palData += 3; } + } else if (_use16ColorMode) { + for (int i = 0; i < bytes; ++i) + palData[i] = ((data[i] & 0xF) << 4) | (data[i] & 0xF0); } else { memcpy(palData, data, bytes); } diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index 15f0ab2079..3720979c62 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -271,6 +271,7 @@ protected: bool _useOverlays; bool _useSJIS; + bool _use16ColorMode; uint8 *_sjisFontData; uint8 *_sjisTempPage; @@ -328,6 +329,7 @@ protected: void drawShapePlotType12(uint8 *dst, uint8 cmd); void drawShapePlotType13(uint8 *dst, uint8 cmd); void drawShapePlotType14(uint8 *dst, uint8 cmd); + void drawShapePlotType20(uint8 *dst, uint8 cmd); void drawShapePlotType33(uint8 *dst, uint8 cmd); void drawShapePlotType37(uint8 *dst, uint8 cmd); void drawShapePlotType48(uint8 *dst, uint8 cmd); diff --git a/engines/kyra/screen_lol.cpp b/engines/kyra/screen_lol.cpp index e370cc9a33..f24d3a4472 100644 --- a/engines/kyra/screen_lol.cpp +++ b/engines/kyra/screen_lol.cpp @@ -32,9 +32,6 @@ namespace Kyra { Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system), _vm(vm) { - _customDimTable = new ScreenDim*[_screenDimTableCount]; - memset(_customDimTable, 0, sizeof(ScreenDim*) * _screenDimTableCount); - _paletteOverlay1 = new uint8[0x100]; _paletteOverlay2 = new uint8[0x100]; _grayOverlay = new uint8[0x100]; @@ -48,7 +45,7 @@ Screen_LoL::Screen_LoL(LoLEngine *vm, OSystem *system) : Screen_v2(vm, system), _fadeFlag = 2; _curDimIndex = 0; - _mapDimX = _mapDimY = _mapDimW = _mapDimH = _mapDimDstX = _mapBlockWidth = _mapDimDstY = _mapBlockHeight = _mapDimU5 = _mapDimU6 = _mapBlockWidth2 = _mapDimU8 = 0; + _internDimX = _internDimY = _internDimW = _internDimH = _internDimDstX = _internBlockWidth = _internDimDstY = _internBlockHeight = _internDimU5 = _internDimU6 = _internBlockWidth2 = _internDimU8 = 0; } Screen_LoL::~Screen_LoL() { @@ -64,6 +61,17 @@ 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) { debugC(9, kDebugLevelScreen, "Screen_LoL::setScreenDim(%d)", dim); assert(dim < _screenDimTableCount); @@ -525,23 +533,23 @@ void Screen_LoL::copyBlockSpecial(int page1, int x1, int y1, int page2, int x2, return; const ScreenDim *cdim = getScreenDim(dim); - _mapDimX = cdim->sx << 3; - _mapDimY = cdim->sy; - _mapDimW = cdim->w << 3; - _mapDimH = cdim->h; + _internDimX = cdim->sx << 3; + _internDimY = cdim->sy; + _internDimW = cdim->w << 3; + _internDimH = cdim->h; calcMapBoundaries(x2, y2, w, h); - if (_mapBlockWidth == -1) + if (_internBlockWidth == -1) return; uint8 *src = getPagePtr(page1) + y1 * 320 + x1; - uint8 *dst = getPagePtr(page2) + (_mapDimDstY + _mapDimY) * 320; + uint8 *dst = getPagePtr(page2) + (_internDimDstY + _internDimY) * 320; - for (int i = 0; i < _mapBlockHeight; i++) { - uint8 *s = src + _mapDimU5; - uint8 *d = dst + (_mapDimDstX + _mapDimX); + for (int i = 0; i < _internBlockHeight; i++) { + uint8 *s = src + _internDimU5; + uint8 *d = dst + (_internDimDstX + _internDimX); - for (int ii = 0; ii < _mapBlockWidth; ii++) { + for (int ii = 0; ii < _internBlockWidth; ii++) { uint8 p = ovl[*s++]; if (p) *d = p; @@ -552,60 +560,97 @@ void Screen_LoL::copyBlockSpecial(int page1, int x1, int y1, int page2, int x2, src += 320; } - addDirtyRect(_mapDimDstX + _mapDimX, _mapDimDstY + _mapDimY, _mapBlockWidth, _mapBlockHeight); + addDirtyRect(_internDimDstX + _internDimX, _internDimDstY + _internDimY, _internBlockWidth, _internBlockHeight); +} + +void Screen_LoL::applyOverlaySpecial(int page1, int x1, int y1, int page2, int x2, int y2, int w, int h, int dim, int flag, uint8 *ovl) { + if (!w || !h || !ovl) + return; + + const ScreenDim *cdim = getScreenDim(dim); + _internDimX = cdim->sx << 3; + _internDimY = cdim->sy; + _internDimW = cdim->w << 3; + _internDimH = cdim->h; + + calcMapBoundaries(x2, y2, w, h); + if (_internBlockWidth == -1) + return; + + uint8 *src = getPagePtr(page1) + y1 * 320 + x1; + uint8 *dst = getPagePtr(page2) + (_internDimDstY + _internDimY) * 320; + + for (int i = 0; i < _internBlockHeight; i++) { + uint8 *s = src + _internDimU5; + uint8 *d = dst + (_internDimDstX + _internDimX); + + if (flag) + d += (i >> 1); + + for (int ii = 0; ii < _internBlockWidth; ii++) { + if (*s++) + *d = ovl[*d]; + d++; + } + + dst += 320; + src += 320; + } + + addDirtyRect(_internDimDstX + _internDimX, _internDimDstY + _internDimY, _internBlockWidth, _internBlockHeight); } void Screen_LoL::calcMapBoundaries(int dstX, int dstY, int width, int height) { - _mapBlockWidth = _mapBlockWidth2 = width; - _mapBlockHeight = height; - _mapDimDstX = dstX; - _mapDimDstY = dstY; + _internBlockWidth = _internBlockWidth2 = width; + _internBlockHeight = height; + _internDimDstX = dstX; + _internDimDstY = dstY; - _mapDimU5 = _mapDimU6 = _mapDimU8 = 0; + _internDimU5 = _internDimU6 = _internDimU8 = 0; - int t = _mapDimDstX + _mapBlockWidth; + int t = _internDimDstX + _internBlockWidth; if (t <= 0) { - _mapBlockWidth = _mapBlockHeight = -1; + _internBlockWidth = _internBlockHeight = -1; return; } - if (t <= _mapDimDstX) { - _mapDimU5 = _mapBlockWidth - t; - _mapBlockWidth = t; - _mapDimDstX = 0; + if (t <= _internDimDstX) { + _internDimU5 = _internBlockWidth - t; + _internBlockWidth = t; + _internDimDstX = 0; } - t = _mapDimW - _mapDimDstX; + t = _internDimW - _internDimDstX; if (t <= 0) { - _mapBlockWidth = _mapBlockHeight = -1; + _internBlockWidth = _internBlockHeight = -1; return; } - if (t <= _mapBlockWidth) - _mapBlockWidth = t; + if (t <= _internBlockWidth) + _internBlockWidth = t; - _mapBlockWidth2 -= _mapBlockWidth; + _internBlockWidth2 -= _internBlockWidth; - t = _mapDimDstY + _mapBlockHeight; + t = _internDimDstY + _internBlockHeight; if (t <= 0) { - _mapBlockWidth = _mapBlockHeight = -1; + _internBlockWidth = _internBlockHeight = -1; return; } - if (t <= _mapDimDstY) { - _mapDimU6 = _mapBlockHeight - t; - _mapBlockHeight = t; - _mapDimDstY = 0; + if (t <= _internDimDstY) { + _internDimU6 = _internBlockHeight - t; + _internBlockHeight = t; + _internDimDstY = 0; } - t = _mapDimH - _mapDimDstY; + t = _internDimH - _internDimDstY; if (t <= 0) { - _mapBlockWidth = _mapBlockHeight = -1; + _internBlockWidth = _internBlockHeight = -1; return; } - if (t <= _mapBlockHeight) - _mapBlockHeight = t; + if (t <= _internBlockHeight) + _internBlockHeight = t; } void Screen_LoL::fadeToBlack(int delay, const UpdateFunctor *upFunc) { diff --git a/engines/kyra/screen_lol.h b/engines/kyra/screen_lol.h index 30567ee808..d7580e1ff8 100644 --- a/engines/kyra/screen_lol.h +++ b/engines/kyra/screen_lol.h @@ -39,6 +39,8 @@ public: Screen_LoL(LoLEngine *vm, OSystem *system); ~Screen_LoL(); + bool init(); + void setScreenDim(int dim); const ScreenDim *getScreenDim(int dim); int curDimIndex() { return _curDimIndex; } @@ -60,11 +62,6 @@ public: void smoothScrollTurnStep2(int srcPage1Num, int srcPage2Num, int dstPageNum); void smoothScrollTurnStep3(int srcPage1Num, int srcPage2Num, int dstPageNum); - // magic atlas - // This method basically works like copyRegion, but the pixels - // copied also have a palette overlay applied to them. - void copyBlockSpecial(int page1, int x1, int y1, int page2, int x2, int y2, int w, int h, int dim, uint8 *ovl); - // palette stuff void fadeToBlack(int delay=0x54, const UpdateFunctor *upFunc = 0); void loadSpecialColours(uint8 *destPalette); @@ -75,6 +72,9 @@ public: uint8 *generateLevelOverlay(const uint8 *srcPal, uint8 *ovl, int opColor, int weight); uint8 *getLevelOverlay(int index) { return _levelOverlays[index]; } + void copyBlockSpecial(int page1, int x1, int y1, int page2, int x2, int y2, int w, int h, int dim, uint8 *ovl); + void applyOverlaySpecial(int page1, int x1, int y1, int page2, int x2, int y2, int w, int h, int dim, int flag, uint8 *ovl); + uint8 getShapePaletteSize(const uint8 *shp); uint8 *_paletteOverlay1; @@ -85,9 +85,12 @@ public: private: LoLEngine *_vm; - static const ScreenDim _screenDimTable[]; + const ScreenDim *_screenDimTable; static const int _screenDimTableCount; + static const ScreenDim _screenDimTable256C[]; + static const ScreenDim _screenDimTable16C[]; + ScreenDim **_customDimTable; int _curDimIndex; @@ -96,18 +99,18 @@ private: // magic atlas void calcMapBoundaries(int dstX, int dstY, int c, int d); - int _mapDimX; - int _mapDimY; - int _mapDimW; - int _mapDimH; - int _mapDimDstX; - int _mapBlockWidth; - int _mapDimDstY; - int _mapBlockHeight; - int _mapDimU5; - int _mapDimU6; - int _mapBlockWidth2; - int _mapDimU8; + int _internDimX; + int _internDimY; + int _internDimW; + int _internDimH; + int _internDimDstX; + int _internBlockWidth; + int _internDimDstY; + int _internBlockHeight; + int _internDimU5; + int _internDimU6; + int _internBlockWidth2; + int _internDimU8; }; } // end of namespace Kyra diff --git a/engines/kyra/screen_v2.cpp b/engines/kyra/screen_v2.cpp index ff8d228c56..50333cd44a 100644 --- a/engines/kyra/screen_v2.cpp +++ b/engines/kyra/screen_v2.cpp @@ -119,7 +119,8 @@ void Screen_v2::getFadeParams(const uint8 *palette, int delay, int &delayInc, in int maxDiff = 0; diff = 0; - for (int i = 0; i < 768; ++i) { + int len = _use16ColorMode ? 48 : 768; + for (int i = 0; i < len; ++i) { diff = ABS(palette[i] - _screenPalette[i]); maxDiff = MAX(maxDiff, diff); } diff --git a/engines/kyra/script_lol.cpp b/engines/kyra/script_lol.cpp index ae27cd6c3d..0015c7c817 100644 --- a/engines/kyra/script_lol.cpp +++ b/engines/kyra/script_lol.cpp @@ -231,7 +231,7 @@ int LoLEngine::olol_getItemPara(EMCState *script) { switch (stackPos(1)) { case 0: - return i->blockPropertyIndex; + return i->block; case 1: return i->x; case 2: @@ -298,7 +298,7 @@ int LoLEngine::olol_getCharacterStat(EMCState *script) { return c->magicPointsMax; case 9: - return c->itemsProtection; + return c->itemProtection; case 10: return c->items[d]; @@ -307,7 +307,7 @@ int LoLEngine::olol_getCharacterStat(EMCState *script) { return c->skillLevels[d] + c->skillModifiers[d]; case 12: - return c->field_27[d]; + return c->protectionAgainstItems[d]; case 13: return (d & 0x80) ? c->itemsMight[7] : c->itemsMight[d]; @@ -341,7 +341,7 @@ int LoLEngine::olol_setCharacterStat(EMCState *script) { break; case 5: - //// TODO + setCharacterMagicOrHitPoints(stackPos(0), 0, e, 0); break; case 6: @@ -349,7 +349,7 @@ int LoLEngine::olol_setCharacterStat(EMCState *script) { break; case 7: - //// TODO + setCharacterMagicOrHitPoints(stackPos(0), 1, e, 0); break; case 8: @@ -357,7 +357,7 @@ int LoLEngine::olol_setCharacterStat(EMCState *script) { break; case 9: - c->itemsProtection = e; + c->itemProtection = e; break; case 10: @@ -369,7 +369,7 @@ int LoLEngine::olol_setCharacterStat(EMCState *script) { break; case 12: - c->field_27[d] = e; + c->protectionAgainstItems[d] = e; break; case 13: @@ -577,7 +577,7 @@ int LoLEngine::olol_getGlobalVar(EMCState *script) { case 11: return _compassBroken; case 12: - return _unkBt2; + return _drainMagic; case 13: return _speechFlag; default: @@ -651,7 +651,7 @@ int LoLEngine::olol_setGlobalVar(EMCState *script) { break; case 12: - _unkBt2 = a & 0xff; + _drainMagic = a & 0xff; break; default: @@ -708,7 +708,7 @@ int LoLEngine::olol_initMonster(EMCState *script) { for (uint8 i = 0; i < 30; i++) { MonsterInPlay *l = &_monsters[i]; - if (l->might || l->mode == 13) + if (l->hitPoints || l->mode == 13) continue; memset(l, 0, sizeof(MonsterInPlay)); @@ -719,13 +719,13 @@ int LoLEngine::olol_initMonster(EMCState *script) { l->type = stackPos(4); l->properties = &_monsterProperties[l->type]; l->direction = l->facing << 1; - l->might = (l->properties->might * _monsterModifiers[_monsterDifficulty]) >> 8; + l->hitPoints = (l->properties->hitPoints * _monsterModifiers[_monsterDifficulty]) >> 8; if (_currentLevel == 12 && l->type == 2) - l->might = (l->might * (_rnd.getRandomNumberRng(1, 128) + 192)) >> 8; + l->hitPoints = (l->hitPoints * (_rnd.getRandomNumberRng(1, 128) + 192)) >> 8; - l->field_25 = l->properties->unk6[0]; - l->field_27 = _rnd.getRandomNumberRng(1, calcMonsterSkillLevel(l->id | 0x8000, 8)) - 1; + l->numDistAttacks = l->properties->numDistAttacks; + l->distAttackTick = _rnd.getRandomNumberRng(1, calcMonsterSkillLevel(l->id | 0x8000, 8)) - 1; l->flyingHeight = 2; l->flags = stackPos(5); l->assignedItems = 0; @@ -740,7 +740,7 @@ int LoLEngine::olol_initMonster(EMCState *script) { for (int ii = 0; ii < 4; ii++) l->field_2A[ii] = stackPos(7 + ii); - checkSceneUpdateNeed(l->blockPropertyIndex); + checkSceneUpdateNeed(l->block); return i; } @@ -779,7 +779,7 @@ int LoLEngine::olol_loadNewLevel(EMCState *script) { disableSysTimer(2); for (int i = 0; i < 8; i++) { - if (!_flyingObjects[i].enable || _flyingObjects[i].a) + if (!_flyingObjects[i].enable || _flyingObjects[i].objectType) continue; endObjectFlight(&_flyingObjects[i], _flyingObjects[i].x, _flyingObjects[i].y, 1); } @@ -800,6 +800,11 @@ int LoLEngine::olol_loadNewLevel(EMCState *script) { return 1; } +int LoLEngine::olol_getNearestMonsterFromCharacter(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getNearestMonsterFromCharacter(%p) (%d)", (const void *)script, stackPos(0)); + return getNearestMonsterFromCharacter(stackPos(0)); +} + int LoLEngine::olol_dummy0(EMCState *script) { return 0; } @@ -835,15 +840,14 @@ int LoLEngine::olol_loadMonsterProperties(EMCState *script) { l->fightingStats[6] = (stackPos(7) << 8) / 100; // l->fightingStats[7] = (stackPos(8) << 8) / 100; // l->fightingStats[8] = 0; - l->fightingStats[9] = 0; for (int i = 0; i < 8; i++) { - l->unk2[i] = stackPos(9 + i); - l->unk3[i] = (stackPos(17 + i) << 8) / 100; + l->itemsMight[i] = stackPos(9 + i); + l->protectionAgainstItems[i] = (stackPos(17 + i) << 8) / 100; } l->itemProtection = stackPos(25); - l->might = stackPos(26); + l->hitPoints = stackPos(26); l->speedTotalWaitTicks = 1; l->flags = stackPos(27); l->unk5 = stackPos(28); @@ -851,13 +855,15 @@ int LoLEngine::olol_loadMonsterProperties(EMCState *script) { l->unk5 = stackPos(29); // - for (int i = 0; i < 5; i++) - l->unk6[i] = stackPos(30 + i); + l->numDistAttacks = stackPos(30); + l->numDistWeapons = stackPos(31); + for (int i = 0; i < 3; i++) + l->distWeapons[i] = stackPos(32 + i); - for (int i = 0; i < 2; i++) { - l->unk7[i] = stackPos(35 + i); - l->unk7[i + 2] = stackPos(37 + i); - } + l->attackSkillChance = stackPos(35); + l->attackSkillType = stackPos(36); + l->defenseSkillChance = stackPos(37); + l->defenseSkillType = stackPos(38); for (int i = 0; i < 3; i++) l->sounds[i] = stackPos(39 + i); @@ -870,6 +876,18 @@ int LoLEngine::olol_battleHitSkillTest(EMCState *script) { return battleHitSkillTest(stackPos(0), stackPos(1), stackPos(2)); } +int LoLEngine::olol_inflictDamage(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_inflictDamage(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4)); + if (stackPos(0) == -1) { + for (int i = 0; i < 4; i++) + inflictDamage(i, stackPos(1), stackPos(2), stackPos(3), stackPos(4)); + } else { + inflictDamage(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4)); + } + + return 1; +} + int LoLEngine::olol_moveMonster(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_moveMonster(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3)); MonsterInPlay *m = &_monsters[stackPos(0)]; @@ -930,6 +948,20 @@ int LoLEngine::olol_createHandItem(EMCState *script) { return 1; } +int LoLEngine::olol_playAttackSound(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playAttackSound(%p) (%d)", (const void *)script, stackPos(0)); + + static const uint8 sounds[] = { 12, 62, 63 }; + int d = stackPos(0); + + if ((d < 70 || d > 74) && (d < 81 || d > 89) && (d < 93 || d > 97) && (d < 102 || d > 106)) + snd_playSoundEffect(sounds[_itemProperties[d].skill & 3], -1); + else + snd_playSoundEffect(12, -1); + + return 1; +} + int LoLEngine::olol_characterJoinsParty(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_characterJoinsParty(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2)); @@ -1043,8 +1075,8 @@ int LoLEngine::olol_getWallFlags(EMCState *script) { return _wllWallFlags[_levelBlockProperties[stackPos(0)].walls[stackPos(1) & 3]]; } -int LoLEngine::olol_changeMonsterSettings(EMCState *script) { - debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_changeMonsterSettings(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2)); +int LoLEngine::olol_changeMonsterStat(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_changeMonsterStat(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2)); if (stackPos(0) == -1) return 1; @@ -1060,7 +1092,7 @@ int LoLEngine::olol_changeMonsterSettings(EMCState *script) { break; case 1: - m->might = d; + m->hitPoints = d; break; case 2: @@ -1084,6 +1116,39 @@ int LoLEngine::olol_changeMonsterSettings(EMCState *script) { return 1; } +int LoLEngine::olol_getMonsterStat(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getMonsterStat(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1)); + if (stackPos(0) == -1) + return 0; + + MonsterInPlay *m = &_monsters[stackPos(0) & 0x7fff]; + int d = stackPos(1); + + switch (d) { + case 0: + return m->mode; + case 1: + return m->hitPoints; + case 2: + return m->block; + case 3: + return m->facing; + case 4: + return m->type; + case 5: + return m->properties->hitPoints; + case 6: + return m->flags; + case 7: + return m->properties->flags; + case 8: + return _monsterUnk[m->properties->shapeIndex]; + default: + break; + } + + return 0; +} int LoLEngine::olol_playCharacterScriptChat(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_playCharacterScriptChat(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2)); @@ -1098,6 +1163,18 @@ int LoLEngine::olol_update(EMCState *script) { return 1; } +int LoLEngine::olol_healCharacter(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_healCharacter(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3)); + if (stackPos(3)) { + processMagicHeal(stackPos(0), stackPos(1)); + } else { + increaseCharacterHitpoints(stackPos(0), stackPos(1), true); + if (stackPos(2)) + gui_drawCharPortraitWithStats(stackPos(0)); + } + return 1; +} + int LoLEngine::olol_drawExitButton(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_drawExitButton(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1)); @@ -1164,6 +1241,17 @@ int LoLEngine::olol_setPaletteBrightness(EMCState *script) { return old; } +int LoLEngine::olol_calcInflictableDamage(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_calcInflictableDamage(%p) (%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2)); + return calcInflictableDamage(stackPos(0), stackPos(1), stackPos(2)); +} + +int LoLEngine::olol_getInflictedDamage(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_getInflictedDamage(%p) (%d)", (const void *)script, stackPos(0)); + int mx = stackPos(0); + return mx ? _rnd.getRandomNumberRng(2, mx) : 0; +} + int LoLEngine::olol_checkForCertainPartyMember(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkForCertainPartyMember(%p) (%d)", (const void *)script, stackPos(0)); for (int i = 0; i < 4; i++) { @@ -1186,14 +1274,19 @@ int LoLEngine::olol_printMessage(EMCState *script) { int LoLEngine::olol_deleteLevelItem(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_deleteLevelItem(%p) (%d)", (const void *)script, stackPos(0)); - if (_itemsInPlay[stackPos(0)].blockPropertyIndex) - removeLevelItem(stackPos(0), _itemsInPlay[stackPos(0)].blockPropertyIndex); + if (_itemsInPlay[stackPos(0)].block) + removeLevelItem(stackPos(0), _itemsInPlay[stackPos(0)].block); deleteItem(stackPos(0)); return 1; } +int LoLEngine::olol_calcInflictableDamagePerItem(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_calcInflictableDamagePerItem(%p) (%d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4)); + return calcInflictableDamagePerItem(stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4)); +} + int LoLEngine::olol_objectLeavesLevel(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_objectLeavesLevel(%p) (%d, %d, %d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5)); int o = _levelBlockProperties[stackPos(0)].assignedObjects; @@ -1216,7 +1309,7 @@ int LoLEngine::olol_objectLeavesLevel(EMCState *script) { MonsterInPlay *m = &_monsters[l]; setMonsterMode(m, 14); - checkSceneUpdateNeed(m->blockPropertyIndex); + checkSceneUpdateNeed(m->block); placeMonster(m, 0, 0); res = 1; @@ -1276,7 +1369,7 @@ 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]; setMonsterMode(m, 14); - checkSceneUpdateNeed(m->blockPropertyIndex); + checkSceneUpdateNeed(m->block); placeMonster(m, 0, 0); return 1; } @@ -1287,9 +1380,9 @@ int LoLEngine::olol_setDoorState(EMCState *script) { return _emcDoorState; } -int LoLEngine::olol_processButtonClick(EMCState *script) { - debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_processButtonClick(%p) (%d)", (const void *)script, stackPos(0)); - _tim->forceDialogue(_activeTim[stackPos(0)]); +int LoLEngine::olol_resetTimDialogueState(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_resetTimDialogueState(%p) (%d)", (const void *)script, stackPos(0)); + _tim->resetDialogueState(_activeTim[stackPos(0)]); return 1; } @@ -1433,7 +1526,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))); - _res->loadFileToBuf(palFile, _screen->getPalette(0), 768); + _screen->loadPalette(palFile, _screen->getPalette(0)); return 1; } @@ -1747,13 +1840,13 @@ void LoLEngine::setupOpcodeTable() { // 0x3C Opcode(olol_loadNewLevel); - OpcodeUnImpl(); + Opcode(olol_getNearestMonsterFromCharacter); Opcode(olol_dummy0); Opcode(olol_loadMonsterProperties); // 0x40 Opcode(olol_battleHitSkillTest); - OpcodeUnImpl(); + Opcode(olol_inflictDamage); OpcodeUnImpl(); OpcodeUnImpl(); @@ -1766,7 +1859,7 @@ void LoLEngine::setupOpcodeTable() { // 0x48 Opcode(olol_setScriptTimer); Opcode(olol_createHandItem); - OpcodeUnImpl(); + Opcode(olol_playAttackSound); Opcode(olol_characterJoinsParty); // 0x4C @@ -1791,17 +1884,17 @@ void LoLEngine::setupOpcodeTable() { Opcode(olol_processDialogue); Opcode(olol_stopTimScript); Opcode(olol_getWallFlags); - Opcode(olol_changeMonsterSettings); + Opcode(olol_changeMonsterStat); // 0x5C - OpcodeUnImpl(); + Opcode(olol_getMonsterStat); OpcodeUnImpl(); Opcode(olol_playCharacterScriptChat); Opcode(olol_update); // 0x60 OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_healCharacter); Opcode(olol_drawExitButton); Opcode(olol_loadSoundFile); @@ -1818,14 +1911,14 @@ void LoLEngine::setupOpcodeTable() { Opcode(olol_setPaletteBrightness); // 0x6C - OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_calcInflictableDamage); + Opcode(olol_getInflictedDamage); Opcode(olol_checkForCertainPartyMember); Opcode(olol_printMessage); // 0x70 Opcode(olol_deleteLevelItem); - OpcodeUnImpl(); + Opcode(olol_calcInflictableDamagePerItem); OpcodeUnImpl(); OpcodeUnImpl(); @@ -1857,7 +1950,7 @@ void LoLEngine::setupOpcodeTable() { OpcodeUnImpl(); OpcodeUnImpl(); Opcode(olol_setDoorState); - Opcode(olol_processButtonClick); + Opcode(olol_resetTimDialogueState); // 0x88 OpcodeUnImpl(); diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index 461cd17083..a3f3268db3 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -618,6 +618,8 @@ int TIMInterpreter::cmd_playVocFile(const uint16 *param) { if (index < ARRAYSIZE(_vocFiles) && !_vocFiles[index].empty()) vm()->sound()->voicePlay(_vocFiles[index].c_str(), volume, true); + else if (index == 7 && !_vm->gameFlags().isTalkie) + vm()->sound()->playTrack(index); else vm()->sound()->playSoundEffect(index); @@ -1144,7 +1146,7 @@ uint16 TIMInterpreter_LoL::processDialogue() { return res; } -void TIMInterpreter_LoL::forceDialogue(TIM *tim) { +void TIMInterpreter_LoL::resetDialogueState(TIM *tim) { if (!tim) return; diff --git a/engines/kyra/script_tim.h b/engines/kyra/script_tim.h index 3748867f54..6e9d5fc6b8 100644 --- a/engines/kyra/script_tim.h +++ b/engines/kyra/script_tim.h @@ -145,7 +145,7 @@ public: virtual void updateBackgroundAnimation(int animIndex) {} virtual void playAnimationPart(int animIndex, int firstFrame, int lastFrame, int delay) {} - virtual void forceDialogue(TIM *tim) {} + virtual void resetDialogueState(TIM *tim) {} int _drawPage2; @@ -231,7 +231,7 @@ public: void drawDialogueBox(int numStr, const char *s1, const char *s2, const char *s3); uint16 processDialogue(); - void forceDialogue(TIM *tim); + void resetDialogueState(TIM *tim); void setupBackgroundAnimationPart(int animIndex, int part, int firstFrame, int lastFrame, int cycles, int nextPart, int partDelay, int f, int sfxIndex, int sfxFrame); void startBackgroundAnimation(int animIndex, int part); diff --git a/engines/kyra/sequences_lol.cpp b/engines/kyra/sequences_lol.cpp index 4037b9c30b..df86b4a519 100644 --- a/engines/kyra/sequences_lol.cpp +++ b/engines/kyra/sequences_lol.cpp @@ -88,6 +88,7 @@ void LoLEngine::setupPrologueData(bool load) { memset(_selectionAnimTimers, 0, sizeof(_selectionAnimTimers)); memset(_screen->getPalette(1), 0, 768); + } else { delete _chargenWSA; _chargenWSA = 0; @@ -114,6 +115,13 @@ void LoLEngine::setupPrologueData(bool load) { _eventList.clear(); } + + // We have three sound.dat files, one for the intro, one for the + // end sequence and one for ingame, each contained in a different + // PAK file. Therefore a new call to loadSoundFile() is required + // whenever the PAK file configuration changes. + if (_flags.platform == Common::kPlatformPC98) + _sound->loadSoundFile("sound.dat"); } void LoLEngine::showIntro() { @@ -122,13 +130,16 @@ void LoLEngine::showIntro() { _tim = new TIMInterpreter(this, _screen, _system); assert(_tim); + if (_flags.platform == Common::kPlatformPC98) + showStarcraftLogo(); + uint8 *pal = _screen->getPalette(0); memset(pal, 0, 768); _screen->setScreenPalette(pal); _screen->clearPage(0); _screen->clearPage(4); - _screen->clearPage(8); + _screen->clearPage(8); TIM *intro = _tim->load("LOLINTRO.TIM", &_timIntroOpcodes); @@ -226,6 +237,9 @@ int LoLEngine::chooseCharacter() { _screen->copyRegion(0, 0, 0, 0, 320, 200, 2, 0, Screen::CR_NO_P_CHECK); _screen->_curPage = 0; + if (_flags.use16ColorMode) + _screen->loadPalette("LOL.NOL", _screen->getPalette(0)); + _screen->fadePalette(_screen->getPalette(0), 30, 0); bool kingIntro = true; @@ -571,6 +585,51 @@ int LoLEngine::selectionCharAccept() { return -1; } +void LoLEngine::showStarcraftLogo() { + WSAMovie_v2 *ci = new WSAMovie_v2(this, _screen); + assert(ci); + + _screen->clearPage(0); + _screen->clearPage(2); + + int endframe = ci->open("ci01.wsa", 0, _screen->_currentPalette); + if (!ci->opened()) { + delete ci; + return; + } + _screen->hideMouse(); + ci->setX(32); + ci->setY(80); + ci->setDrawPage(2); + ci->displayFrame(0, 0); + _screen->copyPage(2, 0); + _screen->fadeFromBlack(); + int inputFlag = 0; + for (int i = 0; i < endframe; i++) { + inputFlag = checkInput(0) & 0xff; + if (shouldQuit() || inputFlag) + break; + ci->displayFrame(i, 0); + _screen->copyPage(2, 0); + _screen->updateScreen(); + delay(4 * _tickLength); + } + + if (!(shouldQuit() || inputFlag)) { + _sound->voicePlay("star2"); + while(_sound->voiceIsPlaying("star2") && !(shouldQuit() || inputFlag)) { + inputFlag = checkInput(0) & 0xff; + delay(_tickLength); + } + } + + _screen->fadeToBlack(); + _screen->showMouse(); + + _eventList.clear(); + delete ci; +} + } // end of namespace Kyra #endif // ENABLE_LOL diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h index 7b7fba8e3a..565e02e917 100644 --- a/engines/kyra/sound.h +++ b/engines/kyra/sound.h @@ -224,9 +224,11 @@ public: */ void voiceStop(const char *file = 0); protected: - const char *fileListEntry(int file) const { return (_soundDataList != 0 && file >= 0 && file < _soundDataList->_fileListLen) ? _soundDataList->_fileList[file] : ""; } - const void *cdaData() const { return _soundDataList != 0 ? _soundDataList->_cdaTracks : 0; } - int cdaTrackNum() const { return _soundDataList != 0 ? _soundDataList->_cdaNumTracks : 0; } + const char *fileListEntry(int file) const { return (_soundDataList != 0 && file >= 0 && file < _soundDataList->fileListLen) ? _soundDataList->fileList[file] : ""; } + int fileListLen() const { return _soundDataList->fileListLen; } + const void *cdaData() const { return _soundDataList != 0 ? _soundDataList->cdaTracks : 0; } + int cdaTrackNum() const { return _soundDataList != 0 ? _soundDataList->cdaNumTracks : 0; } + int extraOffset() const { return _soundDataList != 0 ? _soundDataList->extraOffset : 0; } enum { kNumChannelHandles = 4 diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp index c85c5b3ef0..9b085fc69f 100644 --- a/engines/kyra/sound_towns.cpp +++ b/engines/kyra/sound_towns.cpp @@ -2714,7 +2714,7 @@ void TownsPC98_OpnSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) { finOut += _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0]; } - finOut /= 2; + finOut /= 4; buffer[i << 1] += finOut; buffer[(i << 1) + 1] += finOut; } @@ -2887,7 +2887,7 @@ void TownsPC98_OpnPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) { finOut += _rhChan[ii].out; } - finOut *= 7; + finOut *= 3; buffer[i << 1] += finOut; buffer[(i << 1) + 1] += finOut; @@ -3381,7 +3381,7 @@ void TownsPC98_OpnCore::nextTick(int32 *buffer, uint32 bufferSize) { break; }; - int32 finOut = ((output * 7) / 2); + int32 finOut = ((output * 3) / ((_numChan + _numSSG - 3) / 3)); if (_chanInternal[i].enableLeft) *leftSample += finOut; @@ -4064,8 +4064,7 @@ bool SoundPC98::init() { } void SoundPC98::playTrack(uint8 track) { - if (--track >= 56) - track -= 55; + track += extraOffset(); if (track == _lastTrack && _musicEnabled) return; @@ -4074,6 +4073,10 @@ void SoundPC98::playTrack(uint8 track) { char musicfile[13]; sprintf(musicfile, fileListEntry(0), track); + if (fileListLen() == 1) + sprintf(musicfile, fileListEntry(0), track); + else + strcpy(musicfile, fileListEntry(track)); delete[] _musicTrackData; _musicTrackData = _vm->resource()->fileData(musicfile, 0); if (_musicEnabled) @@ -4126,19 +4129,25 @@ SoundTownsPC98_v2::~SoundTownsPC98_v2() { bool SoundTownsPC98_v2::init() { _driver = new TownsPC98_OpnDriver(_mixer, _vm->gameFlags().platform == Common::kPlatformPC98 ? TownsPC98_OpnDriver::OD_TYPE86 : TownsPC98_OpnDriver::OD_TOWNS); - _useFmSfx = _vm->gameFlags().platform == Common::kPlatformPC98 ? true : false; - _vm->checkCD(); - // FIXME: While checking for 'track1.XXX(X)' looks like - // a good idea, we should definitely not be doing this - // here. Basically our filenaming scheme could change - // or we could add support for other audio formats. Also - // this misses the possibility that we play the tracks - // right off CD. So we should find another way to - // check if we have access to CD audio. - Resource *res = _vm->resource(); - if (_musicEnabled && - (res->exists("track1.mp3") || res->exists("track1.ogg") || res->exists("track1.flac") || res->exists("track1.fla"))) - _musicEnabled = 2; + + if (_vm->gameFlags().platform == Common::kPlatformFMTowns) { + _vm->checkCD(); + // FIXME: While checking for 'track1.XXX(X)' looks like + // a good idea, we should definitely not be doing this + // here. Basically our filenaming scheme could change + // or we could add support for other audio formats. Also + // this misses the possibility that we play the tracks + // right off CD. So we should find another way to + // check if we have access to CD audio. + Resource *res = _vm->resource(); + if (_musicEnabled && + (res->exists("track1.mp3") || res->exists("track1.ogg") || res->exists("track1.flac") || res->exists("track1.fla"))) + _musicEnabled = 2; + _useFmSfx = false; + + } else { + _useFmSfx = true; + } return _driver->init(); } @@ -4153,6 +4162,8 @@ void SoundTownsPC98_v2::process() { } void SoundTownsPC98_v2::playTrack(uint8 track) { + track += extraOffset(); + if (track == _lastTrack && _musicEnabled) return; @@ -4171,7 +4182,10 @@ void SoundTownsPC98_v2::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)); delete[] _musicTrackData; _musicTrackData = _vm->resource()->fileData(musicfile, 0); @@ -4208,6 +4222,8 @@ void SoundTownsPC98_v2::beginFadeOut() { int32 SoundTownsPC98_v2::voicePlay(const char *file, uint8, bool) { static const uint16 rates[] = { 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 }; + static const char patternHOF[] = "%s.PCM"; + static const char patternLOL[] = "%s.VOC"; int h = 0; if (_currentSFX) { @@ -4218,10 +4234,13 @@ int32 SoundTownsPC98_v2::voicePlay(const char *file, uint8, bool) { } char filename[13]; - sprintf(filename, "%s.PCM", file); + const char *pattern = _vm->game() == GI_LOL ? patternLOL : patternHOF; + sprintf(filename, pattern, file); uint8 *data = _vm->resource()->fileData(filename, 0); uint8 *src = data; + if (!src) + return 0; uint16 sfxRate = rates[READ_LE_UINT16(src)]; src += 2; diff --git a/engines/kyra/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp index 7d8ca049a3..9c9038ca71 100644 --- a/engines/kyra/sprites_lol.cpp +++ b/engines/kyra/sprites_lol.cpp @@ -80,8 +80,7 @@ void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int b) { uint8 *tmpPal2 = new uint8[256]; uint16 *tmpPal3 = new uint16[256]; memset (tmpPal1, 0, 64); - memset (tmpPal2, 0, 256); - memset (tmpPal3, 0xff, 512); + memset (tmpPal2, 0, 256); for (int i = 0; i < 64; i++) { tmpPal1[i] = *p; @@ -93,6 +92,7 @@ void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int b) { for (int i = 0; i < 16; i++) { int pos = (monsterIndex << 4) + i; memcpy(tmpPal2, _monsterShapes[pos] + 10, 256); + memset (tmpPal3, 0xff, 512); uint8 numCol = *tmpPal2; for (int ii = 0; ii < numCol; ii++) { @@ -152,7 +152,7 @@ int LoLEngine::deleteMonstersFromBlock(int block) { cnt++; setMonsterMode(m, 14); - checkSceneUpdateNeed(m->blockPropertyIndex); + checkSceneUpdateNeed(m->block); placeMonster(m, 0, 0); @@ -184,14 +184,14 @@ void LoLEngine::setMonsterMode(MonsterInPlay *monster, int mode) { monster->mode = mode; monster->fightCurTick = 0; if (mode == 14) - monster->might = 0; + monster->hitPoints = 0; if (mode == 13 && (monster->flags & 0x20)) { monster->mode = 0; monsterDropItems(monster); if (_currentLevel != 29) setMonsterMode(monster, 14); runLevelScriptCustom(0x404, -1, monster->id, monster->id, 0, 0); - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); if (monster->mode == 14) placeMonster(monster, 0, 0); } @@ -230,7 +230,7 @@ bool LoLEngine::updateMonsterAdjustBlocks(MonsterInPlay *monster) { return false; for (int i = 0; i < 18; i++) - _visibleBlocks[i] = &_levelBlockProperties[(monster->blockPropertyIndex + _dscBlockIndex[dir + i]) & 0x3ff]; + _visibleBlocks[i] = &_levelBlockProperties[(monster->block + _dscBlockIndex[dir + i]) & 0x3ff]; int16 fx1 = 0; int16 fx2 = 0; @@ -241,8 +241,8 @@ bool LoLEngine::updateMonsterAdjustBlocks(MonsterInPlay *monster) { void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) { bool cont = true; - int t = monster->blockPropertyIndex; - if (monster->blockPropertyIndex) { + int t = monster->block; + if (monster->block) { removeAssignedObjectFromBlock(&_levelBlockProperties[t], ((uint16)monster->id) | 0x8000); _levelBlockProperties[t].direction = 5; checkSceneUpdateNeed(t); @@ -250,7 +250,7 @@ void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) { cont = false; } - monster->blockPropertyIndex = calcBlockIndex(x, y); + monster->block = calcBlockIndex(x, y); if (monster->x != x || monster->y != y) { monster->x = x; @@ -258,26 +258,26 @@ void LoLEngine::placeMonster(MonsterInPlay *monster, uint16 x, uint16 y) { monster->currentSubFrame = (++monster->currentSubFrame) & 3; } - if (monster->blockPropertyIndex == 0) + if (monster->block == 0) return; - assignMonsterToBlock(&_levelBlockProperties[monster->blockPropertyIndex].assignedObjects, ((uint16)monster->id) | 0x8000); - _levelBlockProperties[monster->blockPropertyIndex].direction = 5; - checkSceneUpdateNeed(monster->blockPropertyIndex); + assignMonsterToBlock(&_levelBlockProperties[monster->block].assignedObjects, ((uint16)monster->id) | 0x8000); + _levelBlockProperties[monster->block].direction = 5; + checkSceneUpdateNeed(monster->block); if (monster->properties->sounds[0] == 0 || cont == false) return; - if ((!(monster->properties->flags & 0x100) || ((monster->currentSubFrame & 1) == 0)) && monster->blockPropertyIndex == t) + if ((!(monster->properties->flags & 0x100) || ((monster->currentSubFrame & 1) == 0)) && monster->block == t) return; - if (monster->blockPropertyIndex != t) - runLevelScriptCustom(monster->blockPropertyIndex, 0x800, -1, monster->id, 0, 0); + if (monster->block != t) + runLevelScriptCustom(monster->block, 0x800, -1, monster->id, 0, 0); if (_updateFlags & 1) return; - snd_processEnvironmentalSoundEffect(monster->properties->sounds[0], monster->blockPropertyIndex); + snd_processEnvironmentalSoundEffect(monster->properties->sounds[0], monster->block); } int LoLEngine::calcMonsterDirection(uint16 x1, uint16 y1, uint16 x2, uint16 y2) { @@ -319,7 +319,7 @@ void LoLEngine::setMonsterDirection(MonsterInPlay *monster, int dir) { if (!(dir & 1) || ((monster->direction - (monster->facing << 1)) >= 2)) monster->facing = monster->direction >> 1; - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); } void LoLEngine::monsterDropItems(MonsterInPlay *monster) { @@ -651,45 +651,45 @@ void LoLEngine::drawMonster(uint16 id) { } } - if (!m->field_1B) + if (!m->damageReceived) return; int dW = _screen->getShapeScaledWidth(shp, _dmScaleW) >> 1; int dH = _screen->getShapeScaledHeight(shp, _dmScaleH) >> 1; - int a = (m->mode == 13) ? (m->fightCurTick << 1) : (m->properties->might / (m->field_1B & 0x7fff)); + int bloodAmount = (m->mode == 13) ? (m->fightCurTick << 1) : (m->properties->hitPoints / (m->damageReceived & 0x7fff)); shp = _gameShapes[6]; - int cF = m->properties->flags & 0xc000; - if (cF == 0x4000) - cF = 63; - else if (cF == 0x8000) - cF = 15; - else if (cF == 0xc000) - cF = 74; + int bloodType = m->properties->flags & 0xc000; + if (bloodType == 0x4000) + bloodType = 63; + else if (bloodType == 0x8000) + bloodType = 15; + else if (bloodType == 0xc000) + bloodType = 74; else - cF = 0; + bloodType = 0; uint8 *tbl = new uint8[256]; - if (cF) { + if (bloodType) { for (int i = 0; i < 256; i++) { tbl[i] = i; if (i < 2 || i > 7) continue; - tbl[i] += cF; + tbl[i] += bloodType; } } - dW += m->anon8; - dH += m->anonh; + dW += m->hitOffsX; + dH += m->hitOffsY; - a = CLIP(a, 1, 4); + bloodAmount = CLIP(bloodAmount, 1, 4); - int sW = _dmScaleW / a; - int sH = _dmScaleH / a; + int sW = _dmScaleW / bloodAmount; + int sH = _dmScaleH / bloodAmount; - _screen->drawShape(_sceneDrawPage1, shp, _shpDmX + dW, _shpDmY + dH, 13, 0x124, tbl, cF ? 1 : 0, sW, sH); + _screen->drawShape(_sceneDrawPage1, shp, _shpDmX + dW, _shpDmY + dH, 13, 0x124, tbl, bloodType ? 1 : 0, sW, sH); delete[] tbl; } @@ -698,14 +698,14 @@ int LoLEngine::getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags) { switch (_monsterUnk[m->properties->shapeIndex]) { case 0: if (dirFlags) { - return (m->properties->fightingStats[0] & 0xff) == 13 ? -1 : (dirFlags + m->currentSubFrame); + return (m->mode == 13) ? -1 : (dirFlags + m->currentSubFrame); } else { - if (m->field_1B) + if (m->damageReceived) return 12; switch (m->mode - 5) { case 0: - return m->field_1B ? 12 : ((m->properties->flags & 4) ? 13 : 0); + return (m->properties->flags & 4) ? 13 : 0; case 3: return (m->fightCurTick + 13); case 6: @@ -713,7 +713,7 @@ int LoLEngine::getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags) { case 8: return -1; default: - return m->field_1B ? 12 : m->currentSubFrame; + return m->currentSubFrame; } } break; @@ -1013,9 +1013,9 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) { monster->speedTick = 0; if (monster->properties->flags & 0x40) { - monster->might += _rnd.getRandomNumberRng(1, 8); - if (monster->might > monster->properties->might) - monster->might = monster->properties->might; + monster->hitPoints += _rnd.getRandomNumberRng(1, 8); + if (monster->hitPoints > monster->properties->hitPoints) + monster->hitPoints = monster->properties->hitPoints; } if (monster->flags & 8) { @@ -1036,7 +1036,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) { if ((monster->mode != 11) && (monster->mode != 14)) { if (!(getRandomNumberSpecial() & 3)) { monster->shiftStep = (++monster->shiftStep) & 0x0f; - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); } } @@ -1062,7 +1062,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) { if (updateMonsterAdjustBlocks(monster)) setMonsterMode(monster, 7); for (int i = 0; i < 4; i++) { - if (calcNewBlockPosition(monster->blockPropertyIndex, i) == _currentBlock) + if (calcNewBlockPosition(monster->block, i) == _currentBlock) setMonsterMode(monster, 7); } break; @@ -1096,7 +1096,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) { // monster can't change mode before arriving at destination and/or attacking the party if (!chasePartyWithDistanceAttacks(monster)) chasePartyWithCloseAttacks(monster); - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); break; case 8: @@ -1105,7 +1105,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) { setMonsterMode(monster, 5); monster->fightCurTick = (int8) ((((8 << 8) / monster->properties->fightingStats[4]) * _monsterModifiers[6 + _monsterDifficulty]) >> 8); } - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); break; case 9: @@ -1119,7 +1119,7 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) { break; case 12: - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); if (++monster->fightCurTick > 13) runLevelScriptCustom(0x404, -1, monster->id, monster->id, 0, 0); break; @@ -1128,23 +1128,23 @@ void LoLEngine::updateMonster(MonsterInPlay *monster) { // monster death if (++monster->fightCurTick > 2) killMonster(monster); - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); break; case 14: - monster->field_1B = 0; + monster->damageReceived = 0; break; default: break; } - if (monster->field_1B) { - if (monster->field_1B & 0x8000) - monster->field_1B &= 0x7fff; + if (monster->damageReceived) { + if (monster->damageReceived & 0x8000) + monster->damageReceived &= 0x7fff; else - monster->field_1B = 0; - checkSceneUpdateNeed(monster->blockPropertyIndex); + monster->damageReceived = 0; + checkSceneUpdateNeed(monster->block); } monster->flags &= 0xffef; @@ -1174,10 +1174,10 @@ void LoLEngine::walkMonster(MonsterInPlay *monster) { setMonsterDirection(monster, _monsterLastWalkDirection); } else { setMonsterDirection(monster, s); - if (monster->field_25) { - if (getMonsterDistance(monster->blockPropertyIndex, _currentBlock) >= 2) { - if (walkMonster_s3(monster->blockPropertyIndex, monster->direction, 3, _currentBlock) != 5) { - if (monster->field_27) + if (monster->numDistAttacks) { + if (getMonsterDistance(monster->block, _currentBlock) >= 2) { + if (checkForPossibleDistanceAttack(monster->block, monster->direction, 3, _currentBlock) != 5) { + if (monster->distAttackTick) return; } } @@ -1192,9 +1192,80 @@ void LoLEngine::walkMonster(MonsterInPlay *monster) { } bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) { - if (!monster->field_25) + if (!monster->numDistAttacks) return false; + if (monster->distAttackTick > 0) { + monster->distAttackTick--; + return false; + } + + int dir = checkForPossibleDistanceAttack(monster->block, monster->facing, 4, _currentBlock); + if (dir == 5) + return false; + + int s = 0; + + if (monster->flags & 0x10) { + s = monster->properties->numDistWeapons ? _rnd.getRandomNumberRng(1, monster->properties->numDistWeapons) : 0; + } else { + s = monster->curDistWeapon++; + if (monster->curDistWeapon == monster->properties->numDistWeapons) + monster->curDistWeapon = 0; + } + + int flyingObject = monster->properties->distWeapons[s]; + + if (flyingObject & 0xc000) { + if (getMonsterDistance(monster->block, _currentBlock) > 1) { + int type = flyingObject & 0x4000 ? 0 : 1; + flyingObject = makeItem(flyingObject & 0x3fff, 0, 0); + + if (flyingObject) { + if (!launchObject(type, flyingObject, monster->x, monster->y, 12, dir << 1, -1, monster->id | 0x8000, 0x3f)) + deleteItem(flyingObject); + } + } + } else if (!(flyingObject & 0x2000)) { + if (getMonsterDistance(monster->block, _currentBlock) > 1) + return false; + + if (flyingObject == 1) { + snd_playSoundEffect(147, -1); + distObj1Sub(10, 2, 2, 1); + + for (int i = 0; i < 4; i++) { + if (!(_characters[i].flags & 1)) + continue; + + int item = removeCharacterItem(i, 15); + if (item) + setItemPosition(item, _partyPosX, _partyPosY, 0, 1); + + inflictDamage(i, 20, -1, 0, 2); + } + + } else if (flyingObject == 3) { + // shriek + for (int i = 0; i < 30; i++) { + if (getMonsterDistance(monster->block, _monsters[i].block) < 7) + setMonsterMode(monster, 7); + } + _txt->printMessage(2, getLangString(0x401a)); + + } else if (flyingObject == 4) { + launchMagicViper(); + + } else { + return false; + } + } + + if (monster->numDistAttacks != 255) + monster->numDistAttacks--; + + monster->distAttackTick = (monster->properties->fightingStats[4] * 8) >> 8; + return true; } @@ -1209,23 +1280,24 @@ void LoLEngine::chasePartyWithCloseAttacks(MonsterInPlay *monster) { int t = (x1 < 0) ? -x1 : x1; if (y1 <= 160 && t <= 80) { if ((monster->direction == dir) && (monster->facing == (dir >> 1))) { - int dst = getClosestPartyMember(monster->x, monster->y); + int dst = getNearestPartyMemberFromPos(monster->x, monster->y); snd_playSoundEffect(monster->properties->sounds[1], -1); int m = monster->id | 0x8000; int hit = battleHitSkillTest(m, dst, 0); if (hit) { - int dmg = _rnd.getRandomNumberRng(2, calcInflictableDamage(m, dst, hit)); - battleHit_sub2(dst, dmg, m, 0); - battleHit_sub3(monster, dst, dmg); + int mx = calcInflictableDamage(m, dst, hit); + int dmg = mx ? _rnd.getRandomNumberRng(2, mx) : 0; + inflictDamage(dst, dmg, m, 0, 0); + applyMonsterAttackSkill(monster, dst, dmg); } setMonsterMode(monster, 8); - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); } else { setMonsterDirection(monster, dir); - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); } return; } @@ -1308,24 +1380,26 @@ int LoLEngine::getMonsterDistance(uint16 block1, uint16 block2) { return (dx << 1) + dy; } -int LoLEngine::walkMonster_s3(uint16 monsterBlock, int direction, int distance, uint16 curBlock) { +int LoLEngine::checkForPossibleDistanceAttack(uint16 monsterBlock, int direction, int distance, uint16 curBlock) { int mdist = getMonsterDistance(curBlock, monsterBlock); if (mdist > distance) return 5; int dir = calcMonsterDirection(monsterBlock & 0x1f, monsterBlock >> 5, curBlock & 0x1f, curBlock >> 5); - if ((dir & 1) || ((dir << 1) != direction)) + if ((dir & 1) || (dir != direction << 1)) return 5; - if (((monsterBlock & 0x1f) != (curBlock & 0x1f)) || ((monsterBlock & 0xffe0) != (curBlock & 0xffe0))) + if (((monsterBlock & 0x1f) != (curBlock & 0x1f)) && ((monsterBlock & 0xffe0) != (curBlock & 0xffe0))) return 5; if (distance < 0) return 5; + int p = monsterBlock; + for (int i = 0; i < distance; i++) { - int p = calcNewBlockPosition(monsterBlock, direction); + p = calcNewBlockPosition(p, direction); if (p == curBlock) return direction; @@ -1373,7 +1447,7 @@ void LoLEngine::rearrangeAttackingMonster(MonsterInPlay *monster) { if (monster->nextAssignedObject & 0x8000) { r = true; } else { - uint16 id = _levelBlockProperties[monster->blockPropertyIndex].assignedObjects; + uint16 id = _levelBlockProperties[monster->block].assignedObjects; id = (id & 0x8000) ? (id & 0x7fff) : 0xffff; if (id != monster->id) { @@ -1381,7 +1455,7 @@ void LoLEngine::rearrangeAttackingMonster(MonsterInPlay *monster) { } else { for (int i = 0; i < 3; i++) { t = (t + 1) & 3; - id = _levelBlockProperties[calcNewBlockPosition(monster->blockPropertyIndex, t)].assignedObjects; + id = _levelBlockProperties[calcNewBlockPosition(monster->block, t)].assignedObjects; id = (id & 0x8000) ? (id & 0x7fff) : 0xffff; if (id != 0xffff) r = true; @@ -1465,12 +1539,12 @@ void LoLEngine::moveStrayingMonster(MonsterInPlay *monster) { void LoLEngine::killMonster(MonsterInPlay *monster) { setMonsterMode(monster, 14); monsterDropItems(monster); - checkSceneUpdateNeed(monster->blockPropertyIndex); + checkSceneUpdateNeed(monster->block); - uint8 w = _levelBlockProperties[monster->blockPropertyIndex].walls[0]; - uint8 f = _levelBlockProperties[monster->blockPropertyIndex].flags; + uint8 w = _levelBlockProperties[monster->block].walls[0]; + uint8 f = _levelBlockProperties[monster->block].flags; if (_wllVmpMap[w] == 0 && _wllShapeMap[w] == 0 && !(f & 0x40) && !(monster->properties->flags & 0x1000)) - _levelBlockProperties[monster->blockPropertyIndex].flags |= 0x80; + _levelBlockProperties[monster->block].flags |= 0x80; placeMonster(monster, 0, 0); } diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp index ef45c0b6e4..b60a7f1e90 100644 --- a/engines/kyra/staticres.cpp +++ b/engines/kyra/staticres.cpp @@ -44,7 +44,7 @@ namespace Kyra { -#define RESFILE_VERSION 44 +#define RESFILE_VERSION 45 namespace { bool checkKyraDat(Common::SeekableReadStream *file) { @@ -449,6 +449,8 @@ bool StaticResource::init() { { lolMapStringId, kLolRawDataBe16, "MAPSTRID.LST" }, //{ lolMapPal, kRawData, "MAP.PAL" }, + { lolHealShapeFrames, kRawData, "MHEAL.SHP" }, + { 0, 0, 0 } }; #endif // ENABLE_LOL @@ -992,20 +994,13 @@ bool StaticResource::loadCharData(const char *filename, void *&ptr, int &size) { t->id = file->readSint16LE(); t->curFaceFrame = file->readByte(); t->defaultFaceFrame = file->readByte(); - t->field_12 = file->readByte(); + t->screamSfx = file->readByte(); file->readUint32LE(); for (int ii = 0; ii < 8; ii++) t->itemsMight[ii] = file->readUint16LE(); - for (int ii = 0; ii < 2; ii++) - t->field_27[ii] = file->readUint16LE(); - t->field_2B = file->readByte(); - t->field_2C = file->readUint16LE(); - t->field_2E = file->readUint16LE(); - t->field_30 = file->readUint16LE(); - t->field_32 = file->readUint16LE(); - t->field_34 = file->readUint16LE(); - t->field_36 = file->readByte(); - t->itemsProtection = file->readUint16LE(); + for (int ii = 0; ii < 8; ii++) + t->protectionAgainstItems[ii] = file->readUint16LE(); + t->itemProtection = file->readUint16LE(); t->hitPointsCur = file->readSint16LE();; t->hitPointsMax = file->readUint16LE();; t->magicPointsCur = file->readSint16LE();; @@ -1027,9 +1022,9 @@ bool StaticResource::loadCharData(const char *filename, void *&ptr, int &size) { for (int ii = 0; ii < 3; ii++) t->experiencePts[ii] = file->readUint32LE(); for (int ii = 0; ii < 5; ii++) - t->arrayUnk2[ii] = file->readByte(); + t->characterUpdateEvents[ii] = file->readByte(); for (int ii = 0; ii < 5; ii++) - t->arrayUnk1[ii] = file->readByte(); + t->characterUpdateDelay[ii] = file->readByte(); }; ptr = charData; @@ -1430,47 +1425,28 @@ void KyraEngine_LoK::initStaticResource() { // FIXME: It seems Kyra1 MAC CD includes AdLib and MIDI music and sfx, thus we enable // support for those for now. (Based on patch #2767489 "Support for Mac Kyrandia 1 CD" by satz). + memset(_soundData, 0, sizeof(_soundData)); if (_flags.platform == Common::kPlatformPC || _flags.platform == Common::kPlatformMacintosh) { - _soundData[0]._fileList = _soundFilesIntro; - _soundData[0]._fileListLen = _soundFilesIntroSize; - _soundData[0]._cdaTracks = 0; - _soundData[0]._cdaNumTracks = 0; - _soundData[1]._fileList = _soundFiles; - _soundData[1]._fileListLen = _soundFilesSize; - _soundData[1]._cdaTracks = 0; - _soundData[1]._cdaNumTracks = 0; - _soundData[2]._fileList = 0; - _soundData[2]._fileListLen = 0; - _soundData[2]._cdaTracks = 0; - _soundData[2]._cdaNumTracks = 0; + _soundData[0].fileList = _soundFilesIntro; + _soundData[0].fileListLen = _soundFilesIntroSize; + _soundData[1].fileList = _soundFiles; + _soundData[1].fileListLen = _soundFilesSize; } else if (_flags.platform == Common::kPlatformFMTowns) { - _soundData[0]._fileList = _soundFiles; - _soundData[0]._fileListLen = _soundFilesSize; - _soundData[0]._cdaTracks = _cdaTrackTable; - _soundData[0]._cdaNumTracks = _cdaTrackTableSize; - _soundData[1]._fileList = _soundFiles; - _soundData[1]._fileListLen = _soundFilesSize; - _soundData[1]._cdaTracks = _cdaTrackTable; - _soundData[1]._cdaNumTracks = _cdaTrackTableSize; - _soundData[2]._fileList = 0; - _soundData[2]._fileListLen = 0; - _soundData[2]._cdaTracks = 0; - _soundData[2]._cdaNumTracks = 0; + _soundData[0].fileList = _soundFiles; + _soundData[0].fileListLen = _soundFilesSize; + _soundData[0].cdaTracks = _cdaTrackTable; + _soundData[0].cdaNumTracks = _cdaTrackTableSize; + _soundData[1].fileList = _soundFiles; + _soundData[1].fileListLen = _soundFilesSize; + _soundData[1].cdaTracks = _cdaTrackTable; + _soundData[1].cdaNumTracks = _cdaTrackTableSize; } else if (_flags.platform == Common::kPlatformPC98) { - _soundData[0]._fileList = tIntro98; - _soundData[0]._fileListLen = 1; - _soundData[0]._cdaTracks = 0; - _soundData[0]._cdaNumTracks = 0; - _soundData[1]._fileList = tIngame98; - _soundData[1]._fileListLen = 1; - _soundData[1]._cdaTracks = 0; - _soundData[1]._cdaNumTracks = 0; - _soundData[2]._fileList = 0; - _soundData[2]._fileListLen = 0; - _soundData[2]._cdaTracks = 0; - _soundData[2]._cdaNumTracks = 0; - } else { - memset(_soundData, 0, sizeof(_soundData)); + _soundData[0].fileList = tIntro98; + _soundData[0].fileListLen = 1; + _soundData[0].extraOffset = -56; + _soundData[1].fileList = tIngame98; + _soundData[1].fileListLen = 1; + _soundData[1].extraOffset = -1; } } @@ -1673,45 +1649,34 @@ void KyraEngine_HoF::initStaticResource() { static const char *pc98MusicFileListFinale[] = { "finale%d.86" }; static const char *pc98MusicFileListIngame[] = { "km%02d.86" }; + memset(_soundData, 0, sizeof(_soundData)); if (_flags.platform == Common::kPlatformPC) { - _soundData[0]._fileList = _musicFileListIntro; - _soundData[0]._fileListLen = _musicFileListIntroSize; - _soundData[0]._cdaTracks = 0; - _soundData[0]._cdaNumTracks = 0; - _soundData[1]._fileList = _musicFileListIngame; - _soundData[1]._fileListLen = _musicFileListIngameSize; - _soundData[1]._cdaTracks = 0; - _soundData[1]._cdaNumTracks = 0; - _soundData[2]._fileList = _musicFileListFinale; - _soundData[2]._fileListLen = _musicFileListIntroSize; - _soundData[2]._cdaTracks = 0; - _soundData[2]._cdaNumTracks = 0; + _soundData[0].fileList = _musicFileListIntro; + _soundData[0].fileListLen = _musicFileListIntroSize; + _soundData[1].fileList = _musicFileListIngame; + _soundData[1].fileListLen = _musicFileListIngameSize; + _soundData[2].fileList = _musicFileListFinale; + _soundData[2].fileListLen = _musicFileListIntroSize; } else if (_flags.platform == Common::kPlatformFMTowns) { - _soundData[0]._fileList = fmtMusicFileListIntro; - _soundData[0]._fileListLen = 1; - _soundData[0]._cdaTracks = _cdaTrackTableIntro; - _soundData[0]._cdaNumTracks = _cdaTrackTableIntroSize >> 1; - _soundData[1]._fileList = fmtMusicFileListIngame; - _soundData[1]._fileListLen = 1; - _soundData[1]._cdaTracks = _cdaTrackTableIngame; - _soundData[1]._cdaNumTracks = _cdaTrackTableIngameSize >> 1; - _soundData[2]._fileList = fmtMusicFileListFinale; - _soundData[2]._fileListLen = 1; - _soundData[2]._cdaTracks = _cdaTrackTableFinale; - _soundData[2]._cdaNumTracks = _cdaTrackTableFinaleSize >> 1; + _soundData[0].fileList = fmtMusicFileListIntro; + _soundData[0].fileListLen = 1; + _soundData[0].cdaTracks = _cdaTrackTableIntro; + _soundData[0].cdaNumTracks = _cdaTrackTableIntroSize >> 1; + _soundData[1].fileList = fmtMusicFileListIngame; + _soundData[1].fileListLen = 1; + _soundData[1].cdaTracks = _cdaTrackTableIngame; + _soundData[1].cdaNumTracks = _cdaTrackTableIngameSize >> 1; + _soundData[2].fileList = fmtMusicFileListFinale; + _soundData[2].fileListLen = 1; + _soundData[2].cdaTracks = _cdaTrackTableFinale; + _soundData[2].cdaNumTracks = _cdaTrackTableFinaleSize >> 1; } else if (_flags.platform == Common::kPlatformPC98) { - _soundData[0]._fileList = pc98MusicFileListIntro; - _soundData[0]._fileListLen = 1; - _soundData[0]._cdaTracks = 0; - _soundData[0]._cdaNumTracks = 0; - _soundData[1]._fileList = pc98MusicFileListIngame; - _soundData[1]._fileListLen = 1; - _soundData[1]._cdaTracks = 0; - _soundData[1]._cdaNumTracks = 0; - _soundData[2]._fileList = pc98MusicFileListFinale; - _soundData[2]._fileListLen = 1; - _soundData[2]._cdaTracks = 0; - _soundData[2]._cdaNumTracks = 0; + _soundData[0].fileList = pc98MusicFileListIntro; + _soundData[0].fileListLen = 1; + _soundData[1].fileList = pc98MusicFileListIngame; + _soundData[1].fileListLen = 1; + _soundData[2].fileList = pc98MusicFileListFinale; + _soundData[2].fileListLen = 1; } // setup sequence data @@ -1884,10 +1849,33 @@ void LoLEngine::initStaticResource() { memcpy (_mapCursorOverlay, tmp, tmpSize); _staticres->unloadId(lolMapCursorOvl); - /*tmp = _staticres->loadRawData(lolMapPal, tmpSize); - _screen->_automapPal = new uint8[tmpSize]; - memcpy (_screen->_automapPal, tmp, tmpSize); - _staticres->unloadId(lolMapPal);*/ + _healShapeFrames = _staticres->loadRawData(lolHealShapeFrames, _healShapeFramesSize); + + // assign music data + static const char *pcMusicFileListIntro[] = { "LOREINTR" }; + static const char *pcMusicFileListFinale[] = { "LOREFINL" }; + static const char *pcMusicFileListIngame[] = { "LORE%02d%c" }; + + static const char *pc98MusicFileListIntro[] = { 0, "lore84.86", "lore82.86", 0, 0, 0, "lore83.86", "lore81.86" }; + static const char *pc98MusicFileListFinale[] = { "lore%02d.86" }; + static const char *pc98MusicFileListIngame[] = { "lore%02d.86" }; + + memset(_soundData, 0, sizeof(_soundData)); + if (_flags.platform == Common::kPlatformPC) { + _soundData[0].fileList = pcMusicFileListIntro; + _soundData[0].fileListLen = 1; + _soundData[1].fileList = pcMusicFileListIngame; + _soundData[1].fileListLen = 1; + _soundData[2].fileList = pcMusicFileListFinale; + _soundData[3].fileListLen = 1; + } else if (_flags.platform == Common::kPlatformPC98) { + _soundData[0].fileList = pc98MusicFileListIntro; + _soundData[0].fileListLen = ARRAYSIZE(pc98MusicFileListIntro); + _soundData[1].fileList = pc98MusicFileListIngame; + _soundData[1].fileListLen = 1; + _soundData[2].fileList = pc98MusicFileListFinale; + _soundData[2].fileListLen = ARRAYSIZE(pc98MusicFileListFinale);; + } } void LoLEngine::assignButtonCallback(Button *button, int index) { @@ -2949,7 +2937,7 @@ const int8 KyraEngine_MR::_albumWSAY[] = { // lands of lore static res #ifdef ENABLE_LOL -const ScreenDim Screen_LoL::_screenDimTable[] = { +const ScreenDim Screen_LoL::_screenDimTable256C[] = { { 0x00, 0x00, 0x28, 0xC8, 0xC7, 0xCF, 0x00, 0x00 }, // Taken from Intro { 0x08, 0x48, 0x18, 0x38, 0xFE, 0x01, 0x00, 0x00 }, { 0x0E, 0x00, 0x16, 0x78, 0xFE, 0x01, 0x00, 0x00 }, @@ -2966,7 +2954,24 @@ const ScreenDim Screen_LoL::_screenDimTable[] = { { 0x0B, 0x8C, 0x10, 0x23, 0x3D, 0x01, 0x00, 0x00 } // Main menu box (3 entries, floppy version only) }; -const int Screen_LoL::_screenDimTableCount = ARRAYSIZE(Screen_LoL::_screenDimTable); +const ScreenDim Screen_LoL::_screenDimTable16C[] = { + { 0x00, 0x00, 0x28, 0xC8, 0x33, 0x44, 0x00, 0x00 }, // Taken from Intro + { 0x08, 0x48, 0x18, 0x38, 0x33, 0x44, 0x00, 0x00 }, + { 0x0E, 0x00, 0x16, 0x78, 0x33, 0x44, 0x00, 0x00 }, + { 0x0B, 0x7B, 0x1C, 0x12, 0x33, 0x11, 0x00, 0x00 }, + { 0x0B, 0x7B, 0x1C, 0x2D, 0x33, 0x11, 0x00, 0x00 }, + { 0x55, 0x7B, 0xE9, 0x37, 0x33, 0x11, 0x00, 0x00 }, + { 0x0B, 0x8C, 0x10, 0x2B, 0x33, 0x44, 0x00, 0x00 }, // Main menu box (4 entries) + { 0x04, 0x59, 0x20, 0x3C, 0x00, 0x00, 0x00, 0x00 }, + { 0x05, 0x6E, 0x1E, 0x0C, 0x33, 0x44, 0x00, 0x00 }, + { 0x07, 0x19, 0x1A, 0x97, 0x00, 0x00, 0x00, 0x00 }, + { 0x03, 0x1E, 0x22, 0x8C, 0x00, 0x00, 0x00, 0x00 }, + { 0x02, 0x48, 0x24, 0x34, 0x00, 0x00, 0x00, 0x00 }, + { 0x0B, 0x8C, 0x10, 0x33, 0x33, 0x44, 0x00, 0x00 }, // Main menu box (5 entries, not used here) + { 0x0B, 0x8C, 0x10, 0x23, 0x33, 0x44, 0x00, 0x00 } // Main menu box (3 entries) +}; + +const int Screen_LoL::_screenDimTableCount = ARRAYSIZE(Screen_LoL::_screenDimTable256C); const char * const LoLEngine::_languageExt[] = { "ENG", diff --git a/engines/kyra/timer.cpp b/engines/kyra/timer.cpp index f9bb36206e..4d510abcdd 100644 --- a/engines/kyra/timer.cpp +++ b/engines/kyra/timer.cpp @@ -232,7 +232,7 @@ void TimerManager::pauseSingleTimer(uint8 id, bool p) { timer->enabled &= (~2); timer->lastUpdate += elapsedTime; timer->nextRun += elapsedTime; - resync(); + resetNextRun(); timer->pauseStartTime = 0; } } diff --git a/engines/kyra/timer_lol.cpp b/engines/kyra/timer_lol.cpp index f82687b2d5..79bb8d1c2d 100644 --- a/engines/kyra/timer_lol.cpp +++ b/engines/kyra/timer_lol.cpp @@ -40,12 +40,12 @@ void LoLEngine::setupTimers() { _timer->addTimer(0x10, TimerV2(timerProcessMonsters), 6, true); _timer->addTimer(0x11, TimerV2(timerProcessMonsters), 6, true); _timer->setNextRun(0x11, _system->getMillis() + 3 * _tickLength); - _timer->addTimer(3, TimerV2(timerSub3), 15, true); + _timer->addTimer(3, TimerV2(timerSpecialCharacterUpdate), 15, true); _timer->addTimer(4, TimerV2(timerProcessFlyingObjects), 1, true); _timer->addTimer(0x50, TimerV2(timerRunSceneAnimScript), 0, false); _timer->addTimer(0x51, TimerV2(timerRunSceneAnimScript), 0, false); _timer->addTimer(0x52, TimerV2(timerRunSceneAnimScript), 0, false); - _timer->addTimer(8, TimerV2(timerSub6), 1200, true); + _timer->addTimer(8, TimerV2(timerRegeneratePoints), 1200, true); _timer->addTimer(9, TimerV2(timerUpdatePortraitAnimations), 10, true); _timer->addTimer(10, TimerV2(timerUpdateLampState), 360, true); _timer->addTimer(11, TimerV2(timerFadeMessageText), 360, false); @@ -104,22 +104,101 @@ void LoLEngine::timerProcessDoors(int timerNum) { } void LoLEngine::timerProcessMonsters(int timerNum) { -// if (!_updateMonsters) -// return; - for (int i = timerNum & 0x0f; i < 30; i += 2) updateMonster(&_monsters[i]); } -void LoLEngine::timerSub3(int timerNum) { +void LoLEngine::timerSpecialCharacterUpdate(int timerNum) { + int v = 0; + for (int i = 0; i < 4; i++) { + if (!(_characters[i].flags & 1)) + continue; + + for (int ii = 0; ii < 5; ii++) { + if (!(_characters[i].characterUpdateEvents[ii])) + continue; + + if (--_characters[i].characterUpdateDelay[ii] > 0) { + if (_characters[i].characterUpdateDelay[ii] > v) + v = _characters[i].characterUpdateDelay[ii]; + continue; + } + + switch (_characters[i].characterUpdateEvents[ii] - 1) { + case 0: + if (_characters[i].weaponHit) { + _characters[i].weaponHit = 0; + _characters[i].characterUpdateDelay[ii] = calcMonsterSkillLevel(i, 6); + if (_characters[i].characterUpdateDelay[ii] > v) + v = _characters[i].characterUpdateDelay[ii]; + } else { + _characters[i].flags &= 0xfffb; + } + + gui_drawCharPortraitWithStats(i); + break; + + case 1: + _characters[i].damageSuffered = 0; + gui_drawCharPortraitWithStats(i); + break; + + case 2: + _characters[i].flags &= 0xffbf; + gui_drawCharPortraitWithStats(i); + break; + + case 3: + v = _rnd.getRandomNumberRng(1, 2); + if (inflictDamage(i, v, 0x8000, 0, 0x80)) { + _txt->printMessage(2, getLangString(0x4022), _characters[i].name); + _characters[i].characterUpdateDelay[ii] = 10; + if (_characters[i].characterUpdateDelay[ii] > v) + v = _characters[i].characterUpdateDelay[ii]; + } + break; + + case 4: + _characters[i].flags &= 0xfeff; + _txt->printMessage(0, getLangString(0x4027), _characters[i].name); + gui_drawCharPortraitWithStats(i); + break; + + case 5: + setTemporaryFaceFrame(i, 0, 0, 1); + break; + + case 6: + _characters[i].flags &= 0xefff; + gui_drawCharPortraitWithStats(i); + break; + + case 7: + level11specialUnk(); + break; + + default: + break; + } + + if (_characters[i].characterUpdateDelay[ii] <= 0) + _characters[i].characterUpdateEvents[ii] = 0; + } + } + if (v) { + _timer->enable(3); + _timer3Para = v * 15; + } else { + _timer->disable(3); + } } void LoLEngine::timerProcessFlyingObjects(int timerNum) { for (int i = 0; i < 8; i++) { if (!_flyingObjects[i].enable) continue; - updateFlyingObjects(&_flyingObjects[i]); + updateFlyingObject(&_flyingObjects[i]); } } @@ -127,8 +206,24 @@ void LoLEngine::timerRunSceneAnimScript(int timerNum) { runLevelScript(0x401 + (timerNum & 0x0f), -1); } -void LoLEngine::timerSub6(int timerNum) { +void LoLEngine::timerRegeneratePoints(int timerNum) { + for (int i = 0; i < 4; i++) { + if (!(_characters[i].flags & 1)) + continue; + // check for Duble ring + 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].magicPointsCur = CLIP(_characters[i].magicPointsCur + mInc, 0, _characters[i].magicPointsMax); + + if (!(_characters[i].flags & 0x80)) + increaseCharacterHitpoints(i, hInc, false); + + gui_drawCharPortraitWithStats(i); + } } void LoLEngine::timerUpdatePortraitAnimations(int skipUpdate) { diff --git a/engines/kyra/wsamovie.cpp b/engines/kyra/wsamovie.cpp index 818f3c691f..50d17659a4 100644 --- a/engines/kyra/wsamovie.cpp +++ b/engines/kyra/wsamovie.cpp @@ -372,11 +372,20 @@ int WSAMovie_v2::open(const char *filename, int unk1, uint8 *palBuf) { offsPal = 0x300; _flags |= WF_HAS_PALETTE; if (palBuf) - memcpy(palBuf, wsaData + 8 + ((_numFrames << 2) & 0xFFFF), 0x300); + _vm->screen()->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), palBuf, 0x300); } - if (flags & 2) + if (flags & 2) { + if (_vm->gameFlags().use16ColorMode) { + offsPal = 0x30; + _flags |= WF_HAS_PALETTE; + if (palBuf) + _vm->screen()->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), palBuf, 0x30); + } + _flags |= WF_XOR; + } + if (!(unk1 & 2)) { _flags |= WF_OFFSCREEN_DECODE; -- cgit v1.2.3