aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/kyra/eob2.cpp2
-rw-r--r--engines/kyra/eobcommon.cpp20
-rw-r--r--engines/kyra/eobcommon.h20
-rw-r--r--engines/kyra/gui_eob.cpp38
-rw-r--r--engines/kyra/items_eob.cpp3
-rw-r--r--engines/kyra/magic_eob.cpp177
-rw-r--r--engines/kyra/saveload_eob.cpp4
-rw-r--r--engines/kyra/scene_eob.cpp2
-rw-r--r--engines/kyra/sprites_eob.cpp36
-rw-r--r--engines/kyra/staticres_eob.cpp29
-rw-r--r--engines/kyra/timer.cpp20
-rw-r--r--engines/kyra/timer.h2
-rw-r--r--engines/kyra/timer_eob.cpp43
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);