From c965fccab0cd1cb996e00d28e215523ae910d3bf Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 21 Nov 2017 21:36:19 -0500 Subject: XEEN: Add a new iterator class for reading event parameters This make things cleaner for reading in 16 and 32 bit parameters in different opcodes. Also, it solves a crash in the give/take opcode where the third mode/value pair isn't used for all sub-modes, so the code was previously reading beyond the end of the parameters --- engines/xeen/scripts.cpp | 464 ++++++++++++++++++++++++++--------------------- engines/xeen/scripts.h | 149 +++++++++------ 2 files changed, 356 insertions(+), 257 deletions(-) diff --git a/engines/xeen/scripts.cpp b/engines/xeen/scripts.cpp index 2d0123e407..518522c4e1 100644 --- a/engines/xeen/scripts.cpp +++ b/engines/xeen/scripts.cpp @@ -31,6 +31,28 @@ namespace Xeen { +byte EventParameters::Iterator::readByte() { + byte result = (_index >= _data.size()) ? 0 : _data[_index]; + ++_index; + return result; +} + +uint16 EventParameters::Iterator::readUint16LE() { + uint16 result = ((_index + 1) >= _data.size()) ? 0 : + READ_LE_UINT16(&_data[_index]); + _index += 2; + return result; +} + +uint32 EventParameters::Iterator::readUint32LE() { + uint16 result = ((_index + 3) >= _data.size()) ? 0 : + READ_LE_UINT32(&_data[_index]); + _index += 4; + return result; +} + +/*------------------------------------------------------------------------*/ + MazeEvent::MazeEvent() : _direction(DIR_ALL), _line(-1), _opcode(OP_None) { } @@ -317,9 +339,8 @@ void Scripts::openGrate(int wallVal, int action) { } } -typedef bool(Scripts::*ScriptMethodPtr)(Common::Array &); - bool Scripts::doOpcode(MazeEvent &event) { + typedef bool(Scripts::*ScriptMethodPtr)(ParamsIterator &); static const ScriptMethodPtr COMMAND_LIST[] = { &Scripts::cmdDoNothing, &Scripts::cmdDisplay1, &Scripts::cmdDoorTextSml, &Scripts::cmdDoorTextLrg, &Scripts::cmdSignText, @@ -346,7 +367,8 @@ bool Scripts::doOpcode(MazeEvent &event) { }; _event = &event; - bool result = (this->*COMMAND_LIST[event._opcode])(event._parameters); + ParamsIterator params = event._parameters.getIterator(); + bool result = (this->*COMMAND_LIST[event._opcode])(params); if (result) // Move to next line _lineNum = _vm->_party->_partyDead ? -1 : _lineNum + 1; @@ -354,13 +376,13 @@ bool Scripts::doOpcode(MazeEvent &event) { return result; } -bool Scripts::cmdDoNothing(Common::Array ¶ms) { +bool Scripts::cmdDoNothing(ParamsIterator ¶ms) { return true; } -bool Scripts::cmdDisplay1(Common::Array ¶ms) { +bool Scripts::cmdDisplay1(ParamsIterator ¶ms) { Screen &screen = *_vm->_screen; - Common::String paramText = _vm->_map->_events._text[_event->_parameters[0]]; + Common::String paramText = _vm->_map->_events._text[params.readByte()]; Common::String msg = Common::String::format("\r\x03""c%s", paramText.c_str()); screen._windows[12].close(); @@ -372,10 +394,10 @@ bool Scripts::cmdDisplay1(Common::Array ¶ms) { return true; } -bool Scripts::cmdDoorTextSml(Common::Array ¶ms) { +bool Scripts::cmdDoorTextSml(ParamsIterator ¶ms) { Interface &intf = *_vm->_interface; - Common::String paramText = _vm->_map->_events._text[_event->_parameters[0]]; + Common::String paramText = _vm->_map->_events._text[params.readByte()]; intf._screenText = Common::String::format("\x02\f""08\x03""c\t116\v025%s\x03""l\fd""\x01", paramText.c_str()); intf._upDoorText = true; @@ -384,10 +406,10 @@ bool Scripts::cmdDoorTextSml(Common::Array ¶ms) { return true; } -bool Scripts::cmdDoorTextLrg(Common::Array ¶ms) { +bool Scripts::cmdDoorTextLrg(ParamsIterator ¶ms) { Interface &intf = *_vm->_interface; - Common::String paramText = _vm->_map->_events._text[_event->_parameters[0]]; + Common::String paramText = _vm->_map->_events._text[params.readByte()]; intf._screenText = Common::String::format("\f04\x03""c\t116\v030%s\x03""l\fd", paramText.c_str()); intf._upDoorText = true; @@ -396,10 +418,10 @@ bool Scripts::cmdDoorTextLrg(Common::Array ¶ms) { return true; } -bool Scripts::cmdSignText(Common::Array ¶ms) { +bool Scripts::cmdSignText(ParamsIterator ¶ms) { Interface &intf = *_vm->_interface; - Common::String paramText = _vm->_map->_events._text[_event->_parameters[0]]; + Common::String paramText = _vm->_map->_events._text[params.readByte()]; intf._screenText = Common::String::format("\f08\x03""c\t120\v088%s\x03""l\fd", paramText.c_str()); intf._upDoorText = true; @@ -408,25 +430,31 @@ bool Scripts::cmdSignText(Common::Array ¶ms) { return true; } -bool Scripts::cmdNPC(Common::Array ¶ms) { +bool Scripts::cmdNPC(ParamsIterator ¶ms) { Map &map = *_vm->_map; - if (TownMessage::show(_vm, params[2], _message, map._events._text[params[1]], - params[3])) { - _lineNum = params[4]; + params.readByte(); + int textNum = params.readByte(); + int portrait = params.readByte(); + int confirm = params.readByte(); + int lineNum = params.readByte(); + + if (TownMessage::show(_vm, portrait, _message, map._events._text[textNum], + confirm)) { + _lineNum = lineNum; return false; } return true; } -bool Scripts::cmdPlayFX(Common::Array ¶ms) { - _vm->_sound->playFX(params[0]); +bool Scripts::cmdPlayFX(ParamsIterator ¶ms) { + _vm->_sound->playFX(params.readByte()); return true; } -bool Scripts::cmdTeleport(Common::Array ¶ms) { +bool Scripts::cmdTeleport(ParamsIterator ¶ms) { EventsManager &events = *_vm->_events; Interface &intf = *_vm->_interface; Map &map = *_vm->_map; @@ -436,12 +464,12 @@ bool Scripts::cmdTeleport(Common::Array ¶ms) { screen.closeWindows(); - int mapId; + int mapId = params.readByte(); Common::Point pt; - if (params[0]) { - mapId = params[0]; - pt = Common::Point((int8)params[1], (int8)params[2]); + if (mapId) { + pt.x = params.readShort(); + pt.y = params.readShort(); } else { assert(_mirrorId > 0); MirrorEntry &me = _mirror[_mirrorId - 1]; @@ -493,39 +521,40 @@ bool Scripts::cmdTeleport(Common::Array ¶ms) { } } -bool Scripts::cmdIf(Common::Array ¶ms) { +bool Scripts::cmdIf(ParamsIterator ¶ms) { Party &party = *_vm->_party; uint32 mask; int newLineNum; - switch (params[0]) { + int mode = params.readByte(); + switch (mode) { case 16: case 34: case 100: - mask = (params[4] << 24) | (params[3] << 16) | (params[2] << 8) | params[1]; - newLineNum = params[5]; + mask = params.readUint32LE(); + newLineNum = params.readByte(); break; case 25: case 35: case 101: case 106: - mask = (params[2] << 8) | params[1]; - newLineNum = params[3]; + mask = params.readUint16LE(); + newLineNum = params.readByte(); break; default: - mask = params[1]; - newLineNum = params[2]; + mask = params.readByte(); + newLineNum = params.readByte(); break; } bool result; - if ((_charIndex != 0 && _charIndex != 8) || params[0] == 44) { - result = ifProc(params[0], mask, _event->_opcode - 8, _charIndex - 1); + if ((_charIndex != 0 && _charIndex != 8) || mode == 44) { + result = ifProc(mode, 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); + result = ifProc(mode, mask, _event->_opcode - 8, idx); } } } @@ -538,84 +567,78 @@ bool Scripts::cmdIf(Common::Array ¶ms) { return true; } -bool Scripts::cmdMoveObj(Common::Array ¶ms) { - MazeObject &mazeObj = _vm->_map->_mobData._objects[params[0]]; +bool Scripts::cmdMoveObj(ParamsIterator ¶ms) { + MazeObject &mazeObj = _vm->_map->_mobData._objects[params.readByte()]; + int x = params.readShort(), y = params.readShort(); - if (mazeObj._position.x == params[1] && mazeObj._position.y == params[2]) { + if (mazeObj._position.x == x && mazeObj._position.y == y) { // Already in position, so simply flip it mazeObj._flipped = !mazeObj._flipped; } else { - mazeObj._position.x = params[1]; - mazeObj._position.y = params[2]; + mazeObj._position.x = x; + mazeObj._position.y = y; } return true; } -bool Scripts::cmdTakeOrGive(Common::Array ¶ms) { +bool Scripts::cmdTakeOrGive(ParamsIterator ¶ms) { Party &party = *_vm->_party; Screen &screen = *_vm->_screen; int mode1, mode2, mode3, param2; - uint32 mask1, mask2, mask3; - byte *extraP; + uint32 val1, val2, val3; - mode1 = params[0]; + mode1 = params.readByte(); switch (mode1) { case 16: case 34: case 100: - mask1 = (params[4] << 24) | (params[3] << 16) | (params[2] << 8) | params[1]; - extraP = ¶ms[5]; + val1 = params.readUint32LE(); break; case 25: case 35: case 101: case 106: - mask1 = (params[2] << 8) | params[1]; - extraP = ¶ms[3]; + val1 = params.readUint16LE(); break; default: - mask1 = params[1]; - extraP = ¶ms[9]; + val1 = params.readByte(); break; } - param2 = mode2 = *extraP++; + param2 = mode2 = params.readByte(); switch (mode2) { case 16: case 34: case 100: - mask2 = (extraP[3] << 24) | (extraP[2] << 16) | (extraP[1] << 8) | extraP[0]; - extraP += 4; + val2 = params.readUint32LE(); break; case 25: case 35: case 101: case 106: - mask2 = (extraP[1] << 8) | extraP[0]; - extraP += 2; + val2 = params.readUint16LE(); break; default: - mask2 = extraP[0]; - extraP++; + val2 = params.readByte(); break; } - mode3 = *extraP++; + mode3 = params.readByte(); switch (mode3) { case 16: case 34: case 100: - mask3 = (extraP[3] << 24) | (extraP[2] << 16) | (extraP[1] << 8) | extraP[0]; + val3 = params.readUint32LE(); break; case 25: case 35: case 101: case 106: - mask3 = (extraP[1] << 8) | extraP[0]; + val3 = params.readUint16LE(); break; default: - mask3 = extraP[0]; + val3 = params.readByte(); break; } @@ -627,15 +650,15 @@ bool Scripts::cmdTakeOrGive(Common::Array ¶ms) { 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 (ifProc(mode1, val1, _event->_opcode == OP_TakeOrGive_4 ? 2 : 1, idx)) { + party.giveTake(0, 0, mode2, val2, 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); + } else if (ifProc(mode1, val1, _event->_opcode == OP_TakeOrGive_4 ? 2 : 1, _charIndex - 1)) { + party.giveTake(0, 0, mode2, val2, _charIndex - 1); } break; @@ -643,16 +666,16 @@ bool Scripts::cmdTakeOrGive(Common::Array ¶ms) { 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 (ifProc(mode1, val1, 1, idx) && ifProc(mode2, val2, 1, idx)) { + party.giveTake(0, 0, mode2, val3, 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); + } else if (ifProc(mode1, val1, 1, _charIndex - 1) && + ifProc(mode2, val2, 1, _charIndex - 1)) { + party.giveTake(0, 0, mode2, val3, _charIndex - 1); } break; @@ -660,15 +683,15 @@ bool Scripts::cmdTakeOrGive(Common::Array ¶ms) { 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 (ifProc(mode1, val1, _event->_opcode == OP_TakeOrGive_4 ? 2 : 1, idx)) { + party.giveTake(0, 0, mode2, val2, idx); if (mode2 == 82) break; } } } - } else if (ifProc(params[0], mask1, 1, _charIndex - 1)) { - party.giveTake(0, 0, mode2, mask2, _charIndex - 1); + } else if (ifProc(mode1, val1, 1, _charIndex - 1)) { + party.giveTake(0, 0, mode2, val2, _charIndex - 1); } break; @@ -676,7 +699,7 @@ bool Scripts::cmdTakeOrGive(Common::Array ¶ms) { 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); + party.giveTake(mode1, val1, mode1, val2, idx); switch (mode1) { case 8: @@ -747,7 +770,7 @@ bool Scripts::cmdTakeOrGive(Common::Array ¶ms) { } } } else { - if (!party.giveTake(mode1, mask1, mode2, mask2, _charIndex - 1)) { + if (!party.giveTake(mode1, val1, mode2, val2, _charIndex - 1)) { if (mode2 == 79) screen.closeWindows(); } @@ -758,7 +781,7 @@ bool Scripts::cmdTakeOrGive(Common::Array ¶ms) { return true; } -bool Scripts::cmdRemove(Common::Array ¶ms) { +bool Scripts::cmdRemove(ParamsIterator ¶ms) { Interface &intf = *_vm->_interface; Map &map = *_vm->_map; @@ -772,8 +795,8 @@ bool Scripts::cmdRemove(Common::Array ¶ms) { return true; } -bool Scripts::cmdSetChar(Common::Array ¶ms) { - if (params[0] != 7) { +bool Scripts::cmdSetChar(ParamsIterator ¶ms) { + if (params.readByte() != 7) { _charIndex = WhoWill::show(_vm, 22, 3, false); if (_charIndex == 0) { return cmdExit(params); @@ -786,83 +809,88 @@ bool Scripts::cmdSetChar(Common::Array ¶ms) { return true; } -bool Scripts::cmdSpawn(Common::Array ¶ms) { +bool Scripts::cmdSpawn(ParamsIterator ¶ms) { Map &map = *_vm->_map; - if (params[0] >= map._mobData._monsters.size()) - map._mobData._monsters.resize(params[0] + 1); + uint index = params.readByte(); + + if (index >= map._mobData._monsters.size()) + map._mobData._monsters.resize(index + 1); - MazeMonster &monster = _vm->_map->_mobData._monsters[params[0]]; + MazeMonster &monster = _vm->_map->_mobData._monsters[index]; MonsterStruct &monsterData = _vm->_map->_monsterData[monster._spriteId]; monster._monsterData = &monsterData; - monster._position.x = params[1]; - monster._position.y = params[2]; + monster._position.x = params.readShort(); + monster._position.y = params.readShort(); monster._frame = _vm->getRandomNumber(7); - monster._damageType = 0; - monster._isAttacking = params[1] != 0; + monster._damageType = DT_PHYSICAL; + monster._isAttacking = false; monster._hp = monsterData._hp; return true; } -bool Scripts::cmdDoTownEvent(Common::Array ¶ms) { - _scriptResult = _vm->_town->townAction(params[0]); +bool Scripts::cmdDoTownEvent(ParamsIterator ¶ms) { + _scriptResult = _vm->_town->townAction(params.readByte()); _vm->_party->_stepped = true; _refreshIcons = true; return cmdExit(params); } -bool Scripts::cmdExit(Common::Array ¶ms) { +bool Scripts::cmdExit(ParamsIterator ¶ms) { _lineNum = -1; return false; } -bool Scripts::cmdAlterMap(Common::Array ¶ms) { +bool Scripts::cmdAlterMap(ParamsIterator ¶ms) { 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]); + int x = params.readShort(); + int y = params.readShort(); + Direction dir = (Direction)params.readByte(); + int val = params.readByte(); + + if (dir == DIR_ALL) { + for (dir = DIR_NORTH; dir <= DIR_WEST; dir = (Direction)((int)dir + 1)) + map.setWall(Common::Point(x, y), dir, val); } else { - map.setWall(Common::Point(params[0], params[1]), (Direction)params[2], params[3]); + map.setWall(Common::Point(x, y), dir, val); } return true; } -bool Scripts::cmdGiveExtended(Common::Array ¶ms) { +bool Scripts::cmdGiveExtended(ParamsIterator ¶ms) { Party &party = *_vm->_party; - uint32 mask; + uint32 val; int newLineNum; bool result; - switch (params[0]) { + int mode = params.readByte(); + switch (mode) { case 16: case 34: case 100: - mask = (params[4] << 24) | params[3] | (params[2] << 8) | (params[1] << 16); - newLineNum = params[5]; + val = params.readUint32LE(); break; case 25: case 35: case 101: case 106: - mask = (params[2] << 8) | params[1]; - newLineNum = params[3]; + val = params.readUint16LE(); break; default: - mask = params[1]; - newLineNum = params[2]; + val = params.readByte(); break; } + newLineNum = params.readByte(); - if ((_charIndex != 0 && _charIndex != 8) || params[0] == 44) { - result = ifProc(params[0], mask, _event->_opcode - OP_If1, _charIndex - 1); + if ((_charIndex != 0 && _charIndex != 8) || mode == 44) { + result = ifProc(mode, val, _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); + result = ifProc(mode, val, _event->_opcode - OP_If1, idx); } } } @@ -875,22 +903,27 @@ bool Scripts::cmdGiveExtended(Common::Array ¶ms) { return true; } -bool Scripts::cmdConfirmEnding(Common::Array ¶ms) { +bool Scripts::cmdConfirmEnding(ParamsIterator ¶ms) { Map &map = *_vm->_map; Party &party = *_vm->_party; - Common::String msg1 = params[2] ? map._events._text[params[2]] : + int inputType = params.readByte(); + int lineNum = params.readByte(); + int param2 = params.readByte(); + int param3 = params.readByte(); + + Common::String msg1 = param2 ? map._events._text[param2] : _vm->_interface->_interfaceText; Common::String msg2; if (_event->_opcode == OP_ConfirmWord_2) { - msg2 = map._events._text[params[3]]; - } else if (params[3]) { + msg2 = map._events._text[param3]; + } else if (param3) { msg2 = ""; } else { msg2 = Res.WHATS_THE_PASSWORD; } - int result = StringInput::show(_vm, params[0], msg1, msg2,_event->_opcode); + int result = StringInput::show(_vm, inputType, msg1, msg2,_event->_opcode); if (result) { if (result == 33 && _vm->_files->_isDarkCc) { doEndGame2(); @@ -920,14 +953,14 @@ bool Scripts::cmdConfirmEnding(Common::Array ¶ms) { } } - _lineNum = result == -1 ? params[3] : params[1]; + _lineNum = result == -1 ? param3 : lineNum; } } return true; } -bool Scripts::cmdDamage(Common::Array ¶ms) { +bool Scripts::cmdDamage(ParamsIterator ¶ms) { Combat &combat = *_vm->_combat; Interface &intf = *_vm->_interface; @@ -936,47 +969,51 @@ bool Scripts::cmdDamage(Common::Array ¶ms) { _redrawDone = true; } - int damage = (params[1] << 8) | params[0]; - combat.giveCharDamage(damage, (DamageType)params[2], _charIndex); + int damage = params.readUint16LE(); + DamageType damageType = (DamageType)params.readByte(); + combat.giveCharDamage(damage, damageType, _charIndex); return true; } -bool Scripts::cmdJumpRnd(Common::Array ¶ms) { - int v = _vm->getRandomNumber(1, params[0]); - if (v == params[1]) { - _lineNum = params[2]; +bool Scripts::cmdJumpRnd(ParamsIterator ¶ms) { + int v = _vm->getRandomNumber(1, params.readByte()); + if (v == params.readByte()) { + _lineNum = params.readByte(); return false; } return true; } -bool Scripts::cmdAlterEvent(Common::Array ¶ms) { +bool Scripts::cmdAlterEvent(ParamsIterator ¶ms) { Map &map = *_vm->_map; Party &party = *_vm->_party; + int lineNum = params.readByte(); + Opcode opcode = (Opcode)params.readByte(); 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]; + evt._line == lineNum) { + evt._opcode = opcode; } } return true; } -bool Scripts::cmdCallEvent(Common::Array ¶ms) { +bool Scripts::cmdCallEvent(ParamsIterator ¶ms) { _stack.push(StackEntry(_currentPos, _lineNum)); - _currentPos = Common::Point(params[0], params[1]); - _lineNum = params[2]; + _currentPos.x = params.readShort(); + _currentPos.y = params.readShort(); + _lineNum = params.readByte(); return false; } -bool Scripts::cmdReturn(Common::Array ¶ms) { +bool Scripts::cmdReturn(ParamsIterator ¶ms) { StackEntry &se = _stack.top(); _currentPos = se; _lineNum = se.line; @@ -984,35 +1021,36 @@ bool Scripts::cmdReturn(Common::Array ¶ms) { return true; } -bool Scripts::cmdSetVar(Common::Array ¶ms) { +bool Scripts::cmdSetVar(ParamsIterator ¶ms) { Party &party = *_vm->_party; uint val; _refreshIcons = true; - switch (params[0]) { + int mode = params.readByte(); + switch (mode) { case 25: case 35: case 101: case 106: - val = (params[2] << 8) | params[1]; + val = params.readUint16LE(); break; case 16: case 34: case 100: - val = (params[4] << 24) | (params[3] << 16) | (params[2] << 8) | params[3]; + val = params.readUint32LE(); break; default: - val = params[1]; + val = params.readByte(); break; } if (_charIndex != 0 && _charIndex != 8) { - party._activeParty[_charIndex - 1].setValue(params[0], val); + party._activeParty[_charIndex - 1].setValue(mode, 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); + party._activeParty[idx].setValue(mode, val); } } } @@ -1020,10 +1058,12 @@ bool Scripts::cmdSetVar(Common::Array ¶ms) { return true; } -bool Scripts::cmdCutsceneEndClouds(Common::Array ¶ms) { error("TODO"); } +bool Scripts::cmdCutsceneEndClouds(ParamsIterator ¶ms) { error("TODO"); } -bool Scripts::cmdWhoWill(Common::Array ¶ms) { - _charIndex = WhoWill::show(_vm, params[0], params[1], true); +bool Scripts::cmdWhoWill(ParamsIterator ¶ms) { + int msg = params.readByte(); + int action = params.readByte(); + _charIndex = WhoWill::show(_vm, msg, action, true); if (_charIndex == 0) return cmdExit(params); @@ -1031,7 +1071,7 @@ bool Scripts::cmdWhoWill(Common::Array ¶ms) { return true; } -bool Scripts::cmdRndDamage(Common::Array ¶ms) { +bool Scripts::cmdRndDamage(ParamsIterator ¶ms) { Combat &combat = *_vm->_combat; Interface &intf = *_vm->_interface; @@ -1040,47 +1080,56 @@ bool Scripts::cmdRndDamage(Common::Array ¶ms) { _redrawDone = true; } - combat.giveCharDamage(_vm->getRandomNumber(1, params[1]), (DamageType)params[0], _charIndex); + DamageType dmgType = (DamageType)params.readByte(); + int max = params.readByte(); + combat.giveCharDamage(_vm->getRandomNumber(1, max), dmgType, _charIndex); return true; } -bool Scripts::cmdMoveWallObj(Common::Array ¶ms) { +bool Scripts::cmdMoveWallObj(ParamsIterator ¶ms) { Map &map = *_vm->_map; + int itemNum = params.readByte(); + int x = params.readShort(); + int y = params.readShort(); - map._mobData._wallItems[params[0]]._position = Common::Point(params[1], params[2]); + map._mobData._wallItems[itemNum]._position = Common::Point(x, y); return true; } -bool Scripts::cmdAlterCellFlag(Common::Array ¶ms) { +bool Scripts::cmdAlterCellFlag(ParamsIterator ¶ms) { Map &map = *_vm->_map; - Common::Point pt(params[0], params[1]); + Common::Point pt; + pt.x = params.readShort(); + pt.y = params.readShort(); + int surfaceId = params.readByte(); + map.cellFlagLookup(pt); if (map._isOutdoors) { MazeWallLayers &wallData = map.mazeDataCurrent()._wallData[pt.y][pt.x]; - wallData._data = (wallData._data & 0xFFF0) | params[2]; + wallData._data = (wallData._data & 0xFFF0) | surfaceId; } else { pt.x &= 0xF; pt.y &= 0xF; MazeCell &cell = map.mazeDataCurrent()._cells[pt.y][pt.x]; - cell._surfaceId = params[2]; + cell._surfaceId = surfaceId; } return true; } -bool Scripts::cmdAlterHed(Common::Array ¶ms) { +bool Scripts::cmdAlterHed(ParamsIterator ¶ms) { 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]; + he._left = params.readByte(); + he._right = params.readByte(); return true; } -bool Scripts::cmdDisplayStat(Common::Array ¶ms) { +bool Scripts::cmdDisplayStat(ParamsIterator ¶ms) { Party &party = *_vm->_party; Window &w = _vm->_screen->_windows[12]; Character &c = party._activeParty[_charIndex - 1]; @@ -1093,7 +1142,7 @@ bool Scripts::cmdDisplayStat(Common::Array ¶ms) { return true; } -bool Scripts::cmdSignTextSml(Common::Array ¶ms) { +bool Scripts::cmdSignTextSml(ParamsIterator ¶ms) { Interface &intf = *_vm->_interface; intf._screenText = Common::String::format("\x2\f08\x3""c\t116\v090%s\x3l\fd\x1", @@ -1104,75 +1153,79 @@ bool Scripts::cmdSignTextSml(Common::Array ¶ms) { return true; } -bool Scripts::cmdPlayEventVoc(Common::Array ¶ms) { +bool Scripts::cmdPlayEventVoc(ParamsIterator ¶ms) { Sound &sound = *_vm->_sound; sound.stopSound(); - sound.playSound(Res.EVENT_SAMPLES[params[0]], 1); + sound.playSound(Res.EVENT_SAMPLES[params.readByte()], 1); return true; } -bool Scripts::cmdDisplayBottom(Common::Array ¶ms) { +bool Scripts::cmdDisplayBottom(ParamsIterator ¶ms) { _windowIndex = 12; display(false, 0); return true; } -bool Scripts::cmdIfMapFlag(Common::Array ¶ms) { +bool Scripts::cmdIfMapFlag(ParamsIterator ¶ms) { Map &map = *_vm->_map; - MazeMonster &monster = map._mobData._monsters[params[0]]; + MazeMonster &monster = map._mobData._monsters[params.readByte()]; if (monster._position.x >= 32 || monster._position.y >= 32) { - _lineNum = params[1]; + _lineNum = params.readByte(); return false; } return true; } -bool Scripts::cmdSelectRandomChar(Common::Array ¶ms) { +bool Scripts::cmdSelectRandomChar(ParamsIterator ¶ms) { _charIndex = _vm->getRandomNumber(1, _vm->_party->_activeParty.size()); return true; } -bool Scripts::cmdGiveEnchanted(Common::Array ¶ms) { +bool Scripts::cmdGiveEnchanted(ParamsIterator ¶ms) { Party &party = *_vm->_party; - if (params[0] >= 35) { - if (params[0] < 49) { + 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 = params[0] - 35; - item._material = params[1]; - item._bonusFlags = params[2]; + item._id = id - 35; + item._material = material; + item._bonusFlags = flags; party._treasure._hasItems = true; break; } } return true; - } else if (params[0] < 60) { + } else if (id < 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]; + item._id = id - 49; + item._material = material; + item._bonusFlags = flags; party._treasure._hasItems = true; break; } } return true; - } else if (params[0] < 82) { + } else if (id < 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]; + item._id = id; + item._material = material; + item._bonusFlags = flags; party._treasure._hasItems = true; break; } @@ -1187,9 +1240,9 @@ bool Scripts::cmdGiveEnchanted(Common::Array ¶ms) { 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]; + item._id = id; + item._material = material; + item._bonusFlags = flags; party._treasure._hasItems = true; break; } @@ -1198,13 +1251,13 @@ bool Scripts::cmdGiveEnchanted(Common::Array ¶ms) { return true; } -bool Scripts::cmdItemType(Common::Array ¶ms) { - _itemType = params[0]; +bool Scripts::cmdItemType(ParamsIterator ¶ms) { + _itemType = params.readByte(); return true; } -bool Scripts::cmdMakeNothingHere(Common::Array ¶ms) { +bool Scripts::cmdMakeNothingHere(ParamsIterator ¶ms) { Map &map = *_vm->_map; Party &party = *_vm->_party; @@ -1219,31 +1272,33 @@ bool Scripts::cmdMakeNothingHere(Common::Array ¶ms) { return cmdExit(params); } -bool Scripts::cmdCheckProtection(Common::Array ¶ms) { +bool Scripts::cmdCheckProtection(ParamsIterator ¶ms) { if (copyProtectionCheck()) return true; else return cmdExit(params); } -bool Scripts::cmdChooseNumeric(Common::Array ¶ms) { - int choice = Choose123::show(_vm, params[0]); +bool Scripts::cmdChooseNumeric(ParamsIterator ¶ms) { + int choice = Choose123::show(_vm, params.readByte()); if (choice) { - _lineNum = params[choice]; + _lineNum = _event->_parameters[choice]; return false; } return true; } -bool Scripts::cmdDisplayBottomTwoLines(Common::Array ¶ms) { +bool Scripts::cmdDisplayBottomTwoLines(ParamsIterator ¶ms) { Map &map = *_vm->_map; Window &w = _vm->_screen->_windows[12]; - warning("TODO: cmdDisplayBottomTwoLines"); + params.readByte(); + int textId = params.readByte(); + Common::String msg = Common::String::format("\r\x03c\t000\v007%s\n\n%s", "", - map._events._text[params[1]].c_str()); + map._events._text[textId].c_str()); w.close(); w.open(); w.writeString(msg); @@ -1254,16 +1309,18 @@ bool Scripts::cmdDisplayBottomTwoLines(Common::Array ¶ms) { return false; } -bool Scripts::cmdDisplayLarge(Common::Array ¶ms) { +bool Scripts::cmdDisplayLarge(ParamsIterator ¶ms) { error("TODO: Implement event text loading"); display(true, 0); return true; } -bool Scripts::cmdExchObj(Common::Array ¶ms) { - MazeObject &obj1 = _vm->_map->_mobData._objects[params[0]]; - MazeObject &obj2 = _vm->_map->_mobData._objects[params[1]]; +bool Scripts::cmdExchObj(ParamsIterator ¶ms) { + int id1 = params.readByte(), id2 = params.readByte(); + + MazeObject &obj1 = _vm->_map->_mobData._objects[id1]; + MazeObject &obj2 = _vm->_map->_mobData._objects[id2]; Common::Point pt = obj1._position; obj1._position = obj2._position; @@ -1272,40 +1329,41 @@ bool Scripts::cmdExchObj(Common::Array ¶ms) { return true; } -bool Scripts::cmdFallToMap(Common::Array ¶ms) { +bool Scripts::cmdFallToMap(ParamsIterator ¶ms) { Interface &intf = *_vm->_interface; Party &party = *_vm->_party; - party._fallMaze = params[0]; - party._fallPosition = Common::Point(params[1], params[2]); - party._fallDamage = params[3]; + party._fallMaze = params.readByte(); + party._fallPosition.x = params.readShort(); + party._fallPosition.y = params.readShort(); + party._fallDamage = params.readByte(); intf.startFalling(true); _lineNum = -1; return false; } -bool Scripts::cmdDisplayMain(Common::Array ¶ms) { +bool Scripts::cmdDisplayMain(ParamsIterator ¶ms) { display(false, 0); return true; } -bool Scripts::cmdGoto(Common::Array ¶ms) { +bool Scripts::cmdGoto(ParamsIterator ¶ms) { Map &map = *_vm->_map; map.getCell(1); - if (params[0] == map._currentSurfaceId) { - _lineNum = params[1]; + if (map._currentSurfaceId == params.readByte()) { + _lineNum = params.readByte(); return false; } return true; } -bool Scripts::cmdGotoRandom(Common::Array ¶ms) { - _lineNum = params[_vm->getRandomNumber(1, params[0])]; +bool Scripts::cmdGotoRandom(ParamsIterator ¶ms) { + _lineNum = _event->_parameters[_vm->getRandomNumber(1, params.readByte())]; return false; } -bool Scripts::cmdCutsceneEndDarkside(Common::Array ¶ms) { +bool Scripts::cmdCutsceneEndDarkside(ParamsIterator ¶ms) { Party &party = *_vm->_party; _vm->_saves->_wonDarkSide = true; party._questItems[53] = 1; @@ -1318,7 +1376,7 @@ bool Scripts::cmdCutsceneEndDarkside(Common::Array ¶ms) { return false; } -bool Scripts::cmdCutsceneEndWorld(Common::Array ¶ms) { +bool Scripts::cmdCutsceneEndWorld(ParamsIterator ¶ms) { _vm->_saves->_wonWorld = true; _vm->_party->_worldEnd = true; @@ -1326,12 +1384,12 @@ bool Scripts::cmdCutsceneEndWorld(Common::Array ¶ms) { return false; } -bool Scripts::cmdFlipWorld(Common::Array ¶ms) { - _vm->_map->_loadDarkSide = params[0] != 0; +bool Scripts::cmdFlipWorld(ParamsIterator ¶ms) { + _vm->_map->_loadDarkSide = params.readByte() != 0; return true; } -bool Scripts::cmdPlayCD(Common::Array ¶ms) { error("TODO"); } +bool Scripts::cmdPlayCD(ParamsIterator ¶ms) { error("TODO"); } void Scripts::doEndGame() { doEnding("ENDGAME", 0); diff --git a/engines/xeen/scripts.h b/engines/xeen/scripts.h index e1c4fa8014..df02fdc2ee 100644 --- a/engines/xeen/scripts.h +++ b/engines/xeen/scripts.h @@ -99,13 +99,52 @@ enum Opcode { class XeenEngine; +class EventParameters : public Common::Array { +public: + class Iterator { + private: + uint _index; + const EventParameters &_data; + public: + Iterator(const EventParameters &owner) : _data(owner), _index(0) {} + Iterator(const Iterator &it) : _data(it._data), _index(0) {} + + /** + * Return a byte + */ + byte readByte(); + + /** + * Return a signed byte + */ + int8 readShort() { return (int8)readByte(); } + + /** + * Return a word + */ + uint16 readUint16LE(); + + /** + * Return a 32-bit dword + */ + uint32 readUint32LE(); + }; +public: + /** + * Return an iterator for getting parameters + */ + Iterator getIterator() const { + return Iterator(*this); + } +}; + class MazeEvent { public: Common::Point _position; int _direction; int _line; Opcode _opcode; - Common::Array _parameters; + EventParameters _parameters; public: MazeEvent(); @@ -155,6 +194,8 @@ private: Common::String _message; Common::String _displayMessage; + typedef EventParameters::Iterator ParamsIterator; + /** * Handles executing a given script command */ @@ -163,279 +204,279 @@ private: /** * Do nothing */ - bool cmdDoNothing(Common::Array ¶ms); + bool cmdDoNothing(ParamsIterator ¶ms); /** * Display a msesage on-screen */ - bool cmdDisplay1(Common::Array ¶ms); + bool cmdDisplay1(ParamsIterator ¶ms); /** * Displays a door text message using the small font */ - bool cmdDoorTextSml(Common::Array ¶ms); + bool cmdDoorTextSml(ParamsIterator ¶ms); /** * Displays a door text message using the large font */ - bool cmdDoorTextLrg(Common::Array ¶ms); + bool cmdDoorTextLrg(ParamsIterator ¶ms); /** * Show a sign text on-screen */ - bool cmdSignText(Common::Array ¶ms); + bool cmdSignText(ParamsIterator ¶ms); /** * Show an NPC interaction message */ - bool cmdNPC(Common::Array ¶ms); + bool cmdNPC(ParamsIterator ¶ms); /** * Play a sound FX */ - bool cmdPlayFX(Common::Array ¶ms); + bool cmdPlayFX(ParamsIterator ¶ms); /** * Handles teleportation */ - bool cmdTeleport(Common::Array ¶ms); + bool cmdTeleport(ParamsIterator ¶ms); /** * Do a conditional check */ - bool cmdIf(Common::Array ¶ms); + bool cmdIf(ParamsIterator ¶ms); /** * Moves the position of an object */ - bool cmdMoveObj(Common::Array ¶ms); + bool cmdMoveObj(ParamsIterator ¶ms); /** * Take or give amounts from various character or party figures */ - bool cmdTakeOrGive(Common::Array ¶ms); + bool cmdTakeOrGive(ParamsIterator ¶ms); /** * Removes an object from the playfield */ - bool cmdRemove(Common::Array ¶ms); + bool cmdRemove(ParamsIterator ¶ms); /** * Set the currently active character for other script operations */ - bool cmdSetChar(Common::Array ¶ms); + bool cmdSetChar(ParamsIterator ¶ms); /** * Spawn a monster */ - bool cmdSpawn(Common::Array ¶ms); + bool cmdSpawn(ParamsIterator ¶ms); /** * Does various things that can be done within towns, like visiting * banks, guilds, etc. */ - bool cmdDoTownEvent(Common::Array ¶ms); + bool cmdDoTownEvent(ParamsIterator ¶ms); /** * Stop executing the script */ - bool cmdExit(Common::Array ¶ms); + bool cmdExit(ParamsIterator ¶ms); /** * Changes the value for the wall on a given cell */ - bool cmdAlterMap(Common::Array ¶ms); + bool cmdAlterMap(ParamsIterator ¶ms); /** * */ - bool cmdGiveExtended(Common::Array ¶ms); + bool cmdGiveExtended(ParamsIterator ¶ms); /** * Confirms with the player for initiating the endgame */ - bool cmdConfirmEnding(Common::Array ¶ms); + bool cmdConfirmEnding(ParamsIterator ¶ms); /** * Deals damage to a character */ - bool cmdDamage(Common::Array ¶ms); + bool cmdDamage(ParamsIterator ¶ms); /** * Jump if a random number matches a given value */ - bool cmdJumpRnd(Common::Array ¶ms); + bool cmdJumpRnd(ParamsIterator ¶ms); /** * Alter an existing event */ - bool cmdAlterEvent(Common::Array ¶ms); + bool cmdAlterEvent(ParamsIterator ¶ms); /** * Stores the current location and line for later resuming, and set up to execute * a script at a given location */ - bool cmdCallEvent(Common::Array ¶ms); + bool cmdCallEvent(ParamsIterator ¶ms); /** * Return from executing a script to the script location that previously * called the script */ - bool cmdReturn(Common::Array ¶ms); + bool cmdReturn(ParamsIterator ¶ms); /** * Sets variables on characters like race, sex, and class */ - bool cmdSetVar(Common::Array ¶ms); + bool cmdSetVar(ParamsIterator ¶ms); /** * Play the Clouds endgame */ - bool cmdCutsceneEndClouds(Common::Array ¶ms); + bool cmdCutsceneEndClouds(ParamsIterator ¶ms); /** * Prompts the user for which character will do an action */ - bool cmdWhoWill(Common::Array ¶ms); + bool cmdWhoWill(ParamsIterator ¶ms); /** * Deals a random amount of damage to a character */ - bool cmdRndDamage(Common::Array ¶ms); + bool cmdRndDamage(ParamsIterator ¶ms); /** * Moves the wall object to the given coordinates. Doesn't change it's orientation. * Wall objects are only visible when viewed straight on, and were never intended * to be anywhere but on squares directly facing walls */ - bool cmdMoveWallObj(Common::Array ¶ms); + bool cmdMoveWallObj(ParamsIterator ¶ms); /** * Sets the cell flag at the specified X/Y coordinate on the current map */ - bool cmdAlterCellFlag(Common::Array ¶ms); + bool cmdAlterCellFlag(ParamsIterator ¶ms); /** * Sets the word value at the current X/Y location in the HED file * in memory to the given two bytes */ - bool cmdAlterHed(Common::Array ¶ms); + bool cmdAlterHed(ParamsIterator ¶ms); /** * Displays a text string which includes some stat of the currently selected character */ - bool cmdDisplayStat(Common::Array ¶ms); + bool cmdDisplayStat(ParamsIterator ¶ms); /** * Displays text in the scene window for various objects * the user interacts with */ - bool cmdSignTextSml(Common::Array ¶ms); + bool cmdSignTextSml(ParamsIterator ¶ms); /** * An array of six VOC filenames are hard-coded into the game executable file. * This function plays the VOC file at the specified index in this array */ - bool cmdPlayEventVoc(Common::Array ¶ms); + bool cmdPlayEventVoc(ParamsIterator ¶ms); /** * Displays a large text message across the bottom of the screen */ - bool cmdDisplayBottom(Common::Array ¶ms); + bool cmdDisplayBottom(ParamsIterator ¶ms); /** * Checks if a given map flag/monster has been set, and if so * jumps to a given line */ - bool cmdIfMapFlag(Common::Array ¶ms); + bool cmdIfMapFlag(ParamsIterator ¶ms); /** * Selects a random character for further other actions */ - bool cmdSelectRandomChar(Common::Array ¶ms); + bool cmdSelectRandomChar(ParamsIterator ¶ms); /** * Gives an enchanted item to a character */ - bool cmdGiveEnchanted(Common::Array ¶ms); + bool cmdGiveEnchanted(ParamsIterator ¶ms); /** * Sets the item category for used in character operations */ - bool cmdItemType(Common::Array ¶ms); + bool cmdItemType(ParamsIterator ¶ms); /** * Disable all the scripts at the party's current position */ - bool cmdMakeNothingHere(Common::Array ¶ms); + bool cmdMakeNothingHere(ParamsIterator ¶ms); /** * Does a copy protection check */ - bool cmdCheckProtection(Common::Array ¶ms); + bool cmdCheckProtection(ParamsIterator ¶ms); /** * Given a number of options, and a list of line numbers associated with * those options, jumps to whichever line for the option the user selects */ - bool cmdChooseNumeric(Common::Array ¶ms); + bool cmdChooseNumeric(ParamsIterator ¶ms); /** * Displays a two line message at the bottom of the screen */ - bool cmdDisplayBottomTwoLines(Common::Array ¶ms); + bool cmdDisplayBottomTwoLines(ParamsIterator ¶ms); /** * Displays a message */ - bool cmdDisplayLarge(Common::Array ¶ms); + bool cmdDisplayLarge(ParamsIterator ¶ms); /** * Exchange the positions of two objects in the maze */ - bool cmdExchObj(Common::Array ¶ms); + bool cmdExchObj(ParamsIterator ¶ms); /** * Handles making the player fall down to the ground */ - bool cmdFallToMap(Common::Array ¶ms); + bool cmdFallToMap(ParamsIterator ¶ms); /** * Displays a message */ - bool cmdDisplayMain(Common::Array ¶ms); + bool cmdDisplayMain(ParamsIterator ¶ms); /** * Jumps to a given line number if the surface at relative cell position 1 matches * a specified surface. * @remarks This opcode is apparently never actually used */ - bool cmdGoto(Common::Array ¶ms); + bool cmdGoto(ParamsIterator ¶ms); /** * Pick a random value from the parameter list and jump to that line number */ - bool cmdGotoRandom(Common::Array ¶ms); + bool cmdGotoRandom(ParamsIterator ¶ms); /** * Plays the Dark Side of Xeen ending */ - bool cmdCutsceneEndDarkside(Common::Array ¶ms); + bool cmdCutsceneEndDarkside(ParamsIterator ¶ms); /** * Plays the World of Xeen ending */ - bool cmdCutsceneEndWorld(Common::Array ¶ms); + bool cmdCutsceneEndWorld(ParamsIterator ¶ms); /** * Switches the player between the Clouds and Dark Side */ - bool cmdFlipWorld(Common::Array ¶ms); + bool cmdFlipWorld(ParamsIterator ¶ms); /** * Plays a CD track */ - bool cmdPlayCD(Common::Array ¶ms); + bool cmdPlayCD(ParamsIterator ¶ms); int whoWill(int v1, int v2, int v3); -- cgit v1.2.3