diff options
author | athrxx | 2011-07-21 00:28:57 +0200 |
---|---|---|
committer | Johannes Schickel | 2011-12-26 16:18:13 +0100 |
commit | c302b3e43b1d8cfe1eae669e01d3a0775d1f7b51 (patch) | |
tree | 0d718255a0cddb81f6bd0803f6f9479d6bc9722c | |
parent | 9140fd8e91882250e23e2e4b44bf3088f3da827a (diff) | |
download | scummvm-rg350-c302b3e43b1d8cfe1eae669e01d3a0775d1f7b51.tar.gz scummvm-rg350-c302b3e43b1d8cfe1eae669e01d3a0775d1f7b51.tar.bz2 scummvm-rg350-c302b3e43b1d8cfe1eae669e01d3a0775d1f7b51.zip |
KYRA: (EOB) - fix various bugs and implement some spells
-rw-r--r-- | engines/kyra/eob2.cpp | 2 | ||||
-rw-r--r-- | engines/kyra/eobcommon.cpp | 20 | ||||
-rw-r--r-- | engines/kyra/eobcommon.h | 20 | ||||
-rw-r--r-- | engines/kyra/gui_eob.cpp | 38 | ||||
-rw-r--r-- | engines/kyra/items_eob.cpp | 3 | ||||
-rw-r--r-- | engines/kyra/magic_eob.cpp | 177 | ||||
-rw-r--r-- | engines/kyra/saveload_eob.cpp | 4 | ||||
-rw-r--r-- | engines/kyra/scene_eob.cpp | 2 | ||||
-rw-r--r-- | engines/kyra/sprites_eob.cpp | 36 | ||||
-rw-r--r-- | engines/kyra/staticres_eob.cpp | 29 | ||||
-rw-r--r-- | engines/kyra/timer.cpp | 20 | ||||
-rw-r--r-- | engines/kyra/timer.h | 2 | ||||
-rw-r--r-- | engines/kyra/timer_eob.cpp | 43 |
13 files changed, 248 insertions, 148 deletions
diff --git a/engines/kyra/eob2.cpp b/engines/kyra/eob2.cpp index 8f3a10c374..1931572cd2 100644 --- a/engines/kyra/eob2.cpp +++ b/engines/kyra/eob2.cpp @@ -272,7 +272,7 @@ void DarkMoonEngine::replaceMonster(int unit, uint16 block, int pos, int dir, in } bool DarkMoonEngine::killMonsterExtra(EobMonsterInPlay *m) { - if (_currentLevel == 16 && _currentSub == 1 && (_monsterProps[m->type].flags & 4)) { + if (_currentLevel == 16 && _currentSub == 1 && (_monsterProps[m->type].capsFlags & 4)) { if (m->type) { _playFinale = true; _runFlag = false; diff --git a/engines/kyra/eobcommon.cpp b/engines/kyra/eobcommon.cpp index eebe7528b4..bb3848e429 100644 --- a/engines/kyra/eobcommon.cpp +++ b/engines/kyra/eobcommon.cpp @@ -1547,7 +1547,7 @@ void EobCoreEngine::inflictMonsterDamage(EobMonsterInPlay *m, int damage, bool g m->hitPointsCur -= damage; m->flags = (m->flags & 0xf7) | 1; - if (_monsterProps[m->type].flags & 0x2000) { + if (_monsterProps[m->type].capsFlags & 0x2000) { explodeMonster(m); checkSceneUpdateNeed(m->block); m->hitPointsCur = 0; @@ -1762,7 +1762,7 @@ void EobCoreEngine::monsterCloseAttack(EobMonsterInPlay *m) { } if (dmg > 0) { - if ((_monsterProps[m->type].flags & 0x80) && rollDice(1, 4, -1) != 3) { + if ((_monsterProps[m->type].capsFlags & 0x80) && rollDice(1, 4, -1) != 3) { int slot = rollDice(1, 27, -1); for (int iii = 0; iii < 27; iii++) { Item itm = _characters[c].inventory[slot]; @@ -1782,20 +1782,20 @@ void EobCoreEngine::monsterCloseAttack(EobMonsterInPlay *m) { inflictCharacterDamage(c, dmg); - if (_monsterProps[m->type].flags & 0x10) { + if (_monsterProps[m->type].capsFlags & 0x10) { statusAttack(c, 2, _monsterSpecAttStrings[_flags.gameID == GI_EOB1 ? 3 : 2], 0, 1, 8, 1); _characters[c].effectFlags &= ~0x2000; } - if (_monsterProps[m->type].flags & 0x20) + if (_monsterProps[m->type].capsFlags & 0x20) statusAttack(c, 4, _monsterSpecAttStrings[_flags.gameID == GI_EOB1 ? 4 : 3], 2, 5, 9, 1); - if (_monsterProps[m->type].flags & 0x8000) + if (_monsterProps[m->type].capsFlags & 0x8000) statusAttack(c, 8, _monsterSpecAttStrings[4], 2, 0, 0, 1); } - if (!(_monsterProps[m->type].flags & 0x4000)) + if (!(_monsterProps[m->type].capsFlags & 0x4000)) return; } } @@ -1848,7 +1848,7 @@ int EobCoreEngine::calcCloseDistanceMonsterDamage(EobMonsterInPlay *m, int times s = 1; } - if ((flags & 0x100) && ((_flags.gameID == GI_EOB2 && (p->statusFlags & 0x100)) || (_flags.gameID == GI_EOB1 && (p->flags & 4))) && (!(_itemTypes[_items[pips].type].allowedClasses & 4 /* bug in original code ??*/))) + if ((flags & 0x100) && ((_flags.gameID == GI_EOB2 && (p->statusFlags & 0x100)) || (_flags.gameID == GI_EOB1 && (p->capsFlags & 4))) && (!(_itemTypes[_items[pips].type].allowedClasses & 4 /* bug in original code ??*/))) s >>= 1; if (p->statusFlags & 0x2000) { @@ -1866,7 +1866,7 @@ int EobCoreEngine::calcCloseDistanceMonsterDamage(EobMonsterInPlay *m, int times } if (flags & 1) { - if (checkMonsterDamageEvasion(m)) + if (tryMonsterAttackEvasion(m)) s = 0; } @@ -1887,7 +1887,7 @@ int EobCoreEngine::calcDamageModifers(int charIndex, EobMonsterInPlay *m, int it if (item) { EobItemType *p = &_itemTypes[itemType]; int t = m ? m->type : 0; - s += ((m && (_monsterProps[t].flags & 1)) ? rollDice(p->dmgNumDiceL, p->dmgNumPipsL, p->dmgIncS /* bug in original code ? */) : + s += ((m && (_monsterProps[t].capsFlags & 1)) ? rollDice(p->dmgNumDiceL, p->dmgNumPipsL, p->dmgIncS /* bug in original code ? */) : rollDice(p->dmgNumDiceS, p->dmgNumPipsS, p->dmgIncS)); s += _items[item].value; } else { @@ -1941,7 +1941,7 @@ int EobCoreEngine::recalcDamageModifier(int damageType, int dmgModifier) { return dmgModifier; } -bool EobCoreEngine::checkMonsterDamageEvasion(EobMonsterInPlay *m) { +bool EobCoreEngine::tryMonsterAttackEvasion(EobMonsterInPlay *m) { return rollDice(1, 100) < _monsterProps[m->type].dmgModifierEvade ? true : false; } diff --git a/engines/kyra/eobcommon.h b/engines/kyra/eobcommon.h index 0cf2e9dc38..db56951b9a 100644 --- a/engines/kyra/eobcommon.h +++ b/engines/kyra/eobcommon.h @@ -169,8 +169,8 @@ struct EobMonsterProperty { int8 base; } dmgDc[3]; uint16 statusFlags; - uint16 flags; - int32 u22; + uint32 capsFlags; + uint32 typeFlags; int32 experience; uint8 u30; @@ -182,7 +182,7 @@ struct EobMonsterProperty { int8 remoteWeapons[5]; - uint8 u41; + uint8 tuResist; uint8 dmgModifierEvade; uint8 decorations[3]; @@ -199,7 +199,7 @@ struct EobMonsterInPlay { int8 mode; int8 f_9; int8 curAttackFrame; - uint8 f_b; + int8 spellStatusLeft; int16 hitPointsMax; int16 hitPointsCur; uint16 dest; @@ -334,7 +334,7 @@ protected: void setCharEventTimer(int charIndex, uint32 countdown, int evnt, int updateExistingTimer); void deleteCharEventTimer(int charIndex, int evnt); void setupCharacterTimers(); - void manualAdvanceTimer(int sysTimer, uint32 millis); + void advanceTimers(uint32 millis); void timerProcessMonsters(int timerNum); void timerSpecialCharacterUpdate(int timerNum); @@ -511,7 +511,7 @@ protected: bool walkMonsterNextStep(EobMonsterInPlay *m, int destBlock, int direction); void updateMonsterFollowPath(EobMonsterInPlay *m, int turnSteps); void updateMonstersStraying(EobMonsterInPlay *m, int a); - void updateMonsters_mode710(EobMonsterInPlay *m); + void updateMonstersSpellStatus(EobMonsterInPlay *m); void setBlockMonsterDirection(int block, int dir); uint8 *_monsterOvl1; @@ -829,7 +829,7 @@ protected: int getConstModifierTableValue(int hpModifier, int level, int b); bool calcDamageCheckItemType(int itemType); int recalcDamageModifier(int damageType, int dmgModifier); - bool checkMonsterDamageEvasion(EobMonsterInPlay *m); + bool tryMonsterAttackEvasion(EobMonsterInPlay *m); int getStrHitChanceModifier(int charIndex); int getStrDamageModifier(int charIndex); int getDexHitChanceModifier(int charIndex); @@ -856,7 +856,11 @@ protected: void setSpellEventTimer(int spell, int timerBaseFactor, int timerLength, int timerLevelFactor, int updateExistingTimer); void sortCharacterSpellList(int charIndex); - bool magicObjectHit(EobFlyingObject *fo, int dcTimes, int dcPips, int dcOffs, int level); + bool magicObjectDamageHit(EobFlyingObject *fo, int dcTimes, int dcPips, int dcOffs, int level); + bool magicObjectStatusHit(EobMonsterInPlay *m, int type, bool tryEvade, int mod); + + void printWarning(const char* str); + void printNoEffectWarning(); void spellCallback_start_empty() {} bool spellCallback_end_empty(EobFlyingObject *fo) { return true; } diff --git a/engines/kyra/gui_eob.cpp b/engines/kyra/gui_eob.cpp index 3a71642f9b..c13b4da7e9 100644 --- a/engines/kyra/gui_eob.cpp +++ b/engines/kyra/gui_eob.cpp @@ -665,11 +665,13 @@ void EobCoreEngine::gui_drawSpellbook() { int textXs = 71; int textY = 170; int col3 = _bkgColor_1; + int col4 = _color6; if (_flags.gameID == GI_EOB1) { textCol2 = 11; textXa = textXs = 73; textY = 168; + col4 = _bkgColor_1; } for (int i = 0; i < 7; i++) { @@ -686,7 +688,7 @@ void EobCoreEngine::gui_drawSpellbook() { if (d >= 0 && i < 6 && (i + _openBookSpellListOffset) < 9) _screen->printText(_openBookSpellList[d], textXs, 132 + 6 * i, textCol1, col3); else - _screen->printText(_magicStrings1[0], textXa, textY, 12, _color6); + _screen->printText(_magicStrings1[0], textXa, textY, 12, col4); } } @@ -805,7 +807,7 @@ void EobCoreEngine::gui_initButton(int index, int, int, int) { if (_flags.gameID == GI_EOB1) { // EOB1 spellbook modifications - if (index > 61 && index < 67) + if (index > 60 && index < 66) d = &_buttonDefs[index + 33]; if (index == 88) d = &_buttonDefs[index + 12]; @@ -867,7 +869,7 @@ int EobCoreEngine::clickedCamp(Button *button) { _screen->updateScreen(); enableSysTimer(2); - manualAdvanceTimer(2, _restPartyElapsedTime); + advanceTimers(_restPartyElapsedTime); _restPartyElapsedTime = 0; checkPartyStatus(true); @@ -1083,7 +1085,7 @@ int EobCoreEngine::clickedSpellbookList(Button *button) { int s = _openBookAvailableSpells[_openBookSpellLevel * 10 + _openBookSpellListOffset + _openBookSpellSelectedItem]; if (_openBookType == 1) - s += _mageSpellListSize; + s += _clericSpellOffset; castSpell(s, 0); @@ -1100,11 +1102,10 @@ int EobCoreEngine::clickedSpellbookList(Button *button) { } int EobCoreEngine::clickedCastSpellOnCharacter(Button *button) { - _activeSpellCaster = button->arg; + _activeSpellCaster = button->arg & 0xff; - if (_activeSpellCaster == 255) { - _txt->printMessage(_magicStrings3[1]); - snd_playSoundEffect(79); + if (_activeSpellCaster == 0xff) { + printWarning(_magicStrings3[_flags.gameID == GI_EOB1 ? 2 : 1]); if (_castScrollSlot) { gui_updateSlotAfterScrollUse(); } else { @@ -2774,7 +2775,7 @@ void GUI_Eob::runMemorizePrayMenu(int charIndex, int spellType) { for (int i = 0; i < 80; i++) { int8 s = charSpellList[i]; - if (s == 0 || s == _vm->_spellLevelsClericSize) + if (s == 0 || (_vm->game() == GI_EOB2 && s == 29)) continue; if (s < 0) @@ -2938,8 +2939,8 @@ void GUI_Eob::runMemorizePrayMenu(int charIndex, int spellType) { _screen->setFont(Screen::FID_8_FNT); memset(charSpellList, 0, 80); - if (spellType) - charSpellList[0] = _vm->_spellLevelsClericSize; + if (spellType && _vm->game() == GI_EOB2) + charSpellList[0] = 29; for (int i = 0; i < 32; i++) { if (_numAssignedSpellsOfType[i * 2] < _numAssignedSpellsOfType[i * 2 + 1]) @@ -3187,7 +3188,7 @@ bool GUI_Eob::restParty() { *list *= -1; crs[i] = 48; - _vm->_txt->printMessage(Common::String::format(_vm->_menuStringsRest2[0], _vm->_characters[i].name, _vm->_spells[_vm->_mageSpellListSize + *list].name).c_str()); + _vm->_txt->printMessage(Common::String::format(_vm->_menuStringsRest2[0], _vm->_characters[i].name, _vm->_spells[_vm->_clericSpellOffset + *list].name).c_str()); _vm->delay(80); break; } @@ -3485,7 +3486,7 @@ void GUI_Eob::messageDialogue(int dim, int id, int buttonTextCol) { } int GUI_Eob::selectCharacterDialogue(int id) { - uint8 flags = (id == 26) ? 0x14 : 0x02; + uint8 flags = (id == 26) ? (_vm->game() == GI_EOB1 ? 0x04 : 0x14) : 0x02; _vm->removeInputTop(); _charSelectRedraw = false; @@ -3613,10 +3614,13 @@ int GUI_Eob::selectCharacterDialogue(int id) { _screen->setFont(Screen::FID_8_FNT); if (result != -1 && id != 53) { - if (flags == 0x14) { - if (_vm->_classModifierFlags[_vm->_characters[result].cClass] & 0x10 && _vm->_characters[result].level[0] < 9) { - displayTextBox(24); - result = -1; + if (flags & 4) { + int lv = _vm->getCharacterLevelIndex(4, _vm->_characters[result].cClass); + if (lv != -1) { + if (_vm->_characters[result].level[lv] < 9) { + displayTextBox(24); + result = -1; + } } } else { if (_vm->checkInventoryForItem(result, 29, -1) == -1) { diff --git a/engines/kyra/items_eob.cpp b/engines/kyra/items_eob.cpp index c6ec81a00e..6c331e80be 100644 --- a/engines/kyra/items_eob.cpp +++ b/engines/kyra/items_eob.cpp @@ -445,8 +445,7 @@ void EobCoreEngine::eatItemInHand(int charIndex) { } else if (_itemInHand && _items[_itemInHand].type != 31) { _txt->printMessage(_warningStrings[3]); } else if (_items[_itemInHand].value == -1) { - _txt->printMessage(_warningStrings[2]); - snd_playSoundEffect(79); + printWarning(_warningStrings[2]); } else { c->food += _items[_itemInHand].value; if (c->food > 100) diff --git a/engines/kyra/magic_eob.cpp b/engines/kyra/magic_eob.cpp index fe770d465e..2275bd53a4 100644 --- a/engines/kyra/magic_eob.cpp +++ b/engines/kyra/magic_eob.cpp @@ -156,14 +156,12 @@ void EobCoreEngine::castSpell(int spell, int weaponSlot) { if (s->flags & 0x400) { if (c->inventory[0] && c->inventory[1]) { - _txt->printMessage(_magicStrings1[2]); - snd_playSoundEffect(79); + printWarning(_magicStrings1[2]); return; } if (isMagicWeapon(c->inventory[0]) || isMagicWeapon(c->inventory[1])) { - _txt->printMessage(_magicStrings1[3]); - snd_playSoundEffect(79); + printWarning(_magicStrings1[3]); return; } } @@ -205,10 +203,8 @@ void EobCoreEngine::removeCharacterEffect(int spell, int charIndex, int showWarn EobCharacter *c = &_characters[charIndex]; EobSpell *s = &_spells[spell]; - if (showWarning) { - _txt->printMessage(_magicStrings3[2], -1, c->name, s->name); - snd_playSoundEffect(79); - } + if (showWarning) + printWarning(Common::String::format(_magicStrings3[_flags.gameID == GI_EOB1 ? 3 : 2], c->name, s->name).c_str()); if (s->endCallback) (this->*s->endCallback)(0); @@ -262,8 +258,7 @@ void EobCoreEngine::removeAllCharacterEffects(int charIndex) { } void EobCoreEngine::castOnWhomDialogue() { - _txt->printMessage(_magicStrings3[0]); - snd_playSoundEffect(79); + printWarning(_magicStrings3[0]); gui_setCastOnWhomButtons(); } @@ -281,15 +276,13 @@ void EobCoreEngine::startSpell(int spell) { if (s->flags & 0x20) { _txt->printMessage(c->name); - _txt->printMessage(_magicStrings1[5]); + _txt->printMessage(_flags.gameID == GI_EOB1 ? _magicStrings3[1] : _magicStrings1[5]); } if ((s->flags & 0x30) && (s->effectFlags & c->effectFlags)) { - _txt->printMessage(_magicStrings7[0], -1, c->name, s->name); - snd_playSoundEffect(79); + printWarning(Common::String::format(_magicStrings7[0], c->name, s->name).c_str()); } else if ((s->flags & 0x50) && (s->effectFlags & _partyEffectFlags)) { - _txt->printMessage(_magicStrings7[1], -1, s->name); - snd_playSoundEffect(79); + printWarning(Common::String::format(_magicStrings7[1], s->name).c_str()); } else { if (s->flags & 8) setSpellEventTimer(spell, s->timingPara[0], s->timingPara[1], s->timingPara[2], s->timingPara[3]); @@ -452,7 +445,7 @@ void EobCoreEngine::sortCharacterSpellList(int charIndex) { } } -bool EobCoreEngine::magicObjectHit(EobFlyingObject *fo, int dcTimes, int dcPips, int dcOffs, int level) { +bool EobCoreEngine::magicObjectDamageHit(EobFlyingObject *fo, int dcTimes, int dcPips, int dcOffs, int level) { int ignoreAttackerId = fo->flags & 0x10; int singleTargetCheckAdjacent = fo->flags & 1; int blockDamage = fo->flags & 2; @@ -527,6 +520,70 @@ bool EobCoreEngine::magicObjectHit(EobFlyingObject *fo, int dcTimes, int dcPips, return res; } +bool EobCoreEngine::magicObjectStatusHit(EobMonsterInPlay *m, int type, bool tryEvade, int mod) { + EobMonsterProperty *p = &_monsterProps[m->type]; + if (tryEvade) { + if (tryMonsterAttackEvasion(m) || (p->capsFlags & 0x10)) + return true; + } + + if (checkUnkConstModifiers(m, 0, p->level, mod, 6)) + return false; + + int para = 0; + + switch (type) { + case 0: + case 1: + case 2: + para = (type == 0) ? ((p->typeFlags & 1) ? 1 : 0) : ((type == 1) ? ((p->typeFlags & 2) ? 1 : 0) : 1); + if (para && !(p->statusFlags & 2)) { + m->mode = 10; + m->spellStatusLeft = 15; + } + + break; + + case 3: + if (!(p->statusFlags & 8)) + inflictMonsterDamage(m, 1000, true); + break; + + case 4: + inflictMonsterDamage(m, 1000, true); + break; + + case 5: + m->flags |= 0x20; + _sceneUpdateRequired = true; + break; + + case 6: + if (!(p->statusFlags & 4) && m->mode != 7 && m->mode != 8 && m->mode != 10) { + m->mode = 0; + m->spellStatusLeft = 20; + para = (getNextMonsterDirection(m->block, _currentBlock) ^ 4) >> 1; + m->flags |= 8; + walkMonsterNextStep(m, -1, para); + } + break; + + default: + break; + } + + return true; +} + +void EobCoreEngine::printWarning(const char* str) { + _txt->printMessage(str); + snd_playSoundEffect(79); +} + +void EobCoreEngine::printNoEffectWarning() { + printWarning(_magicStrings4[0]); +} + void EobCoreEngine::spellCallback_start_armor() { } @@ -548,7 +605,7 @@ void EobCoreEngine::spellCallback_start_magicMissile() { } bool EobCoreEngine::spellCallback_end_magicMissile(EobFlyingObject *fo) { - return magicObjectHit(fo, 1, 4, 1, (getCharacterMageLevel(fo->attackerId) - 1) >> 1); + return magicObjectDamageHit(fo, 1, 4, 1, (getCharacterMageLevel(fo->attackerId) - 1) >> 1); } void EobCoreEngine::spellCallback_start_shockingGrasp() { @@ -568,7 +625,7 @@ void EobCoreEngine::spellCallback_start_melfsAcidArrow() { } bool EobCoreEngine::spellCallback_end_melfsAcidArrow(EobFlyingObject *fo) { - return magicObjectHit(fo, 2, 4, 0, getCharacterMageLevel(fo->attackerId) / 3); + return magicObjectDamageHit(fo, 2, 4, 0, getCharacterMageLevel(fo->attackerId) / 3); } void EobCoreEngine::spellCallback_start_dispelMagic() { @@ -580,7 +637,7 @@ void EobCoreEngine::spellCallback_start_fireball() { } bool EobCoreEngine::spellCallback_end_fireball(EobFlyingObject *fo) { - return magicObjectHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId)); + return magicObjectDamageHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId)); } void EobCoreEngine::spellCallback_start_flameArrow() { @@ -588,7 +645,7 @@ void EobCoreEngine::spellCallback_start_flameArrow() { } bool EobCoreEngine::spellCallback_end_flameArrow(EobFlyingObject *fo) { - return magicObjectHit(fo, 5, 6, 0, getCharacterMageLevel(fo->attackerId)); + return magicObjectDamageHit(fo, 5, 6, 0, getCharacterMageLevel(fo->attackerId)); } void EobCoreEngine::spellCallback_start_holdPerson() { @@ -596,7 +653,28 @@ void EobCoreEngine::spellCallback_start_holdPerson() { } bool EobCoreEngine::spellCallback_end_holdPerson(EobFlyingObject *fo) { - return true; + bool res = false; + + if (_flags.gameID == GI_EOB2 && fo->curBlock == _currentBlock) { + // party hit + int numChar = rollDice(1, 4, 0); + int charIndex = rollDice(1, 6, 0); + for (int i = 0; i < 6 && numChar; i++) { + if (testCharacter(charIndex, 3)) { + statusAttack(charIndex, 4, _magicStrings8[1], 4, 5, 9, 1); + numChar--; + } + charIndex = (charIndex + 1) % 6; + } + res = true; + + } else { + // monster hit + for (const int16 *m = findBlockMonsters(fo->curBlock, fo->curPos, fo->direction, 1, 1); *m != -1; m++) + res |= magicObjectStatusHit(&_monsters[*m], 0, true, 4); + } + + return res; } void EobCoreEngine::spellCallback_start_lightningBolt() { @@ -604,7 +682,7 @@ void EobCoreEngine::spellCallback_start_lightningBolt() { } bool EobCoreEngine::spellCallback_end_lightningBolt(EobFlyingObject *fo) { - return magicObjectHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId)); + return magicObjectDamageHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId)); } void EobCoreEngine::spellCallback_start_vampiricTouch() { @@ -616,7 +694,12 @@ bool EobCoreEngine::spellCallback_end_vampiricTouch(EobFlyingObject*) { } void EobCoreEngine::spellCallback_start_fear() { - + sparkEffectOffensive(); + uint16 bl = calcNewBlockPosition(_currentBlock, _currentDirection); + for (int i = 0; i < 30; i++) { + if (_monsters[i].block == bl) + magicObjectStatusHit(&_monsters[i], 6, true, 4); + } } void EobCoreEngine::spellCallback_start_iceStorm() { @@ -625,12 +708,12 @@ void EobCoreEngine::spellCallback_start_iceStorm() { bool EobCoreEngine::spellCallback_end_iceStorm(EobFlyingObject *fo) { static int8 blockAdv[] = { -32, 32, 1, -1 }; - bool res = magicObjectHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId)); + bool res = magicObjectDamageHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId)); if (res) { for (int i = 0; i < 4; i++) { uint16 bl = fo->curBlock; fo->curBlock = (fo->curBlock + blockAdv[i]) & 0x3ff; - magicObjectHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId)); + magicObjectDamageHit(fo, 1, 6, 0, getCharacterMageLevel(fo->attackerId)); fo->curBlock = bl; } } @@ -650,7 +733,10 @@ void EobCoreEngine::spellCallback_start_holdMonster() { } bool EobCoreEngine::spellCallback_end_holdMonster(EobFlyingObject *fo) { - return true; + bool res = false; + for (const int16 *m = findBlockMonsters(fo->curBlock, fo->curPos, fo->direction, 1, 1); *m != -1; m++) + res |= magicObjectStatusHit(&_monsters[*m], 1, true, 4); + return res; } void EobCoreEngine::spellCallback_start_wallOfForce() { @@ -662,18 +748,27 @@ void EobCoreEngine::spellCallback_start_disintegrate() { } void EobCoreEngine::spellCallback_start_fleshToStone() { - + sparkEffectOffensive(); + int t = getClosestMonsterPos(_openBookChar, calcNewBlockPosition(_currentBlock, _currentDirection)); + if (t != -1) + magicObjectStatusHit(&_monsters[t], 5, true, 4); + else + printWarning(_magicStrings8[4]); } void EobCoreEngine::spellCallback_start_stoneToFlesh() { - + if (_characters[_activeSpellCaster].flags & 8) + _characters[_activeSpellCaster].flags &= ~8; + else + printNoEffectWarning(); } void EobCoreEngine::spellCallback_start_trueSeeing() { - + _wllVmpMap[46] = 0; } bool EobCoreEngine::spellCallback_end_trueSeeing(EobFlyingObject*) { + _wllVmpMap[46] = 1; return true; } @@ -722,7 +817,13 @@ void EobCoreEngine::spellCallback_start_createFood() { } void EobCoreEngine::spellCallback_start_removeParalysis() { - + int numChar = 4; + for (int i = 0; i < 6; i++) { + if (!(_characters[i].flags & 4) || !numChar) + continue; + _characters[i].flags &= ~4; + numChar--; + } } void EobCoreEngine::spellCallback_start_causeSeriousWounds() { @@ -750,7 +851,7 @@ void EobCoreEngine::spellCallback_start_flameStrike() { } bool EobCoreEngine::spellCallback_end_flameStrike(EobFlyingObject *fo) { - return magicObjectHit(fo, 6, 8, 0, 0); + return magicObjectDamageHit(fo, 6, 8, 0, 0); } void EobCoreEngine::spellCallback_start_raiseDead() { @@ -763,12 +864,10 @@ void EobCoreEngine::spellCallback_start_harm() { void EobCoreEngine::spellCallback_start_heal() { EobCharacter *c = &_characters[_activeSpellCaster]; - if (c->hitPointsMax <= c->hitPointsCur) { - _txt->printMessage(_magicStrings4[0]); - snd_playSoundEffect(79); - } else { + if (c->hitPointsMax <= c->hitPointsCur) + printWarning(_magicStrings4[0]); + else modifyCharacterHitpoints(_activeSpellCaster, c->hitPointsMax - c->hitPointsCur); - } } void EobCoreEngine::spellCallback_start_layOnHands() { @@ -782,19 +881,19 @@ void EobCoreEngine::spellCallback_start_turnUndead() { bool EobCoreEngine::spellCallback_end_unk1Passive(EobFlyingObject *fo) { bool res = false; if (_partyEffectFlags & 0x20000) { - res = magicObjectHit(fo, 4, 10, 6, 0); + res = magicObjectDamageHit(fo, 4, 10, 6, 0); if (res) { gui_drawAllCharPortraitsWithStats(); _partyEffectFlags &= ~0x20000; } } else { - res = magicObjectHit(fo, 12, 10, 6, 0); + res = magicObjectDamageHit(fo, 12, 10, 6, 0); } return res; } bool EobCoreEngine::spellCallback_end_unk2Passive(EobFlyingObject *fo) { - return magicObjectHit(fo, 0, 0, 18, 0); + return magicObjectDamageHit(fo, 0, 0, 18, 0); } bool EobCoreEngine::spellCallback_end_deathSpellPassive(EobFlyingObject *fo) { diff --git a/engines/kyra/saveload_eob.cpp b/engines/kyra/saveload_eob.cpp index cde900bc12..1fa26c26b1 100644 --- a/engines/kyra/saveload_eob.cpp +++ b/engines/kyra/saveload_eob.cpp @@ -315,7 +315,7 @@ Common::Error EobCoreEngine::loadGameState(int slot) { m->mode = in.readSByte(); m->f_9 = in.readSByte(); m->curAttackFrame = in.readSByte(); - m->f_b = in.readByte(); + m->spellStatusLeft = in.readSByte(); m->hitPointsMax = in.readSint16BE(); m->hitPointsCur = in.readSint16BE(); m->dest = in.readUint16BE(); @@ -523,7 +523,7 @@ Common::Error EobCoreEngine::saveGameStateIntern(int slot, const char *saveName, out->writeSByte(m->mode); out->writeSByte(m->f_9); out->writeSByte(m->curAttackFrame); - out->writeByte(m->f_b); + out->writeSByte(m->spellStatusLeft); out->writeSint16BE(m->hitPointsMax); out->writeSint16BE(m->hitPointsCur); out->writeUint16BE(m->dest); diff --git a/engines/kyra/scene_eob.cpp b/engines/kyra/scene_eob.cpp index e92d813af9..36584d462b 100644 --- a/engines/kyra/scene_eob.cpp +++ b/engines/kyra/scene_eob.cpp @@ -583,7 +583,7 @@ void LolEobBaseEngine::openCloseDoor(int block, int openClose) { } } - enableTimer(_flags.gameID == GI_LOL ? 0 : 12); + enableTimer(_flags.gameID == GI_LOL ? 0 : 4); } else { while (!(flg & _wllWallFlags[v])) diff --git a/engines/kyra/sprites_eob.cpp b/engines/kyra/sprites_eob.cpp index 8c492aa4e2..baa7a0bfda 100644 --- a/engines/kyra/sprites_eob.cpp +++ b/engines/kyra/sprites_eob.cpp @@ -99,9 +99,9 @@ const uint8 *EobCoreEngine::loadMonsterProperties(const uint8 *data) { d->dmgDc[3].base = (int8)*data++; d->statusFlags = READ_LE_UINT16(data); data += 2; - d->flags = READ_LE_UINT16(data); + d->capsFlags = READ_LE_UINT16(data); data += 2; - d->u22 = (int16)READ_LE_UINT16(data); + d->typeFlags = READ_LE_UINT16(data); data += 2; d->experience = READ_LE_UINT16(data); data += 2; @@ -121,7 +121,7 @@ const uint8 *EobCoreEngine::loadMonsterProperties(const uint8 *data) { } } - d->u41 = *data++; + d->tuResist = *data++; d->dmgModifierEvade = *data++; for (int i = 0; i < 3; i++) @@ -176,7 +176,7 @@ void EobCoreEngine::initMonster(int index, int unit, uint16 block, int pos, int m->pos = pos; m->shpIndex = shpIndex; m->mode = mode; - m->f_b = i; + m->spellStatusLeft = i; m->dir = dir; m->palette = _flags.gameID == GI_EOB2 ? (index % 3) : 0; m->hitPointsCur = m->hitPointsMax = _flags.gameID == GI_EOB2 ? rollDice(p->hpDcTimes, p->hpDcPips, p->hpDcBase) : (p->hpDcTimes == 255 ? rollDice(1, 4, 0) : rollDice(p->hpDcTimes, 8, 0)); @@ -503,11 +503,11 @@ void EobCoreEngine::drawMonsters(int index) { EobMonsterProperty *p = &_monsterProps[d->type]; - if (_flags.gameID == GI_EOB2 && (p->flags & 0x100) && !(_partyEffectFlags & 0x220) && !(d->flags & 2)) + if (_flags.gameID == GI_EOB2 && (p->capsFlags & 0x100) && !(_partyEffectFlags & 0x220) && !(d->flags & 2)) continue; int f = (d->animStep << 4) + cDirOffs + d->dir; - f = (p->flags & 2) ? _monsterFrmOffsTable1[f] : _monsterFrmOffsTable2[f]; + f = (p->capsFlags & 2) ? _monsterFrmOffsTable1[f] : _monsterFrmOffsTable2[f]; if (!blockDistance && d->curAttackFrame < 0) f = d->curAttackFrame + 7; @@ -719,7 +719,7 @@ void EobCoreEngine::updateMonsters(int unit) { break; case 7: case 10: - updateMonsters_mode710(m); + updateMonstersSpellStatus(m); break; default: break; @@ -871,7 +871,7 @@ void EobCoreEngine::updateMoveMonster(EobMonsterInPlay *m) { EobMonsterProperty *p = &_monsterProps[m->type]; int d = getNextMonsterDirection(m->block, _currentBlock); - if ((p->flags & 0x800) && !(d & 1)) + if ((p->capsFlags & 0x800) && !(d & 1)) d >>= 1; else d = m->dir; @@ -892,13 +892,13 @@ void EobCoreEngine::updateMoveMonster(EobMonsterInPlay *m) { m->curAttackFrame = 0; walkMonster(m, m->dest); - if (p->flags & 8) + if (p->capsFlags & 8) updateMonsterTryCloseAttack(m, -1); } bool EobCoreEngine::updateMonsterTryDistanceAttack(EobMonsterInPlay *m) { EobMonsterProperty *p = &_monsterProps[m->type]; - if (!m->numRemoteAttacks || ((_flags.gameID == GI_EOB1) && !(p->flags & 0x40))) + if (!m->numRemoteAttacks || ((_flags.gameID == GI_EOB1) && !(p->capsFlags & 0x40))) return false; if ((_flags.gameID == GI_EOB1 && m->stepsTillRemoteAttack == 5) || (_flags.gameID == GI_EOB2 && rollDice(1, 3) > m->stepsTillRemoteAttack)) { @@ -1073,8 +1073,8 @@ void EobCoreEngine::walkMonster(EobMonsterInPlay *m, int destBlock) { if (m->flags & 8) { if (_flags.gameID == GI_EOB1 ) { d ^= 4; - } else if (--m->f_b <= 0) { - m->f_b = 0; + } else if (--m->spellStatusLeft <= 0) { + m->spellStatusLeft = 0; m->flags &= ~8; } else { d ^= 4; @@ -1095,7 +1095,7 @@ void EobCoreEngine::walkMonster(EobMonsterInPlay *m, int destBlock) { } else if (_flags.gameID == GI_EOB2) { if (d & 1) { int e = _monsterStepTable1[((d - 1) << 1) + m->dir]; - if (e && !((_monsterProps[m->type].flags & 0x200) && (rollDice(1, 4) == 4))) { + if (e && !((_monsterProps[m->type].capsFlags & 0x200) && (rollDice(1, 4) == 4))) { if (walkMonsterNextStep(m, b + e, -1)) return; } @@ -1144,11 +1144,11 @@ bool EobCoreEngine::walkMonsterNextStep(EobMonsterInPlay *m, int destBlock, int uint8 w = l->walls[direction ^ 2]; if (!(_wllWallFlags[w] & 4)) { - if (_flags.gameID == GI_EOB1 ||!(p->flags & 0x1000) || _wllShapeMap[w] != -1) + if (_flags.gameID == GI_EOB1 || !(p->capsFlags & 0x1000) || _wllShapeMap[w] != -1) return false; if (_wllWallFlags[w] & 0x20) { - if (p->flags & 4 && m->type == 1) + if (p->capsFlags & 4 && m->type == 1) l->walls[direction] = l->walls[direction ^ 2] = 72; else openDoor(destBlock); @@ -1219,9 +1219,9 @@ void EobCoreEngine::updateMonstersStraying(EobMonsterInPlay *m, int a) { } } -void EobCoreEngine::updateMonsters_mode710(EobMonsterInPlay *m) { - if (m->f_b) { - if (!--m->f_b) +void EobCoreEngine::updateMonstersSpellStatus(EobMonsterInPlay *m) { + if (m->spellStatusLeft) { + if (!--m->spellStatusLeft) m->mode = 0; } } diff --git a/engines/kyra/staticres_eob.cpp b/engines/kyra/staticres_eob.cpp index 19789bbb3c..f422d6993e 100644 --- a/engines/kyra/staticres_eob.cpp +++ b/engines/kyra/staticres_eob.cpp @@ -631,7 +631,7 @@ void EobCoreEngine::initButtonData() { { 4, 0, 0x1100, 113, 122, 20, 8, EOB_CB(clickedSpellbookTab), 2 }, { 5, 0, 0x1100, 134, 122, 20, 8, EOB_CB(clickedSpellbookTab), 3 }, { 6, 0, 0x1100, 155, 122, 20, 8, EOB_CB(clickedSpellbookTab), 4 }, - { 110, 0, 0x1100, 75, 168, 97, 6, EOB_CB(clickedSpellbookAbort), 0 }, + { 110, 0, 0x1100, 75, 168, 97, 6, EOB_CB(clickedSpellbookAbort), 0 } }; _buttonDefs = buttonDefs; @@ -975,11 +975,19 @@ void EobCoreEngine::initSpells() { ec2(fleshToStonePassive); _spells = new EobSpell[_numSpells]; - memset(_spells, 0, _numSpells * sizeof(EobSpell)); + memset(_spells, 0, _numSpells * sizeof(EobSpell)); - for (int i = 0; i < _numSpells; i++) { + for (int i = 0, n = 0; i < _numSpells; i++, n++) { EobSpell *s = &_spells[i]; - s->name = _flags.gameID == GI_EOB2 ? ((i == 0 || i == _mageSpellListSize) ? _mageSpellList[0] : ((i < (_mageSpellListSize + 1)) ? _spellNames[i - 1] : _spellNames[i - 2])) : _spellNames[i]; + + // Fix Eob 1 spell names + bool skip = false; + if (i == 5 || i == 9) { + n--; + skip = true; + } + + s->name = _flags.gameID == GI_EOB2 ? ((i == 0 || i == _mageSpellListSize) ? _mageSpellList[0] : ((i < (_mageSpellListSize + 1)) ? _spellNames[i - 1] : _spellNames[i - 2])) : (skip ? _spellNames[0] : _spellNames[n]); s->startCallback = startCallback[i]; s->timingPara = magicTimingParaAssign[i]; s->endCallback = endCallback[i]; @@ -1031,8 +1039,7 @@ void EobEngine::initStaticResource() { temp /= 27; _monsterProps = new EobMonsterProperty[temp]; memset(_monsterProps, 0, temp * sizeof(EobMonsterProperty)); - // Try to convert EOB1 (hard coded) monster properties to EOB2 type monster properties. - // This is still WIP, since most properties are unknown for now. + // Convert EOB1 (hard coded) monster properties to EOB2 type monster properties. for (int i = 0; i < temp; i++) { EobMonsterProperty *p = &_monsterProps[i]; p->armorClass = (int8)*ps++; @@ -1049,9 +1056,9 @@ void EobEngine::initStaticResource() { p->dmgDc[2].pips = *ps++; p->dmgDc[2].base = (int8)*ps++; ps++; - p->flags = *ps++; - ps++; - ps++; + p->capsFlags = *ps++; + p->typeFlags = READ_LE_UINT16(ps); + ps += 2; ps++; ps++; p->experience = READ_LE_UINT16(ps); @@ -1060,7 +1067,7 @@ void EobEngine::initStaticResource() { p->sound1 = *ps++; p->sound2 = *ps++; p->numRemoteAttacks = *ps++; - ps++; + p->tuResist = *ps++; p->dmgModifierEvade = *ps++; } } @@ -1132,7 +1139,7 @@ void EobEngine::initSpells() { int temp; const uint8 *src = _staticres->loadRawData(kEobBaseSpellProperties, temp); - _clericSpellOffset -= 3; + _clericSpellOffset -= 1; for (int i = 0; i < _numSpells; i++) { EobSpell *s = &_spells[i]; diff --git a/engines/kyra/timer.cpp b/engines/kyra/timer.cpp index 4722966cad..2ab2b621f3 100644 --- a/engines/kyra/timer.cpp +++ b/engines/kyra/timer.cpp @@ -129,26 +129,6 @@ void TimerManager::update() { } } -void TimerManager::manualAdvance(uint32 millis) { - uint32 curTime = _system->getMillis(); - for (Iterator pos = _timers.begin(); pos != _timers.end(); ++pos) { - if (pos->enabled == 1 && pos->countdown >= 0) { - pos->nextRun -= curTime; - while (pos->nextRun <= millis) { - if (pos->func && pos->func->isValid()) - (*pos->func)(pos->id); - - pos->lastUpdate = curTime; - pos->nextRun = pos->countdown * _vm->tickLength(); - millis -= pos->nextRun; - } - pos->nextRun += curTime; - _nextRun = MIN(_nextRun, pos->nextRun); - } - } - -} - void TimerManager::resync() { const uint32 curTime = _isPaused ? _pauseStart : _system->getMillis(); diff --git a/engines/kyra/timer.h b/engines/kyra/timer.h index 5e53d615d3..205be5957d 100644 --- a/engines/kyra/timer.h +++ b/engines/kyra/timer.h @@ -61,8 +61,6 @@ public: void update(); - void manualAdvance(uint32 millis); - void resetNextRun(); void setCountdown(uint8 id, int32 countdown); diff --git a/engines/kyra/timer_eob.cpp b/engines/kyra/timer_eob.cpp index 00dc758a27..903dec2102 100644 --- a/engines/kyra/timer_eob.cpp +++ b/engines/kyra/timer_eob.cpp @@ -133,19 +133,21 @@ void EobCoreEngine::setCharEventTimer(int charIndex, uint32 countdown, int evnt, _timer->setNextRun(timerId, ntime); if (updateExistingTimer) { - bool br = false; + bool updated = false; int d = -1; - for (int i = 0; i < 10 && br == false; i++) { + for (int i = 0; i < 10 && updated == false; i++) { if (d == -1 && !c->timers[i]) d = i; - if (!br && c->events[i] == evnt) { + if (!updated && c->events[i] == evnt) { d = i; - br = true; + updated = true; } } + assert(d != -1); + c->timers[d] = ntime; c->events[d] = evnt; } else { @@ -179,7 +181,7 @@ void EobCoreEngine::setupCharacterTimers() { uint32 nextTimer = 0xffffffff; for (int ii = 0; ii < 10; ii++) { - if (c->timers[ii] < nextTimer) + if (c->timers[ii] && c->timers[ii] < nextTimer) nextTimer = c->timers[ii]; } uint32 ctime = _system->getMillis(); @@ -193,21 +195,28 @@ void EobCoreEngine::setupCharacterTimers() { } } -void EobCoreEngine::manualAdvanceTimer(int sysTimer, uint32 millis) { - if (sysTimer != 2) - return; - +void EobCoreEngine::advanceTimers(uint32 millis) { uint32 ct = _system->getMillis(); for (int i = 0; i < 6; i++) { + EobCharacter *c = &_characters[i]; for (int ii = 0; ii < 10; ii++) { - if (_characters[i].timers[ii]) { - uint32 chrt = _characters[i].timers[ii] - ct; - _characters[i].timers[ii] = chrt > millis ? chrt - millis : 1; + if (c->timers[ii] > ct) { + uint32 chrt = c->timers[ii] - ct; + c->timers[ii] = chrt > millis ? chrt - millis : ct; } } } - _timer->manualAdvance(millis); + setupCharacterTimers(); + + if (_scriptTimersMode & 2) { + for (int i = 0; i < _scriptTimersCount; i++) { + if (_scriptTimers[i].next > ct) { + uint32 chrt = _scriptTimers[i].next - ct; + _scriptTimers[i].next = chrt > millis ? chrt - millis : ct; + } + } + } } void EobCoreEngine::timerProcessCharacterExchange(int timerNum) { @@ -314,7 +323,7 @@ void EobCoreEngine::timerSpecialCharacterUpdate(int timerNum) { calcAndInflictCharacterDamage(charIndex, 0, 0, 5, 0x400, 5, 3); setCharEventTimer(charIndex, 546, 8, 1); } else { - c->flags &= 0xfd; + c->flags &= ~2; gui_drawCharPortraitWithStats(charIndex); } break; @@ -329,7 +338,7 @@ void EobCoreEngine::timerSpecialCharacterUpdate(int timerNum) { case 11: if (c->disabledSlots & 4) { - c->disabledSlots &= 0xfb; + c->disabledSlots &= ~4; if (_openBookChar == charIndex && _updateFlags) gui_drawSpellbook(); } @@ -345,13 +354,13 @@ void EobCoreEngine::timerSpecialCharacterUpdate(int timerNum) { } } - uint32 nextTimer = (uint32)(-1); + uint32 nextTimer = 0xffffffff; for (int i = 0; i < 10; i++) { if (c->timers[i] && c->timers[i] < nextTimer) nextTimer = c->timers[i]; } - if (nextTimer == (uint32)(-1)) + if (nextTimer == 0xffffffff) _timer->disable(timerNum); else _timer->setCountdown(timerNum, (nextTimer - ctime) / _tickLength); |