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.cpp1770
1 files changed, 1770 insertions, 0 deletions
diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp
new file mode 100644
index 0000000000..0e752529d5
--- /dev/null
+++ b/engines/xeen/scripts.cpp
@@ -0,0 +1,1770 @@
+/* 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 "common/config-manager.h"
+#include "xeen/scripts.h"
+#include "xeen/dialogs_input.h"
+#include "xeen/dialogs_whowill.h"
+#include "xeen/dialogs_query.h"
+#include "xeen/party.h"
+#include "xeen/resources.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+MazeEvent::MazeEvent() : _direction(DIR_ALL), _line(-1), _opcode(OP_None) {
+}
+
+void MazeEvent::synchronize(Common::Serializer &s) {
+ int len = 5 + _parameters.size();
+ s.syncAsByte(len);
+
+ s.syncAsByte(_position.x);
+ s.syncAsByte(_position.y);
+ s.syncAsByte(_direction);
+ s.syncAsByte(_line);
+ s.syncAsByte(_opcode);
+
+ len -= 5;
+ if (s.isLoading())
+ _parameters.resize(len);
+ for (int i = 0; i < len; ++i)
+ s.syncAsByte(_parameters[i]);
+}
+
+/*------------------------------------------------------------------------*/
+
+void MazeEvents::synchronize(XeenSerializer &s) {
+ MazeEvent e;
+
+ if (s.isLoading()) {
+ clear();
+ while (!s.finished()) {
+ e.synchronize(s);
+ push_back(e);
+ }
+ } else {
+ for (uint i = 0; i < size(); ++i)
+ (*this).operator[](i).synchronize(s);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+
+bool MirrorEntry::synchronize(Common::SeekableReadStream &s) {
+ if (s.pos() >= s.size())
+ return false;
+
+ char buffer[28];
+ s.read(buffer, 28);
+ buffer[27] = '\0';
+
+ _name = Common::String(buffer);
+ _mapId = s.readByte();
+ _position.x = s.readSByte();
+ _position.y = s.readSByte();
+ _direction = s.readSByte();
+ return true;
+}
+
+/*------------------------------------------------------------------------*/
+
+Scripts::Scripts(XeenEngine *vm) : _vm(vm) {
+ _whoWill = 0;
+ _itemType = 0;
+ _treasureItems = 0;
+ _lineNum = 0;
+ _charIndex = 0;
+ _v2 = 0;
+ _nEdamageType = 0;
+ _animCounter = 0;
+ _eventSkipped = false;
+ _mirrorId = -1;
+ _refreshIcons = false;
+ _scriptResult = false;
+ _scriptExecuted = false;
+ _var50 = false;
+ _redrawDone = false;
+ _windowIndex = -1;
+}
+
+int Scripts::checkEvents() {
+ Combat &combat = *_vm->_combat;
+ EventsManager &events = *_vm->_events;
+ Interface &intf = *_vm->_interface;
+ Map &map = *_vm->_map;
+ Party &party = *_vm->_party;
+ Screen &screen = *_vm->_screen;
+ SoundManager &sound = *_vm->_sound;
+ Town &town = *_vm->_town;
+ bool isDarkCc = _vm->_files->_isDarkCc;
+
+ _refreshIcons = false;
+ _itemType = 0;
+ _scriptExecuted = false;
+ _var50 = false;
+ _whoWill = 0;
+ Mode oldMode = _vm->_mode;
+ Common::fill(&intf._charFX[0], &intf._charFX[MAX_ACTIVE_PARTY], 0);
+ //int items = _treasureItems;
+
+ if (party._treasure._gold & party._treasure._gems) {
+ // Backup any current treasure data
+ party._savedTreasure = party._treasure;
+ party._treasure._hasItems = false;
+ party._treasure._gold = 0;
+ party._treasure._gems = 0;
+ } else {
+ party._savedTreasure._hasItems = false;
+ party._savedTreasure._gold = 0;
+ party._savedTreasure._gems = 0;
+ }
+
+ do {
+ _lineNum = 0;
+ _scriptResult = false;
+ _animCounter = 0;
+ _redrawDone = false;
+ _currentPos = party._mazePosition;
+ _charIndex = 1;
+ _v2 = 1;
+ _nEdamageType = 0;
+// int var40 = -1;
+
+ while (!_vm->shouldQuit() && _lineNum >= 0) {
+ // Break out of the events if there's an attacking monster
+ if (combat._attackMonsters[0] != -1) {
+ _eventSkipped = true;
+ break;
+ }
+
+ _eventSkipped = false;
+ uint eventIndex;
+ for (eventIndex = 0; eventIndex < map._events.size(); ++eventIndex) {
+ MazeEvent &event = map._events[eventIndex];
+
+ if (event._position == _currentPos && party._mazeDirection !=
+ (_currentPos.x | _currentPos.y) && event._line == _lineNum) {
+ if (event._direction == party._mazeDirection || event._direction == DIR_ALL) {
+ _vm->_mode = MODE_9;
+ _scriptExecuted = true;
+ doOpcode(event);
+ break;
+ } else {
+ _var50 = true;
+ }
+ }
+ }
+ if (eventIndex == map._events.size())
+ _lineNum = -1;
+ }
+ } while (!_vm->shouldQuit() && !_eventSkipped && _lineNum != -1);
+
+ intf._face1State = intf._face2State = 2;
+ if (_refreshIcons) {
+ screen.closeWindows();
+ intf.drawParty(true);
+ }
+
+ party.checkPartyDead();
+ 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 (selectedObj._spriteId == (isDarkCc ? 15 : 16)) {
+ for (uint idx = 0; idx < 16; ++idx) {
+ MazeObject &obj = map._mobData._objects[idx];
+ if (obj._spriteId == (isDarkCc ? 62 : 57)) {
+ selectedObj._id = idx;
+ selectedObj._spriteId = isDarkCc ? 62 : 57;
+ break;
+ }
+ }
+ } else if (selectedObj._spriteId == 73) {
+ for (uint idx = 0; idx < 16; ++idx) {
+ MazeObject &obj = map._mobData._objects[idx];
+ if (obj._spriteId == 119) {
+ selectedObj._id = idx;
+ selectedObj._spriteId = 119;
+ break;
+ }
+ }
+ }
+ }
+
+ _animCounter = 0;
+ _vm->_mode = oldMode;
+ screen.closeWindows();
+
+ if (_scriptExecuted || !intf._objNumber || _var50) {
+ if (_var50 && !_scriptExecuted && intf._objNumber && !map._currentIsEvent) {
+ sound.playFX(21);
+ }
+ } else {
+ Window &w = screen._windows[38];
+ w.open();
+ w.writeString(NOTHING_HERE);
+ w.update();
+
+ do {
+ intf.draw3d(true);
+ events.updateGameCounter();
+ events.wait(1, true);
+ } while (!events.isKeyMousePressed());
+ events.clearEvents();
+
+ w.close();
+ }
+
+ // Restore saved treasure
+ if (party._savedTreasure._hasItems || party._savedTreasure._gold ||
+ party._savedTreasure._gems) {
+ party._treasure = party._savedTreasure;
+ }
+
+ // Clear any town loaded sprites
+ town.clearSprites();
+
+ _v2 = 1;
+ Common::fill(&intf._charFX[0], &intf._charFX[6], 0);
+
+ return _scriptResult;
+}
+
+void Scripts::openGrate(int wallVal, int action) {
+ Combat &combat = *_vm->_combat;
+ Interface &intf = *_vm->_interface;
+ Map &map = *_vm->_map;
+ Party &party = *_vm->_party;
+ SoundManager &sound = *_vm->_sound;
+ bool isDarkCc = _vm->_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;
+ }
+
+ // 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);
+ }
+
+ // Check whether character can unlock the door
+ Character &c = party._activeParty[charIndex];
+ if ((c.getThievery() + _vm->getRandomNumber(1, 20)) <
+ map.mazeData()._difficulties._unlockDoor)
+ return;
+
+ c._experience += map.mazeData()._difficulties._unlockDoor * c.getCurrentLevel();
+ }
+
+ // Flag the grate as unlocked, and the wall the grate is on
+ map.setCellSurfaceFlags(party._mazePosition, 0x80);
+ map.setWall(party._mazePosition, party._mazeDirection, wallVal);
+
+ // 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);
+ }
+}
+
+typedef void(Scripts::*ScriptMethodPtr)(Common::Array<byte> &);
+
+void Scripts::doOpcode(MazeEvent &event) {
+ static const ScriptMethodPtr COMMAND_LIST[] = {
+ nullptr, &Scripts::cmdDisplay1, &Scripts::cmdDoorTextSml,
+ &Scripts::cmdDoorTextLrg, &Scripts::cmdSignText,
+ &Scripts::cmdNPC, &Scripts::cmdPlayFX, &Scripts::cmdTeleport,
+ &Scripts::cmdIf, &Scripts::cmdIf, &Scripts::cmdIf,
+ &Scripts::cmdMoveObj, &Scripts::cmdTakeOrGive, &Scripts::cmdNoAction,
+ &Scripts::cmdRemove, &Scripts::cmdSetChar, &Scripts::cmdSpawn,
+ &Scripts::cmdDoTownEvent, &Scripts::cmdExit, &Scripts::cmdAlterMap,
+ &Scripts::cmdGiveExtended, &Scripts::cmdConfirmWord, &Scripts::cmdDamage,
+ &Scripts::cmdJumpRnd, &Scripts::cmdAlterEvent, &Scripts::cmdCallEvent,
+ &Scripts::cmdReturn, &Scripts::cmdSetVar, &Scripts::cmdTakeOrGive,
+ &Scripts::cmdTakeOrGive, &Scripts::cmdCutsceneEndClouds,
+ &Scripts::cmdTeleport, &Scripts::cmdWhoWill,
+ &Scripts::cmdRndDamage, &Scripts::cmdMoveWallObj, &Scripts::cmdAlterCellFlag,
+ &Scripts::cmdAlterHed, &Scripts::cmdDisplayStat, &Scripts::cmdTakeOrGive,
+ &Scripts::cmdSeatTextSml, &Scripts::cmdPlayEventVoc, &Scripts::cmdDisplayBottom,
+ &Scripts::cmdIfMapFlag, &Scripts::cmdSelRndChar, &Scripts::cmdGiveEnchanted,
+ &Scripts::cmdItemType, &Scripts::cmdMakeNothingHere, &Scripts::cmdCheckProtection,
+ &Scripts::cmdChooseNumeric, &Scripts::cmdDisplayBottomTwoLines,
+ &Scripts::cmdDisplayLarge, &Scripts::cmdExchObj, &Scripts::cmdFallToMap,
+ &Scripts::cmdDisplayMain, &Scripts::cmdGoto, &Scripts::cmdConfirmWord,
+ &Scripts::cmdGotoRandom, &Scripts::cmdCutsceneEndDarkside,
+ &Scripts::cmdCutsceneEdWorld, &Scripts::cmdFlipWorld, &Scripts::cmdPlayCD
+ };
+
+ _event = &event;
+ (this->*COMMAND_LIST[event._opcode])(event._parameters);
+}
+
+void Scripts::cmdDisplay1(Common::Array<byte> &params) {
+ Screen &screen = *_vm->_screen;
+ Common::String paramText = _vm->_map->_events._text[_event->_parameters[0]];
+ Common::String msg = Common::String::format("\r\x03""c%s", paramText.c_str());
+
+ screen._windows[12].close();
+ if (screen._windows[38]._enabled)
+ screen._windows[38].open();
+ screen._windows[38].writeString(msg);
+ screen._windows[38].update();
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdDoorTextSml(Common::Array<byte> &params) {
+ Interface &intf = *_vm->_interface;
+
+ Common::String paramText = _vm->_map->_events._text[_event->_parameters[0]];
+ intf._screenText = Common::String::format("\x02\f""08\x03""c\t116\v025%s\x03""l\fd""\x01",
+ paramText.c_str());
+ intf._upDoorText = true;
+ intf.draw3d(true);
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdDoorTextLrg(Common::Array<byte> &params) {
+ Interface &intf = *_vm->_interface;
+
+ Common::String paramText = _vm->_map->_events._text[_event->_parameters[0]];
+ intf._screenText = Common::String::format("\f04\x03""c\t116\v030%s\x03""l\fd",
+ paramText.c_str());
+ intf._upDoorText = true;
+ intf.draw3d(true);
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdSignText(Common::Array<byte> &params) {
+ Interface &intf = *_vm->_interface;
+
+ Common::String paramText = _vm->_map->_events._text[_event->_parameters[0]];
+ intf._screenText = Common::String::format("\f08\x03""c\t120\v088%s\x03""l\fd",
+ paramText.c_str());
+ intf._upDoorText = true;
+ intf.draw3d(true);
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdNPC(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+
+ if (TownMessage::show(_vm, params[2], _message, map._events._text[params[1]],
+ params[3]))
+ _lineNum = params[4] - 1;
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdPlayFX(Common::Array<byte> &params) {
+ _vm->_sound->playFX(params[0]);
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdTeleport(Common::Array<byte> &params) {
+ EventsManager &events = *_vm->_events;
+ Interface &intf = *_vm->_interface;
+ Map &map = *_vm->_map;
+ Party &party = *_vm->_party;
+ Screen &screen = *_vm->_screen;
+ SoundManager &sound = *_vm->_sound;
+
+ screen.closeWindows();
+
+ int mapId;
+ Common::Point pt;
+
+ if (params[0]) {
+ mapId = params[0];
+ pt = Common::Point((int8)params[1], (int8)params[2]);
+ } else {
+ assert(_mirrorId > 0);
+ MirrorEntry &me = _mirror[_mirrorId - 1];
+ mapId = me._mapId;
+ pt = me._position;
+ if (me._direction != -1)
+ party._mazeDirection = (Direction)me._direction;
+
+ if (pt.x == 0 && pt.y == 0)
+ pt.x = 999;
+
+ sound.playFX(51);
+ }
+
+ party._stepped = true;
+ if (mapId != party._mazeId) {
+ int spriteId = (intf._objNumber == 0) ? -1 :
+ map._mobData._objects[intf._objNumber - 1]._spriteId;
+
+ switch (spriteId) {
+ case 47:
+ sound.playFX(45);
+ break;
+ case 48:
+ sound.playFX(44);
+ break;
+ default:
+ break;
+ }
+
+ // Load the new map
+ map.load(mapId);
+ }
+
+ if (pt.x == 999) {
+ party.moveToRunLocation();
+ } else {
+ party._mazePosition = pt;
+ }
+
+ events.clearEvents();
+
+ if (_event->_opcode == OP_TeleportAndContinue) {
+ intf.draw3d(true);
+ _lineNum = 0;
+ } else {
+ cmdExit(params);
+ }
+}
+
+void Scripts::cmdIf(Common::Array<byte> &params) {
+ Party &party = *_vm->_party;
+ uint32 mask;
+ int newLineNum;
+
+ switch (params[0]) {
+ case 16:
+ case 34:
+ case 100:
+ mask = (params[4] << 24) | (params[3] << 16) | (params[2] << 8) | params[1];
+ newLineNum = params[5];
+ break;
+ case 25:
+ case 35:
+ case 101:
+ case 106:
+ mask = (params[2] << 8) | params[1];
+ newLineNum = params[3];
+ break;
+ default:
+ mask = params[1];
+ newLineNum = params[2];
+ break;
+ }
+
+ bool result;
+ if ((_charIndex != 0 && _charIndex != 8) || params[0] == 44) {
+ result = ifProc(params[0], mask, _event->_opcode - 8, _charIndex - 1);
+ } else {
+ result = false;
+ for (int idx = 0; idx < (int)party._activeParty.size() && !result; ++idx) {
+ if (_charIndex == 0 || (_charIndex == 8 && (int)idx != _v2)) {
+ result = ifProc(params[0], mask, _event->_opcode - 8, idx);
+ }
+ }
+ }
+
+ if (result)
+ _lineNum = newLineNum - 1;
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdMoveObj(Common::Array<byte> &params) {
+ MazeObject &mazeObj = _vm->_map->_mobData._objects[params[0]];
+
+ if (mazeObj._position.x == params[1] && mazeObj._position.y == params[2]) {
+ // Already in position, so simply flip it
+ mazeObj._flipped = !mazeObj._flipped;
+ } else {
+ mazeObj._position.x = params[1];
+ mazeObj._position.y = params[2];
+ }
+}
+
+void Scripts::cmdTakeOrGive(Common::Array<byte> &params) {
+ Party &party = *_vm->_party;
+ Screen &screen = *_vm->_screen;
+ int mode1, mode2, mode3;
+ uint32 mask1, mask2, mask3;
+ byte *extraP;
+ // TODO: See if this needs to maintain values set in other opcodes
+ int param2 = 0;
+
+ mode1 = params[0];
+ switch (mode1) {
+ case 16:
+ case 34:
+ case 100:
+ mask1 = (params[4] << 24) | (params[3] << 16) | (params[2] << 8) | params[1];
+ extraP = &params[5];
+ break;
+ case 25:
+ case 35:
+ case 101:
+ case 106:
+ mask1 = (params[2] << 8) | params[1];
+ extraP = &params[3];
+ break;
+ default:
+ mask1 = params[1];
+ extraP = &params[2];
+ break;
+ }
+
+ mode2 = *extraP++;
+ switch (mode2) {
+ case 16:
+ case 34:
+ case 100:
+ mask2 = (extraP[3] << 24) | (extraP[2] << 16) | (extraP[1] << 8) | extraP[0];
+ extraP += 4;
+ break;
+ case 25:
+ case 35:
+ case 101:
+ case 106:
+ mask2 = (extraP[1] << 8) | extraP[0];
+ extraP += 2;
+ break;
+ default:
+ mask2 = extraP[0];
+ extraP++;
+ break;
+ }
+
+ mode3 = *extraP++;
+ switch (mode3) {
+ case 16:
+ case 34:
+ case 100:
+ mask3 = (extraP[3] << 24) | (extraP[2] << 16) | (extraP[1] << 8) | extraP[0];
+ break;
+ case 25:
+ case 35:
+ case 101:
+ case 106:
+ mask3 = (extraP[1] << 8) | extraP[0];
+ break;
+ default:
+ mask3 = extraP[0];
+ break;
+ }
+
+ if (mode2)
+ screen.closeWindows();
+
+ switch (_event->_opcode) {
+ case OP_TakeOrGive_2:
+ if (_charIndex == 0 || _charIndex == 8) {
+ for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
+ if (_charIndex == 0 || (_charIndex == 8 && (int)idx != _v2)) {
+ if (ifProc(params[0], mask1, _event->_opcode == OP_TakeOrGive_4 ? 2 : 1, idx)) {
+ party.giveTake(0, 0, mode2, mask2, idx);
+ if (mode2 == 82)
+ break;
+ }
+ }
+ }
+ } else if (ifProc(params[0], mask1, _event->_opcode == OP_TakeOrGive_4 ? 2 : 1, _charIndex - 1)) {
+ party.giveTake(0, 0, mode2, mask2, _charIndex - 1);
+ }
+ break;
+
+ case OP_TakeOrGive_3:
+ if (_charIndex == 0 || _charIndex == 8) {
+ for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
+ if (_charIndex == 0 || (_charIndex == 8 && (int)idx != _v2)) {
+ if (ifProc(params[0], mask1, 1, idx) && ifProc(mode2, mask2, 1, idx)) {
+ party.giveTake(0, 0, mode2, mask3, idx);
+ if (mode2 == 82)
+ break;
+ }
+ }
+ }
+ } else if (ifProc(params[0], mask1, 1, _charIndex - 1) &&
+ ifProc(mode2, mask2, 1, _charIndex - 1)) {
+ party.giveTake(0, 0, mode2, mask3, _charIndex - 1);
+ }
+ break;
+
+ case OP_TakeOrGive_4:
+ if (_charIndex == 0 || _charIndex == 8) {
+ for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
+ if (_charIndex == 0 || (_charIndex == 8 && (int)idx != _v2)) {
+ if (ifProc(params[0], mask1, _event->_opcode == OP_TakeOrGive_4 ? 2 : 1, idx)) {
+ party.giveTake(0, 0, mode2, mask2, idx);
+ if (mode2 == 82)
+ break;
+ }
+ }
+ }
+ } else if (ifProc(params[0], mask1, 1, _charIndex - 1)) {
+ party.giveTake(0, 0, mode2, mask2, _charIndex - 1);
+ }
+ break;
+
+ default:
+ if (_charIndex == 0 || _charIndex == 8) {
+ for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
+ if (_charIndex == 0 || (_charIndex == 8 && (int)idx != _v2)) {
+ party.giveTake(mode1, mask1, mode1, mask2, idx);
+
+ switch (mode1) {
+ case 8:
+ mode1 = 0;
+ // Deliberate fall-through
+ case 21:
+ case 66:
+ if (param2) {
+ switch (mode2) {
+ case 82:
+ mode1 = 0;
+ // Deliberate fall-through
+ case 21:
+ case 34:
+ case 35:
+ case 65:
+ case 66:
+ case 100:
+ case 101:
+ case 106:
+ if (param2)
+ continue;
+
+ // Break out of character loop
+ idx = party._activeParty.size();
+ break;
+ }
+ }
+ break;
+
+ case 34:
+ case 35:
+ case 65:
+ case 100:
+ case 101:
+ case 106:
+ if (param2) {
+ _lineNum = -1;
+ return;
+ }
+
+ // Break out of character loop
+ idx = party._activeParty.size();
+ break;
+
+ default:
+ switch (mode2) {
+ case 82:
+ mode1 = 0;
+ // Deliberate fall-through
+ case 21:
+ case 34:
+ case 35:
+ case 65:
+ case 66:
+ case 100:
+ case 101:
+ case 106:
+ if (param2)
+ continue;
+
+ // Break out of character loop
+ idx = party._activeParty.size();
+ break;
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ if (!party.giveTake(mode1, mask1, mode2, mask2, _charIndex - 1)) {
+ if (mode2 == 79)
+ screen.closeWindows();
+ }
+ }
+ break;
+ }
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdNoAction(Common::Array<byte> &params) {
+ // Move to next line
+ _lineNum = _vm->_party->_partyDead ? -1 : _lineNum + 1;
+}
+
+void Scripts::cmdRemove(Common::Array<byte> &params) {
+ Interface &intf = *_vm->_interface;
+ Map &map = *_vm->_map;
+
+ if (intf._objNumber) {
+ // Give the active object a completely way out of bounds position
+ MazeObject &obj = map._mobData._objects[intf._objNumber - 1];
+ obj._position = Common::Point(128, 128);
+ }
+
+ cmdMakeNothingHere(params);
+}
+
+void Scripts::cmdSetChar(Common::Array<byte> &params) {
+ if (params[0] != 7) {
+ _charIndex = WhoWill::show(_vm, 22, 3, false);
+ if (_charIndex == 0) {
+ cmdExit(params);
+ return;
+ }
+ } else {
+ _charIndex = _vm->getRandomNumber(1, _vm->_party->_activeParty.size());
+ }
+
+ _v2 = 1;
+ cmdNoAction(params);
+}
+
+void Scripts::cmdSpawn(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+ if (params[0] >= map._mobData._monsters.size())
+ map._mobData._monsters.resize(params[0] + 1);
+
+ MazeMonster &monster = _vm->_map->_mobData._monsters[params[0]];
+ MonsterStruct &monsterData = _vm->_map->_monsterData[monster._spriteId];
+ monster._monsterData = &monsterData;
+ monster._position.x = params[1];
+ monster._position.y = params[2];
+ monster._frame = _vm->getRandomNumber(7);
+ monster._damageType = 0;
+ monster._isAttacking = params[1] != 0;
+ monster._hp = monsterData._hp;
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdDoTownEvent(Common::Array<byte> &params) {
+ _scriptResult = _vm->_town->townAction(params[0]);
+ _vm->_party->_stepped = true;
+ _refreshIcons = true;
+
+ cmdExit(params);
+}
+
+void Scripts::cmdExit(Common::Array<byte> &params) {
+ _lineNum = -1;
+}
+
+void Scripts::cmdAlterMap(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+
+ if (params[2] == DIR_ALL) {
+ for (int dir = DIR_NORTH; dir <= DIR_WEST; ++dir)
+ map.setWall(Common::Point(params[0], params[1]), (Direction)dir, params[3]);
+ } else {
+ map.setWall(Common::Point(params[0], params[1]), (Direction)params[2], params[3]);
+ }
+
+ cmdNoAction(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:
+ mask = (params[4] << 24) | params[3] | (params[2] << 8) | (params[1] << 16);
+ newLineNum = params[5];
+ break;
+ case 25:
+ case 35:
+ case 101:
+ case 106:
+ 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 < (int)party._activeParty.size() && !result; ++idx) {
+ if (_charIndex == 0 || (_charIndex == 8 && _v2 != idx)) {
+ result = ifProc(params[0], mask, _event->_opcode - OP_If1, idx);
+ }
+ }
+ }
+
+ if (result)
+ _lineNum = newLineNum - 1;
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdConfirmWord(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+ Party &party = *_vm->_party;
+ Common::String msg1 = params[2] ? map._events._text[params[2]] :
+ _vm->_interface->_interfaceText;
+ Common::String msg2;
+
+ if (_event->_opcode == OP_ConfirmWord_2) {
+ msg2 = map._events._text[params[3]];
+ } else if (params[3]) {
+ msg2 = "";
+ } else {
+ msg2 = WHATS_THE_PASSWORD;
+ }
+
+ int result = StringInput::show(_vm, params[0], msg1, msg2,_event->_opcode);
+ if (result) {
+ if (result == 33 && _vm->_files->_isDarkCc) {
+ doEndGame2();
+ } else if (result == 34 && _vm->_files->_isDarkCc) {
+ doWorldEnd();
+ } else if (result == 35 && _vm->_files->_isDarkCc &&
+ _vm->getGameID() == GType_WorldOfXeen) {
+ doEndGame();
+ } else if (result == 40 && !_vm->_files->_isDarkCc) {
+ doEndGame();
+ } else if (result == 60 && !_vm->_files->_isDarkCc) {
+ doEndGame2();
+ }
+ else if (result == 61 && !_vm->_files->_isDarkCc) {
+ doWorldEnd();
+ } else {
+ if (result == 59 && !_vm->_files->_isDarkCc) {
+ for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
+ XeenItem &item = party._treasure._weapons[idx];
+ if (!item._id) {
+ item._id = 34;
+ item._material = 0;
+ item._bonusFlags = 0;
+ party._treasure._hasItems = true;
+
+ cmdExit(params);
+ return;
+ }
+ }
+ }
+
+ _lineNum = result == -1 ? params[3] : params[1];
+
+ return;
+ }
+ }
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdDamage(Common::Array<byte> &params) {
+ Combat &combat = *_vm->_combat;
+ Interface &intf = *_vm->_interface;
+
+ if (!_redrawDone) {
+ intf.draw3d(true);
+ _redrawDone = true;
+ }
+
+ int damage = (params[1] << 8) | params[0];
+ combat.giveCharDamage(damage, (DamageType)params[2], _charIndex);
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdJumpRnd(Common::Array<byte> &params) {
+ int v = _vm->getRandomNumber(1, params[0]);
+ if (v == params[1])
+ _lineNum = params[2] - 1;
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdAlterEvent(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+ Party &party = *_vm->_party;
+
+ for (uint idx = 0; idx < map._events.size(); ++idx) {
+ MazeEvent &evt = map._events[idx];
+ if (evt._position == party._mazePosition &&
+ (evt._direction == DIR_ALL || evt._direction == party._mazeDirection) &&
+ evt._line == params[0]) {
+ evt._opcode = (Opcode)params[1];
+ }
+ }
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdCallEvent(Common::Array<byte> &params) {
+ _stack.push(StackEntry(_currentPos, _lineNum));
+ _currentPos = Common::Point(params[0], params[1]);
+ _lineNum = params[2] - 1;
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdReturn(Common::Array<byte> &params) {
+ StackEntry &se = _stack.top();
+ _currentPos = se;
+ _lineNum = se.line;
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdSetVar(Common::Array<byte> &params) {
+ Party &party = *_vm->_party;
+ uint val;
+ _refreshIcons = true;
+
+ switch (params[0]) {
+ case 25:
+ case 35:
+ case 101:
+ case 106:
+ val = (params[2] << 8) | params[1];
+ break;
+ case 16:
+ case 34:
+ case 100:
+ val = (params[4] << 24) | (params[3] << 16) | (params[2] << 8) | params[3];
+ break;
+ default:
+ val = params[1];
+ break;
+ }
+
+ if (_charIndex != 0 && _charIndex != 8) {
+ party._activeParty[_charIndex - 1].setValue(params[0], val);
+ } else {
+ // Set value for entire party
+ for (int idx = 0; idx < (int)party._activeParty.size(); ++idx) {
+ if (_charIndex == 0 || (_charIndex == 8 && _v2 != idx)) {
+ party._activeParty[idx].setValue(params[0], val);
+ }
+ }
+ }
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdCutsceneEndClouds(Common::Array<byte> &params) { error("TODO"); }
+
+void Scripts::cmdWhoWill(Common::Array<byte> &params) {
+ _charIndex = WhoWill::show(_vm, params[0], params[1], true);
+
+ if (_charIndex == 0)
+ cmdExit(params);
+ else
+ cmdNoAction(params);
+}
+
+void Scripts::cmdRndDamage(Common::Array<byte> &params) {
+ Combat &combat = *_vm->_combat;
+ Interface &intf = *_vm->_interface;
+
+ if (!_redrawDone) {
+ intf.draw3d(true);
+ _redrawDone = true;
+ }
+
+ combat.giveCharDamage(_vm->getRandomNumber(1, params[1]), (DamageType)params[0], _charIndex);
+ cmdNoAction(params);
+}
+
+void Scripts::cmdMoveWallObj(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+
+ map._mobData._wallItems[params[0]]._position = Common::Point(params[1], params[2]);
+ cmdNoAction(params);
+}
+
+void Scripts::cmdAlterCellFlag(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+ Common::Point pt(params[0], params[1]);
+ map.cellFlagLookup(pt);
+
+ if (map._isOutdoors) {
+ MazeWallLayers &wallData = map.mazeDataCurrent()._wallData[pt.y][pt.x];
+ wallData._data = (wallData._data & 0xFFF0) | params[2];
+ } else {
+ pt.x &= 0xF;
+ pt.y &= 0xF;
+ MazeCell &cell = map.mazeDataCurrent()._cells[pt.y][pt.x];
+ cell._surfaceId = params[2];
+ }
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdAlterHed(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+ Party &party = *_vm->_party;
+
+ HeadData::HeadEntry &he = map._headData[party._mazePosition.y][party._mazePosition.x];
+ he._left = params[0];
+ he._right = params[1];
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdDisplayStat(Common::Array<byte> &params) {
+ Party &party = *_vm->_party;
+ Window &w = _vm->_screen->_windows[12];
+ Character &c = party._activeParty[_charIndex - 1];
+
+ if (!w._enabled)
+ w.open();
+ w.writeString(Common::String::format(_message.c_str(), c._name.c_str()));
+ w.update();
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdSeatTextSml(Common::Array<byte> &params) {
+ Interface &intf = *_vm->_interface;
+
+ intf._screenText = Common::String::format("\x2\f08\x3""c\t116\v090%s\x3l\fd\x1",
+ _message.c_str());
+ intf._upDoorText = true;
+ intf.draw3d(true);
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdPlayEventVoc(Common::Array<byte> &params) {
+ SoundManager &sound = *_vm->_sound;
+ sound.playSample(nullptr, 0);
+ File f(EVENT_SAMPLES[params[0]]);
+ sound.playSample(&f, 1);
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdDisplayBottom(Common::Array<byte> &params) {
+ _windowIndex = 12;
+
+ display(false, 0);
+ cmdNoAction(params);
+}
+
+void Scripts::cmdIfMapFlag(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+ MazeMonster &monster = map._mobData._monsters[params[0]];
+
+ if (monster._position.x >= 32 || monster._position.y >= 32) {
+ _lineNum = params[1] - 1;
+ }
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdSelRndChar(Common::Array<byte> &params) {
+ _charIndex = _vm->getRandomNumber(1, _vm->_party->_activeParty.size());
+ cmdNoAction(params);
+}
+
+void Scripts::cmdGiveEnchanted(Common::Array<byte> &params) {
+ Party &party = *_vm->_party;
+
+ if (params[0] >= 35) {
+ if (params[0] < 49) {
+ for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
+ XeenItem &item = party._treasure._armor[idx];
+ if (!item.empty()) {
+ item._id = params[0] - 35;
+ item._material = params[1];
+ item._bonusFlags = params[2];
+ party._treasure._hasItems = true;
+ break;
+ }
+ }
+
+ cmdNoAction(params);
+ return;
+ } else if (params[0] < 60) {
+ for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
+ XeenItem &item = party._treasure._accessories[idx];
+ if (!item.empty()) {
+ item._id = params[0] - 49;
+ item._material = params[1];
+ item._bonusFlags = params[2];
+ party._treasure._hasItems = true;
+ break;
+ }
+ }
+
+ cmdNoAction(params);
+ return;
+ } else if (params[0] < 82) {
+ for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
+ XeenItem &item = party._treasure._misc[idx];
+ if (!item.empty()) {
+ item._id = params[0];
+ item._material = params[1];
+ item._bonusFlags = params[2];
+ party._treasure._hasItems = true;
+ break;
+ }
+ }
+
+ cmdNoAction(params);
+ return;
+ } else {
+ party._gameFlags[6 + params[0]] = true;
+ }
+ }
+
+ for (int idx = 0; idx < MAX_TREASURE_ITEMS; ++idx) {
+ XeenItem &item = party._treasure._weapons[idx];
+ if (!item.empty()) {
+ item._id = params[0];
+ item._material = params[1];
+ item._bonusFlags = params[2];
+ party._treasure._hasItems = true;
+ break;
+ }
+ }
+}
+
+void Scripts::cmdItemType(Common::Array<byte> &params) {
+ _itemType = params[0];
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdMakeNothingHere(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+ Party &party = *_vm->_party;
+
+ // Scan through the event list and mark the opcodes for all the lines of any scripts
+ // on the party's current cell as having no operation, effectively disabling them
+ for (uint idx = 0; idx < map._events.size(); ++idx) {
+ MazeEvent &evt = map._events[idx];
+ if (evt._position == party._mazePosition)
+ evt._opcode = OP_None;
+ }
+
+ cmdExit(params);
+}
+
+void Scripts::cmdCheckProtection(Common::Array<byte> &params) {
+ if (copyProtectionCheck())
+ cmdNoAction(params);
+ else
+ cmdExit(params);
+}
+
+void Scripts::cmdChooseNumeric(Common::Array<byte> &params) {
+ int choice = Choose123::show(_vm, params[0]);
+ if (choice) {
+ _lineNum = params[choice] - 1;
+ }
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdDisplayBottomTwoLines(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+ Window &w = _vm->_screen->_windows[12];
+
+ warning("TODO: cmdDisplayBottomTwoLines");
+ Common::String msg = Common::String::format("\r\x03c\t000\v007%s\n\n%s",
+ "",
+ map._events._text[params[1]].c_str());
+ w.close();
+ w.open();
+ w.writeString(msg);
+ w.update();
+
+ YesNo::show(_vm, true);
+ _lineNum = -1;
+}
+
+void Scripts::cmdDisplayLarge(Common::Array<byte> &params) {
+ error("TODO: Implement event text loading");
+
+ display(true, 0);
+ cmdNoAction(params);
+}
+
+void Scripts::cmdExchObj(Common::Array<byte> &params) {
+ MazeObject &obj1 = _vm->_map->_mobData._objects[params[0]];
+ MazeObject &obj2 = _vm->_map->_mobData._objects[params[1]];
+
+ Common::Point pt = obj1._position;
+ obj1._position = obj2._position;
+ obj2._position = pt;
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdFallToMap(Common::Array<byte> &params) {
+ Interface &intf = *_vm->_interface;
+ Party &party = *_vm->_party;
+ party._fallMaze = params[0];
+ party._fallPosition = Common::Point(params[1], params[2]);
+ party._fallDamage = params[3];
+ intf.startFalling(true);
+
+ _lineNum = -1;
+}
+
+void Scripts::cmdDisplayMain(Common::Array<byte> &params) {
+ display(false, 0);
+ cmdNoAction(params);
+}
+
+void Scripts::cmdGoto(Common::Array<byte> &params) {
+ Map &map = *_vm->_map;
+ map.getCell(1);
+ if (params[0] == map._currentSurfaceId)
+ _lineNum = params[1] - 1;
+
+ cmdNoAction(params);
+}
+
+void Scripts::cmdGotoRandom(Common::Array<byte> &params) {
+ _lineNum = params[_vm->getRandomNumber(1, params[0])] - 1;
+ cmdNoAction(params);
+}
+
+void Scripts::cmdCutsceneEndDarkside(Common::Array<byte> &params) {
+ Party &party = *_vm->_party;
+ _vm->_saves->_wonDarkSide = true;
+ party._questItems[53] = 1;
+ party._darkSideEnd = true;
+ party._mazeId = 29;
+ party._mazeDirection = DIR_NORTH;
+ party._mazePosition = Common::Point(25, 21);
+
+ doEndGame2();
+}
+
+void Scripts::cmdCutsceneEdWorld(Common::Array<byte> &params) {
+ _vm->_saves->_wonWorld = true;
+ _vm->_party->_worldEnd = true;
+ doWorldEnd();
+}
+
+void Scripts::cmdFlipWorld(Common::Array<byte> &params) {
+ _vm->_map->_loadDarkSide = params[0] != 0;
+}
+
+void Scripts::cmdPlayCD(Common::Array<byte> &params) { error("TODO"); }
+
+void Scripts::doEndGame() {
+ doEnding("ENDGAME", 0);
+}
+
+void Scripts::doEndGame2() {
+ Party &party = *_vm->_party;
+ int v2 = 0;
+
+ for (uint idx = 0; idx < party._activeParty.size(); ++idx) {
+ Character &player = party._activeParty[idx];
+ if (player.hasAward(77)) {
+ v2 = 2;
+ break;
+ }
+ else if (player.hasAward(76)) {
+ v2 = 1;
+ break;
+ }
+ }
+
+ doEnding("ENDGAME2", v2);
+}
+
+void Scripts::doWorldEnd() {
+
+}
+
+void Scripts::doEnding(const Common::String &endStr, int v2) {
+ _vm->_saves->saveChars();
+
+ warning("TODO: doEnding");
+}
+
+bool Scripts::ifProc(int action, uint32 mask, int mode, int charIndex) {
+ Party &party = *_vm->_party;
+ Character &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[category][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);
+ v = party._gameFlags[mask] ? mask : 0xffffffff;
+ 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]._id == mask) {
+ v = mask;
+ break;
+ }
+ } else if (mask < 49) {
+ if (ps._armor[idx]._id == (mask - 35)) {
+ v = mask;
+ break;
+ }
+ } else if (mask < 60) {
+ if (ps._accessories[idx]._id == (mask - 49)) {
+ v = mask;
+ break;
+ }
+ } else {
+ if (ps._misc[idx]._id == (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);
+ v = (!v && !mask) ? 2 : mask;
+ 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((Attribute)(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
+ v = party.checkSkill((Skill)mask) ? mask : 0xffffffff;
+ break;
+ case 102:
+ // Thievery skill
+ v = ps.getThievery();
+ break;
+ case 103:
+ // Get value of world flag
+ v = party._worldFlags[mask] ? mask : 0xffffffff;
+ break;
+ case 104:
+ // Get value of quest flag
+ v = party._quests[mask + (_vm->_files->_isDarkCc ? 30 : 0)] ?
+ mask : 0xffffffff;
+ 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;
+ }
+}
+
+bool Scripts::copyProtectionCheck() {
+ // Only bother doing the protection check if it's been explicitly turned on
+ if (!ConfMan.getBool("copy_protection"))
+ return true;
+
+ // Currently not implemented
+ return true;
+}
+
+void Scripts::display(bool justifyFlag, int var46) {
+ EventsManager &events = *_vm->_events;
+ Interface &intf = *_vm->_interface;
+ Screen &screen = *_vm->_screen;
+ Window &w = screen._windows[_windowIndex];
+
+ if (!_redrawDone) {
+ intf.draw3d(true);
+ _redrawDone = true;
+ }
+ screen._windows[38].close();
+
+ if (!justifyFlag)
+ _displayMessage = Common::String::format("\r\x3""c%s", _message.c_str());
+
+ if (!w._enabled)
+ w.open();
+
+ while (!_vm->shouldQuit()) {
+ _displayMessage = w.writeString(_displayMessage);
+ w.update();
+ if (_displayMessage.empty())
+ break;
+ events.clearEvents();
+
+ do {
+ events.updateGameCounter();
+ intf.draw3d(true);
+
+ events.wait(1, true);
+ } while (!_vm->shouldQuit() && !events.isKeyMousePressed());
+
+ w.writeString(justifyFlag ? "\r" : "\r\x3""c");
+ }
+}
+
+} // End of namespace Xeen