diff options
author | Walter van Niftrik | 2016-12-16 15:29:02 +0100 |
---|---|---|
committer | Walter van Niftrik | 2016-12-16 15:29:38 +0100 |
commit | 1f801bee433624e8bde214264a2d0c2359be4c13 (patch) | |
tree | 454fc71b488a34c2ffd17910589d2ce0f6a0c716 /engines/adl | |
parent | f29a2f31f1e37ee733f1015c3d36df798c755172 (diff) | |
download | scummvm-rg350-1f801bee433624e8bde214264a2d0c2359be4c13.tar.gz scummvm-rg350-1f801bee433624e8bde214264a2d0c2359be4c13.tar.bz2 scummvm-rg350-1f801bee433624e8bde214264a2d0c2359be4c13.zip |
ADL: Partially implement hires5 opcodes
Diffstat (limited to 'engines/adl')
-rw-r--r-- | engines/adl/adl.cpp | 22 | ||||
-rw-r--r-- | engines/adl/adl.h | 11 | ||||
-rw-r--r-- | engines/adl/adl_v2.cpp | 2 | ||||
-rw-r--r-- | engines/adl/adl_v4.cpp | 212 | ||||
-rw-r--r-- | engines/adl/adl_v4.h | 18 | ||||
-rw-r--r-- | engines/adl/hires5.cpp | 157 |
6 files changed, 413 insertions, 9 deletions
diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 76f5bac5b5..0d96cb67af 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -428,6 +428,20 @@ void AdlEngine::bell(uint count) const { _speaker->bell(count); } +const Region &AdlEngine::getRegion(uint i) const { + if (i < 1 || i > _state.regions.size()) + error("Region %i out of range [1, %i]", i, _state.regions.size()); + + return _state.regions[i - 1]; +} + +Region &AdlEngine::getRegion(uint i) { + if (i < 1 || i > _state.regions.size()) + error("Region %i out of range [1, %i]", i, _state.regions.size()); + + return _state.regions[i - 1]; +} + const Room &AdlEngine::getRoom(uint i) const { if (i < 1 || i > _state.rooms.size()) error("Room %i out of range [1, %i]", i, _state.rooms.size()); @@ -442,6 +456,14 @@ Room &AdlEngine::getRoom(uint i) { return _state.rooms[i - 1]; } +const Region &AdlEngine::getCurRegion() const { + return getRegion(_state.region); +} + +Region &AdlEngine::getCurRegion() { + return getRegion(_state.region); +} + const Room &AdlEngine::getCurRoom() const { return getRoom(_state.room); } diff --git a/engines/adl/adl.h b/engines/adl/adl.h index 06be0e072d..a825200587 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -143,6 +143,7 @@ enum { struct Item { byte id; byte noun; + byte region; byte room; byte picture; bool isLineArt; @@ -175,14 +176,14 @@ struct State { Common::List<Item> items; Common::Array<byte> vars; - byte region; + byte region, prevRegion; byte room; byte curPicture; uint16 moves; bool isDark; Time time; - State() : region(0), room(1), curPicture(0), moves(1), isDark(false) { } + State() : region(0), prevRegion(0), room(1), curPicture(0), moves(1), isDark(false) { } }; typedef Common::List<Command> Commands; @@ -300,8 +301,12 @@ protected: void bell(uint count = 1) const; // Game state functions + const Region &getRegion(uint i) const; + Region &getRegion(uint i); const Room &getRoom(uint i) const; Room &getRoom(uint i); + const Region &getCurRegion() const; + Region &getCurRegion(); const Room &getCurRoom() const; Room &getCurRoom(); const Item &getItem(uint i) const; @@ -309,7 +314,7 @@ protected: byte getVar(uint i) const; void setVar(uint i, byte value); virtual void takeItem(byte noun); - void dropItem(byte noun); + virtual void dropItem(byte noun); bool matchCommand(ScriptEnv &env) const; void doActions(ScriptEnv &env); bool doOneCommand(const Commands &commands, byte verb, byte noun); diff --git a/engines/adl/adl_v2.cpp b/engines/adl/adl_v2.cpp index 45810d64ca..b34d4c9a06 100644 --- a/engines/adl/adl_v2.cpp +++ b/engines/adl/adl_v2.cpp @@ -372,7 +372,7 @@ void AdlEngine_v2::loadItems(Common::ReadStream &stream) { item.noun = stream.readByte(); item.room = stream.readByte(); item.picture = stream.readByte(); - item.isLineArt = stream.readByte(); // Disk number in later games + item.region = stream.readByte(); item.position.x = stream.readByte(); item.position.y = stream.readByte(); item.state = stream.readByte(); diff --git a/engines/adl/adl_v4.cpp b/engines/adl/adl_v4.cpp index 00a393facc..6dfee8084a 100644 --- a/engines/adl/adl_v4.cpp +++ b/engines/adl/adl_v4.cpp @@ -195,13 +195,14 @@ void AdlEngine_v4::loadRegion(byte region) { break; } case 0x7b00: - // Global commands - readCommands(*stream, _globalCommands); - break; - case 0x9500: + // TODO: hires6 has global and room lists swapped // Room commands readCommands(*stream, _roomCommands); break; + case 0x9500: + // Global commands + readCommands(*stream, _globalCommands); + break; default: error("Unknown data block found (addr %04x; size %04x)", addr, size); } @@ -216,6 +217,8 @@ void AdlEngine_v4::loadRegion(byte region) { } } } + + restoreVars(); } void AdlEngine_v4::loadItemPicIndex(Common::ReadStream &stream, uint items) { @@ -225,4 +228,205 @@ void AdlEngine_v4::loadItemPicIndex(Common::ReadStream &stream, uint items) { error("Error reading item index"); } +void AdlEngine_v4::backupRoomState(byte room) { + RoomState &backup = getCurRegion().rooms[room - 1]; + + backup.isFirstTime = getRoom(room).isFirstTime; + backup.picture = getRoom(room).picture; +} + +void AdlEngine_v4::restoreRoomState(byte room) { + const RoomState &backup = getCurRegion().rooms[room - 1]; + + getRoom(room).isFirstTime = backup.isFirstTime; + getRoom(room).picture = backup.picture; +} + +void AdlEngine_v4::backupVars() { + Region ®ion = getCurRegion(); + + for (uint i = 0; i < region.vars.size(); ++i) + region.vars[i] = getVar(i); +} + +void AdlEngine_v4::restoreVars() { + const Region ®ion = getCurRegion(); + + for (uint i = 0; i < region.vars.size(); ++i) + setVar(i, region.vars[i]); +} + +void AdlEngine_v4::switchRegion(byte region) { + backupVars(); + backupRoomState(_state.room); + _state.prevRegion = _state.region; + _state.region = region; + loadRegion(region); + _state.room = 1; + _picOnScreen = _roomOnScreen = 0; +} + +// TODO: Merge this into v2? +void AdlEngine_v4::takeItem(byte noun) { + Common::List<Item>::iterator item; + + for (item = _state.items.begin(); item != _state.items.end(); ++item) { + if (item->noun != noun || item->room != _state.room || item->region != _state.region) + continue; + + if (item->state == IDI_ITEM_DOESNT_MOVE) { + printMessage(_messageIds.itemDoesntMove); + return; + } + + if (item->state == IDI_ITEM_DROPPED) { + item->room = IDI_ANY; + _itemRemoved = true; + return; + } + + Common::Array<byte>::const_iterator pic; + for (pic = item->roomPictures.begin(); pic != item->roomPictures.end(); ++pic) { + if (*pic == getCurRoom().curPicture || *pic == IDI_ANY) { + if (!isInventoryFull()) { + item->room = IDI_ANY; + _itemRemoved = true; + item->state = IDI_ITEM_DROPPED; + } + return; + } + } + } + + printMessage(_messageIds.itemNotHere); +} + +// TODO: Merge this into v2? +void AdlEngine_v4::dropItem(byte noun) { + Common::List<Item>::iterator item; + + for (item = _state.items.begin(); item != _state.items.end(); ++item) { + if (item->noun != noun || item->room != IDI_ANY) + continue; + + item->room = _state.room; + item->region = _state.region; + item->state = IDI_ITEM_DROPPED; + return; + } + + printMessage(_messageIds.dontUnderstand); +} + +int AdlEngine_v4::o4_isItemInRoom(ScriptEnv &e) { + OP_DEBUG_2("\t&& GET_ITEM_ROOM(%s) == %s", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str()); + + const Item &item = getItem(e.arg(1)); + + if (e.arg(2) != IDI_ANY && item.region != _state.region) + return -1; + + if (item.room == roomArg(e.arg(2))) + return 2; + + return -1; +} + +int AdlEngine_v4::o4_isVarGT(ScriptEnv &e) { + OP_DEBUG_2("\t&& VARS[%d] > %d", e.arg(1), e.arg(2)); + + if (getVar(e.arg(1)) > e.arg(2)) + return 2; + + return -1; +} + +int AdlEngine_v4::o4_moveItem(ScriptEnv &e) { + o2_moveItem(e); + getItem(e.arg(1)).region = _state.region; + return 2; +} + +int AdlEngine_v4::o4_setRoom(ScriptEnv &e) { + OP_DEBUG_1("\tROOM = %d", e.arg(1)); + + getCurRoom().curPicture = getCurRoom().picture; + getCurRoom().isFirstTime = false; + backupRoomState(_state.room); + _state.room = e.arg(1); + restoreRoomState(_state.room); + return 1; +} + +int AdlEngine_v4::o4_setRegionToPrev(ScriptEnv &e) { + OP_DEBUG_0("\tREGION = PREV_REGION"); + + switchRegion(_state.prevRegion); + // Long jump + _isRestarting = true; + return -1; +} + +int AdlEngine_v4::o4_moveAllItems(ScriptEnv &e) { + OP_DEBUG_2("\tMOVE_ALL_ITEMS(%s, %s)", itemRoomStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str()); + + byte room1 = roomArg(e.arg(1)); + + if (room1 == _state.room) + _picOnScreen = 0; + + byte room2 = roomArg(e.arg(2)); + + Common::List<Item>::iterator item; + + for (item = _state.items.begin(); item != _state.items.end(); ++item) { + if (room1 != item->room) + continue; + + if (room1 != IDI_ANY) { + if (_state.region != item->region) + continue; + if (room2 == IDI_ANY) { + if (isInventoryFull()) + break; + if (item->state == IDI_ITEM_DOESNT_MOVE) + continue; + } + } + + item->room = room2; + item->region = _state.region; + + if (room1 == IDI_ANY) + item->state = IDI_ITEM_DROPPED; + } + + return 2; +} + +int AdlEngine_v4::o4_setRegion(ScriptEnv &e) { + OP_DEBUG_1("\tREGION = %d", e.arg(1)); + + switchRegion(e.arg(1)); + // Long jump + _isRestarting = true; + return -1; +} + +int AdlEngine_v4::o4_setRegionRoom(ScriptEnv &e) { + OP_DEBUG_2("\tSET_REGION_ROOM(%d, %d)", e.arg(1), e.arg(2)); + + switchRegion(e.arg(1)); + _state.room = e.arg(2); + // Long jump + _isRestarting = true; + return -1; +} + +int AdlEngine_v4::o4_setRoomPic(ScriptEnv &e) { + o1_setRoomPic(e); + backupRoomState(e.arg(1)); + return 2; +} + } // End of namespace Adl diff --git a/engines/adl/adl_v4.h b/engines/adl/adl_v4.h index 2a5ceb422d..8516e40bd2 100644 --- a/engines/adl/adl_v4.h +++ b/engines/adl/adl_v4.h @@ -63,6 +63,24 @@ protected: void fixupDiskOffset(byte &track, byte §or) const; void loadRegion(byte region); void loadItemPicIndex(Common::ReadStream &stream, uint items); + void backupRoomState(byte room); + void restoreRoomState(byte room); + void backupVars(); + void restoreVars(); + void switchRegion(byte region); + virtual bool isInventoryFull() { return false; } + virtual void takeItem(byte noun); + virtual void dropItem(byte noun); + + int o4_isItemInRoom(ScriptEnv &e); + int o4_isVarGT(ScriptEnv &e); + int o4_moveItem(ScriptEnv &e); + int o4_setRoom(ScriptEnv &e); + int o4_setRegionToPrev(ScriptEnv &e); + int o4_moveAllItems(ScriptEnv &e); + int o4_setRegion(ScriptEnv &e); + int o4_setRegionRoom(ScriptEnv &e); + int o4_setRoomPic(ScriptEnv &e); byte _currentVolume; Common::Array<RegionLocation> _regionLocations; diff --git a/engines/adl/hires5.cpp b/engines/adl/hires5.cpp index d33fd8a18a..f298cecf55 100644 --- a/engines/adl/hires5.cpp +++ b/engines/adl/hires5.cpp @@ -41,14 +41,159 @@ public: private: // AdlEngine + void setupOpcodeTables(); void runIntro(); void init(); void initGameState(); + // AdlEngine_v4 + bool isInventoryFull(); + + int o_checkItemTimeLimits(ScriptEnv &e); + int o_startAnimation(ScriptEnv &e); + int o_winGame(ScriptEnv &e); + static const uint kRegions = 41; static const uint kItems = 69; + + Common::Array<byte> _itemTimeLimits; + Common::String _itemTimeLimitMsg; + + struct { + Common::String itemTimeLimit; + Common::String carryingTooMuch; + } _gameStrings; }; +typedef Common::Functor1Mem<ScriptEnv &, int, HiRes5Engine> OpcodeH5; +#define SetOpcodeTable(x) table = &x; +#define Opcode(x) table->push_back(new OpcodeH5(this, &HiRes5Engine::x)) +#define OpcodeUnImpl() table->push_back(new OpcodeH5(this, 0)) + +void HiRes5Engine::setupOpcodeTables() { + Common::Array<const Opcode *> *table = 0; + + SetOpcodeTable(_condOpcodes); + // 0x00 + OpcodeUnImpl(); + Opcode(o2_isFirstTime); + Opcode(o2_isRandomGT); + Opcode(o4_isItemInRoom); + // 0x04 + Opcode(o3_isNounNotInRoom); + Opcode(o1_isMovesGT); + Opcode(o1_isVarEQ); + Opcode(o2_isCarryingSomething); + // 0x08 + Opcode(o4_isVarGT); + Opcode(o1_isCurPicEQ); + OpcodeUnImpl(); + + SetOpcodeTable(_actOpcodes); + // 0x00 + OpcodeUnImpl(); + Opcode(o1_varAdd); + Opcode(o1_varSub); + Opcode(o1_varSet); + // 0x04 + Opcode(o1_listInv); + Opcode(o4_moveItem); + Opcode(o4_setRoom); + Opcode(o2_setCurPic); + // 0x08 + Opcode(o2_setPic); + Opcode(o1_printMsg); + Opcode(o4_setRegionToPrev); + Opcode(o_checkItemTimeLimits); + // 0x0c + Opcode(o4_moveAllItems); + Opcode(o1_quit); + Opcode(o4_setRegion); + Opcode(o2_save); // TODO + // 0x10 + Opcode(o2_restore); // TODO + Opcode(o1_restart); // TODO + Opcode(o4_setRegionRoom); + Opcode(o_startAnimation); + // 0x14 + Opcode(o1_resetPic); + Opcode(o1_goDirection<IDI_DIR_NORTH>); + Opcode(o1_goDirection<IDI_DIR_SOUTH>); + Opcode(o1_goDirection<IDI_DIR_EAST>); + // 0x18 + Opcode(o1_goDirection<IDI_DIR_WEST>); + Opcode(o1_goDirection<IDI_DIR_UP>); + Opcode(o1_goDirection<IDI_DIR_DOWN>); + Opcode(o1_takeItem); + // 0x1c + Opcode(o1_dropItem); + Opcode(o4_setRoomPic); + Opcode(o_winGame); + OpcodeUnImpl(); + // 0x20 + Opcode(o2_initDisk); +} + +bool HiRes5Engine::isInventoryFull() { + Common::List<Item>::const_iterator item; + byte weight = 0; + + for (item = _state.items.begin(); item != _state.items.end(); ++item) { + if (item->room == IDI_ANY) + weight += item->description; + } + + if (weight >= 100) { + printString(_gameStrings.carryingTooMuch); + inputString(); + return true; + } + + return false; +} + +int HiRes5Engine::o_checkItemTimeLimits(ScriptEnv &e) { + OP_DEBUG_1("\tCHECK_ITEM_TIME_LIMITS(VARS[%d])", e.arg(1)); + + bool lostAnItem = false; + Common::List<Item>::iterator item; + + for (item = _state.items.begin(); item != _state.items.end(); ++item) { + const byte room = item->room; + const byte region = item->region; + + if (room == IDI_ANY || room == IDI_CUR_ROOM || (room == _state.room && region == _state.region)) { + if (getVar(e.arg(1)) < _itemTimeLimits[item->id - 1]) { + item->room = IDI_VOID_ROOM; + lostAnItem = true; + } + } + } + + if (lostAnItem) { + printString(_gameStrings.itemTimeLimit); + inputString(); + } + + return 1; +} + +int HiRes5Engine::o_startAnimation(ScriptEnv &e) { + OP_DEBUG_0("\tSTART_ANIMATION()"); + + // TODO: sets a flag that triggers an animation + + return 0; +} + +int HiRes5Engine::o_winGame(ScriptEnv &e) { + OP_DEBUG_0("\tWIN_GAME()"); + + // TODO: draws room and plays music + + return o1_quit(e); +} + void HiRes5Engine::runIntro() { insertDisk(2); @@ -114,8 +259,18 @@ void HiRes5Engine::init() { stream.reset(_disk->createReadStream(0xb, 0xa, 0x05, 1)); loadItemPicIndex(*stream, kItems); + stream.reset(_disk->createReadStream(0x7, 0x8, 0x01)); + for (uint i = 0; i < kItems; ++i) + _itemTimeLimits.push_back(stream->readByte()); + if (stream->eos() || stream->err()) - error("Error reading item index"); + error("Failed to read item time limits"); + + stream.reset(_disk->createReadStream(0x8, 0x2, 0x2d)); + _gameStrings.itemTimeLimit = readString(*stream); + + stream.reset(_disk->createReadStream(0x8, 0x7, 0x02)); + _gameStrings.carryingTooMuch = readString(*stream); } void HiRes5Engine::initGameState() { |