aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2015-02-16 19:58:53 -0500
committerPaul Gilbert2015-02-16 19:58:53 -0500
commitc045adae76e414a8e6b57e48a651ea6c29ed280a (patch)
treea670a69209db79e8344d060c07f44b84c96f6804 /engines
parent30d94950beb02188644dcfd71f3c3a067d0a0c5a (diff)
downloadscummvm-rg350-c045adae76e414a8e6b57e48a651ea6c29ed280a.tar.gz
scummvm-rg350-c045adae76e414a8e6b57e48a651ea6c29ed280a.tar.bz2
scummvm-rg350-c045adae76e414a8e6b57e48a651ea6c29ed280a.zip
XEEN: Implementing more combat logic
Diffstat (limited to 'engines')
-rw-r--r--engines/xeen/character.cpp25
-rw-r--r--engines/xeen/character.h4
-rw-r--r--engines/xeen/combat.cpp154
-rw-r--r--engines/xeen/combat.h29
-rw-r--r--engines/xeen/dialogs_control_panel.cpp42
-rw-r--r--engines/xeen/dialogs_control_panel.h43
-rw-r--r--engines/xeen/dialogs_fight_options.cpp39
-rw-r--r--engines/xeen/dialogs_fight_options.h43
-rw-r--r--engines/xeen/interface.cpp358
-rw-r--r--engines/xeen/interface.h4
-rw-r--r--engines/xeen/map.cpp9
-rw-r--r--engines/xeen/map.h2
-rw-r--r--engines/xeen/module.mk2
-rw-r--r--engines/xeen/party.cpp7
-rw-r--r--engines/xeen/party.h2
-rw-r--r--engines/xeen/resources.cpp2
-rw-r--r--engines/xeen/resources.h2
-rw-r--r--engines/xeen/scripts.cpp2
18 files changed, 754 insertions, 15 deletions
diff --git a/engines/xeen/character.cpp b/engines/xeen/character.cpp
index ac25b32c55..afe385448a 100644
--- a/engines/xeen/character.cpp
+++ b/engines/xeen/character.cpp
@@ -818,6 +818,9 @@ void Character::synchronize(Common::Serializer &s) {
s.syncAsByte(_currentCombatSpell);
}
+/**
+ * Returns the worst condition the character is suffering from
+ */
Condition Character::worstCondition() const {
for (int cond = ERADICATED; cond >= CURSED; --cond) {
if (_conditions[cond])
@@ -827,6 +830,28 @@ Condition Character::worstCondition() const {
return NO_CONDITION;
}
+/**
+ * Returns whether the given character has a disabling condition, but still alive
+ */
+bool Character::isDisabled() const {
+ Condition condition = worstCondition();
+
+ return condition == ASLEEP || condition == PARALYZED || condition == UNCONSCIOUS
+ || condition == STONED || condition == ERADICATED;
+}
+
+/**
+* Returns whether the given character has a disabling condition, or is dead
+*/
+bool Character::isDisabledOrDead() const {
+ Condition condition = worstCondition();
+
+ return condition == ASLEEP || (condition >= PARALYZED && condition <= ERADICATED);
+}
+
+/**
+ * Get the character's age
+ */
int Character::getAge(bool ignoreTemp) const {
int year = MIN(Party::_vm->_party->_year - _birthYear, (uint)254);
diff --git a/engines/xeen/character.h b/engines/xeen/character.h
index 9e8687dbd7..be38ba5da1 100644
--- a/engines/xeen/character.h
+++ b/engines/xeen/character.h
@@ -270,6 +270,10 @@ public:
Condition worstCondition() const;
+ bool isDisabled() const;
+
+ bool isDisabledOrDead() const;
+
int getAge(bool ignoreTemp = false) const;
int getMaxHP() const;
diff --git a/engines/xeen/combat.cpp b/engines/xeen/combat.cpp
index d66081754c..c8f5824db9 100644
--- a/engines/xeen/combat.cpp
+++ b/engines/xeen/combat.cpp
@@ -96,6 +96,10 @@ Combat::Combat(XeenEngine *vm): _vm(vm) {
_itemFlag = false;
_monstersAttacking = false;
_combatMode = 0;
+ _monsterIndex = 0;
+ _partyRan = false;
+ _monster2Attack = -1;
+ _whosSpeed = 0;
}
void Combat::clear() {
@@ -412,9 +416,7 @@ void Combat::monstersAttack() {
if (_vm->_mode != MODE_COMBAT) {
// Combat wasn't previously active, but it is now. Set up
// the combat party from the currently active party
- _combatParty.clear();
- for (uint idx = 0; idx < party._activeParty.size(); ++idx)
- _combatParty.push_back(&party._activeParty[idx]);
+ setupCombatParty();
}
for (int idx = 0; idx < 36; ++idx) {
@@ -575,4 +577,150 @@ bool Combat::stopAttack(const Common::Point &diffPt) {
return false;
}
+/**
+ * Setup the combat party with a copy of the currently active party
+ */
+void Combat::setupCombatParty() {
+ Party &party = *_vm->_party;
+
+ _combatParty.clear();
+ for (uint idx = 0; idx < party._activeParty.size(); ++idx)
+ _combatParty.push_back(&party._activeParty[idx]);
+}
+
+void Combat::setSpeedTable() {
+ Map &map = *_vm->_map;
+ Common::Array<int> charSpeeds;
+ bool flag = _whosSpeed != -1;
+ int oldSpeed = (_whosSpeed == -1) ? 0 : _speedTable[_whosSpeed];
+
+ Common::fill(&_speedTable[0], &_speedTable[12], -1);
+ Common::fill(&charSpeeds[0], &charSpeeds[12], -1);
+
+ // Set up speeds for party membres
+ int maxSpeed = 0;
+ for (uint charNum = 0; charNum < _combatParty.size(); ++charNum) {
+ Character &c = *_combatParty[charNum];
+ charSpeeds.push_back(c.getStat(SPEED));
+
+ maxSpeed = MAX(charSpeeds[charNum], maxSpeed);
+ }
+
+ // Add in speeds of attacking monsters
+ for (int monsterNum = 0; monsterNum < 3; ++monsterNum) {
+ if (_attackMonsters[monsterNum] != -1) {
+ MazeMonster &monster = map._mobData._monsters[_attackMonsters[monsterNum]];
+ MonsterStruct &monsterData = map._monsterData[monster._spriteId];
+ charSpeeds.push_back(monsterData._speed);
+
+ maxSpeed = MAX(maxSpeed, monsterData._speed);
+ } else {
+ charSpeeds.push_back(0);
+ }
+ }
+
+ _speedTable.clear();
+ for (; maxSpeed >= 0; --maxSpeed) {
+ for (uint idx = 0; idx < charSpeeds.size(); ++idx) {
+ if (charSpeeds[idx] == maxSpeed)
+ _speedTable.push_back(idx);
+ }
+ }
+
+ if (flag) {
+ if (_speedTable[_whosSpeed] != oldSpeed) {
+ for (uint idx = 0; idx < charSpeeds.size(); ++idx) {
+ if (oldSpeed == _speedTable[idx]) {
+ _whosSpeed = idx;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Returns true if all participants in the combat are disabled
+ */
+bool Combat::allHaveGone() const {
+ for (uint idx = 0; idx < _charsGone.size(); ++idx) {
+ if (!_charsGone[idx]) {
+ if (idx >= _combatParty.size()) {
+ return false;
+ } else {
+ Condition condition = _combatParty[idx]->worstCondition();
+ if (condition < PARALYZED || condition == NO_CONDITION)
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool Combat::charsCantAct() const {
+ for (uint idx = 0; idx < _combatParty.size(); ++idx) {
+ Condition condition = _combatParty[idx]->worstCondition();
+
+ if (!(condition == ASLEEP || (condition >= PARALYZED && condition != NO_CONDITION)))
+ return false;
+ }
+
+ return true;
+}
+
+Common::String Combat::getMonsterDescriptions() {
+ Map &map = *_vm->_map;
+ Common::String lines[3];
+
+ // Get names of monsters attacking, if any
+ for (int idx = 0; idx < 3; ++idx) {
+ if (_attackMonsters[idx] != -1) {
+ MazeMonster &monster = map._mobData._monsters[_attackMonsters[idx]];
+ MonsterStruct &monsterData = map._monsterData[monster._spriteId];
+
+ Common::String format = "\n\v020\f%2u%s\fd";
+ format.setChar('2' + idx, 3);
+ lines[idx] = Common::String::format(format.c_str(), monsterData._name.c_str());
+ }
+ }
+
+ if (_monsterIndex == 2 && _attackMonsters[2] != -1) {
+ _monster2Attack = _attackMonsters[2];
+ } if (_monsterIndex == 1 && _attackMonsters[1] != -1) {
+ _monster2Attack = _attackMonsters[1];
+ } else {
+ _monster2Attack = _attackMonsters[0];
+ _monsterIndex = 0;
+ }
+
+ return Common::String::format(COMBAT_DETAILS, lines[0].c_str(),
+ lines[1].c_str(), lines[2].c_str());
+}
+
+void Combat::attack(Character &c, int v2) {
+ error("TODO");
+}
+
+void Combat::block() {
+ _charsBlocked[_whosTurn] = true;
+}
+
+bool Combat::castSpell(bool flag) {
+ error("TODO: castSpell");
+}
+
+void Combat::quickFight() {
+ error("TODO: quickFight");
+}
+
+void Combat::giveTreasure() {
+ error("TODO: giveTreasure");
+}
+
+void Combat::run() {
+ error("TODO: run");
+}
+
+
} // End of namespace Xeen
diff --git a/engines/xeen/combat.h b/engines/xeen/combat.h
index 6b306b4991..dee15edf6c 100644
--- a/engines/xeen/combat.h
+++ b/engines/xeen/combat.h
@@ -57,15 +57,17 @@ private:
XeenEngine *_vm;
public:
Common::Array<Character *> _combatParty;
- Common::Array<int> _charsBlocked;
+ Common::Array<bool> _charsBlocked;
Common::Array<int> _charsGone;
SpriteResource _powSprites;
int _attackMonsters[26];
+ int _monster2Attack;
int _charsArray1[12];
bool _monPow[12];
int _monsterScale[12];
int _elemPow[12];
int _elemScale[12];
+ Common::Array<int> _speedTable;
int _shooting[8];
int _globalCombat;
int _whosTurn;
@@ -76,6 +78,9 @@ public:
int _gmonHit[36];
bool _monstersAttacking;
int _combatMode;
+ int _monsterIndex;
+ bool _partyRan;
+ int _whosSpeed;
void monstersAttack();
@@ -101,6 +106,28 @@ public:
void giveCharDamage(int damage, DamageType attackType, int charIndex);
void moveMonsters();
+
+ void setupCombatParty();
+
+ void setSpeedTable();
+
+ bool allHaveGone() const;
+
+ bool charsCantAct() const;
+
+ Common::String getMonsterDescriptions();
+
+ void attack(Character &c, int v2);
+
+ void block();
+
+ bool castSpell(bool flag);
+
+ void quickFight();
+
+ void giveTreasure();
+
+ void run();
};
} // End of namespace Xeen
diff --git a/engines/xeen/dialogs_control_panel.cpp b/engines/xeen/dialogs_control_panel.cpp
new file mode 100644
index 0000000000..7e8f89cc39
--- /dev/null
+++ b/engines/xeen/dialogs_control_panel.cpp
@@ -0,0 +1,42 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "xeen/dialogs_control_panel.h"
+#include "xeen/party.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+int ControlPanel::show(XeenEngine *vm) {
+ ControlPanel *dlg = new ControlPanel(vm);
+ int result = dlg->execute();
+ delete dlg;
+
+ return result;
+}
+
+int ControlPanel::execute() {
+ error("TODO: ControlPanel");
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs_control_panel.h b/engines/xeen/dialogs_control_panel.h
new file mode 100644
index 0000000000..16c3781789
--- /dev/null
+++ b/engines/xeen/dialogs_control_panel.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_CONTROL_PANEL_H
+#define XEEN_DIALOGS_CONTROL_PANEL_H
+
+#include "xeen/dialogs.h"
+
+namespace Xeen {
+
+class ControlPanel : public ButtonContainer {
+private:
+ XeenEngine *_vm;
+
+ ControlPanel(XeenEngine *vm) : ButtonContainer(), _vm(vm) {}
+
+ int execute();
+public:
+ static int show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_CONTROL_PANEL_H */
diff --git a/engines/xeen/dialogs_fight_options.cpp b/engines/xeen/dialogs_fight_options.cpp
new file mode 100644
index 0000000000..c84e754dc2
--- /dev/null
+++ b/engines/xeen/dialogs_fight_options.cpp
@@ -0,0 +1,39 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "xeen/dialogs_fight_options.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+void FightOptions::show(XeenEngine *vm) {
+ FightOptions *dlg = new FightOptions(vm);
+ dlg->execute();
+ delete dlg;
+}
+
+void FightOptions::execute() {
+ error("TODO: FightOptions");
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/dialogs_fight_options.h b/engines/xeen/dialogs_fight_options.h
new file mode 100644
index 0000000000..7b058bc6e9
--- /dev/null
+++ b/engines/xeen/dialogs_fight_options.h
@@ -0,0 +1,43 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_DIALOGS_FIGHT_OPTIONS_H
+#define XEEN_DIALOGS_FIGHT_OPTIONS_H
+
+#include "xeen/dialogs.h"
+
+namespace Xeen {
+
+class FightOptions : public ButtonContainer {
+private:
+ XeenEngine *_vm;
+
+ FightOptions(XeenEngine *vm) : ButtonContainer(), _vm(vm) {}
+
+ void execute();
+public:
+ static void show(XeenEngine *vm);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_DIALOGS_FIGHT_OPTIONS_H */
diff --git a/engines/xeen/interface.cpp b/engines/xeen/interface.cpp
index 479795db4b..a8396288ee 100644
--- a/engines/xeen/interface.cpp
+++ b/engines/xeen/interface.cpp
@@ -21,10 +21,13 @@
*/
#include "xeen/interface.h"
+#include "xeen/dialogs_automap.h"
#include "xeen/dialogs_char_info.h"
+#include "xeen/dialogs_control_panel.h"
#include "xeen/dialogs_error.h"
-#include "xeen/dialogs_automap.h"
+#include "xeen/dialogs_fight_options.h"
#include "xeen/dialogs_info.h"
+#include "xeen/dialogs_items.h"
#include "xeen/dialogs_query.h"
#include "xeen/dialogs_quests.h"
#include "xeen/dialogs_quick_ref.h"
@@ -121,6 +124,9 @@ void PartyDrawer::unhighlightChar() {
}
}
+void PartyDrawer::resetHighlight() {
+ _hiliteChar = -1;
+}
/*------------------------------------------------------------------------*/
Interface::Interface(XeenEngine *vm) : ButtonContainer(), InterfaceMap(vm),
@@ -320,7 +326,11 @@ void Interface::perform() {
case Common::KEYCODE_TAB:
// Stop mosters doing any movement
_vm->_moveMonsters = false;
- warning("TODO: showControlPanel");
+ if (ControlPanel::show(_vm) == -1) {
+ _vm->_quitMode = 2;
+ } else {
+ _vm->_moveMonsters = 1;
+ }
break;
case Common::KEYCODE_SPACE:
@@ -1811,9 +1821,13 @@ void Interface::assembleBorder() {
void Interface::doCombat() {
Combat &combat = *_vm->_combat;
EventsManager &events = *_vm->_events;
+ Map &map = *_vm->_map;
+ Party &party = *_vm->_party;
Screen &screen = *_vm->_screen;
- bool isDarkCc = _vm->_files->_isDarkCc;
+ Scripts &scripts = *_vm->_scripts;
+ SoundManager &sound = *_vm->_sound;
bool upDoorText = _upDoorText;
+ bool reloadMap = false;
_upDoorText = false;
combat._combatMode = 2;
@@ -1827,9 +1841,345 @@ void Interface::doCombat() {
setMainButtons(true);
mainIconsPrint();
+ combat._combatParty.clear();
+ combat._charsGone.clear();
+ combat._charsBlocked.clear();
+ combat._charsArray1[0] = 0;
+ combat._charsArray1[1] = 0;
+ combat._charsArray1[2] = 0;
+ combat._monstersAttacking = 0;
+ combat._partyRan = false;
+
+ // Set up the combat party
+ combat.setupCombatParty();
+ combat.setSpeedTable();
+ combat._whosSpeed = -1;
+ combat._whosTurn = -1;
+ resetHighlight();
+
+ nextChar();
+
+ if (!party._dead) {
+ combat.setSpeedTable();
+ if (_tillMove) {
+ combat.moveMonsters();
+ draw3d(true);
+ }
+
+ Window &w = screen._windows[2];
+ w.open();
+ bool breakFlag = false;
+
+ while (!_vm->shouldQuit() && !breakFlag) {
+ highlightChar(combat._whosTurn);
+ combat.setSpeedTable();
+
+ // Write out the description of the monsters being battled
+ w.writeString(combat.getMonsterDescriptions());
+ _iconSprites.draw(screen, 32, Common::Point(233, combat._monsterIndex * 10 + 27),
+ 0x8010000);
+ w.update();
+
+ // Wait for keypress
+ int index = 0;
+ do {
+ events.updateGameCounter();
+ draw3d(true);
+
+ if (++index == 5 && combat._attackMonsters[0] != -1) {
+ MazeMonster &monster = map._mobData._monsters[combat._monster2Attack];
+ MonsterStruct &monsterData = map._monsterData[monster._spriteId];
+ sound.playFX(monsterData._fx);
+ }
+
+ do {
+ events.pollEventsAndWait();
+ checkEvents(_vm);
+ } while (!_vm->shouldQuit() && events.timeElapsed() < 1 && !_buttonValue);
+ } while (!_vm->shouldQuit() && !_buttonValue);
+ if (_vm->shouldQuit())
+ return;
+
+ switch (_buttonValue) {
+ case Common::KEYCODE_TAB:
+ // Show the control panel
+ if (ControlPanel::show(_vm) == 2) {
+ reloadMap = true;
+ breakFlag = true;
+ } else {
+ highlightChar(combat._whosTurn);
+ }
+ break;
+
+ case Common::KEYCODE_1:
+ case Common::KEYCODE_2:
+ case Common::KEYCODE_3:
+ _buttonValue -= Common::KEYCODE_1;
+ if (combat._attackMonsters[_buttonValue] != -1) {
+ combat._monster2Attack = combat._attackMonsters[_buttonValue];
+ combat._monsterIndex = _buttonValue;
+ }
+ break;
+
+ case Common::KEYCODE_a:
+ // Attack
+ combat.attack(*combat._combatParty[combat._whosTurn], 0);
+ nextChar();
+ break;
+
+ case Common::KEYCODE_b:
+ // Block
+ combat.block();
+ nextChar();
+ break;
+
+ case Common::KEYCODE_c:
+ // Cast Spell
+ if (combat.castSpell(false)) {
+ nextChar();
+ } else {
+ highlightChar(combat._combatParty[combat._whosTurn]->_rosterId);
+ }
+ break;
+
+ case Common::KEYCODE_f:
+ // Quick Fight
+ combat.quickFight();
+ nextChar();
+ break;
+
+ case Common::KEYCODE_i:
+ // Info dialog
+ InfoDialog::show(_vm);
+ highlightChar(combat._whosTurn);
+ break;
+
+ case Common::KEYCODE_o:
+ // Fight Options
+ FightOptions::show(_vm);
+ highlightChar(combat._whosTurn);
+ break;
+
+ case Common::KEYCODE_q:
+ // Quick Reference dialog
+ QuickReferenceDialog::show(_vm);
+ highlightChar(combat._whosTurn);
+ break;
+
+ case Common::KEYCODE_r:
+ // Run from combat
+ combat.run();
+ nextChar();
+
+ if (_vm->_mode == MODE_1) {
+ warning("TODO: loss of treasure");
+ party.moveToRunLocation();
+ breakFlag = true;
+ }
+ break;
+
+ case Common::KEYCODE_u: {
+ int whosTurn = combat._whosTurn;
+ ItemsDialog::show(_vm, combat._combatParty[combat._whosTurn], ITEMMODE_COMBAT);
+ if (combat._whosTurn == whosTurn) {
+ highlightChar(combat._whosTurn);
+ } else {
+ combat._whosTurn = whosTurn;
+ nextChar();
+ }
+ break;
+ }
+
+ case Common::KEYCODE_F1:
+ case Common::KEYCODE_F2:
+ case Common::KEYCODE_F3:
+ case Common::KEYCODE_F4:
+ case Common::KEYCODE_F5:
+ case Common::KEYCODE_F6:
+ // Show character info
+ _buttonValue -= Common::KEYCODE_F1;
+ if (_buttonValue < (int)combat._combatParty.size()) {
+ CharacterInfo::show(_vm, _buttonValue);
+ }
+ highlightChar(combat._whosTurn);
+ break;
+
+ case Common::KEYCODE_LEFT:
+ case Common::KEYCODE_RIGHT:
+ // Rotate party direction left or right
+ if (_buttonValue == Common::KEYCODE_LEFT) {
+ party._mazeDirection = (party._mazeDirection == DIR_NORTH) ?
+ DIR_WEST : (Direction)((int)party._mazeDirection - 1);
+ } else {
+ party._mazeDirection = (party._mazeDirection == DIR_WEST) ?
+ DIR_NORTH : (Direction)((int)party._mazeDirection + 1);
+ }
+
+ _flipSky ^= 1;
+ if (_tillMove)
+ combat.moveMonsters();
+ party._stepped = true;
+ break;
+ }
+
+ // Handling for if the combat turn is complete
+ if (combat.allHaveGone()) {
+ Common::fill(&combat._charsGone[0], &combat._charsGone[combat._charsGone.size()], false);
+ Common::fill(&combat._charsBlocked[0], &combat._charsBlocked[combat._charsBlocked.size()], false);
+ combat.setSpeedTable();
+ combat._whosTurn = -1;
+ combat._whosSpeed = -1;
+ nextChar();
+
+ for (uint idx = 0; idx < map._mobData._monsters.size(); ++idx) {
+ MazeMonster &monster = map._mobData._monsters[idx];
+ if (monster._spriteId == 53) {
+ warning("TODO: Monster 53's HP is altered here?!");
+ }
+ }
+
+ combat.moveMonsters();
+ setIndoorsMonsters();
+ party.changeTime(1);
+ }
+
+ if (combat._attackMonsters[0] == -1 && combat._attackMonsters[1] == -1
+ && combat._attackMonsters[2] == -1) {
+ party.changeTime(1);
+ draw3d(true);
+
+ if (combat._attackMonsters[0] == -1 && combat._attackMonsters[1] == -1
+ && combat._attackMonsters[2] == -1)
+ break;
+ }
+
+ party.checkPartyDead();
+ if (party._dead || _vm->_mode != MODE_COMBAT)
+ break;
+ }
+
+ _vm->_mode = MODE_1;
+ if (combat._partyRan && (combat._attackMonsters[0] != -1 ||
+ combat._attackMonsters[1] != -1 || combat._attackMonsters[2] != -1)) {
+ party.checkPartyDead();
+ if (!party._dead) {
+ party.moveToRunLocation();
+
+ for (uint idx = 0; idx < combat._combatParty.size(); ++idx) {
+ Character &c = *combat._combatParty[idx];
+ if (c.isDisabled())
+ c._conditions[DEAD] = 1;
+ }
+ }
+ }
+
+ w.close();
+ events.clearEvents();
+
+ _vm->_mode = MODE_COMBAT;
+ draw3d(true);
+ combat.giveTreasure();
+ _vm->_mode = MODE_1;
+ party._stepped = true;
+ unhighlightChar();
+
+ combat.setupCombatParty();
+ drawParty(true);
+ }
+
+ _iconSprites.load("main.icn");
+ for (int idx = 1; idx < 16; ++idx)
+ _mainList[idx]._sprites = &_iconSprites;
+
+ setMainButtons();
+ mainIconsPrint();
+ combat._monster2Attack = -1;
+
+ if (upDoorText) {
+ map.cellFlagLookup(party._mazePosition);
+ if (map._currentIsEvent)
+ scripts.checkEvents();
+ }
+
+ if (reloadMap) {
+ sound.playFX(51);
+ map._loadDarkSide = _vm->getGameID() != GType_WorldOfXeen;
+ map.load(_vm->getGameID() == GType_WorldOfXeen ? 28 : 29);
+ party._mazeDirection = _vm->getGameID() == GType_WorldOfXeen ?
+ DIR_EAST : DIR_SOUTH;
+ }
+ combat._combatMode = 1;
+}
- error("TODO");
+/**
+ * Select next character or monster to be attacking
+ */
+void Interface::nextChar() {
+ Combat &combat = *_vm->_combat;
+ Party &party = *_vm->_party;
+
+ if (combat.allHaveGone())
+ return;
+ if ((combat._attackMonsters[0] == -1 && combat._attackMonsters[1] == -1 &&
+ combat._attackMonsters[2] == -1) || combat._combatParty.size() == 0) {
+ _vm->_mode = MODE_1;
+ return;
+ }
+
+ for (;;) {
+ // Check if party is dead
+ party.checkPartyDead();
+ if (party._dead) {
+ _vm->_mode = MODE_1;
+ break;
+ }
+
+ if (combat._whosTurn < (int)combat._combatParty.size()) {
+ if (!combat.allHaveGone())
+ highlightChar(combat._whosTurn);
+ break;
+ } else {
+ combat.attackMonster(0);
+ if (!party._dead)
+ party.checkPartyDead();
+
+ if (party._dead)
+ break;
+ }
+
+ // Check the combat participants
+ bool resetFlag = false;
+ for (uint idx = 0; idx < combat._speedTable.size(); ++idx) {
+ // Mark the given character as haven taken their turn
+ if (combat._whosTurn != -1) {
+ combat._charsGone[combat._whosTurn] = true;
+ }
+
+ combat._whosSpeed %= combat._speedTable.size();
+ combat._whosTurn = combat._speedTable[combat._whosSpeed];
+
+ if (combat.allHaveGone()) {
+ if (combat.charsCantAct()) {
+ combat.setSpeedTable();
+ combat._whosTurn = -1;
+ combat._whosSpeed = -1;
+
+ combat._charsGone.resize(combat._speedTable.size());
+ Common::fill(&combat._charsGone[0], &combat._charsGone[combat._charsGone.size()], 0);
+ resetFlag = true;
+ break;
+ }
+ return;
+ } else if (combat._whosTurn >= (int)combat._combatParty.size() ||
+ !combat._combatParty[combat._whosTurn]->isDisabledOrDead()) {
+ break;
+ }
+ }
+
+ if (party._dead)
+ break;
+ }
}
} // End of namespace Xeen
diff --git a/engines/xeen/interface.h b/engines/xeen/interface.h
index 40926ac6ea..80b798047c 100644
--- a/engines/xeen/interface.h
+++ b/engines/xeen/interface.h
@@ -54,6 +54,8 @@ public:
void highlightChar(int charId);
void unhighlightChar();
+
+ void resetHighlight();
};
/**
@@ -103,6 +105,8 @@ private:
void shake(int time);
void drawMiniMap();
+
+ void nextChar();
public:
int _intrIndex1;
Common::String _interfaceText;
diff --git a/engines/xeen/map.cpp b/engines/xeen/map.cpp
index 1c7cbd8a39..01c050a10a 100644
--- a/engines/xeen/map.cpp
+++ b/engines/xeen/map.cpp
@@ -67,7 +67,7 @@ MonsterStruct::MonsterStruct() {
_imageNumber = 0;
_loopAnimation = 0;
_animationEffect = 0;
- _field32 = 0;
+ _fx = 0;
}
MonsterStruct::MonsterStruct(Common::String name, int experience, int hp, int accuracy,
@@ -78,7 +78,7 @@ MonsterStruct::MonsterStruct(Common::String name, int experience, int hp, int ac
int poisonResistence, int energyResistence, int magicResistence,
int phsyicalResistence, int field29, int gold, int gems, int itemDrop,
bool flying, int imageNumber, int loopAnimation, int animationEffect,
- int field32, Common::String attackVoc):
+ int fx, Common::String attackVoc):
_name(name), _experience(experience), _hp(hp), _accuracy(accuracy),
_speed(speed), _numberOfAttacks(numberOfAttacks), _hatesClass(hatesClass),
_strikes(strikes), _dmgPerStrike(dmgPerStrike), _attackType(attackType),
@@ -89,10 +89,9 @@ MonsterStruct::MonsterStruct(Common::String name, int experience, int hp, int ac
_magicResistence(magicResistence), _phsyicalResistence(phsyicalResistence),
_field29(field29), _gold(gold), _gems(gems), _itemDrop(itemDrop),
_flying(flying), _imageNumber(imageNumber), _loopAnimation(loopAnimation),
- _animationEffect(animationEffect), _field32(field32), _attackVoc(attackVoc) {
+ _animationEffect(animationEffect), _fx(fx), _attackVoc(attackVoc) {
}
-
void MonsterStruct::synchronize(Common::SeekableReadStream &s) {
char name[16];
s.read(name, 16);
@@ -127,7 +126,7 @@ void MonsterStruct::synchronize(Common::SeekableReadStream &s) {
_imageNumber = s.readByte();
_loopAnimation = s.readByte();
_animationEffect = s.readByte();
- _field32 = s.readByte();
+ _fx = s.readByte();
char attackVoc[10];
s.read(attackVoc, 9);
diff --git a/engines/xeen/map.h b/engines/xeen/map.h
index 806b4084c7..a43cef516e 100644
--- a/engines/xeen/map.h
+++ b/engines/xeen/map.h
@@ -77,7 +77,7 @@ public:
int _imageNumber;
int _loopAnimation;
int _animationEffect;
- int _field32;
+ int _fx;
Common::String _attackVoc;
public:
MonsterStruct();
diff --git a/engines/xeen/module.mk b/engines/xeen/module.mk
index 083abb9a8c..a17311c6af 100644
--- a/engines/xeen/module.mk
+++ b/engines/xeen/module.mk
@@ -12,9 +12,11 @@ MODULE_OBJS := \
automap.o \
dialogs_automap.o \
dialogs_char_info.o \
+ dialogs_control_panel.o \
dialogs_dismiss.o \
dialogs_error.o \
dialogs_exchange.o \
+ dialogs_fight_options.o \
dialogs_options.o \
dialogs_info.o \
dialogs_input.o \
diff --git a/engines/xeen/party.cpp b/engines/xeen/party.cpp
index 3913ad6a0d..993f156204 100644
--- a/engines/xeen/party.cpp
+++ b/engines/xeen/party.cpp
@@ -545,4 +545,11 @@ void Party::checkPartyDead() {
_dead = true;
}
+/**
+ * Move party position to the run destination on the current map
+ */
+void Party::moveToRunLocation() {
+ _mazePosition = _vm->_map->mazeData()._runPosition;
+}
+
} // End of namespace Xeen
diff --git a/engines/xeen/party.h b/engines/xeen/party.h
index 035b344c9b..5d98c55b82 100644
--- a/engines/xeen/party.h
+++ b/engines/xeen/party.h
@@ -150,6 +150,8 @@ public:
void notEnough(int consumableId, int whereId, bool mode, ErrorWaitType wait);
void checkPartyDead();
+
+ void moveToRunLocation();
};
} // End of namespace Xeen
diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp
index 7dca04fd03..c57b6a72cc 100644
--- a/engines/xeen/resources.cpp
+++ b/engines/xeen/resources.cpp
@@ -1496,4 +1496,6 @@ const int NEW_CHARACTER_SPELLS[10][4] = {
{ 20, 1, -1, -1 }
};
+const char *const COMBAT_DETAILS = "\r\f00\x03c\v000\t000\x02Combat%s%s%s\x1";
+
} // End of namespace Xeen
diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h
index 53c548fbf5..d6902129e8 100644
--- a/engines/xeen/resources.h
+++ b/engines/xeen/resources.h
@@ -522,6 +522,8 @@ extern const int RACE_ENERGY_RESISTENCES[5];
extern const int RACE_POISON_RESISTENCES[5];
extern const int NEW_CHARACTER_SPELLS[10][4];
+extern const char *const COMBAT_DETAILS;
+
} // End of namespace Xeen
#endif /* XEEN_RESOURCES_H */
diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp
index 086c0d436a..37222a3d76 100644
--- a/engines/xeen/scripts.cpp
+++ b/engines/xeen/scripts.cpp
@@ -378,7 +378,7 @@ void Scripts::cmdTeleport(Common::Array<byte> &params) {
}
if (pt.x == 999) {
- party._mazePosition = map.mazeData()._runPosition;
+ party.moveToRunLocation();
} else {
party._mazePosition = pt;
}