From 6e566a9b1ed14d63497686ad1f61fb4192c0c8f9 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Mon, 27 Apr 2009 19:38:28 +0000 Subject: LOL: added some drawing code and fixed some bugs svn-id: r40167 --- engines/kyra/gui_lol.cpp | 6 +++--- engines/kyra/kyra_v1.h | 2 +- engines/kyra/lol.cpp | 32 +++++++++++++++++++++++++++----- engines/kyra/lol.h | 17 +++++++++++------ engines/kyra/screen.cpp | 18 ++++++++++++++++-- engines/kyra/screen.h | 1 + engines/kyra/script_lol.cpp | 35 +++++++++++++++++++++++++++-------- engines/kyra/script_tim.cpp | 20 ++++++++++++++------ engines/kyra/sprites_lol.cpp | 43 +++++++++++++++++++++++++++++++------------ 9 files changed, 131 insertions(+), 43 deletions(-) diff --git a/engines/kyra/gui_lol.cpp b/engines/kyra/gui_lol.cpp index 2769692a65..ade70c8a85 100644 --- a/engines/kyra/gui_lol.cpp +++ b/engines/kyra/gui_lol.cpp @@ -390,7 +390,7 @@ void LoLEngine::gui_drawCharPortraitWithStats(int charNum) { } uint16 f = _characters[charNum].flags & 0x314C; - if ((f == 0 && _weaponsDisabled) || (f && (f != 4 || _characters[charNum].weaponHit == 0 || _weaponsDisabled))) + if ((f == 0 && _weaponsDisabled) || (f && (f != 4 || _characters[charNum].weaponHit == 0 || (_characters[charNum].weaponHit && _weaponsDisabled)))) _screen->drawGridBox(44, 0, 22, 34, 1); if (_characters[charNum].weaponHit) { @@ -1086,7 +1086,7 @@ int LoLEngine::clickedMagicButton(Button *button) { if (_characters[c].flags & 0x314C) return 1; - if (notEnoughMagic(c, _availableSpells[_selectedSpell], 0)) + if (checkMagic(c, _availableSpells[_selectedSpell], 0)) return 1; _characters[c].flags ^= 0x10; @@ -1104,7 +1104,7 @@ int LoLEngine::clickedMagicSubmenu(Button *button) { gui_enableDefaultPlayfieldButtons(); - if (notEnoughMagic(c, _availableSpells[_selectedSpell], spellLevel)) { + if (checkMagic(c, _availableSpells[_selectedSpell], spellLevel)) { _characters[c].flags &= 0xffef; gui_drawCharPortraitWithStats(c); } else { diff --git a/engines/kyra/kyra_v1.h b/engines/kyra/kyra_v1.h index 148da506c4..baf812d07d 100644 --- a/engines/kyra/kyra_v1.h +++ b/engines/kyra/kyra_v1.h @@ -201,7 +201,7 @@ protected: // input void updateInput(); - int checkInput(Button *buttonList, bool mainLoop = false); + virtual int checkInput(Button *buttonList, bool mainLoop = false); void removeInputTop(); int _mouseX, _mouseY; diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp index 601846d0de..ffce5d8570 100644 --- a/engines/kyra/lol.cpp +++ b/engines/kyra/lol.cpp @@ -99,7 +99,7 @@ LoLEngine::LoLEngine(OSystem *system, const GameFlags &flags) : KyraEngine_v1(sy _monsterShapes = _monsterPalettes = 0; _monsterShapesEx = 0; _gameShapeMap = 0; - memset(_monsterUnk, 0, 3); + memset(_monsterAnimType, 0, 3); _pageSavedFlag = false; _healOverlay = 0; @@ -637,6 +637,27 @@ void LoLEngine::loadItemIconShapes() { _screen->setMouseCursor(0, 0, _itemIconShapes[0]); } +int LoLEngine::checkInput(Button *buttonList, bool mainLoop) { + int mx = _mouseX; + int my = _mouseY; + + int inputFlag = KyraEngine_v1::checkInput(buttonList, mainLoop); + + if (!inputFlag) { + // This fixes a bug with some interactive sequences (like the inn where you mee Timothy). + // In the original code Mouse position variables are only updated when mouse button + // or keyboard events get triggered. + + // TODO/FIXME: Check whether this is the correct way to do it in KYRA, too. In this case a + // fix could be added to KyraEngine_v1::checkInput() and the virtual stuff would not be + // necessary. + _mouseX = mx; + _mouseY = my; + } + + return inputFlag; +} + void LoLEngine::setMouseCursorToIcon(int icon) { _gameFlags[15] |= 0x200; int i = _itemProperties[_itemsInPlay[_itemInHand].itemPropertyIndex].shpIndex; @@ -2125,17 +2146,17 @@ void LoLEngine::processMagicHeal(int charNum, int points) { updateDrawPage2(); } -bool LoLEngine::notEnoughMagic(int charNum, int spellNum, int spellLevel) { +int LoLEngine::checkMagic(int charNum, int spellNum, int spellLevel) { if (_spellProperties[spellNum].mpRequired[spellLevel] > _characters[charNum].magicPointsCur) { if (characterSays(0x4043, _characters[charNum].id, true)) _txt->printMessage(6, getLangString(0x4043), _characters[charNum].name); - return true; + return 1; } else if (_spellProperties[spellNum + 1].unkArr[spellLevel] >= _characters[charNum].hitPointsCur) { _txt->printMessage(2, getLangString(0x4179), _characters[charNum].name); - return true; + return 1; } - return false; + return 0; } // fight @@ -2280,6 +2301,7 @@ void LoLEngine::resetCharacterState(LoLCharacter *c, int first, int last) { for (int i = first; i <= last; i++) { switch (i - 1) { case 0: + c->flags &= 0xfffb; c->weaponHit = 0; break; diff --git a/engines/kyra/lol.h b/engines/kyra/lol.h index 8d4162698b..dce5a81a25 100644 --- a/engines/kyra/lol.h +++ b/engines/kyra/lol.h @@ -288,6 +288,8 @@ private: void updateEnvironmentalSfx(int soundId); // mouse + int checkInput(Button *buttonList, bool mainLoop = false); + void setMouseCursorToIcon(int icon); void setMouseCursorToItemInHand(); uint8 *getItemIconShapePtr(int index); @@ -551,7 +553,7 @@ private: bool _sceneUpdateRequired; int16 _visibleBlockIndex[18]; uint16 _gameFlags[16]; - uint16 _globalScriptVars[16]; + int16 _globalScriptVars[24]; // emc opcode int olol_setWallType(EMCState *script); @@ -594,6 +596,7 @@ private: int olol_getGlobalVar(EMCState *script); int olol_setGlobalVar(EMCState *script); int olol_triggerDoorSwitch(EMCState *script); + int olol_setDoorState(EMCState *script); int olol_updateBlockAnimations(EMCState *script); int olol_mapShapeToBlock(EMCState *script); int olol_resetBlockShapeAssignment(EMCState *script); @@ -622,6 +625,7 @@ private: int olol_initSceneWindowDialogue(EMCState *script); int olol_restoreAfterSceneWindowDialogue(EMCState *script); int olol_getItemInHand(EMCState *script); + int olol_checkMagic(EMCState *script); int olol_giveItemToMonster(EMCState *script); int olol_loadLangFile(EMCState *script); int olol_playSoundEffect(EMCState *script); @@ -651,7 +655,7 @@ private: int olol_setNextFunc(EMCState *script); int olol_dummy1(EMCState *script); int olol_suspendMonster(EMCState *script); - int olol_setDoorState(EMCState *script); + int olol_setUnkDoorVar(EMCState *script); int olol_resetTimDialogueState(EMCState *script); int olol_savePage5(EMCState *script); int olol_restorePage5(EMCState *script); @@ -663,6 +667,7 @@ private: int olol_assignCustomSfx(EMCState *script); int olol_resetPortraitsAndDisableSysTimer(EMCState *script); int olol_enableSysTimer(EMCState *script); + int olol_checkNeedSceneRestore(EMCState *script); int olol_disableControls(EMCState *script); int olol_enableControls(EMCState *script); int olol_characterSays(EMCState *script); @@ -1116,8 +1121,8 @@ private: void calcSpriteRelPosition(uint16 x1, uint16 y1, int &x2, int &y2, uint16 direction); void drawDoor(uint8 *shape, uint8 *table, int index, int unk2, int w, int h, int flags); void drawDoorOrMonsterShape(uint8 *shape, uint8 *table, int x, int y, int flags, const uint8 *ovl); - uint8 *drawItemOrMonster(uint8 *shape, uint8 *ovl, int x, int y, int fineX, int fineY, int flags, int tblValue, bool flip); - int calcDrawingLayerParameters(int srcX, int srcY, int &x2, int &y2, uint16 &w, uint16 &h, uint8 *shape, int flip); + uint8 *drawItemOrMonster(uint8 *shape, uint8 *ovl, int x, int y, int fineX, int fineY, int flags, int tblValue, bool vflip); + int calcDrawingLayerParameters(int srcX, int srcY, int &x2, int &y2, uint16 &w, uint16 &h, uint8 *shape, int vflip); void updateMonster(MonsterInPlay *monster); void moveMonster(MonsterInPlay *monster); @@ -1138,7 +1143,7 @@ private: uint8 **_monsterShapes; uint8 **_monsterPalettes; uint8 **_monsterShapesEx; - uint8 _monsterUnk[3]; + uint8 _monsterAnimType[3]; uint16 _monsterCurBlock; int _monsterLastWalkDirection; int _monsterCountUnk; @@ -1171,7 +1176,7 @@ private: // spells void processMagicHeal(int charNum, int points); - bool notEnoughMagic(int charNum, int spellNum, int spellLevel); + int checkMagic(int charNum, int spellNum, int spellLevel); int8 _availableSpells[7]; int _selectedSpell; diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp index c505152b11..1e5e0839be 100644 --- a/engines/kyra/screen.cpp +++ b/engines/kyra/screen.cpp @@ -1266,8 +1266,9 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int &Screen::drawShapePlotType11_15, // used by Kyra 1 (invisibility) 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::drawShapePlotType21, // used by LoL (white tower spirits) + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, &Screen::drawShapePlotType33, // used by LoL (blood spots on the floor) 0, 0, 0, &Screen::drawShapePlotType37, // used by LoL (monsters) @@ -1843,6 +1844,19 @@ void Screen::drawShapePlotType20(uint8 *dst, uint8 cmd) { *dst = cmd; } +void Screen::drawShapePlotType21(uint8 *dst, uint8 cmd) { + cmd = _dsTable2[cmd]; + uint8 tOffs = _dsTable3[cmd]; + if (!(tOffs & 0x80)) + cmd = _dsTable4[tOffs << 8 | *dst]; + + for (int i = 0; i < _dsTableLoopCount; ++i) + cmd = _dsTable[cmd]; + + if (cmd) + *dst = cmd; +} + void Screen::drawShapePlotType33(uint8 *dst, uint8 cmd) { if (cmd == 255) { *dst = _dsTable5[*dst]; diff --git a/engines/kyra/screen.h b/engines/kyra/screen.h index 3720979c62..de53e33e3c 100644 --- a/engines/kyra/screen.h +++ b/engines/kyra/screen.h @@ -330,6 +330,7 @@ protected: void drawShapePlotType13(uint8 *dst, uint8 cmd); void drawShapePlotType14(uint8 *dst, uint8 cmd); void drawShapePlotType20(uint8 *dst, uint8 cmd); + void drawShapePlotType21(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/script_lol.cpp b/engines/kyra/script_lol.cpp index 0015c7c817..d056352b36 100644 --- a/engines/kyra/script_lol.cpp +++ b/engines/kyra/script_lol.cpp @@ -545,7 +545,7 @@ int LoLEngine::olol_getGlobalScriptVar(EMCState *script) { int LoLEngine::olol_setGlobalScriptVar(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setGlobalScriptVar(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1)); - assert(stackPos(0) < 16); + assert(stackPos(0) < 24); _globalScriptVars[stackPos(0)] = stackPos(1); return 1; } @@ -667,6 +667,15 @@ int LoLEngine::olol_triggerDoorSwitch(EMCState *script) { return 1; } +int LoLEngine::olol_setDoorState(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setDoorState(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1)); + if (stackPos(1)) + _levelBlockProperties[stackPos(0)].flags = (_levelBlockProperties[stackPos(0)].flags & 0xef) | 0x20; + else + _levelBlockProperties[stackPos(0)].flags &= 0xdf; + return 1; +} + int LoLEngine::olol_updateBlockAnimations(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_updateBlockAnimations(%p) (%d, %d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2), stackPos(3)); int block = stackPos(0); @@ -1035,6 +1044,11 @@ int LoLEngine::olol_getItemInHand(EMCState *script) { return _itemInHand; } +int LoLEngine::olol_checkMagic(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkMagic(%p )(%d, %d, %d)", (const void *)script, stackPos(0), stackPos(1), stackPos(2)); + return checkMagic(stackPos(0), stackPos(1), stackPos(2)); +} + int LoLEngine::olol_giveItemToMonster(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_giveItemToMonster(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1)); if (stackPos(0) == -1) @@ -1142,7 +1156,7 @@ int LoLEngine::olol_getMonsterStat(EMCState *script) { case 7: return m->properties->flags; case 8: - return _monsterUnk[m->properties->shapeIndex]; + return _monsterAnimType[m->properties->shapeIndex]; default: break; } @@ -1374,8 +1388,8 @@ int LoLEngine::olol_suspendMonster(EMCState *script) { return 1; } -int LoLEngine::olol_setDoorState(EMCState *script) { - debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setDoorState(%p) (%d)", (const void *)script, stackPos(0)); +int LoLEngine::olol_setUnkDoorVar(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_setUnkDoorVar(%p) (%d)", (const void *)script, stackPos(0)); _emcDoorState = stackPos(0); return _emcDoorState; } @@ -1457,6 +1471,11 @@ int LoLEngine::olol_enableSysTimer(EMCState *script) { return 1; } +int LoLEngine::olol_checkNeedSceneRestore(EMCState *script) { + debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_checkNeedSceneRestore(%p)", (const void *)script); + return _needSceneRestore; +} + int LoLEngine::olol_disableControls(EMCState *script) { debugC(3, kDebugLevelScriptFuncs, "LoLEngine::olol_disableControls(%p) (%d)", (const void *)script, stackPos(0)); return gui_disableControls(stackPos(0)); @@ -1824,7 +1843,7 @@ void LoLEngine::setupOpcodeTable() { Opcode(olol_setGlobalVar); Opcode(olol_triggerDoorSwitch); OpcodeUnImpl(); - OpcodeUnImpl(); + Opcode(olol_setDoorState); // 0x34 Opcode(olol_updateBlockAnimations); @@ -1875,7 +1894,7 @@ void LoLEngine::setupOpcodeTable() { Opcode(olol_getItemInHand); // 0x54 - OpcodeUnImpl(); + Opcode(olol_checkMagic); Opcode(olol_giveItemToMonster); Opcode(olol_loadLangFile); Opcode(olol_playSoundEffect); @@ -1949,7 +1968,7 @@ void LoLEngine::setupOpcodeTable() { // 0x84 OpcodeUnImpl(); OpcodeUnImpl(); - Opcode(olol_setDoorState); + Opcode(olol_setUnkDoorVar); Opcode(olol_resetTimDialogueState); // 0x88 @@ -1983,7 +2002,7 @@ void LoLEngine::setupOpcodeTable() { Opcode(olol_enableSysTimer); // 0x9C - OpcodeUnImpl(); + Opcode(olol_checkNeedSceneRestore); OpcodeUnImpl(); OpcodeUnImpl(); OpcodeUnImpl(); diff --git a/engines/kyra/script_tim.cpp b/engines/kyra/script_tim.cpp index a3f3268db3..4165053c15 100644 --- a/engines/kyra/script_tim.cpp +++ b/engines/kyra/script_tim.cpp @@ -1028,7 +1028,10 @@ void TIMInterpreter_LoL::playAnimationPart(int animIndex, int firstFrame, int la anim->wsa->displayFrame(i - 1, 0); _screen->updateScreen(); } - _vm->delay(next - _system->getMillis()); + while ((int)(next - _system->getMillis()) > 0) { + _vm->updateInput(); + _vm->delay(_vm->_tickLength); + } } } @@ -1064,11 +1067,14 @@ uint16 TIMInterpreter_LoL::processDialogue() { if (_dialogueNumButtons == 0) { int e = _vm->checkInput(0, false) & 0xFF; _vm->removeInputTop(); - _vm->gui_notifyButtonListChanged(); - if (e == 43 || e == 61) { - _vm->snd_stopSpeech(true); - //_dlgTimer = 0; + if (e) { + _vm->gui_notifyButtonListChanged(); + + if (e == 43 || e == 61) { + _vm->snd_stopSpeech(true); + //_dlgTimer = 0; + } } if (_vm->snd_characterSpeaking() != 2) { @@ -1083,7 +1089,9 @@ uint16 TIMInterpreter_LoL::processDialogue() { } else { int e = _vm->checkInput(0, false) & 0xFF; _vm->removeInputTop(); - _vm->gui_notifyButtonListChanged(); + if (e) + _vm->gui_notifyButtonListChanged(); + switch (e) { case 43: case 61: diff --git a/engines/kyra/sprites_lol.cpp b/engines/kyra/sprites_lol.cpp index a609847988..daff86545c 100644 --- a/engines/kyra/sprites_lol.cpp +++ b/engines/kyra/sprites_lol.cpp @@ -30,7 +30,7 @@ namespace Kyra { -void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int b) { +void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int animType) { releaseMonsterShapes(monsterIndex); _screen->loadBitmap(file, 3, 3, 0); @@ -69,7 +69,7 @@ void LoLEngine::loadMonsterShapes(const char *file, int monsterIndex, int b) { of[2] = _screen->makeShapeCopy(p, s + 2); } } - _monsterUnk[monsterIndex] = b & 0xff; + _monsterAnimType[monsterIndex] = animType & 0xff; uint8 *tsh = _screen->makeShapeCopy(p, 16); @@ -695,8 +695,10 @@ void LoLEngine::drawMonster(uint16 id) { } int LoLEngine::getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags) { - switch (_monsterUnk[m->properties->shapeIndex]) { + int tmp = 0; + switch (_monsterAnimType[m->properties->shapeIndex]) { case 0: + // default if (dirFlags) { return (m->mode == 13) ? -1 : (dirFlags + m->currentSubFrame); } else { @@ -718,8 +720,26 @@ int LoLEngine::getMonsterCurFrame(MonsterInPlay *m, uint16 dirFlags) { } break; case 1: - /////// - // TODO + // monsters whose outward appearance reflects the damage they have taken + tmp = (m->properties->hitPoints * _monsterModifiers[_monsterDifficulty]) >> 8; + if (m->hitPoints > (tmp >> 1)) + tmp = 0; + else if (m->hitPoints > (tmp >> 2)) + tmp = 4; + else + tmp = 8; + + switch (m->mode) { + case 8: + return (m->fightCurTick + tmp); + case 11: + return 12; + case 13: + return (m->fightCurTick + 12); + default: + return tmp; + } + break; case 2: /////// @@ -918,7 +938,7 @@ void LoLEngine::drawDoorOrMonsterShape(uint8 *shape, uint8 *table, int x, int y, } } -uint8 *LoLEngine::drawItemOrMonster(uint8 *shape, uint8 *table, int x, int y, int fineX, int fineY, int flags, int tblValue, bool flip) { +uint8 *LoLEngine::drawItemOrMonster(uint8 *shape, uint8 *table, int x, int y, int fineX, int fineY, int flags, int tblValue, bool vflip) { uint8 *ovl2 = 0; uint8 *ovl = 0; uint8 tmpOvl[16]; @@ -931,7 +951,7 @@ uint8 *LoLEngine::drawItemOrMonster(uint8 *shape, uint8 *table, int x, int y, in ovl2 = _screen->getLevelOverlay(4); } - int r = calcDrawingLayerParameters(x, y, _shpDmX, _shpDmY, _dmScaleW, _dmScaleH, shape, flip); + int r = calcDrawingLayerParameters(x, y, _shpDmX, _shpDmY, _dmScaleW, _dmScaleH, shape, vflip); if (tblValue == -1) { r = 7 - ((r / 3) - 1); @@ -980,7 +1000,7 @@ uint8 *LoLEngine::drawItemOrMonster(uint8 *shape, uint8 *table, int x, int y, in return ovl; } -int LoLEngine::calcDrawingLayerParameters(int x1, int y1, int &x2, int &y2, uint16 &w, uint16 &h, uint8 *shape, int flip) { +int LoLEngine::calcDrawingLayerParameters(int x1, int y1, int &x2, int &y2, uint16 &w, uint16 &h, uint8 *shape, int vflip) { calcSpriteRelPosition(_partyPosX, _partyPosY, x1, y1, _currentDirection); if (y1 < 0) { @@ -993,8 +1013,9 @@ int LoLEngine::calcDrawingLayerParameters(int x1, int y1, int &x2, int &y2, uint x2 = ((_monsterScaleX[l] * x1) >> 8) + 200; w = h = (_shpDmY > 120) ? 0x100 : _monsterScaleWH[_shpDmY - 56]; - if (flip) - y2 = ((120 - y2) >> 1) + _screen->getShapeScaledHeight(shape, _dmScaleH); + if (vflip) + // objects aligned to the ceiling (like the "lobsters" in the mines) + y2 = ((120 - y2) >> 1) + (_screen->getShapeScaledHeight(shape, _dmScaleH) >> 1); else y2 -= (_screen->getShapeScaledHeight(shape, _dmScaleH) >> 1); @@ -1242,8 +1263,6 @@ bool LoLEngine::chasePartyWithDistanceAttacks(MonsterInPlay *monster) { if (item) setItemPosition(item, _partyPosX, _partyPosY, 0, 1); - // FIXME: attacker is a uint16, and -1 was used here. It has been substituted with 0xFFFF, which could - // be the original intended value inflictDamage(i, 20, 0xFFFF, 0, 2); } -- cgit v1.2.3