aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/xeen/interface.cpp2
-rw-r--r--engines/xeen/party.cpp31
-rw-r--r--engines/xeen/party.h19
-rw-r--r--engines/xeen/resources.cpp19
-rw-r--r--engines/xeen/resources.h2
-rw-r--r--engines/xeen/scripts.cpp414
-rw-r--r--engines/xeen/scripts.h6
7 files changed, 474 insertions, 19 deletions
diff --git a/engines/xeen/interface.cpp b/engines/xeen/interface.cpp
index 307027bacc..a23cee69e5 100644
--- a/engines/xeen/interface.cpp
+++ b/engines/xeen/interface.cpp
@@ -355,7 +355,7 @@ void Interface::charIconsPrint(bool updateFlag) {
PlayerStruct &ps = _vm->_party->_activeParty[charIndex];
// Draw the Hp bar
- int maxHp = ps.getMaxHp();
+ int maxHp = ps.getMaxHP();
int frame;
if (ps._currentHp < 1)
frame = 4;
diff --git a/engines/xeen/party.cpp b/engines/xeen/party.cpp
index 8d59e686fd..43c2ecabab 100644
--- a/engines/xeen/party.cpp
+++ b/engines/xeen/party.cpp
@@ -158,17 +158,22 @@ Condition PlayerStruct::worstCondition() const {
return NO_CONDITION;
}
-int PlayerStruct::getAge(int partyYear, bool ignoreTemp) {
- int year = MIN(partyYear - _ybDay, 254);
+int PlayerStruct::getAge(bool ignoreTemp) const {
+ int year = MIN(Party::_vm->_party->_year - _ybDay, 254);
return ignoreTemp ? year : year + _tempAge;
}
-int PlayerStruct::getMaxHp() {
+int PlayerStruct::getMaxHP() const {
warning("TODO: getMaxHp");
return 20;
}
+int PlayerStruct::getMaxSP() const {
+ warning("TODO: getMaxSP");
+ return 20;
+}
+
int PlayerStruct::getStat(int statNum, int v2) {
// TODO
return 10;
@@ -194,7 +199,7 @@ void PlayerStruct::setAward(int awardId, bool value) {
_awards[v] = value;
}
-bool PlayerStruct::hasAward(int awardId) {
+bool PlayerStruct::hasAward(int awardId) const {
int v = awardId;
if (awardId == 73)
v = 126;
@@ -204,6 +209,15 @@ bool PlayerStruct::hasAward(int awardId) {
return _awards[v];
}
+int PlayerStruct::getArmorClass(bool baseOnly) const {
+ // TODO
+ return 1;
+}
+
+int PlayerStruct::getThievery() const {
+ // TODO
+ return 1;
+}
/*------------------------------------------------------------------------*/
@@ -217,7 +231,10 @@ void Roster::synchronize(Common::Serializer &s) {
/*------------------------------------------------------------------------*/
-Party::Party(XeenEngine *vm): _vm(vm) {
+XeenEngine *Party::_vm;
+
+Party::Party(XeenEngine *vm) {
+ _vm = vm;
_partyCount = 0;
_realPartyCount = 0;
Common::fill(&_partyMembers[0], &_partyMembers[8], 0);
@@ -258,7 +275,7 @@ Party::Party(XeenEngine *vm): _vm(vm) {
_rested = false;
Common::fill(&_gameFlags[0], &_gameFlags[512], false);
- Common::fill(&_autoNotes[0], &_autoNotes[128], false);
+ Common::fill(&_worldFlags[0], &_worldFlags[128], false);
Common::fill(&_quests[0], &_quests[64], false);
Common::fill(&_questItems[0], &_questItems[85], 0);
@@ -337,7 +354,7 @@ void Party::synchronize(Common::Serializer &s) {
s.syncAsUint32LE(_totalTime);
s.syncAsByte(_rested);
SavesManager::syncBitFlags(s, &_gameFlags[0], &_gameFlags[512]);
- SavesManager::syncBitFlags(s, &_autoNotes[0], &_autoNotes[128]);
+ SavesManager::syncBitFlags(s, &_worldFlags[0], &_worldFlags[128]);
SavesManager::syncBitFlags(s, &_quests[0], &_quests[64]);
for (int i = 0; i < 85; ++i)
diff --git a/engines/xeen/party.h b/engines/xeen/party.h
index 3962ba45c0..2677813228 100644
--- a/engines/xeen/party.h
+++ b/engines/xeen/party.h
@@ -132,9 +132,11 @@ public:
Condition worstCondition() const;
- int getAge(int partyYear, bool ignoreTemp);
+ int getAge(bool ignoreTemp) const;
- int getMaxHp();
+ int getMaxHP() const;
+
+ int getMaxSP() const;
int getStat(int statNum, int v2);
@@ -142,9 +144,13 @@ public:
bool noActions();
- bool hasAward(int awardId);
-
void setAward(int awardId, bool value);
+
+ bool hasAward(int awardId) const;
+
+ int getArmorClass(bool baseOnly) const;
+
+ int getThievery() const;
};
class Roster: public Common::Array<PlayerStruct> {
@@ -155,8 +161,9 @@ public:
};
class Party {
+ friend class PlayerStruct;
private:
- XeenEngine *_vm;
+ static XeenEngine *_vm;
public:
// Dynamic data that's saved
int _partyCount;
@@ -204,7 +211,7 @@ public:
int _totalTime;
bool _rested;
bool _gameFlags[512];
- bool _autoNotes[128];
+ bool _worldFlags[128];
bool _quests[64];
int _questItems[85];
XeenItem _blacksmithWeapons2[ITEMS_COUNT];
diff --git a/engines/xeen/resources.cpp b/engines/xeen/resources.cpp
index c167bdbb48..837ff15d36 100644
--- a/engines/xeen/resources.cpp
+++ b/engines/xeen/resources.cpp
@@ -471,4 +471,23 @@ const int MONSTER_EFFECT_FLAGS[15][8] = {
{ 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108, 0x108 }
};
+const int SPELLS_ALLOWED[3][40] = {
+ {
+ 0, 1, 2, 3, 5, 6, 7, 8, 9, 10,
+ 12, 14, 16, 23, 26, 27, 28, 30, 31, 32,
+ 33, 42, 46, 48, 49, 50, 52, 55, 56, 58,
+ 59, 62, 64, 65, 67, 68, 71, 73, 74, 76
+ }, {
+ 1, 4, 11, 13, 15, 17, 18, 19, 20, 21,
+ 22, 24, 25, 29, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 47, 51, 53, 54,
+ 57, 60, 61, 63, 66, 69, 70, 72, 75, 76
+ }, {
+ 0, 1, 2, 3, 4, 5, 7, 9, 10, 20,
+ 25, 26, 27, 28, 30, 31, 34, 38, 40, 41,
+ 42, 43, 44, 45, 49, 50, 52, 53, 55, 59,
+ 60, 61, 62, 67, 68, 72, 73, 74, 75, 76
+ }
+};
+
} // End of namespace Xeen
diff --git a/engines/xeen/resources.h b/engines/xeen/resources.h
index e62454eafd..36ac6b2a21 100644
--- a/engines/xeen/resources.h
+++ b/engines/xeen/resources.h
@@ -110,6 +110,8 @@ extern const int COMBAT_FLOAT_Y[8];
extern const int MONSTER_EFFECT_FLAGS[15][8];
+extern const int SPELLS_ALLOWED[3][40];
+
} // End of namespace Xeen
#endif /* XEEN_RESOURCES_H */
diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp
index 6a08286148..d59346ef7e 100644
--- a/engines/xeen/scripts.cpp
+++ b/engines/xeen/scripts.cpp
@@ -23,6 +23,7 @@
#include "xeen/scripts.h"
#include "xeen/dialogs_string_input.h"
#include "xeen/dialogs_whowill.h"
+#include "xeen/dialogs_yesno.h"
#include "xeen/party.h"
#include "xeen/resources.h"
#include "xeen/xeen.h"
@@ -171,7 +172,7 @@ void Scripts::doOpcode(MazeEvent &event) {
&Scripts::cmdRemove, &Scripts::cmdSetChar, &Scripts::cmdSpawn,
&Scripts::cmdDoTownEvent, &Scripts::cmdExit, &Scripts::cmdAlterMap,
&Scripts::cmdGiveExtended, &Scripts::cmdConfirmWord, &Scripts::cmdDamage,
- &Scripts::cmdJumpRnd, &Scripts::cmdAfterEvent, &Scripts::cmdCallEvent,
+ &Scripts::cmdJumpRnd, &Scripts::cmdAlterEvent, &Scripts::cmdCallEvent,
&Scripts::cmdReturn, &Scripts::cmdSetVar, &Scripts::cmdTakeOrGive,
&Scripts::cmdTakeOrGive, &Scripts::cmdCutsceneEndClouds,
&Scripts::cmdTeleport, &Scripts::cmdWhoWill,
@@ -378,21 +379,47 @@ void Scripts::cmdAlterMap(Common::Array<byte> &params) {
}
void Scripts::cmdGiveExtended(Common::Array<byte> &params) {
+ Party &party = *_vm->_party;
+ uint32 mask;
+ int newLineNum;
+ bool result;
+
switch (params[0]) {
case 16:
case 34:
case 100:
- // TODO
+ mask = (params[4] << 24) | params[3] | (params[2] << 8) | (params[1] << 16);
+ newLineNum = params[5];
break;
case 25:
case 35:
case 101:
case 106:
- // TODO
+ mask = (params[2] << 8) | params[1];
+ newLineNum = params[3];
break;
default:
+ mask = params[1];
+ newLineNum = params[2];
break;
}
+
+ if ((_charIndex != 0 & _charIndex != 8) || params[0] == 44) {
+ result = ifProc(params[0], mask, _event->_opcode - OP_If1, _charIndex - 1);
+ } else {
+ result = false;
+ for (int idx = 0; idx < party._partyCount && !result; ++idx) {
+ if (_charIndex == 0 || (_charIndex == 8 && _v2 != idx)) {
+ result = ifProc(params[0], mask, _event->_opcode - OP_If1, idx);
+ }
+ }
+ }
+
+ if (result)
+ _lineNum = newLineNum - 1;
+
+ _var4F = true;
+ cmdNoAction(params);
}
void Scripts::cmdConfirmWord(Common::Array<byte> &params) {
@@ -634,5 +661,386 @@ void Scripts::doEnding(const Common::String &endStr, int v2) {
warning("TODO: doEnding");
}
+/**
+ * This monstrosity handles doing the various types of If checks on various data
+ */
+bool Scripts::ifProc(int action, uint32 mask, int mode, int charIndex) {
+ Party &party = *_vm->_party;
+ PlayerStruct &ps = party._activeParty[charIndex];
+ uint v = 0;
+
+ switch (action) {
+ case 3:
+ // Player sex
+ v = (uint)ps._sex;
+ break;
+ case 4:
+ // Player race
+ v = (uint)ps._race;
+ break;
+ case 5:
+ // Player class
+ v = (uint)ps._class;
+ break;
+ case 8:
+ // Current health points
+ v = (uint)ps._currentHp;
+ break;
+ case 9:
+ // Current spell points
+ v = (uint)ps._currentSp;
+ break;
+ case 10:
+ // Get armor class
+ v = (uint)ps.getArmorClass(false);
+ break;
+ case 11:
+ // Level bonus (extra beyond base)
+ v = ps._level._temporary;
+ break;
+ case 12:
+ // Current age, including unnatural aging
+ v = ps.getAge(false);
+ break;
+ case 13:
+ assert(mask < 18);
+ if (ps._skills[mask])
+ v = mask;
+ break;
+ case 15:
+ // Award
+ assert(mask < 128);
+ if (ps.hasAward(mask))
+ v = mask;
+ break;
+ case 16:
+ // Experience
+ v = ps._experience;
+ break;
+ case 17:
+ // Party poison resistence
+ v = party._poisonResistence;
+ break;
+ case 18:
+ // Condition
+ assert(mask < 16);
+ if (!ps._conditions[mask] && !(mask & 0x10))
+ v = mask;
+ break;
+ case 19: {
+ // Can player cast a given spell
+
+ // Get the type of character
+ int category;
+ switch (ps._class) {
+ case CLASS_KNIGHT:
+ case CLASS_ARCHER:
+ category = 0;
+ break;
+ case CLASS_PALADIN:
+ case CLASS_CLERIC:
+ category = 1;
+ break;
+ case CLASS_BARBARIAN:
+ case CLASS_DRUID:
+ category = 2;
+ break;
+ default:
+ category = 0;
+ break;
+ }
+
+ // Check if the character class can cast the particular spell
+ for (int idx = 0; idx < 39; ++idx) {
+ if (SPELLS_ALLOWED[mode][idx] == mask) {
+ // Can cast it. Check if the player has it in their spellbook
+ if (ps._spells[idx])
+ v = mask;
+ break;
+ }
+ }
+ break;
+ }
+ case 20:
+ if (_vm->_files->_isDarkCc)
+ mask += 0x100;
+ assert(mask < 0x200);
+ if (party._gameFlags[mask])
+ v = mask;
+ break;
+ case 21:
+ // Scans inventories for given item number
+ v = 0xFFFFFFFF;
+ if (mask < 82) {
+ for (int idx = 0; idx < 9; ++idx) {
+ if (mask == 35) {
+ if (ps._weapons[idx]._name == mask) {
+ v = mask;
+ break;
+ }
+ } else if (mask < 49) {
+ if (ps._armor[idx]._name == (mask - 35)) {
+ v = mask;
+ break;
+ }
+ } else if (mask < 60) {
+ if (ps._accessories[idx]._name == (mask - 49)) {
+ v = mask;
+ break;
+ }
+ } else {
+ if (ps._misc[idx]._name == (mask - 60)) {
+ v = mask;
+ break;
+ }
+ }
+ }
+ } else {
+ int baseFlag = 8 * (6 + mask);
+ for (int idx = 0; idx < 8; ++idx) {
+ if (party._gameFlags[baseFlag + idx]) {
+ v = mask;
+ break;
+ }
+ }
+ }
+ break;
+ case 25:
+ // Returns number of minutes elapsed in the day (0-1440)
+ v = party._minutes;
+ break;
+ case 34:
+ // Current party gold
+ v = party._gold;
+ break;
+ case 35:
+ // Current party gems
+ v = party._gems;
+ break;
+ case 37:
+ // Might bonus (extra beond base)
+ v = ps._might._temporary;
+ break;
+ case 38:
+ // Intellect bonus (extra beyond base)
+ v = ps._intellect._temporary;
+ break;
+ case 39:
+ // Personality bonus (extra beyond base)
+ v = ps._personality._temporary;
+ break;
+ case 40:
+ // Endurance bonus (extra beyond base)
+ v = ps._endurance._temporary;
+ break;
+ case 41:
+ // Speed bonus (extra beyond base)
+ v = ps._speed._temporary;
+ break;
+ case 42:
+ // Accuracy bonus (extra beyond base)
+ v = ps._accuracy._temporary;
+ break;
+ case 43:
+ // Luck bonus (extra beyond base)
+ v = ps._luck._temporary;
+ break;
+ case 44:
+ v = YesNo::show(_vm, mask, 0);
+ if (!mask && v)
+ v = 0;
+ break;
+ case 45:
+ // Might base (before bonus)
+ v = ps._might._permanent;
+ break;
+ case 46:
+ // Intellect base (before bonus)
+ v = ps._intellect._permanent;
+ break;
+ case 47:
+ // Personality base (before bonus)
+ v = ps._personality._permanent;
+ break;
+ case 48:
+ // Endurance base (before bonus)
+ v = ps._endurance._permanent;
+ break;
+ case 49:
+ // Speed base (before bonus)
+ v = ps._speed._permanent;
+ break;
+ case 50:
+ // Accuracy base (before bonus)
+ v = ps._accuracy._permanent;
+ break;
+ case 51:
+ // Luck base (before bonus)
+ v = ps._luck._permanent;
+ break;
+ case 52:
+ // Fire resistence (before bonus)
+ v = ps._fireResistence._permanent;
+ break;
+ case 53:
+ // Elecricity resistence (before bonus)
+ v = ps._electricityResistence._permanent;
+ break;
+ case 54:
+ // Cold resistence (before bonus)
+ v = ps._coldResistence._permanent;
+ break;
+ case 55:
+ // Poison resistence (before bonus)
+ v = ps._poisonResistence._permanent;
+ break;
+ case 56:
+ // Energy reistence (before bonus)
+ v = ps._energyResistence._permanent;
+ break;
+ case 57:
+ // Energy resistence (before bonus)
+ v = ps._magicResistence._permanent;
+ break;
+ case 58:
+ // Fire resistence (extra beyond base)
+ v = ps._fireResistence._temporary;
+ break;
+ case 59:
+ // Electricity resistence (extra beyond base)
+ v = ps._electricityResistence._temporary;
+ break;
+ case 60:
+ // Cold resistence (extra beyond base)
+ v = ps._coldResistence._temporary;
+ break;
+ case 61:
+ // Poison resistence (extra beyod base)
+ v = ps._poisonResistence._temporary;
+ break;
+ case 62:
+ // Energy resistence (extra beyond base)
+ v = ps._energyResistence._temporary;
+ break;
+ case 63:
+ // Magic resistence (extra beyond base)
+ v = ps._magicResistence._temporary;
+ break;
+ case 64:
+ // Level (before bonus)
+ v = ps._level._permanent;
+ break;
+ case 65:
+ // Total party food
+ v = party._food;
+ break;
+ case 69:
+ // Test for Levitate being active
+ v = party._levitateActive ? 1 : 0;
+ break;
+ case 70:
+ // Amount of light
+ v = party._lightCount;
+ break;
+ case 71:
+ // Party magical fire resistence
+ v = party._fireResistence;
+ break;
+ case 72:
+ // Party magical electricity resistence
+ v = party._electricityResistence;
+ break;
+ case 73:
+ // Party magical cold resistence
+ v = party._coldResistence;
+ break;
+ case 76:
+ // Day of the year (100 per year)
+ v = party._day;
+ break;
+ case 77:
+ // Armor class (extra beyond base)
+ v = ps._ACTemp;
+ break;
+ case 78:
+ // Test whether current Hp is equal to or exceeds the max HP
+ v = ps._currentHp >= ps.getMaxHP() ? 1 : 0;
+ break;
+ case 79:
+ // Test for Wizard Eye being active
+ v = party._wizardEyeActive ? 1 : 0;
+ break;
+ case 81:
+ // Test whether current Sp is equal to or exceeds the max SP
+ v = ps._currentSp >= ps.getMaxSP() ? 1 : 0;
+ break;
+ case 84:
+ // Current facing direction
+ v = (uint)party._mazeDirection;
+ break;
+ case 85:
+ // Current game year since start
+ v = party._year;
+ break;
+ case 86:
+ case 87:
+ case 88:
+ case 89:
+ case 90:
+ case 91:
+ case 92:
+ // Get a player stat
+ v = ps.getStat(action - 86, 0);
+ break;
+ case 93:
+ // Current day of the week (10 days per week)
+ v = party._day / 10;
+ break;
+ case 94:
+ // Test whether Walk on Water is currently active
+ v = party._walkOnWaterActive ? 1 : 0;
+ break;
+ case 99:
+ // Party skills check
+ if (party.checkSkill((Skill)mask))
+ v = mask;
+ break;
+ case 102:
+ // Thievery skill
+ v = ps.getThievery();
+ break;
+ case 103:
+ // Get value of world flag
+ if (party._worldFlags[mask])
+ v = mask;
+ break;
+ case 104:
+ // Get value of quest flag
+ if (party._quests[mask + (_vm->_files->_isDarkCc ? 30 : 0)])
+ v = mask;
+ break;
+ case 105:
+ // Test number of Megacredits in party. Only used by King's Engineer in Castle Burlock
+ v = party._questItems[26];
+ break;
+ case 107:
+ // Get value of character flag
+ error("Unused");
+ break;
+ default:
+ break;
+ }
+
+ switch (mode) {
+ case 0:
+ return mask >= v;
+ case 1:
+ return mask == v;
+ case 2:
+ return mask <= v;
+ default:
+ return false;
+ }
+}
} // End of namespace Xeen
diff --git a/engines/xeen/scripts.h b/engines/xeen/scripts.h
index 862c54d229..fb415cac8d 100644
--- a/engines/xeen/scripts.h
+++ b/engines/xeen/scripts.h
@@ -41,8 +41,8 @@ enum Opcode {
OP_NPC = 0x05,
OP_PlayFX = 0x06,
OP_TeleportAndExit = 0x07,
- OP_If_1 = 0x08,
- OP_If_2 = 0x09,
+ OP_If1 = 0x08,
+ OP_If2 = 0x09,
OP_If3 = 0x0A,
OP_MoveObj = 0x0B,
OP_TakeOrGive = 0x0C,
@@ -207,6 +207,8 @@ private:
void doWorldEnd();
void doEnding(const Common::String &endStr, int v2);
+
+ bool ifProc(int action, uint32 mask, int mode, int charIndex);
public:
int _animCounter;
bool _eventSkipped;