From 8fdd055bf114840cdee906dec0a09e859f5cf434 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Wed, 11 Apr 2018 21:04:51 -0400 Subject: XEEN: Fix monster attacks that target the entire party --- engines/xeen/character.h | 2 +- engines/xeen/combat.cpp | 143 ++++++++++++++++++++++------------------------- engines/xeen/combat.h | 9 +++ 3 files changed, 78 insertions(+), 76 deletions(-) diff --git a/engines/xeen/character.h b/engines/xeen/character.h index 6639d837f3..47312efe66 100644 --- a/engines/xeen/character.h +++ b/engines/xeen/character.h @@ -55,7 +55,7 @@ enum CharacterClass { }; enum HatesClass { - HATES_DWARF = 12, HATES_ALL_CLASSES = 15, HATES_NO_CLASSES = 16 + HATES_DWARF = 12, HATES_PARTY = 15, HATES_NOBODY = 16 }; enum Attribute { diff --git a/engines/xeen/combat.cpp b/engines/xeen/combat.cpp index 0ac80650eb..e5e518fa37 100644 --- a/engines/xeen/combat.cpp +++ b/engines/xeen/combat.cpp @@ -814,15 +814,20 @@ void Combat::doMonsterTurn(int monsterId) { } MonsterStruct &monsterData = map._monsterData[monsterId]; - bool flag = false; for (int attackNum = 0; attackNum < monsterData._numberOfAttacks; ++attackNum) { int charNum = -1; bool isHated = false; - if (monsterData._hatesClass != -1) { - if (monsterData._hatesClass == HATES_ALL_CLASSES) - // Monster hates all classes - goto loop; + if (monsterData._hatesClass != CLASS_PALADIN) { + if (monsterData._hatesClass == HATES_PARTY) { + // Monster hates entire party, even the disabled/dead + for (uint idx = 0; idx < _combatParty.size(); ++idx) { + doMonsterTurn(monsterId, idx); + } + + // Move onto monster's next attack (if any) + continue; + } for (uint charIndex = 0; charIndex < _combatParty.size(); ++charIndex) { Character &c = *_combatParty[charIndex]; @@ -830,10 +835,8 @@ void Combat::doMonsterTurn(int monsterId) { if (cond >= PARALYZED && cond <= ERADICATED) continue; - isHated = false; switch (monsterData._hatesClass) { case CLASS_KNIGHT: - case CLASS_PALADIN: case CLASS_ARCHER: case CLASS_CLERIC: case CLASS_SORCERER: @@ -859,88 +862,78 @@ void Combat::doMonsterTurn(int monsterId) { } if (!isHated) { - // No particularly hated foe, so decide which character to start with + // No particularly hated foe, so pick a random character to start with // Note: Original had a whole switch statement depending on party size, that boiled down to // picking a random character in all cases anyway charNum = _vm->getRandomNumber(0, _combatParty.size() - 1); } - // Attacking loop - do { - if (!flag) { - Condition cond = _combatParty[charNum]->worstCondition(); - - if (cond >= PARALYZED && cond <= ERADICATED) { - Common::Array ableChars; - bool skip = false; - - for (uint idx = 0; idx < _combatParty.size() && !skip; ++idx) { - switch (_combatParty[idx]->worstCondition()) { - case PARALYZED: - case UNCONSCIOUS: - //if (flag) - // skip = true; - break; - case DEAD: - case STONED: - case ERADICATED: - break; - default: - ableChars.push_back(idx); - break; - } - } - - if (!skip) { - if (ableChars.size() == 0) { - party._dead = true; - _vm->_mode = MODE_1; - return; - } - - charNum = ableChars[_vm->getRandomNumber(0, ableChars.size() - 1)]; - } + // If the chosen character is already disabled, we need to pick a still able body character + // from the remainder of the combat party + Condition cond = _combatParty[charNum]->worstCondition(); + if (cond >= PARALYZED && cond <= ERADICATED) { + Common::Array ableChars; + + for (uint idx = 0; idx < _combatParty.size(); ++idx) { + switch (_combatParty[idx]->worstCondition()) { + case PARALYZED: + case UNCONSCIOUS: + case DEAD: + case STONED: + case ERADICATED: + break; + default: + ableChars.push_back(idx); + break; } } - // Unconditional if to get around goto initialization errors - if (true) { - Character &c = *_combatParty[charNum]; - if (monsterData._attackType != DT_PHYSICAL || c._conditions[ASLEEP]) { - doCharDamage(c, charNum, monsterId); - } else { - int v = _vm->getRandomNumber(1, 20); - if (v == 1) { - // Critical Save - sound.playFX(6); - } else { - if (v == 20) - // Critical failure - doCharDamage(c, charNum, monsterId); - v += monsterData._hitChance / 4 + _vm->getRandomNumber(1, - monsterData._hitChance); - - int ac = c.getArmorClass() + (!_charsBlocked[charNum] ? 10 : - c.getCurrentLevel() / 2 + 15); - if (ac > v) { - sound.playFX(6); - } else { - doCharDamage(c, charNum, monsterId); - } - } - } - - if (flag) - break; + if (ableChars.size() == 0) { + party._dead = true; + _vm->_mode = MODE_1; + return; } -loop: - flag = true; - } while (++charNum < (int)_combatParty.size()); + + charNum = ableChars[_vm->getRandomNumber(0, ableChars.size() - 1)]; + } + + doMonsterTurn(monsterId, charNum); } intf.drawParty(true); } +void Combat::doMonsterTurn(int monsterId, int charNum) { + Map &map = *_vm->_map; + Sound &sound = *_vm->_sound; + MonsterStruct &monsterData = map._monsterData[monsterId]; + Character &c = *_combatParty[charNum]; + + if (monsterData._attackType != DT_PHYSICAL || c._conditions[ASLEEP]) { + doCharDamage(c, charNum, monsterId); + } else { + int v = _vm->getRandomNumber(1, 20); + if (v == 1) { + // Critical Save + sound.playFX(6); + } else { + if (v == 20) + // Critical failure + doCharDamage(c, charNum, monsterId); + v += monsterData._hitChance / 4 + _vm->getRandomNumber(1, + monsterData._hitChance); + + int ac = c.getArmorClass() + (!_charsBlocked[charNum] ? 10 : + c.getCurrentLevel() / 2 + 15); + if (ac > v) { + sound.playFX(6); + } else { + doCharDamage(c, charNum, monsterId); + } + } + } +} + int Combat::stopAttack(const Common::Point &diffPt) { Map &map = *_vm->_map; Party &party = *_vm->_party; diff --git a/engines/xeen/combat.h b/engines/xeen/combat.h index e55c8b7553..e6ac1e27bb 100644 --- a/engines/xeen/combat.h +++ b/engines/xeen/combat.h @@ -77,6 +77,7 @@ enum RangeType { class XeenEngine; class Character; class XeenItem; +class MonsterStruct; struct PowSlot { bool _active; @@ -291,8 +292,16 @@ public: */ void moveMonster(int monsterId, const Common::Point &moveDelta); + /** + * Handle a monster's turn at attacking combat party members + */ void doMonsterTurn(int monsterId); + /** + * Handles a monster's turn at attacking a specific member of the combat party + */ + void doMonsterTurn(int monsterId, int charNum); + /** * Called when combat has ended */ -- cgit v1.2.3