KYRA: (EOB) - fix various bugs and implement some spells

This commit is contained in:
athrxx 2011-07-21 00:28:57 +02:00 committed by Johannes Schickel
parent 9140fd8e91
commit c302b3e43b
13 changed files with 248 additions and 148 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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; }

View File

@ -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) {

View File

@ -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)

View File

@ -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) {

View File

@ -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);

View File

@ -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]))

View File

@ -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;
}
}

View File

@ -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];

View File

@ -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();

View File

@ -61,8 +61,6 @@ public:
void update();
void manualAdvance(uint32 millis);
void resetNextRun();
void setCountdown(uint8 id, int32 countdown);

View File

@ -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);