aboutsummaryrefslogtreecommitdiff
path: root/engines/xeen/scripts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/xeen/scripts.cpp')
-rw-r--r--engines/xeen/scripts.cpp548
1 files changed, 295 insertions, 253 deletions
diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp
index 8777cdc6e0..bc0b179d4c 100644
--- a/engines/xeen/scripts.cpp
+++ b/engines/xeen/scripts.cpp
@@ -21,7 +21,10 @@
*/
#include "common/config-manager.h"
+#include "common/textconsole.h"
+#include "backends/audiocd/audiocd.h"
#include "xeen/scripts.h"
+#include "xeen/dialogs/dialogs_copy_protection.h"
#include "xeen/dialogs/dialogs_input.h"
#include "xeen/dialogs/dialogs_whowill.h"
#include "xeen/dialogs/dialogs_query.h"
@@ -138,7 +141,7 @@ int Scripts::checkEvents() {
Party &party = *_vm->_party;
Sound &sound = *_vm->_sound;
Windows &windows = *_vm->_windows;
- bool isDarkCc = files._isDarkCc;
+ int ccNum = files._ccNum;
_refreshIcons = false;
_itemType = 0;
@@ -182,10 +185,10 @@ int Scripts::checkEvents() {
for (eventIndex = 0; eventIndex < map._events.size() && !_vm->shouldExit(); ++eventIndex) {
MazeEvent &event = map._events[eventIndex];
- if (event._position == _currentPos && party._mazeDirection !=
- (_currentPos.x | _currentPos.y) && event._line == _lineNum) {
+ if (event._position == _currentPos && event._line == _lineNum &&
+ (party._mazeDirection | _currentPos.x | _currentPos.y)) {
if (event._direction == party._mazeDirection || event._direction == DIR_ALL) {
- _vm->_mode = MODE_RECORD_EVENTS;
+ _vm->_mode = MODE_SCRIPT_IN_PROGRESS;
_scriptExecuted = true;
doOpcode(event);
break;
@@ -209,24 +212,27 @@ int Scripts::checkEvents() {
if (party._treasure._hasItems || party._treasure._gold || party._treasure._gems)
party.giveTreasure();
- if (_animCounter > 0 && intf._objNumber) {
- MazeObject &selectedObj = map._mobData._objects[intf._objNumber - 1];
+ if (_animCounter > 0 && intf._objNumber != -1) {
+ MazeObject &selectedObj = map._mobData._objects[intf._objNumber];
- if (selectedObj._spriteId == (isDarkCc ? 15 : 16)) {
- for (uint idx = 0; idx < 16; ++idx) {
- MazeObject &obj = map._mobData._objects[idx];
- if (obj._spriteId == (isDarkCc ? 62 : 57)) {
+ if (selectedObj._spriteId == (ccNum ? 15 : 16)) {
+ // Treasure chests that were opened will be set to be in an open, empty state
+ for (uint idx = 0; idx < map._mobData._objectSprites.size(); ++idx) {
+ MonsterObjectData::SpriteResourceEntry &e = map._mobData._objectSprites[idx];
+ if (e._spriteId == (ccNum ? 57 : 62)) {
selectedObj._id = idx;
- selectedObj._spriteId = isDarkCc ? 62 : 57;
+ selectedObj._spriteId = ccNum ? 57 : 62;
+ selectedObj._sprites = &e._sprites;
break;
}
}
} else if (selectedObj._spriteId == 73) {
- for (uint idx = 0; idx < 16; ++idx) {
- MazeObject &obj = map._mobData._objects[idx];
- if (obj._spriteId == 119) {
+ for (uint idx = 0; idx < map._mobData._objectSprites.size(); ++idx) {
+ MonsterObjectData::SpriteResourceEntry &e = map._mobData._objectSprites[idx];
+ if (e._spriteId == 119) {
selectedObj._id = idx;
selectedObj._spriteId = 119;
+ selectedObj._sprites = &e._sprites;
break;
}
}
@@ -237,8 +243,17 @@ int Scripts::checkEvents() {
_vm->_mode = oldMode;
windows.closeAll();
- if (_scriptExecuted || !intf._objNumber || _dirFlag) {
- if (_dirFlag && !_scriptExecuted && intf._objNumber && !map._currentIsEvent) {
+ if (g_vm->getIsCD() && g_system->getAudioCDManager()->isPlaying())
+ // Stop any playing voice
+ g_system->getAudioCDManager()->stop();
+
+ if (g_vm->shouldExit())
+ return g_vm->_gameMode;
+
+ if (_scriptExecuted)
+ intf.clearEvents();
+ if (_scriptExecuted || intf._objNumber == -1 || _dirFlag) {
+ if (_dirFlag && !_scriptExecuted && intf._objNumber != -1 && !map._currentIsEvent) {
sound.playFX(21);
}
} else {
@@ -269,69 +284,71 @@ int Scripts::checkEvents() {
return _scriptResult;
}
-void Scripts::openGrate(int wallVal, int action) {
+bool Scripts::openGrate(int wallVal, int action) {
Combat &combat = *_vm->_combat;
FileManager &files = *_vm->_files;
Interface &intf = *_vm->_interface;
Map &map = *_vm->_map;
Party &party = *_vm->_party;
Sound &sound = *_vm->_sound;
- bool isDarkCc = files._isDarkCc;
-
- if ((wallVal != 13 || map._currentGrateUnlocked) && (!isDarkCc || wallVal != 9 ||
- map.mazeData()._wallKind != 2)) {
- if (wallVal != 9 && !map._currentGrateUnlocked) {
- int charIndex = WhoWill::show(_vm, 13, action, false) - 1;
- if (charIndex < 0) {
- intf.draw3d(true);
- return;
- }
+ int ccNum = files._ccNum;
- // There is a 1 in 4 chance the character will receive damage
- if (_vm->getRandomNumber(1, 4) == 1) {
- combat.giveCharDamage(map.mazeData()._trapDamage,
- (DamageType)_vm->getRandomNumber(0, 6), charIndex);
- }
+ if (!((wallVal != 13 || map._currentGrateUnlocked) && (!ccNum || wallVal != 9 ||
+ map.mazeData()._wallKind != 2)))
+ return false;
- // Check whether character can unlock the door
- Character &c = party._activeParty[charIndex];
- if ((c.getThievery() + _vm->getRandomNumber(1, 20)) <
- map.mazeData()._difficulties._unlockDoor)
- return;
+ if (wallVal != 9 && !map._currentGrateUnlocked) {
+ int charIndex = WhoWill::show(_vm, 13, action, false) - 1;
+ if (charIndex < 0) {
+ intf.draw3d(true);
+ return true;
+ }
- c._experience += map.mazeData()._difficulties._unlockDoor * c.getCurrentLevel();
+ // There is a 1 in 4 chance the character will receive damage
+ if (_vm->getRandomNumber(1, 4) == 1) {
+ combat.giveCharDamage(map.mazeData()._trapDamage,
+ (DamageType)_vm->getRandomNumber(0, 6), charIndex);
}
- // Flag the grate as unlocked, and the wall the grate is on
- map.setCellSurfaceFlags(party._mazePosition, 0x80);
- map.setWall(party._mazePosition, party._mazeDirection, wallVal);
+ // Check whether character can unlock the door
+ Character &c = party._activeParty[charIndex];
+ if ((c.getThievery() + _vm->getRandomNumber(1, 20)) <
+ map.mazeData()._difficulties._unlockDoor)
+ return true;
- // Set the grate as opened and the wall on the other side of the grate
- Common::Point pt = party._mazePosition;
- Direction dir = (Direction)((int)party._mazeDirection ^ 2);
- switch (party._mazeDirection) {
- case DIR_NORTH:
- pt.y++;
- break;
- case DIR_EAST:
- pt.x++;
- break;
- case DIR_SOUTH:
- pt.y--;
- break;
- case DIR_WEST:
- pt.x--;
- break;
- default:
- break;
- }
+ c._experience += map.mazeData()._difficulties._unlockDoor * c.getCurrentLevel();
+ }
- map.setCellSurfaceFlags(pt, 0x80);
- map.setWall(pt, dir, wallVal);
+ // Flag the grate as unlocked, and the wall the grate is on
+ map.setCellSurfaceFlags(party._mazePosition, 0x80);
+ map.setWall(party._mazePosition, party._mazeDirection, wallVal);
- sound.playFX(10);
- intf.draw3d(true);
+ // Set the grate as opened and the wall on the other side of the grate
+ Common::Point pt = party._mazePosition;
+ Direction dir = (Direction)((int)party._mazeDirection ^ 2);
+ switch (party._mazeDirection) {
+ case DIR_NORTH:
+ pt.y++;
+ break;
+ case DIR_EAST:
+ pt.x++;
+ break;
+ case DIR_SOUTH:
+ pt.y--;
+ break;
+ case DIR_WEST:
+ pt.x--;
+ break;
+ default:
+ break;
}
+
+ map.setCellSurfaceFlags(pt, 0x80);
+ map.setWall(pt, dir, wallVal);
+
+ sound.playFX(10);
+ intf.draw3d(true);
+ return true;
}
bool Scripts::doOpcode(MazeEvent &event) {
@@ -373,7 +390,7 @@ bool Scripts::doOpcode(MazeEvent &event) {
bool result = (this->*COMMAND_LIST[event._opcode])(params);
if (result)
// Move to next line
- _lineNum = _vm->_party->_partyDead ? -1 : _lineNum + 1;
+ _lineNum = _vm->_party->_dead ? SCRIPT_ABORT : _lineNum + 1;
return result;
}
@@ -465,7 +482,7 @@ bool Scripts::cmdTeleport(ParamsIterator &params) {
Sound &sound = *_vm->_sound;
windows.closeAll();
-
+
bool restartFlag = _event->_opcode == OP_TeleportAndContinue;
int mapId = params.readByte();
Common::Point pt;
@@ -491,8 +508,7 @@ bool Scripts::cmdTeleport(ParamsIterator &params) {
party._stepped = true;
if (mapId != party._mazeId) {
- int spriteId = (intf._objNumber == 0) ? -1 :
- map._mobData._objects[intf._objNumber - 1]._spriteId;
+ int spriteId = (intf._objNumber == -1) ? -1 : map._mobData._objects[intf._objNumber]._spriteId;
switch (spriteId) {
case 47:
@@ -519,7 +535,7 @@ bool Scripts::cmdTeleport(ParamsIterator &params) {
if (restartFlag) {
// Draw the new location and start any script at that location
- intf.draw3d(true);
+ events.ipause(2);
_lineNum = SCRIPT_RESET;
return false;
} else {
@@ -592,7 +608,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
Combat &combat = *_vm->_combat;
Party &party = *_vm->_party;
Windows &windows = *_vm->_windows;
- int mode1, mode2, mode3, param2;
+ int mode1, mode2, mode3;
uint32 val1, val2, val3;
_refreshIcons = true;
@@ -614,7 +630,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
break;
}
- param2 = mode2 = params.readByte();
+ mode2 = params.readByte();
switch (mode2) {
case 16:
case 34:
@@ -707,7 +723,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
if (_charIndex == 0 || _charIndex == 8) {
for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
if (_charIndex == 0 || (_charIndex == 8 && (int)idx != combat._combatTarget)) {
- party.giveTake(mode1, val1, mode2, val2, idx);
+ bool flag = party.giveTake(mode1, val1, mode2, val2, idx);
switch (mode1) {
case 8:
@@ -715,7 +731,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
// fall through
case 21:
case 66:
- if (param2) {
+ if (flag) {
switch (mode2) {
case 82:
mode1 = 0;
@@ -728,13 +744,18 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
case 100:
case 101:
case 106:
- if (param2)
+ if (flag)
continue;
// Break out of character loop
idx = party._activeParty.size();
break;
+ default:
+ break;
}
+ } else {
+ // Break out of character loop
+ idx = party._activeParty.size();
}
break;
@@ -744,7 +765,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
case 100:
case 101:
case 106:
- if (param2) {
+ if (flag) {
_lineNum = -1;
return false;
}
@@ -766,7 +787,7 @@ bool Scripts::cmdTakeOrGive(ParamsIterator &params) {
case 100:
case 101:
case 106:
- if (param2)
+ if (flag)
continue;
// Break out of character loop
@@ -793,9 +814,9 @@ bool Scripts::cmdRemove(ParamsIterator &params) {
Interface &intf = *_vm->_interface;
Map &map = *_vm->_map;
- if (intf._objNumber) {
+ if (intf._objNumber != -1) {
// Give the active object a completely way out of bounds position
- MazeObject &obj = map._mobData._objects[intf._objNumber - 1];
+ MazeObject &obj = map._mobData._objects[intf._objNumber];
obj._position = Common::Point(128, 128);
}
@@ -845,7 +866,7 @@ bool Scripts::cmdSpawn(ParamsIterator &params) {
}
bool Scripts::cmdDoTownEvent(ParamsIterator &params) {
- _scriptResult = _vm->_locations->doAction((LocationAction)params.readByte());
+ _scriptResult = _vm->_locations->doAction(params.readByte());
_vm->_party->_stepped = true;
_refreshIcons = true;
@@ -930,40 +951,46 @@ bool Scripts::cmdConfirmWord(ParamsIterator &params) {
int param2 = params.readByte();
int param3 = params.readByte();
- Common::String msg1 = param2 ? map._events._text[param2] : _message;
- Common::String msg2;
+ Common::String expected2;
+ Common::String title;
if (_event->_opcode == OP_ConfirmWord_2) {
- msg2 = "";
+ title = "";
} else if (param3) {
- msg2 = map._events._text[param3];
+ title = map._events._text[param3];
} else {
- msg2 = Res.WHATS_THE_PASSWORD;
+ title = Res.WHATS_THE_PASSWORD;
}
- _mirrorId = StringInput::show(_vm, inputType, msg1, msg2, _event->_opcode);
+ if (!param2) {
+ expected2 = _message;
+ } else if (param2 < (int)map._events._text.size()) {
+ expected2 = map._events._text[param2];
+ }
+
+ _mirrorId = StringInput::show(_vm, inputType, expected2, title, _event->_opcode);
if (_mirrorId) {
- if (_mirrorId == 33 && files._isDarkCc) {
+ if (_mirrorId == 33 && files._ccNum) {
doDarkSideEnding();
- } else if (_mirrorId == 34 && files._isDarkCc) {
+ } else if (_mirrorId == 34 && files._ccNum) {
doWorldEnding();
- } else if (_mirrorId == 35 && files._isDarkCc &&
+ } else if (_mirrorId == 35 && files._ccNum &&
_vm->getGameID() == GType_WorldOfXeen) {
doCloudsEnding();
- } else if (_mirrorId == 40 && !files._isDarkCc) {
+ } else if (_mirrorId == 40 && !files._ccNum) {
doCloudsEnding();
- } else if (_mirrorId == 60 && !files._isDarkCc) {
+ } else if (_mirrorId == 60 && !files._ccNum) {
doDarkSideEnding();
- } else if (_mirrorId == 61 && !files._isDarkCc) {
+ } else if (_mirrorId == 61 && !files._ccNum) {
doWorldEnding();
} else {
- if (_mirrorId == 59 && !files._isDarkCc) {
+ if (_mirrorId == 59 && !files._ccNum) {
for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
XeenItem &item = party._treasure._weapons[idx];
if (!item._id) {
- item._id = 34;
+ item._id = XEEN_SLAYER_SWORD;
item._material = 0;
- item._bonusFlags = 0;
+ item._state.clear();
party._treasure._hasItems = true;
return cmdExit(params);
@@ -990,7 +1017,7 @@ bool Scripts::cmdDamage(ParamsIterator &params) {
int damage = params.readUint16LE();
DamageType damageType = (DamageType)params.readByte();
- combat.giveCharDamage(damage, damageType, _charIndex);
+ combat.giveCharDamage(damage, damageType, _charIndex - 1);
return true;
}
@@ -1033,11 +1060,16 @@ bool Scripts::cmdCallEvent(ParamsIterator &params) {
}
bool Scripts::cmdReturn(ParamsIterator &params) {
- StackEntry &se = _stack.top();
- _currentPos = se;
- _lineNum = se.line;
+ if (_stack.empty()) {
+ // WORKAROUND: Some scripts in Swords of Xeen use cmdReturn as a substitute for cmdExit
+ return cmdExit(params);
+ } else {
+ StackEntry se = _stack.pop();
+ _currentPos = se;
+ _lineNum = se.line;
- return true;
+ return true;
+ }
}
bool Scripts::cmdSetVar(ParamsIterator &params) {
@@ -1114,17 +1146,17 @@ bool Scripts::cmdRndDamage(ParamsIterator &params) {
DamageType dmgType = (DamageType)params.readByte();
int max = params.readByte();
- combat.giveCharDamage(_vm->getRandomNumber(1, max), dmgType, _charIndex);
+ combat.giveCharDamage(_vm->getRandomNumber(1, max), dmgType, _charIndex - 1);
return true;
}
bool Scripts::cmdMoveWallObj(ParamsIterator &params) {
Map &map = *_vm->_map;
- int itemNum = params.readByte();
+ int index = params.readByte();
int x = params.readShort();
int y = params.readShort();
- map._mobData._wallItems[itemNum]._position = Common::Point(x, y);
+ map._mobData._wallItems[index]._position = Common::Point(x, y);
return true;
}
@@ -1203,14 +1235,25 @@ bool Scripts::cmdDisplayBottom(ParamsIterator &params) {
bool Scripts::cmdIfMapFlag(ParamsIterator &params) {
Map &map = *_vm->_map;
- MazeMonster &monster = map._mobData._monsters[params.readByte()];
+ int monsterNum = params.readByte();
+ int lineNum = params.readByte();
- if (monster._position.x >= 32 || monster._position.y >= 32) {
- _lineNum = params.readByte();
- return false;
+ if (monsterNum == 0xff) {
+ for (monsterNum = 0; monsterNum < (int)map._mobData._monsters.size(); ++monsterNum) {
+ MazeMonster &monster = map._mobData._monsters[monsterNum];
+
+ if ((uint)monster._position.x < 32 && (uint)monster._position.y < 32)
+ return true;
+ }
+ } else {
+ MazeMonster &monster = map._mobData._monsters[monsterNum];
+
+ if ((uint)monster._position.x < 32 && (uint)monster._position.y < 32)
+ return true;
}
- return true;
+ _lineNum = lineNum;
+ return false;
}
bool Scripts::cmdSelectRandomChar(ParamsIterator &params) {
@@ -1220,64 +1263,47 @@ bool Scripts::cmdSelectRandomChar(ParamsIterator &params) {
bool Scripts::cmdGiveEnchanted(ParamsIterator &params) {
Party &party = *_vm->_party;
-
+ int itemOffset = _vm->getGameID() == GType_Swords ? 6 : 0;
+ XeenItem *item;
+ int invIndex;
int id = params.readByte();
- int material = params.readByte();
- int flags = params.readByte();
-
- if (id >= 35) {
- if (id < 49) {
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- XeenItem &item = party._treasure._armor[idx];
- if (!item.empty()) {
- item._id = id - 35;
- item._material = material;
- item._bonusFlags = flags;
- party._treasure._hasItems = true;
- break;
- }
- }
- return true;
- } else if (id < 60) {
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- XeenItem &item = party._treasure._accessories[idx];
- if (!item.empty()) {
- item._id = id - 49;
- item._material = material;
- item._bonusFlags = flags;
- party._treasure._hasItems = true;
- break;
- }
- }
+ // Get category of item to add
+ ItemCategory cat = CATEGORY_WEAPON;
+ if (id < (35 + itemOffset)) {
+ } else if (id < (49 + itemOffset)) {
+ cat = CATEGORY_ARMOR;
+ id -= 35 + itemOffset;
+ } else if (id < (60 + itemOffset)) {
+ cat = CATEGORY_ACCESSORY;
+ id -= 49 + itemOffset;
+ } else if (id < (82 + itemOffset)) {
+ cat = CATEGORY_MISC;
+ id -= 60 + itemOffset;
+ } else {
+ party._questItems[id - (82 + itemOffset)]++;
+ }
- return true;
- } else if (id < 82) {
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- XeenItem &item = party._treasure._misc[idx];
- if (!item.empty()) {
- item._id = id;
- item._material = material;
- item._bonusFlags = flags;
- party._treasure._hasItems = true;
- break;
- }
- }
+ // Check for an empty slot
+ for (invIndex = 0, item = party._treasure[cat]; invIndex < MAX_TREASURE_ITEMS && !item->empty(); ++invIndex, ++item)
+ ;
- return true;
- } else {
- party._questItems[id - 82]++;
- }
- }
+ if (invIndex == MAX_TREASURE_ITEMS) {
+ // Treasure category entirely full. Should never happen
+ warning("Treasure category was completely filled up");
+ } else {
+ party._treasure._hasItems = true;
- for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
- XeenItem &item = party._treasure._weapons[idx];
- if (!item.empty()) {
- item._id = id;
- item._material = material;
- item._bonusFlags = flags;
- party._treasure._hasItems = true;
- break;
+ if (cat == CATEGORY_MISC) {
+ // Handling of misc items. Note that for them, id actually specifies the material field
+ item->_material = id;
+ item->_id = params.readByte();
+ item->_state._counter = (item->_material == 10 || item->_material == 11) ? 1 : _vm->getRandomNumber(3, 10);
+ } else {
+ // Weapons, armor, and accessories
+ item->_id = id;
+ item->_material = params.readByte();
+ item->_state = params.readByte();
}
}
@@ -1391,6 +1417,8 @@ bool Scripts::cmdFallToMap(ParamsIterator &params) {
}
bool Scripts::cmdDisplayMain(ParamsIterator &params) {
+ _windowIndex = 11;
+
display(false, 0);
return true;
}
@@ -1415,7 +1443,7 @@ bool Scripts::cmdCutsceneEndDarkside(ParamsIterator &params) {
Party &party = *_vm->_party;
_vm->_saves->_wonDarkSide = true;
party._questItems[53] = 1;
- party._darkSideEnd = true;
+ party._darkSideCompleted = true;
party._mazeId = 29;
party._mazeDirection = DIR_NORTH;
party._mazePosition = Common::Point(25, 21);
@@ -1436,24 +1464,55 @@ bool Scripts::cmdCutsceneEndWorld(ParamsIterator &params) {
g_vm->saveSettings();
_vm->_saves->_wonWorld = true;
- _vm->_party->_worldEnd = true;
+ _vm->_party->_worldCompleted = true;
doWorldEnding();
return false;
}
bool Scripts::cmdFlipWorld(ParamsIterator &params) {
- _vm->_map->_loadDarkSide = params.readByte() != 0;
+ _vm->_map->_loadCcNum = params.readByte();
+ return true;
+}
+
+bool Scripts::cmdPlayCD(ParamsIterator &params) {
+ int trackNum = params.readByte();
+ int start = params.readUint16LE();
+ int finish = params.readUint16LE();
+ debugC(3, kDebugScripts, "cmdPlayCD Track=%d start=%d finish=%d", trackNum, start, finish);
+
+ if (_vm->_files->_ccNum && trackNum < 31)
+ trackNum += 30;
+ assert(trackNum <= 60);
+
+ start = convertCDTime(start);
+ finish = convertCDTime(finish);
+
+ g_system->getAudioCDManager()->play(trackNum, 1, start, finish - start, false, Audio::Mixer::kSpeechSoundType);
return true;
}
-bool Scripts::cmdPlayCD(ParamsIterator &params) { error("TODO"); }
+#define CD_FRAME_RATE 75
+uint Scripts::convertCDTime(uint srcTime) {
+ // Times are encoded as MMSSCC - MM=Minutes, SS=Seconds, CC=Centiseconds (1/100th second)
+ uint mins = srcTime / 10000;
+ uint csec = srcTime % 10000;
+ return (mins * 6000 + csec) * CD_FRAME_RATE / 100;
+}
void Scripts::doCloudsEnding() {
+ g_vm->_party->_cloudsCompleted = true;
doEnding("ENDGAME");
+
+ g_vm->_mode = MODE_INTERACTIVE;
+ g_vm->_saves->saveGame();
+
+ g_vm->_gameMode = GMODE_MENU;
+ g_vm->_mode = MODE_STARTUP;
}
void Scripts::doDarkSideEnding() {
+ g_vm->_party->_darkSideCompleted = true;
doEnding("ENDGAME2");
}
@@ -1487,56 +1546,56 @@ void Scripts::doEnding(const Common::String &endStr) {
bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
FileManager &files = *_vm->_files;
Party &party = *_vm->_party;
- Character &ps = party._activeParty[charIndex];
+ Character *ps = (charIndex == -1) ? nullptr : &party._activeParty[charIndex];
uint v = 0;
switch (action) {
case 3:
// Player sex
- v = (uint)ps._sex;
+ v = (uint)ps->_sex;
break;
case 4:
// Player race
- v = (uint)ps._race;
+ v = (uint)ps->_race;
break;
case 5:
// Player class
- v = (uint)ps._class;
+ v = (uint)ps->_class;
break;
case 8:
// Current health points
- v = (uint)ps._currentHp;
+ v = (uint)ps->_currentHp;
break;
case 9:
// Current spell points
- v = (uint)ps._currentSp;
+ v = (uint)ps->_currentSp;
break;
case 10:
// Get armor class
- v = (uint)ps.getArmorClass(false);
+ v = (uint)ps->getArmorClass(false);
break;
case 11:
// Level bonus (extra beyond base)
- v = ps._level._temporary;
+ v = ps->_level._temporary;
break;
case 12:
// Current age, including unnatural aging
- v = ps.getAge(false);
+ v = ps->getAge(false);
break;
case 13:
assert(val < 18);
- if (ps._skills[val])
+ if (ps->_skills[val])
v = val;
break;
case 15:
// Award
assert(val < AWARDS_TOTAL);
- if (ps.hasAward(val))
+ if (ps->hasAward(val))
v = val;
break;
case 16:
// Experience
- v = ps._experience;
+ v = ps->_experience;
break;
case 17:
// Party poison resistence
@@ -1544,38 +1603,19 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 18:
// Condition
- assert(val < 16);
- if (!ps._conditions[val] && !(val & 0x10))
- v = val;
+ assert(val <= NO_CONDITION);
+ v = (ps->_conditions[val] || val == NO_CONDITION) ? val : 0xffffffff;
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;
- }
+ SpellsCategory category = ps->getSpellsCategory();
+ assert(category != SPELLCAT_INVALID);
// Check if the character class can cast the particular spell
- for (int idx = 0; idx < 39; ++idx) {
+ for (int idx = 0; idx < SPELLS_PER_CLASS; ++idx) {
if (Res.SPELLS_ALLOWED[category][idx] == (int)val) {
// Can cast it. Check if the player has it in their spellbook
- if (ps._spells[idx])
+ if (ps->_spells[idx])
v = val;
break;
}
@@ -1583,42 +1623,44 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
}
case 20:
- if (files._isDarkCc)
+ assert(val < 256);
+ if (files._ccNum && _vm->getGameID() != GType_Swords)
val += 256;
- assert(val < 512);
v = party._gameFlags[val / 256][val % 256] ? val : 0xffffffff;
break;
- case 21:
+ case 21: {
// Scans inventories for given item number
+ uint itemOffset = _vm->getGameID() == GType_Swords ? 6 : 0;
v = 0xFFFFFFFF;
- if (val < 82) {
- for (int idx = 0; idx < 9; ++idx) {
- if (val == 35) {
- if (ps._weapons[idx]._id == val) {
+ if (val < (82 + itemOffset)) {
+ for (int idx = 0; idx < INV_ITEMS_TOTAL; ++idx) {
+ if (val < (35 + itemOffset)) {
+ if (ps->_weapons[idx]._id == val) {
v = val;
break;
}
- } else if (val < 49) {
- if (ps._armor[idx]._id == (val - 35)) {
+ } else if (val < (49 + itemOffset)) {
+ if (ps->_armor[idx]._id == (val - 35)) {
v = val;
break;
}
- } else if (val < 60) {
- if (ps._accessories[idx]._id == (val - 49)) {
+ } else if (val < (60 + itemOffset)) {
+ if (ps->_accessories[idx]._id == (val - (49 + itemOffset))) {
v = val;
break;
}
} else {
- if (ps._misc[idx]._id == (val - 60)) {
+ if (ps->_misc[idx]._id == (val - (60 + itemOffset))) {
v = val;
break;
}
}
}
- } else if (party._questItems[val - 82]) {
+ } else if (party._questItems[val - (82 + itemOffset)]) {
v = val;
}
break;
+ }
case 25:
// Returns number of minutes elapsed in the day (0-1440)
v = party._minutes;
@@ -1632,32 +1674,32 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
v = party._gems;
break;
case 37:
- // Might bonus (extra beond base)
- v = ps._might._temporary;
+ // Might bonus (extra beyond base)
+ v = ps->_might._temporary;
break;
case 38:
// Intellect bonus (extra beyond base)
- v = ps._intellect._temporary;
+ v = ps->_intellect._temporary;
break;
case 39:
// Personality bonus (extra beyond base)
- v = ps._personality._temporary;
+ v = ps->_personality._temporary;
break;
case 40:
// Endurance bonus (extra beyond base)
- v = ps._endurance._temporary;
+ v = ps->_endurance._temporary;
break;
case 41:
// Speed bonus (extra beyond base)
- v = ps._speed._temporary;
+ v = ps->_speed._temporary;
break;
case 42:
// Accuracy bonus (extra beyond base)
- v = ps._accuracy._temporary;
+ v = ps->_accuracy._temporary;
break;
case 43:
// Luck bonus (extra beyond base)
- v = ps._luck._temporary;
+ v = ps->_luck._temporary;
break;
case 44:
v = YesNo::show(_vm, val);
@@ -1665,83 +1707,83 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 45:
// Might base (before bonus)
- v = ps._might._permanent;
+ v = ps->_might._permanent;
break;
case 46:
// Intellect base (before bonus)
- v = ps._intellect._permanent;
+ v = ps->_intellect._permanent;
break;
case 47:
// Personality base (before bonus)
- v = ps._personality._permanent;
+ v = ps->_personality._permanent;
break;
case 48:
// Endurance base (before bonus)
- v = ps._endurance._permanent;
+ v = ps->_endurance._permanent;
break;
case 49:
// Speed base (before bonus)
- v = ps._speed._permanent;
+ v = ps->_speed._permanent;
break;
case 50:
// Accuracy base (before bonus)
- v = ps._accuracy._permanent;
+ v = ps->_accuracy._permanent;
break;
case 51:
// Luck base (before bonus)
- v = ps._luck._permanent;
+ v = ps->_luck._permanent;
break;
case 52:
// Fire resistence (before bonus)
- v = ps._fireResistence._permanent;
+ v = ps->_fireResistence._permanent;
break;
case 53:
// Elecricity resistence (before bonus)
- v = ps._electricityResistence._permanent;
+ v = ps->_electricityResistence._permanent;
break;
case 54:
// Cold resistence (before bonus)
- v = ps._coldResistence._permanent;
+ v = ps->_coldResistence._permanent;
break;
case 55:
// Poison resistence (before bonus)
- v = ps._poisonResistence._permanent;
+ v = ps->_poisonResistence._permanent;
break;
case 56:
// Energy reistence (before bonus)
- v = ps._energyResistence._permanent;
+ v = ps->_energyResistence._permanent;
break;
case 57:
// Energy resistence (before bonus)
- v = ps._magicResistence._permanent;
+ v = ps->_magicResistence._permanent;
break;
case 58:
// Fire resistence (extra beyond base)
- v = ps._fireResistence._temporary;
+ v = ps->_fireResistence._temporary;
break;
case 59:
// Electricity resistence (extra beyond base)
- v = ps._electricityResistence._temporary;
+ v = ps->_electricityResistence._temporary;
break;
case 60:
// Cold resistence (extra beyond base)
- v = ps._coldResistence._temporary;
+ v = ps->_coldResistence._temporary;
break;
case 61:
// Poison resistence (extra beyod base)
- v = ps._poisonResistence._temporary;
+ v = ps->_poisonResistence._temporary;
break;
case 62:
// Energy resistence (extra beyond base)
- v = ps._energyResistence._temporary;
+ v = ps->_energyResistence._temporary;
break;
case 63:
// Magic resistence (extra beyond base)
- v = ps._magicResistence._temporary;
+ v = ps->_magicResistence._temporary;
break;
case 64:
// Level (before bonus)
- v = ps._level._permanent;
+ v = ps->_level._permanent;
break;
case 65:
// Total party food
@@ -1772,19 +1814,19 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 77:
// Armor class (extra beyond base)
- v = ps._ACTemp;
+ 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;
+ // Test whether current Hp exceeds max HP or not
+ 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;
+ // Test whether current Sp exceeds the max SP or not
+ v = ps->_currentSp <= ps->getMaxSP() ? 1 : 0;
break;
case 84:
// Current facing direction
@@ -1802,7 +1844,7 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
case 91:
case 92:
// Get a player stat
- v = ps.getStat((Attribute)(action - 86), 0);
+ v = ps->getStat((Attribute)(action - 86), 0);
break;
case 93:
// Current day of the week (10 days per week)
@@ -1818,7 +1860,7 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 102:
// Thievery skill
- v = ps.getThievery();
+ v = ps->getThievery();
break;
case 103:
// Get value of world flag
@@ -1826,7 +1868,7 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 104:
// Get value of quest flag
- v = party._questFlags[files._isDarkCc][val] ? val : 0xffffffff;
+ v = party._questFlags[(_vm->getGameID() == GType_Swords ? 0 : files._ccNum * 30) + val] ? val : 0xffffffff;
break;
case 105:
// Test number of Megacredits in party. Only used by King's Engineer in Castle Burlock
@@ -1834,7 +1876,7 @@ bool Scripts::ifProc(int action, uint32 val, int mode, int charIndex) {
break;
case 107:
// Get value of character flag
- error("Unused");
+ v = party._characterFlags[ps->_rosterId][val] ? val : 0xffffffff;
break;
default:
break;
@@ -1857,8 +1899,8 @@ bool Scripts::copyProtectionCheck() {
if (!ConfMan.getBool("copy_protection"))
return true;
- // Currently not implemented
- return true;
+ // Show the copy protection dialog
+ return CopyProtection::show(_vm);
}
void Scripts::display(bool justifyFlag, int var46) {