aboutsummaryrefslogtreecommitdiff
path: root/engines/adl
diff options
context:
space:
mode:
authorWalter van Niftrik2016-12-16 15:29:02 +0100
committerWalter van Niftrik2016-12-16 15:29:38 +0100
commit1f801bee433624e8bde214264a2d0c2359be4c13 (patch)
tree454fc71b488a34c2ffd17910589d2ce0f6a0c716 /engines/adl
parentf29a2f31f1e37ee733f1015c3d36df798c755172 (diff)
downloadscummvm-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.cpp22
-rw-r--r--engines/adl/adl.h11
-rw-r--r--engines/adl/adl_v2.cpp2
-rw-r--r--engines/adl/adl_v4.cpp212
-rw-r--r--engines/adl/adl_v4.h18
-rw-r--r--engines/adl/hires5.cpp157
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 &region = getCurRegion();
+
+ for (uint i = 0; i < region.vars.size(); ++i)
+ region.vars[i] = getVar(i);
+}
+
+void AdlEngine_v4::restoreVars() {
+ const Region &region = 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 &sector) 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() {