aboutsummaryrefslogtreecommitdiff
path: root/engines/adl
diff options
context:
space:
mode:
Diffstat (limited to 'engines/adl')
-rw-r--r--engines/adl/adl.cpp22
-rw-r--r--engines/adl/adl.h1
-rw-r--r--engines/adl/adl_v2.cpp74
-rw-r--r--engines/adl/adl_v2.h9
-rw-r--r--engines/adl/adl_v3.cpp229
-rw-r--r--engines/adl/adl_v3.h29
-rw-r--r--engines/adl/adl_v4.cpp258
-rw-r--r--engines/adl/adl_v4.h (renamed from engines/adl/hires2.h)63
-rw-r--r--engines/adl/detection.cpp21
-rw-r--r--engines/adl/detection.h1
-rw-r--r--engines/adl/disk.cpp72
-rw-r--r--engines/adl/disk.h20
-rw-r--r--engines/adl/display.h2
-rw-r--r--engines/adl/hires0.cpp311
-rw-r--r--engines/adl/hires0.h59
-rw-r--r--engines/adl/hires1.cpp103
-rw-r--r--engines/adl/hires1.h134
-rw-r--r--engines/adl/hires2.cpp98
-rw-r--r--engines/adl/hires4.cpp271
-rw-r--r--engines/adl/hires6.cpp119
-rw-r--r--engines/adl/hires6.h92
-rw-r--r--engines/adl/module.mk2
22 files changed, 1114 insertions, 876 deletions
diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp
index 19595606e1..9afb2c6700 100644
--- a/engines/adl/adl.cpp
+++ b/engines/adl/adl.cpp
@@ -402,6 +402,15 @@ byte AdlEngine::roomArg(byte room) const {
return room;
}
+void AdlEngine::loadDroppedItemOffsets(Common::ReadStream &stream, byte count) {
+ for (uint i = 0; i < count; ++i) {
+ Common::Point p;
+ p.x = stream.readByte();
+ p.y = stream.readByte();
+ _itemOffsets.push_back(p);
+ }
+}
+
void AdlEngine::clearScreen() const {
_display->setMode(DISPLAY_MODE_MIXED);
_display->clear(0x00);
@@ -1263,16 +1272,17 @@ Common::String AdlEngine::toAscii(const Common::String &str) {
}
Common::String AdlEngine::itemStr(uint i) const {
- byte desc = getItem(i).description;
- byte noun = getItem(i).noun;
+ const Item &item(getItem(i));
+
Common::String name = Common::String::format("%d", i);
- if (noun > 0) {
+ if (item.noun > 0) {
name += "/";
- name += _priNouns[noun - 1];
+ name += _priNouns[item.noun - 1];
}
- if (desc > 0) {
+ Common::String desc = getItemDescription(item);
+ if (!desc.empty()) {
name += "/";
- name += toAscii(loadMessage(desc));
+ name += toAscii(desc);
}
return name;
}
diff --git a/engines/adl/adl.h b/engines/adl/adl.h
index 89cdabe384..971336ef50 100644
--- a/engines/adl/adl.h
+++ b/engines/adl/adl.h
@@ -247,6 +247,7 @@ protected:
virtual void initState();
virtual byte roomArg(byte room) const;
virtual void advanceClock() { }
+ void loadDroppedItemOffsets(Common::ReadStream &stream, byte count);
// Opcodes
int o1_isItemInRoom(ScriptEnv &e);
diff --git a/engines/adl/adl_v2.cpp b/engines/adl/adl_v2.cpp
index e18f3339f8..979d794146 100644
--- a/engines/adl/adl_v2.cpp
+++ b/engines/adl/adl_v2.cpp
@@ -359,9 +359,83 @@ DataBlockPtr AdlEngine_v2::readDataBlockPtr(Common::ReadStream &f) const {
if (track == 0 && sector == 0 && offset == 0 && size == 0)
return DataBlockPtr();
+ adjustDataBlockPtr(track, sector, offset, size);
+
return _disk->getDataBlock(track, sector, offset, size);
}
+void AdlEngine_v2::loadItems(Common::ReadStream &stream) {
+ byte id;
+ while ((id = stream.readByte()) != 0xff && !stream.eos() && !stream.err()) {
+ Item item = Item();
+ item.id = id;
+ item.noun = stream.readByte();
+ item.room = stream.readByte();
+ item.picture = stream.readByte();
+ item.isLineArt = stream.readByte(); // Disk number in later games
+ item.position.x = stream.readByte();
+ item.position.y = stream.readByte();
+ item.state = stream.readByte();
+ item.description = stream.readByte();
+
+ stream.readByte(); // Struct size
+
+ byte picListSize = stream.readByte();
+
+ // Flag to keep track of what has been drawn on the screen
+ stream.readByte();
+
+ for (uint i = 0; i < picListSize; ++i)
+ item.roomPictures.push_back(stream.readByte());
+
+ _state.items.push_back(item);
+ }
+
+ if (stream.eos() || stream.err())
+ error("Error loading items");
+}
+
+void AdlEngine_v2::loadRooms(Common::ReadStream &stream, byte count) {
+ for (uint i = 0; i < count; ++i) {
+ Room room;
+
+ stream.readByte(); // number
+ for (uint j = 0; j < 6; ++j)
+ room.connections[j] = stream.readByte();
+ room.data = readDataBlockPtr(stream);
+ room.picture = stream.readByte();
+ room.curPicture = stream.readByte();
+ room.isFirstTime = stream.readByte();
+
+ _state.rooms.push_back(room);
+ }
+
+ if (stream.eos() || stream.err())
+ error("Error loading rooms");
+}
+
+void AdlEngine_v2::loadMessages(Common::ReadStream &stream, byte count) {
+ for (uint i = 0; i < count; ++i)
+ _messages.push_back(readDataBlockPtr(stream));
+}
+
+void AdlEngine_v2::loadPictures(Common::ReadStream &stream) {
+ byte picNr;
+ while ((picNr = stream.readByte()) != 0xff) {
+ if (stream.eos() || stream.err())
+ error("Error reading global pic list");
+
+ _pictures[picNr] = readDataBlockPtr(stream);
+ }
+}
+
+void AdlEngine_v2::loadItemPictures(Common::ReadStream &stream, byte count) {
+ for (uint i = 0; i < count; ++i) {
+ stream.readByte(); // number
+ _itemPics.push_back(readDataBlockPtr(stream));
+ }
+}
+
int AdlEngine_v2::o2_isFirstTime(ScriptEnv &e) {
OP_DEBUG_0("\t&& IS_FIRST_TIME()");
diff --git a/engines/adl/adl_v2.h b/engines/adl/adl_v2.h
index 4a473e9b1f..8f36b5cdb8 100644
--- a/engines/adl/adl_v2.h
+++ b/engines/adl/adl_v2.h
@@ -25,9 +25,6 @@
#include "adl/adl.h"
-// Note: this version of ADL redraws only when necessary, but
-// this is not currently implemented.
-
namespace Common {
class RandomSource;
}
@@ -55,6 +52,12 @@ protected:
void takeItem(byte noun);
virtual DataBlockPtr readDataBlockPtr(Common::ReadStream &f) const;
+ virtual void adjustDataBlockPtr(byte &track, byte &sector, byte &offset, byte &size) const { }
+ void loadItems(Common::ReadStream &stream);
+ void loadRooms(Common::ReadStream &stream, byte count);
+ void loadMessages(Common::ReadStream &stream, byte count);
+ void loadPictures(Common::ReadStream &stream);
+ void loadItemPictures(Common::ReadStream &stream, byte count);
void checkTextOverflow(char c);
diff --git a/engines/adl/adl_v3.cpp b/engines/adl/adl_v3.cpp
index 005478c376..ba9e4a063e 100644
--- a/engines/adl/adl_v3.cpp
+++ b/engines/adl/adl_v3.cpp
@@ -20,162 +20,50 @@
*
*/
-#include "common/random.h"
-#include "common/error.h"
-
#include "adl/adl_v3.h"
-#include "adl/display.h"
-#include "adl/graphics.h"
namespace Adl {
AdlEngine_v3::AdlEngine_v3(OSystem *syst, const AdlGameDescription *gd) :
- AdlEngine_v2(syst, gd),
- _curDisk(0) {
-}
-
-Common::String AdlEngine_v3::loadMessage(uint idx) const {
- Common::String str = AdlEngine_v2::loadMessage(idx);
-
- for (uint i = 0; i < str.size(); ++i) {
- const char *xorStr = "AVISDURGAN";
- str.setChar(str[i] ^ xorStr[i % strlen(xorStr)], i);
- }
-
- return str;
+ AdlEngine_v2(syst, gd) {
}
Common::String AdlEngine_v3::getItemDescription(const Item &item) const {
- return _itemDesc[item.id - 1];
+ return _itemDesc[item.description - 1];
}
-void AdlEngine_v3::applyDiskOffset(byte &track, byte &sector) const {
- sector += _diskOffsets[_curDisk].sector;
- if (sector >= 16) {
- sector -= 16;
- ++track;
- }
+void AdlEngine_v3::loadItemDescriptions(Common::SeekableReadStream &stream, byte count) {
+ int32 startPos = stream.pos();
+ uint16 baseAddr = stream.readUint16LE();
- track += _diskOffsets[_curDisk].track;
-}
-
-DataBlockPtr AdlEngine_v3::readDataBlockPtr(Common::ReadStream &f) const {
- byte track = f.readByte();
- byte sector = f.readByte();
- byte offset = f.readByte();
- byte size = f.readByte();
-
- if (f.eos() || f.err())
- error("Error reading DataBlockPtr");
+ // This code assumes that the first pointer points to a string that
+ // directly follows the pointer table
+ assert(baseAddr != 0);
+ baseAddr -= count * 2;
- if (track == 0 && sector == 0 && offset == 0 && size == 0)
- return DataBlockPtr();
+ for (uint i = 0; i < count; ++i) {
+ stream.seek(startPos + i * 2);
+ uint16 offset = stream.readUint16LE();
- applyDiskOffset(track, sector);
+ if (offset > 0) {
+ stream.seek(startPos + offset - baseAddr);
+ _itemDesc.push_back(readString(stream, 0xff));
+ } else
+ _itemDesc.push_back(Common::String());
+ }
- return _disk->getDataBlock(track, sector, offset, size);
+ if (stream.eos() || stream.err())
+ error("Error loading item descriptions");
}
typedef Common::Functor1Mem<ScriptEnv &, int, AdlEngine_v3> OpcodeV3;
-#define SetOpcodeTable(x) table = &x;
-#define Opcode(x) table->push_back(new OpcodeV3(this, &AdlEngine_v3::x))
-#define OpcodeUnImpl() table->push_back(new OpcodeV3(this, 0))
void AdlEngine_v3::setupOpcodeTables() {
- Common::Array<const Opcode *> *table = 0;
-
- SetOpcodeTable(_condOpcodes);
- // 0x00
- OpcodeUnImpl();
- Opcode(o2_isFirstTime);
- Opcode(o2_isRandomGT);
- Opcode(o3_isItemInRoom);
- // 0x04
- Opcode(o3_isNounNotInRoom);
- Opcode(o1_isMovesGT);
- Opcode(o1_isVarEQ);
- Opcode(o2_isCarryingSomething);
- // 0x08
- Opcode(o3_isVarGT);
- Opcode(o1_isCurPicEQ);
- Opcode(o3_skipOneCommand);
-
- SetOpcodeTable(_actOpcodes);
- // 0x00
- OpcodeUnImpl();
- Opcode(o1_varAdd);
- Opcode(o1_varSub);
- Opcode(o1_varSet);
- // 0x04
- Opcode(o1_listInv);
- Opcode(o3_moveItem);
- Opcode(o1_setRoom);
- Opcode(o2_setCurPic);
- // 0x08
- Opcode(o2_setPic);
- Opcode(o1_printMsg);
- Opcode(o3_dummy);
- Opcode(o3_setTextMode);
- // 0x0c
- Opcode(o2_moveAllItems);
- Opcode(o1_quit);
- Opcode(o3_dummy);
- Opcode(o2_save);
- // 0x10
- Opcode(o2_restore);
- Opcode(o1_restart);
- Opcode(o3_setDisk);
- Opcode(o3_dummy);
- // 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(o1_setRoomPic);
- Opcode(o3_sound);
- OpcodeUnImpl();
- // 0x20
- Opcode(o2_initDisk);
-}
-
-int AdlEngine_v3::o3_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_v3::o3_skipOneCommand(ScriptEnv &e) {
- OP_DEBUG_0("\t&& SKIP_ONE_COMMAND()");
-
- _skipOneCommand = true;
- setVar(2, 0);
-
- return -1;
-}
-
-// FIXME: Rename "isLineArt" and look at code duplication
-int AdlEngine_v3::o3_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.isLineArt != _curDisk)
- return -1;
-
- if (item.room == roomArg(e.arg(2)))
- return 2;
-
- return -1;
+ AdlEngine_v2::setupOpcodeTables();
+ delete _condOpcodes[0x04];
+ _condOpcodes[0x04] = new OpcodeV3(this, &AdlEngine_v3::o3_isNounNotInRoom);
+ delete _actOpcodes[0x04];
+ _actOpcodes[0x04] = new OpcodeV3(this, &AdlEngine_v3::o3_listInv);
}
int AdlEngine_v3::o3_isNounNotInRoom(ScriptEnv &e) {
@@ -183,75 +71,28 @@ int AdlEngine_v3::o3_isNounNotInRoom(ScriptEnv &e) {
Common::List<Item>::const_iterator item;
- setVar(24, 0);
+ bool isAnItem = false;
- for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ for (item = _state.items.begin(); item != _state.items.end(); ++item) {
if (item->noun == e.getNoun()) {
- setVar(24, 1);
+ isAnItem = true;
if (item->room == roomArg(e.arg(1)))
return -1;
}
-
- return 1;
-}
-
-int AdlEngine_v3::o3_moveItem(ScriptEnv &e) {
- OP_DEBUG_2("\tSET_ITEM_ROOM(%s, %s)", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
-
- byte room = roomArg(e.arg(2));
-
- Item &item = getItem(e.arg(1));
-
- if (item.room == _roomOnScreen)
- _picOnScreen = 0;
-
- // Set items that move from inventory to a room to state "dropped"
- if (item.room == IDI_ANY && room != IDI_VOID_ROOM)
- item.state = IDI_ITEM_DROPPED;
-
- item.room = room;
- item.isLineArt = _curDisk;
- return 2;
-}
-
-int AdlEngine_v3::o3_dummy(ScriptEnv &e) {
- OP_DEBUG_0("\tDUMMY()");
-
- return 0;
-}
-
-int AdlEngine_v3::o3_setTextMode(ScriptEnv &e) {
- OP_DEBUG_1("\tSET_TEXT_MODE(%d)", e.arg(1));
-
- // TODO
- // 1: 4-line mode
- // 2: 24-line mode
-
- switch (e.arg(1)) {
- case 3:
- // We re-use the restarting flag here, to simulate a long jump
- _isRestarting = true;
- return -1;
}
- return 1;
+ return (isAnItem ? 1 : -1);
}
-int AdlEngine_v3::o3_setDisk(ScriptEnv &e) {
- OP_DEBUG_2("\tSET_DISK(%d, %d)", e.arg(1), e.arg(2));
-
- // TODO
- // Arg 1: disk
- // Arg 2: room
-
- return 2;
-}
+int AdlEngine_v3::o3_listInv(ScriptEnv &e) {
+ OP_DEBUG_0("\tLIST_INVENTORY()");
-int AdlEngine_v3::o3_sound(ScriptEnv &e) {
- OP_DEBUG_0("\tSOUND()");
+ Common::List<Item>::const_iterator item;
- // TODO
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->room == IDI_ANY)
+ printString(_itemDesc[item->description - 1]);
return 0;
}
diff --git a/engines/adl/adl_v3.h b/engines/adl/adl_v3.h
index 61dd5852e7..b0d40f3993 100644
--- a/engines/adl/adl_v3.h
+++ b/engines/adl/adl_v3.h
@@ -25,18 +25,6 @@
#include "adl/adl_v2.h"
-// Note: this version of ADL redraws only when necessary, but
-// this is not currently implemented.
-
-namespace Common {
-class RandomSource;
-}
-
-struct DiskOffset {
- byte track;
- byte sector;
-};
-
namespace Adl {
class AdlEngine_v3 : public AdlEngine_v2 {
@@ -48,27 +36,14 @@ protected:
// AdlEngine
virtual void setupOpcodeTables();
- virtual Common::String loadMessage(uint idx) const;
Common::String getItemDescription(const Item &item) const;
- // AdlEngine_v2
- virtual DataBlockPtr readDataBlockPtr(Common::ReadStream &f) const;
-
- void applyDiskOffset(byte &track, byte &sector) const;
+ void loadItemDescriptions(Common::SeekableReadStream &stream, byte count);
- int o3_isVarGT(ScriptEnv &e);
- int o3_isItemInRoom(ScriptEnv &e);
int o3_isNounNotInRoom(ScriptEnv &e);
- int o3_skipOneCommand(ScriptEnv &e);
- int o3_moveItem(ScriptEnv &e);
- int o3_dummy(ScriptEnv &e);
- int o3_setTextMode(ScriptEnv &e);
- int o3_setDisk(ScriptEnv &e);
- int o3_sound(ScriptEnv &e);
+ int o3_listInv(ScriptEnv &e);
Common::Array<Common::String> _itemDesc;
- byte _curDisk;
- Common::Array<DiskOffset> _diskOffsets;
};
} // End of namespace Adl
diff --git a/engines/adl/adl_v4.cpp b/engines/adl/adl_v4.cpp
new file mode 100644
index 0000000000..ed20c82513
--- /dev/null
+++ b/engines/adl/adl_v4.cpp
@@ -0,0 +1,258 @@
+/* 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/random.h"
+#include "common/error.h"
+
+#include "adl/adl_v4.h"
+#include "adl/display.h"
+#include "adl/graphics.h"
+
+namespace Adl {
+
+AdlEngine_v4::AdlEngine_v4(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine_v3(syst, gd),
+ _curDisk(0) {
+}
+
+Common::String AdlEngine_v4::loadMessage(uint idx) const {
+ Common::String str = AdlEngine_v2::loadMessage(idx);
+
+ for (uint i = 0; i < str.size(); ++i) {
+ const char *xorStr = "AVISDURGAN";
+ str.setChar(str[i] ^ xorStr[i % strlen(xorStr)], i);
+ }
+
+ return str;
+}
+
+Common::String AdlEngine_v4::getItemDescription(const Item &item) const {
+ return _itemDesc[item.id - 1];
+}
+
+void AdlEngine_v4::applyDiskOffset(byte &track, byte &sector) const {
+ sector += _diskOffsets[_curDisk].sector;
+ if (sector >= 16) {
+ sector -= 16;
+ ++track;
+ }
+
+ track += _diskOffsets[_curDisk].track;
+}
+
+void AdlEngine_v4::adjustDataBlockPtr(byte &track, byte &sector, byte &offset, byte &size) const {
+ applyDiskOffset(track, sector);
+}
+
+typedef Common::Functor1Mem<ScriptEnv &, int, AdlEngine_v4> OpcodeV4;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV4(this, &AdlEngine_v4::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeV4(this, 0))
+
+void AdlEngine_v4::setupOpcodeTables() {
+ Common::Array<const Opcode *> *table = 0;
+
+ SetOpcodeTable(_condOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ Opcode(o2_isFirstTime);
+ Opcode(o2_isRandomGT);
+ Opcode(o4_isItemInRoom);
+ // 0x04
+ Opcode(o4_isNounNotInRoom);
+ Opcode(o1_isMovesGT);
+ Opcode(o1_isVarEQ);
+ Opcode(o2_isCarryingSomething);
+ // 0x08
+ Opcode(o4_isVarGT);
+ Opcode(o1_isCurPicEQ);
+ Opcode(o4_skipOneCommand);
+
+ SetOpcodeTable(_actOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ Opcode(o1_varAdd);
+ Opcode(o1_varSub);
+ Opcode(o1_varSet);
+ // 0x04
+ Opcode(o4_listInv);
+ Opcode(o4_moveItem);
+ Opcode(o1_setRoom);
+ Opcode(o2_setCurPic);
+ // 0x08
+ Opcode(o2_setPic);
+ Opcode(o1_printMsg);
+ Opcode(o4_dummy);
+ Opcode(o4_setTextMode);
+ // 0x0c
+ Opcode(o2_moveAllItems);
+ Opcode(o1_quit);
+ Opcode(o4_dummy);
+ Opcode(o2_save);
+ // 0x10
+ Opcode(o2_restore);
+ Opcode(o1_restart);
+ Opcode(o4_setDisk);
+ Opcode(o4_dummy);
+ // 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(o1_setRoomPic);
+ Opcode(o4_sound);
+ OpcodeUnImpl();
+ // 0x20
+ Opcode(o2_initDisk);
+}
+
+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_skipOneCommand(ScriptEnv &e) {
+ OP_DEBUG_0("\t&& SKIP_ONE_COMMAND()");
+
+ _skipOneCommand = true;
+ setVar(2, 0);
+
+ return -1;
+}
+
+// FIXME: Rename "isLineArt" and look at code duplication
+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.isLineArt != _curDisk)
+ return -1;
+
+ if (item.room == roomArg(e.arg(2)))
+ return 2;
+
+ return -1;
+}
+
+int AdlEngine_v4::o4_isNounNotInRoom(ScriptEnv &e) {
+ OP_DEBUG_1("\t&& NO_SUCH_ITEMS_IN_ROOM(%s)", itemRoomStr(e.arg(1)).c_str());
+
+ Common::List<Item>::const_iterator item;
+
+ setVar(24, 0);
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->noun == e.getNoun()) {
+ setVar(24, 1);
+
+ if (item->room == roomArg(e.arg(1)))
+ return -1;
+ }
+
+ return 1;
+}
+
+int AdlEngine_v4::o4_listInv(ScriptEnv &e) {
+ OP_DEBUG_0("\tLIST_INVENTORY()");
+
+ Common::List<Item>::const_iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->room == IDI_ANY)
+ printString(_itemDesc[item->id - 1]);
+
+ return 0;
+}
+
+int AdlEngine_v4::o4_moveItem(ScriptEnv &e) {
+ OP_DEBUG_2("\tSET_ITEM_ROOM(%s, %s)", itemStr(e.arg(1)).c_str(), itemRoomStr(e.arg(2)).c_str());
+
+ byte room = roomArg(e.arg(2));
+
+ Item &item = getItem(e.arg(1));
+
+ if (item.room == _roomOnScreen)
+ _picOnScreen = 0;
+
+ // Set items that move from inventory to a room to state "dropped"
+ if (item.room == IDI_ANY && room != IDI_VOID_ROOM)
+ item.state = IDI_ITEM_DROPPED;
+
+ item.room = room;
+ item.isLineArt = _curDisk;
+ return 2;
+}
+
+int AdlEngine_v4::o4_dummy(ScriptEnv &e) {
+ OP_DEBUG_0("\tDUMMY()");
+
+ return 0;
+}
+
+int AdlEngine_v4::o4_setTextMode(ScriptEnv &e) {
+ OP_DEBUG_1("\tSET_TEXT_MODE(%d)", e.arg(1));
+
+ // TODO
+ // 1: 4-line mode
+ // 2: 24-line mode
+
+ switch (e.arg(1)) {
+ case 3:
+ // We re-use the restarting flag here, to simulate a long jump
+ _isRestarting = true;
+ return -1;
+ }
+
+ return 1;
+}
+
+int AdlEngine_v4::o4_setDisk(ScriptEnv &e) {
+ OP_DEBUG_2("\tSET_DISK(%d, %d)", e.arg(1), e.arg(2));
+
+ // TODO
+ // Arg 1: disk
+ // Arg 2: room
+
+ return 2;
+}
+
+int AdlEngine_v4::o4_sound(ScriptEnv &e) {
+ OP_DEBUG_0("\tSOUND()");
+
+ // TODO
+
+ return 0;
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/hires2.h b/engines/adl/adl_v4.h
index 50016725d6..79aa824d92 100644
--- a/engines/adl/hires2.h
+++ b/engines/adl/adl_v4.h
@@ -20,45 +20,52 @@
*
*/
-#ifndef ADL_HIRES2_H
-#define ADL_HIRES2_H
+#ifndef ADL_ADL_V4_H
+#define ADL_ADL_V4_H
-#include "common/str.h"
-
-#include "adl/adl_v2.h"
-#include "adl/disk.h"
+#include "adl/adl_v3.h"
namespace Common {
-class ReadStream;
-struct Point;
+class RandomSource;
}
+struct DiskOffset {
+ byte track;
+ byte sector;
+};
+
namespace Adl {
-#define IDS_HR2_DISK_IMAGE "WIZARD.DSK"
+class AdlEngine_v4 : public AdlEngine_v3 {
+public:
+ virtual ~AdlEngine_v4() { }
-#define IDI_HR2_NUM_ROOMS 135
-#define IDI_HR2_NUM_MESSAGES 255
-#define IDI_HR2_NUM_VARS 40
-#define IDI_HR2_NUM_ITEM_PICS 38
-#define IDI_HR2_NUM_ITEM_OFFSETS 16
+protected:
+ AdlEngine_v4(OSystem *syst, const AdlGameDescription *gd);
-// Messages used outside of scripts
-#define IDI_HR2_MSG_CANT_GO_THERE 123
-#define IDI_HR2_MSG_DONT_UNDERSTAND 19
-#define IDI_HR2_MSG_ITEM_DOESNT_MOVE 242
-#define IDI_HR2_MSG_ITEM_NOT_HERE 4
-#define IDI_HR2_MSG_THANKS_FOR_PLAYING 239
+ // AdlEngine
+ virtual void setupOpcodeTables();
+ virtual Common::String loadMessage(uint idx) const;
+ Common::String getItemDescription(const Item &item) const;
-class HiRes2Engine : public AdlEngine_v2 {
-public:
- HiRes2Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine_v2(syst, gd) { }
+ // AdlEngine_v2
+ virtual void adjustDataBlockPtr(byte &track, byte &sector, byte &offset, byte &size) const;
-private:
- // AdlEngine
- void runIntro() const;
- void init();
- void initGameState();
+ void applyDiskOffset(byte &track, byte &sector) const;
+
+ int o4_isVarGT(ScriptEnv &e);
+ int o4_isItemInRoom(ScriptEnv &e);
+ int o4_isNounNotInRoom(ScriptEnv &e);
+ int o4_skipOneCommand(ScriptEnv &e);
+ int o4_listInv(ScriptEnv &e);
+ int o4_moveItem(ScriptEnv &e);
+ int o4_dummy(ScriptEnv &e);
+ int o4_setTextMode(ScriptEnv &e);
+ int o4_setDisk(ScriptEnv &e);
+ int o4_sound(ScriptEnv &e);
+
+ byte _curDisk;
+ Common::Array<DiskOffset> _diskOffsets;
};
} // End of namespace Adl
diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index 200e0b592a..10812d79ea 100644
--- a/engines/adl/detection.cpp
+++ b/engines/adl/detection.cpp
@@ -76,6 +76,7 @@ static const PlainGameDescriptor adlGames[] = {
{ "hires0", "Hi-Res Adventure #0: Mission Asteroid" },
{ "hires1", "Hi-Res Adventure #1: Mystery House" },
{ "hires2", "Hi-Res Adventure #2: Wizard and the Princess" },
+ { "hires4", "Hi-Res Adventure #4: Ulysses and the Golden Fleece" },
{ "hires6", "Hi-Res Adventure #6: The Dark Crystal" },
{ 0, 0 }
};
@@ -139,6 +140,21 @@ static const AdlGameDescription gameDescriptions[] = {
},
GAME_TYPE_HIRES0
},
+ { // Hi-Res Adventure #4: Ulysses and the Golden Fleece - Atari 8-bit - Re-release
+ {
+ "hires4", 0,
+ {
+ { "ULYS1A.XFD", 0, "26365d2b06509fd21e7a7919e33f7199", 92160 },
+ // FIXME: Add sides 1B and 2C
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformAtariST, // FIXME
+ ADGF_UNSTABLE,
+ GUIO2(GAMEOPTION_COLOR_DEFAULT_ON, GAMEOPTION_SCANLINES)
+ },
+ GAME_TYPE_HIRES4
+ },
{ // Hi-Res Adventure #6: The Dark Crystal - Apple II - Roberta Williams Anthology
{
"hires6", 0,
@@ -189,6 +205,7 @@ bool AdlMetaEngine::hasFeature(MetaEngineFeature f) const {
case kSavesSupportThumbnail:
case kSavesSupportCreationDate:
case kSavesSupportPlayTime:
+ case kSimpleSavesNames:
return true;
default:
return false;
@@ -297,6 +314,7 @@ void AdlMetaEngine::removeSaveState(const char *target, int slot) const {
Engine *HiRes1Engine_create(OSystem *syst, const AdlGameDescription *gd);
Engine *HiRes2Engine_create(OSystem *syst, const AdlGameDescription *gd);
Engine *HiRes0Engine_create(OSystem *syst, const AdlGameDescription *gd);
+Engine *HiRes4Engine_create(OSystem *syst, const AdlGameDescription *gd);
Engine *HiRes6Engine_create(OSystem *syst, const AdlGameDescription *gd);
bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const {
@@ -315,6 +333,9 @@ bool AdlMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD
case GAME_TYPE_HIRES0:
*engine = HiRes0Engine_create(syst, adlGd);
break;
+ case GAME_TYPE_HIRES4:
+ *engine = HiRes4Engine_create(syst, adlGd);
+ break;
case GAME_TYPE_HIRES6:
*engine = HiRes6Engine_create(syst, adlGd);
break;
diff --git a/engines/adl/detection.h b/engines/adl/detection.h
index 533466c094..b4dc3c430f 100644
--- a/engines/adl/detection.h
+++ b/engines/adl/detection.h
@@ -35,6 +35,7 @@ enum GameType {
GAME_TYPE_HIRES0,
GAME_TYPE_HIRES1,
GAME_TYPE_HIRES2,
+ GAME_TYPE_HIRES4,
GAME_TYPE_HIRES6
};
diff --git a/engines/adl/disk.cpp b/engines/adl/disk.cpp
index 49e01f9d0f..d429556670 100644
--- a/engines/adl/disk.cpp
+++ b/engines/adl/disk.cpp
@@ -28,15 +28,7 @@
namespace Adl {
-#define TRACKS 35
-// The Apple II uses either 13- or 16-sector disks. We currently pad out
-// 13-sector disks, so we set SECTORS_PER_TRACK to 16 here.
-#define SECTORS_PER_TRACK 16
-#define BYTES_PER_SECTOR 256
-#define RAW_IMAGE_SIZE(S) (TRACKS * (S) * BYTES_PER_SECTOR)
-#define NIB_IMAGE_SIZE (RAW_IMAGE_SIZE(13) * 2)
-
-static Common::SeekableReadStream *readImage_DSK(const Common::String &filename) {
+static Common::SeekableReadStream *readImage(const Common::String &filename) {
Common::File *f = new Common::File;
if (!f->open(filename)) {
@@ -44,9 +36,6 @@ static Common::SeekableReadStream *readImage_DSK(const Common::String &filename)
return nullptr;
}
- if (f->size() != RAW_IMAGE_SIZE(16))
- error("Unrecognized DSK image '%s' of size %d bytes", filename.c_str(), f->size());
-
return f;
}
@@ -63,7 +52,7 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename)
if (!f.open(filename))
return nullptr;
- if (f.size() != NIB_IMAGE_SIZE)
+ if (f.size() != 232960)
error("Unrecognized NIB image '%s' of size %d bytes", filename.c_str(), f.size());
// starting at 0xaa, 32 is invalid (see below)
@@ -73,7 +62,9 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename)
// we always pad it out
const uint sectorsPerTrack = 16;
- byte *diskImage = (byte *)calloc(RAW_IMAGE_SIZE(sectorsPerTrack), 1);
+ const uint bytesPerSector = 256;
+ const uint imageSize = 35 * sectorsPerTrack * bytesPerSector;
+ byte *const diskImage = (byte *)calloc(imageSize, 1);
bool sawAddress = false;
uint8 volNo, track, sector;
@@ -120,13 +111,13 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename)
// We should always find the data field after an address field.
// TODO: we ignore volNo?
- byte *output = diskImage + (track * sectorsPerTrack + sector) * BYTES_PER_SECTOR;
+ byte *output = diskImage + (track * sectorsPerTrack + sector) * bytesPerSector;
if (newStyle) {
// We hardcode the DOS 3.3 mapping here. TODO: Do we also need raw/prodos?
int raw2dos[16] = { 0, 7, 14, 6, 13, 5, 12, 4, 11, 3, 10, 2, 9, 1, 8, 15 };
sector = raw2dos[sector];
- output = diskImage + (track * sectorsPerTrack + sector) * BYTES_PER_SECTOR;
+ output = diskImage + (track * sectorsPerTrack + sector) * bytesPerSector;
// 6-and-2 uses 342 on-disk bytes
byte inbuffer[342];
@@ -216,42 +207,65 @@ static Common::SeekableReadStream *readImage_NIB(const Common::String &filename)
}
}
- return new Common::MemoryReadStream(diskImage, RAW_IMAGE_SIZE(sectorsPerTrack), DisposeAfterUse::YES);
+ return new Common::MemoryReadStream(diskImage, imageSize, DisposeAfterUse::YES);
}
bool DiskImage::open(const Common::String &filename) {
Common::String lcName(filename);
lcName.toLowercase();
- if (lcName.hasSuffix(".dsk"))
- _stream = readImage_DSK(filename);
- else if (lcName.hasSuffix(".nib"))
+ if (lcName.hasSuffix(".dsk")) {
+ _stream = readImage(filename);
+ _tracks = 35;
+ _sectorsPerTrack = 16;
+ _bytesPerSector = 256;
+ } else if (lcName.hasSuffix(".nib")) {
_stream = readImage_NIB(filename);
+ _tracks = 35;
+ _sectorsPerTrack = 16;
+ _bytesPerSector = 256;
+ } else if (lcName.hasSuffix(".xfd")) {
+ _stream = readImage(filename);
+ _tracks = 40;
+ _sectorsPerTrack = 18;
+ _bytesPerSector = 128;
+ }
+
+ int expectedSize = _tracks * _sectorsPerTrack * _bytesPerSector;
+
+ if (!_stream)
+ return false;
+
+ if (_stream->size() != expectedSize)
+ error("Unrecognized disk image '%s' of size %d bytes (expected %d bytes)", filename.c_str(), _stream->size(), expectedSize);
- return _stream != nullptr;
+ return true;
}
const DataBlockPtr DiskImage::getDataBlock(uint track, uint sector, uint offset, uint size) const {
- return DataBlockPtr(new DiskImage::DataBlock(this, track, sector, offset, size, _mode13));
+ return DataBlockPtr(new DiskImage::DataBlock(this, track, sector, offset, size, _sectorLimit));
}
-Common::SeekableReadStream *DiskImage::createReadStream(uint track, uint sector, uint offset, uint size, uint sectorsPerTrackToRead) const {
- const uint bytesToRead = size * BYTES_PER_SECTOR + BYTES_PER_SECTOR - offset;
+Common::SeekableReadStream *DiskImage::createReadStream(uint track, uint sector, uint offset, uint size, uint sectorLimit) const {
+ const uint bytesToRead = size * _bytesPerSector + _bytesPerSector - offset;
byte *const data = (byte *)malloc(bytesToRead);
uint dataOffset = 0;
- if (sector > sectorsPerTrackToRead - 1)
- error("Sector %i is out of bounds for %i-sector reading", sector, sectorsPerTrackToRead);
+ if (sectorLimit == 0)
+ sectorLimit = _sectorsPerTrack;
+
+ if (sector >= sectorLimit)
+ error("Sector %i is out of bounds for %i-sector reading", sector, sectorLimit);
while (dataOffset < bytesToRead) {
- uint bytesRemInTrack = (sectorsPerTrackToRead - 1 - sector) * BYTES_PER_SECTOR + BYTES_PER_SECTOR - offset;
- _stream->seek((track * SECTORS_PER_TRACK + sector) * BYTES_PER_SECTOR + offset);
+ uint bytesRemInTrack = (sectorLimit - 1 - sector) * _bytesPerSector + _bytesPerSector - offset;
+ _stream->seek((track * _sectorsPerTrack + sector) * _bytesPerSector + offset);
if (bytesToRead - dataOffset < bytesRemInTrack)
bytesRemInTrack = bytesToRead - dataOffset;
if (_stream->read(data + dataOffset, bytesRemInTrack) < bytesRemInTrack)
- error("Error reading disk image");
+ error("Error reading disk image at track %d; sector %d", track, sector);
++track;
diff --git a/engines/adl/disk.h b/engines/adl/disk.h
index 1041f0cebd..653d76ff10 100644
--- a/engines/adl/disk.h
+++ b/engines/adl/disk.h
@@ -74,7 +74,10 @@ class DiskImage {
public:
DiskImage() :
_stream(nullptr),
- _mode13(false) { }
+ _tracks(0),
+ _sectorsPerTrack(0),
+ _bytesPerSector(0),
+ _sectorLimit(0) { }
~DiskImage() {
delete _stream;
@@ -82,32 +85,33 @@ public:
bool open(const Common::String &filename);
const DataBlockPtr getDataBlock(uint track, uint sector, uint offset = 0, uint size = 0) const;
- Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0, uint sectorsPerTrackToRead = 16) const;
- void setMode13(bool enable) { _mode13 = enable; }
+ Common::SeekableReadStream *createReadStream(uint track, uint sector, uint offset = 0, uint size = 0, uint sectorsUsed = 0) const;
+ void setSectorLimit(uint sectorLimit) { _sectorLimit = sectorLimit; } // Maximum number of sectors to read per track before stepping
protected:
class DataBlock : public Adl::DataBlock {
public:
- DataBlock(const DiskImage *disk, uint track, uint sector, uint offset, uint size, bool mode13) :
+ DataBlock(const DiskImage *disk, uint track, uint sector, uint offset, uint size, uint sectorLimit) :
_track(track),
_sector(sector),
_offset(offset),
_size(size),
- _mode13(mode13),
+ _sectorLimit(sectorLimit),
_disk(disk) { }
Common::SeekableReadStream *createReadStream() const {
- return _disk->createReadStream(_track, _sector, _offset, _size, (_mode13 ? 13 : 16));
+ return _disk->createReadStream(_track, _sector, _offset, _size, _sectorLimit);
}
private:
uint _track, _sector, _offset, _size;
- bool _mode13;
+ uint _sectorLimit;
const DiskImage *_disk;
};
Common::SeekableReadStream *_stream;
- bool _mode13; // Older 13-sector format
+ uint _tracks, _sectorsPerTrack, _bytesPerSector;
+ uint _sectorLimit;
};
// Data in plain files
diff --git a/engines/adl/display.h b/engines/adl/display.h
index e761e63f2e..311a05893c 100644
--- a/engines/adl/display.h
+++ b/engines/adl/display.h
@@ -23,7 +23,7 @@
#ifndef ADL_DISPLAY_H
#define ADL_DISPLAY_H
-#include <common/types.h>
+#include "common/types.h"
namespace Common {
class ReadStream;
diff --git a/engines/adl/hires0.cpp b/engines/adl/hires0.cpp
index 316f77a9b6..9a0af05d20 100644
--- a/engines/adl/hires0.cpp
+++ b/engines/adl/hires0.cpp
@@ -1,168 +1,143 @@
-/* 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/textconsole.h"
-
-#include "adl/hires0.h"
-#include "adl/graphics.h"
-#include "adl/disk.h"
-
-namespace Adl {
-
-void HiRes0Engine::init() {
- _graphics = new Graphics_v2(*_display);
-
- _disk = new DiskImage();
- if (!_disk->open(IDS_HR0_DISK_IMAGE))
- error("Failed to open disk image '" IDS_HR0_DISK_IMAGE "'");
-
- _disk->setMode13(true);
-
- StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 2));
-
- // TODO: all these strings/offsets/etc are the same as hires2
-
- for (uint i = 0; i < IDI_HR0_NUM_MESSAGES; ++i)
- _messages.push_back(readDataBlockPtr(*stream));
-
- // Read parser messages
- stream.reset(_disk->createReadStream(0x1a, 0x1));
- _strings.verbError = readStringAt(*stream, 0x4f);
- _strings.nounError = readStringAt(*stream, 0x8e);
- _strings.enterCommand = readStringAt(*stream, 0xbc);
-
- // Read time string
- stream.reset(_disk->createReadStream(0x19, 0x7, 0xd7));
- _strings_v2.time = readString(*stream, 0xff);
-
- // Read line feeds
- stream.reset(_disk->createReadStream(0x19, 0xb, 0xf8, 1));
- _strings.lineFeeds = readString(*stream);
-
- // Read opcode strings
- stream.reset(_disk->createReadStream(0x1a, 0x6, 0x00, 2));
- _strings_v2.saveInsert = readStringAt(*stream, 0x5f);
- _strings_v2.saveReplace = readStringAt(*stream, 0xe5);
- _strings_v2.restoreInsert = readStringAt(*stream, 0x132);
- _strings_v2.restoreReplace = readStringAt(*stream, 0x1c2);
- _strings.playAgain = readStringAt(*stream, 0x225);
- _strings.pressReturn = readStringAt(*stream, 0x25f);
-
- _messageIds.cantGoThere = IDI_HR0_MSG_CANT_GO_THERE;
- _messageIds.dontUnderstand = IDI_HR0_MSG_DONT_UNDERSTAND;
- _messageIds.itemDoesntMove = IDI_HR0_MSG_ITEM_DOESNT_MOVE;
- _messageIds.itemNotHere = IDI_HR0_MSG_ITEM_NOT_HERE;
- _messageIds.thanksForPlaying = IDI_HR0_MSG_THANKS_FOR_PLAYING;
-
- // Load global picture data
- stream.reset(_disk->createReadStream(0x19, 0xa, 0x80, 0));
- byte picNr;
- while ((picNr = stream->readByte()) != 0xff) {
- if (stream->eos() || stream->err())
- error("Error reading global pic list");
-
- _pictures[picNr] = readDataBlockPtr(*stream);
- }
-
- // Load item picture data
- stream.reset(_disk->createReadStream(0x1e, 0x9, 0x05));
- for (uint i = 0; i < IDI_HR0_NUM_ITEM_PICS; ++i) {
- stream->readByte(); // number
- _itemPics.push_back(readDataBlockPtr(*stream));
- }
-
- // Load commands from executable
- stream.reset(_disk->createReadStream(0x1d, 0x7, 0x00, 2));
- readCommands(*stream, _roomCommands);
-
- stream.reset(_disk->createReadStream(0x1f, 0x7, 0x00, 3));
- readCommands(*stream, _globalCommands);
-
- // Load dropped item offsets
- stream.reset(_disk->createReadStream(0x1b, 0x4, 0x15));
- for (uint i = 0; i < IDI_HR0_NUM_ITEM_OFFSETS; ++i) {
- Common::Point p;
- p.x = stream->readByte();
- p.y = stream->readByte();
- _itemOffsets.push_back(p);
- }
-
- // Load verbs
- stream.reset(_disk->createReadStream(0x19, 0x0, 0x00, 3));
- loadWords(*stream, _verbs, _priVerbs);
-
- // Load nouns
- stream.reset(_disk->createReadStream(0x22, 0x2, 0x00, 2));
- loadWords(*stream, _nouns, _priNouns);
-}
-
-void HiRes0Engine::initGameState() {
- _state.vars.resize(IDI_HR0_NUM_VARS);
-
- StreamPtr stream(_disk->createReadStream(0x21, 0x5, 0x0e, 2));
-
- for (uint i = 0; i < IDI_HR0_NUM_ROOMS; ++i) {
- Room room;
- stream->readByte(); // number
- for (uint j = 0; j < 6; ++j)
- room.connections[j] = stream->readByte();
- room.data = readDataBlockPtr(*stream);
- room.picture = stream->readByte();
- room.curPicture = stream->readByte();
- room.isFirstTime = stream->readByte();
- _state.rooms.push_back(room);
- }
-
- stream.reset(_disk->createReadStream(0x21, 0x0));
-
- byte id;
- while ((id = stream->readByte()) != 0xff) {
- Item item = Item();
- item.id = id;
- item.noun = stream->readByte();
- item.room = stream->readByte();
- item.picture = stream->readByte();
- item.isLineArt = stream->readByte();
- item.position.x = stream->readByte();
- item.position.y = stream->readByte();
- item.state = stream->readByte();
- item.description = stream->readByte();
-
- stream->readByte(); // Struct size
-
- byte picListSize = stream->readByte();
-
- // Flag to keep track of what has been drawn on the screen
- stream->readByte();
-
- for (uint i = 0; i < picListSize; ++i)
- item.roomPictures.push_back(stream->readByte());
-
- _state.items.push_back(item);
- }
-}
-
-Engine *HiRes0Engine_create(OSystem *syst, const AdlGameDescription *gd) {
- return new HiRes0Engine(syst, gd);
-}
-
-} // End of namespace Adl
+/* 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/textconsole.h"
+
+#include "adl/adl_v2.h"
+#include "adl/graphics.h"
+#include "adl/disk.h"
+
+namespace Adl {
+
+#define IDS_HR0_DISK_IMAGE "MISSION.NIB"
+
+#define IDI_HR0_NUM_ROOMS 43
+#define IDI_HR0_NUM_MESSAGES 142
+#define IDI_HR0_NUM_VARS 40
+#define IDI_HR0_NUM_ITEM_PICS 2
+#define IDI_HR0_NUM_ITEM_OFFSETS 16
+
+// Messages used outside of scripts
+#define IDI_HR0_MSG_CANT_GO_THERE 110
+#define IDI_HR0_MSG_DONT_UNDERSTAND 112
+#define IDI_HR0_MSG_ITEM_DOESNT_MOVE 114
+#define IDI_HR0_MSG_ITEM_NOT_HERE 115
+#define IDI_HR0_MSG_THANKS_FOR_PLAYING 113
+
+class HiRes0Engine : public AdlEngine_v2 {
+public:
+ HiRes0Engine(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine_v2(syst, gd) { }
+ ~HiRes0Engine() { }
+
+private:
+ // AdlEngine
+ void init();
+ void initGameState();
+};
+
+void HiRes0Engine::init() {
+ _graphics = new Graphics_v2(*_display);
+
+ _disk = new DiskImage();
+ if (!_disk->open(IDS_HR0_DISK_IMAGE))
+ error("Failed to open disk image '" IDS_HR0_DISK_IMAGE "'");
+
+ _disk->setSectorLimit(13);
+
+ // TODO: all these strings/offsets/etc are the same as hires2
+
+ StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 2));
+ loadMessages(*stream, IDI_HR0_NUM_MESSAGES);
+
+ // Read parser messages
+ stream.reset(_disk->createReadStream(0x1a, 0x1));
+ _strings.verbError = readStringAt(*stream, 0x4f);
+ _strings.nounError = readStringAt(*stream, 0x8e);
+ _strings.enterCommand = readStringAt(*stream, 0xbc);
+
+ // Read time string
+ stream.reset(_disk->createReadStream(0x19, 0x7, 0xd7));
+ _strings_v2.time = readString(*stream, 0xff);
+
+ // Read line feeds
+ stream.reset(_disk->createReadStream(0x19, 0xb, 0xf8, 1));
+ _strings.lineFeeds = readString(*stream);
+
+ // Read opcode strings
+ stream.reset(_disk->createReadStream(0x1a, 0x6, 0x00, 2));
+ _strings_v2.saveInsert = readStringAt(*stream, 0x5f);
+ _strings_v2.saveReplace = readStringAt(*stream, 0xe5);
+ _strings_v2.restoreInsert = readStringAt(*stream, 0x132);
+ _strings_v2.restoreReplace = readStringAt(*stream, 0x1c2);
+ _strings.playAgain = readStringAt(*stream, 0x225);
+ _strings.pressReturn = readStringAt(*stream, 0x25f);
+
+ _messageIds.cantGoThere = IDI_HR0_MSG_CANT_GO_THERE;
+ _messageIds.dontUnderstand = IDI_HR0_MSG_DONT_UNDERSTAND;
+ _messageIds.itemDoesntMove = IDI_HR0_MSG_ITEM_DOESNT_MOVE;
+ _messageIds.itemNotHere = IDI_HR0_MSG_ITEM_NOT_HERE;
+ _messageIds.thanksForPlaying = IDI_HR0_MSG_THANKS_FOR_PLAYING;
+
+ // Load global picture data
+ stream.reset(_disk->createReadStream(0x19, 0xa, 0x80, 0));
+ loadPictures(*stream);
+
+ // Load item picture data
+ stream.reset(_disk->createReadStream(0x1e, 0x9, 0x05));
+ loadItemPictures(*stream, IDI_HR0_NUM_ITEM_PICS);
+
+ // Load commands from executable
+ stream.reset(_disk->createReadStream(0x1d, 0x7, 0x00, 2));
+ readCommands(*stream, _roomCommands);
+
+ stream.reset(_disk->createReadStream(0x1f, 0x7, 0x00, 3));
+ readCommands(*stream, _globalCommands);
+
+ // Load dropped item offsets
+ stream.reset(_disk->createReadStream(0x1b, 0x4, 0x15));
+ loadDroppedItemOffsets(*stream, IDI_HR0_NUM_ITEM_OFFSETS);
+
+ // Load verbs
+ stream.reset(_disk->createReadStream(0x19, 0x0, 0x00, 3));
+ loadWords(*stream, _verbs, _priVerbs);
+
+ // Load nouns
+ stream.reset(_disk->createReadStream(0x22, 0x2, 0x00, 2));
+ loadWords(*stream, _nouns, _priNouns);
+}
+
+void HiRes0Engine::initGameState() {
+ _state.vars.resize(IDI_HR0_NUM_VARS);
+
+ StreamPtr stream(_disk->createReadStream(0x21, 0x5, 0x0e, 2));
+ loadRooms(*stream, IDI_HR0_NUM_ROOMS);
+
+ stream.reset(_disk->createReadStream(0x21, 0x0));
+ loadItems(*stream);
+}
+
+Engine *HiRes0Engine_create(OSystem *syst, const AdlGameDescription *gd) {
+ return new HiRes0Engine(syst, gd);
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/hires0.h b/engines/adl/hires0.h
deleted file mode 100644
index 624f248ea8..0000000000
--- a/engines/adl/hires0.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* 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.
- *
- */
-
-#ifndef ADL_HIRES0_H
-#define ADL_HIRES0_H
-
-#include "adl/adl_v2.h"
-
-namespace Adl {
-
-#define IDS_HR0_DISK_IMAGE "MISSION.NIB"
-
-#define IDI_HR0_NUM_ROOMS 43
-#define IDI_HR0_NUM_MESSAGES 142
-#define IDI_HR0_NUM_VARS 40
-#define IDI_HR0_NUM_ITEM_PICS 2
-#define IDI_HR0_NUM_ITEM_OFFSETS 16
-
-// Messages used outside of scripts
-#define IDI_HR0_MSG_CANT_GO_THERE 110
-#define IDI_HR0_MSG_DONT_UNDERSTAND 112
-#define IDI_HR0_MSG_ITEM_DOESNT_MOVE 114
-#define IDI_HR0_MSG_ITEM_NOT_HERE 115
-#define IDI_HR0_MSG_THANKS_FOR_PLAYING 113
-
-class HiRes0Engine : public AdlEngine_v2 {
-public:
- HiRes0Engine(OSystem *syst, const AdlGameDescription *gd) :
- AdlEngine_v2(syst, gd) { }
- ~HiRes0Engine() { }
-
-private:
- // AdlEngine
- void init();
- void initGameState();
-};
-
-} // End of namespace Adl
-
-#endif
diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
index 26565c03c3..217a9013ba 100644
--- a/engines/adl/hires1.cpp
+++ b/engines/adl/hires1.cpp
@@ -27,11 +27,105 @@
#include "common/stream.h"
#include "common/ptr.h"
-#include "adl/hires1.h"
+#include "adl/adl.h"
+#include "adl/graphics.h"
#include "adl/display.h"
namespace Adl {
+#define IDS_HR1_EXE_0 "AUTO LOAD OBJ"
+#define IDS_HR1_EXE_1 "ADVENTURE"
+#define IDS_HR1_LOADER "MYSTERY.HELLO"
+#define IDS_HR1_MESSAGES "MESSAGES"
+
+#define IDI_HR1_NUM_ROOMS 41
+#define IDI_HR1_NUM_PICS 97
+#define IDI_HR1_NUM_VARS 20
+#define IDI_HR1_NUM_ITEM_OFFSETS 21
+#define IDI_HR1_NUM_MESSAGES 168
+
+// Messages used outside of scripts
+#define IDI_HR1_MSG_CANT_GO_THERE 137
+#define IDI_HR1_MSG_DONT_UNDERSTAND 37
+#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151
+#define IDI_HR1_MSG_ITEM_NOT_HERE 152
+#define IDI_HR1_MSG_THANKS_FOR_PLAYING 140
+#define IDI_HR1_MSG_DONT_HAVE_IT 127
+#define IDI_HR1_MSG_GETTING_DARK 7
+
+#define IDI_HR1_OFS_STR_ENTER_COMMAND 0x5bbc
+#define IDI_HR1_OFS_STR_VERB_ERROR 0x5b4f
+#define IDI_HR1_OFS_STR_NOUN_ERROR 0x5b8e
+#define IDI_HR1_OFS_STR_PLAY_AGAIN 0x5f1e
+#define IDI_HR1_OFS_STR_CANT_GO_THERE 0x6c0a
+#define IDI_HR1_OFS_STR_DONT_HAVE_IT 0x6c31
+#define IDI_HR1_OFS_STR_DONT_UNDERSTAND 0x6c51
+#define IDI_HR1_OFS_STR_GETTING_DARK 0x6c7c
+#define IDI_HR1_OFS_STR_PRESS_RETURN 0x5f68
+#define IDI_HR1_OFS_STR_LINE_FEEDS 0x59d4
+
+#define IDI_HR1_OFS_PD_TEXT_0 0x005d
+#define IDI_HR1_OFS_PD_TEXT_1 0x012b
+#define IDI_HR1_OFS_PD_TEXT_2 0x016d
+#define IDI_HR1_OFS_PD_TEXT_3 0x0259
+
+#define IDI_HR1_OFS_INTRO_TEXT 0x0066
+#define IDI_HR1_OFS_GAME_OR_HELP 0x000f
+
+#define IDI_HR1_OFS_LOGO_0 0x1003
+#define IDI_HR1_OFS_LOGO_1 0x1800
+
+#define IDI_HR1_OFS_ITEMS 0x0100
+#define IDI_HR1_OFS_ROOMS 0x050a
+#define IDI_HR1_OFS_PICS 0x4b03
+#define IDI_HR1_OFS_CMDS_0 0x3c00
+#define IDI_HR1_OFS_CMDS_1 0x3d00
+#define IDI_HR1_OFS_MSGS 0x4d00
+
+#define IDI_HR1_OFS_ITEM_OFFSETS 0x68ff
+#define IDI_HR1_OFS_CORNERS 0x4f00
+
+#define IDI_HR1_OFS_VERBS 0x3800
+#define IDI_HR1_OFS_NOUNS 0x0f00
+
+class HiRes1Engine : public AdlEngine {
+public:
+ HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine(syst, gd),
+ _files(nullptr),
+ _messageDelay(true) { }
+ ~HiRes1Engine() { delete _files; }
+
+private:
+ // AdlEngine
+ void runIntro() const;
+ void init();
+ void initGameState();
+ void restartGame();
+ void printString(const Common::String &str);
+ Common::String loadMessage(uint idx) const;
+ void printMessage(uint idx);
+ void drawItems();
+ void drawItem(Item &item, const Common::Point &pos);
+ void loadRoom(byte roomNr);
+ void showRoom();
+
+ void wordWrap(Common::String &str) const;
+
+ Files *_files;
+ Common::File _exe;
+ Common::Array<DataBlockPtr> _corners;
+ Common::Array<byte> _roomDesc;
+ bool _messageDelay;
+
+ struct {
+ Common::String cantGoThere;
+ Common::String dontHaveIt;
+ Common::String dontUnderstand;
+ Common::String gettingDark;
+ } _gameStrings;
+};
+
void HiRes1Engine::runIntro() const {
StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_0));
@@ -183,12 +277,7 @@ void HiRes1Engine::init() {
// Load dropped item offsets
stream->seek(IDI_HR1_OFS_ITEM_OFFSETS);
- for (uint i = 0; i < IDI_HR1_NUM_ITEM_OFFSETS; ++i) {
- Common::Point p;
- p.x = stream->readByte();
- p.y = stream->readByte();
- _itemOffsets.push_back(p);
- }
+ loadDroppedItemOffsets(*stream, IDI_HR1_NUM_ITEM_OFFSETS);
// Load right-angle line art
stream->seek(IDI_HR1_OFS_CORNERS);
diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h
deleted file mode 100644
index c060bc892e..0000000000
--- a/engines/adl/hires1.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/* 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.
- *
- */
-
-#ifndef ADL_HIRES1_H
-#define ADL_HIRES1_H
-
-#include "common/str.h"
-
-#include "adl/adl.h"
-#include "adl/graphics.h"
-#include "adl/disk.h"
-
-namespace Common {
-class ReadStream;
-struct Point;
-}
-
-namespace Adl {
-
-#define IDS_HR1_EXE_0 "AUTO LOAD OBJ"
-#define IDS_HR1_EXE_1 "ADVENTURE"
-#define IDS_HR1_LOADER "MYSTERY.HELLO"
-#define IDS_HR1_MESSAGES "MESSAGES"
-
-#define IDI_HR1_NUM_ROOMS 41
-#define IDI_HR1_NUM_PICS 97
-#define IDI_HR1_NUM_VARS 20
-#define IDI_HR1_NUM_ITEM_OFFSETS 21
-#define IDI_HR1_NUM_MESSAGES 168
-
-// Messages used outside of scripts
-#define IDI_HR1_MSG_CANT_GO_THERE 137
-#define IDI_HR1_MSG_DONT_UNDERSTAND 37
-#define IDI_HR1_MSG_ITEM_DOESNT_MOVE 151
-#define IDI_HR1_MSG_ITEM_NOT_HERE 152
-#define IDI_HR1_MSG_THANKS_FOR_PLAYING 140
-#define IDI_HR1_MSG_DONT_HAVE_IT 127
-#define IDI_HR1_MSG_GETTING_DARK 7
-
-#define IDI_HR1_OFS_STR_ENTER_COMMAND 0x5bbc
-#define IDI_HR1_OFS_STR_VERB_ERROR 0x5b4f
-#define IDI_HR1_OFS_STR_NOUN_ERROR 0x5b8e
-#define IDI_HR1_OFS_STR_PLAY_AGAIN 0x5f1e
-#define IDI_HR1_OFS_STR_CANT_GO_THERE 0x6c0a
-#define IDI_HR1_OFS_STR_DONT_HAVE_IT 0x6c31
-#define IDI_HR1_OFS_STR_DONT_UNDERSTAND 0x6c51
-#define IDI_HR1_OFS_STR_GETTING_DARK 0x6c7c
-#define IDI_HR1_OFS_STR_PRESS_RETURN 0x5f68
-#define IDI_HR1_OFS_STR_LINE_FEEDS 0x59d4
-
-#define IDI_HR1_OFS_PD_TEXT_0 0x005d
-#define IDI_HR1_OFS_PD_TEXT_1 0x012b
-#define IDI_HR1_OFS_PD_TEXT_2 0x016d
-#define IDI_HR1_OFS_PD_TEXT_3 0x0259
-
-#define IDI_HR1_OFS_INTRO_TEXT 0x0066
-#define IDI_HR1_OFS_GAME_OR_HELP 0x000f
-
-#define IDI_HR1_OFS_LOGO_0 0x1003
-#define IDI_HR1_OFS_LOGO_1 0x1800
-
-#define IDI_HR1_OFS_ITEMS 0x0100
-#define IDI_HR1_OFS_ROOMS 0x050a
-#define IDI_HR1_OFS_PICS 0x4b03
-#define IDI_HR1_OFS_CMDS_0 0x3c00
-#define IDI_HR1_OFS_CMDS_1 0x3d00
-#define IDI_HR1_OFS_MSGS 0x4d00
-
-#define IDI_HR1_OFS_ITEM_OFFSETS 0x68ff
-#define IDI_HR1_OFS_CORNERS 0x4f00
-
-#define IDI_HR1_OFS_VERBS 0x3800
-#define IDI_HR1_OFS_NOUNS 0x0f00
-
-class HiRes1Engine : public AdlEngine {
-public:
- HiRes1Engine(OSystem *syst, const AdlGameDescription *gd) :
- AdlEngine(syst, gd),
- _files(nullptr),
- _messageDelay(true) { }
- ~HiRes1Engine() { delete _files; }
-
-private:
- // AdlEngine
- void runIntro() const;
- void init();
- void initGameState();
- void restartGame();
- void printString(const Common::String &str);
- Common::String loadMessage(uint idx) const;
- void printMessage(uint idx);
- void drawItems();
- void drawItem(Item &item, const Common::Point &pos);
- void loadRoom(byte roomNr);
- void showRoom();
-
- void wordWrap(Common::String &str) const;
-
- Files *_files;
- Common::File _exe;
- Common::Array<DataBlockPtr> _corners;
- Common::Array<byte> _roomDesc;
- bool _messageDelay;
-
- struct {
- Common::String cantGoThere;
- Common::String dontHaveIt;
- Common::String dontUnderstand;
- Common::String gettingDark;
- } _gameStrings;
-};
-
-} // End of namespace Adl
-
-#endif
diff --git a/engines/adl/hires2.cpp b/engines/adl/hires2.cpp
index 14db237d82..199f457b4f 100644
--- a/engines/adl/hires2.cpp
+++ b/engines/adl/hires2.cpp
@@ -26,18 +26,44 @@
#include "common/file.h"
#include "common/stream.h"
-#include "adl/hires2.h"
+#include "adl/adl_v2.h"
#include "adl/display.h"
#include "adl/graphics.h"
#include "adl/disk.h"
namespace Adl {
+#define IDS_HR2_DISK_IMAGE "WIZARD.DSK"
+
+#define IDI_HR2_NUM_ROOMS 135
+#define IDI_HR2_NUM_MESSAGES 255
+#define IDI_HR2_NUM_VARS 40
+#define IDI_HR2_NUM_ITEM_PICS 38
+#define IDI_HR2_NUM_ITEM_OFFSETS 16
+
+// Messages used outside of scripts
+#define IDI_HR2_MSG_CANT_GO_THERE 123
+#define IDI_HR2_MSG_DONT_UNDERSTAND 19
+#define IDI_HR2_MSG_ITEM_DOESNT_MOVE 242
+#define IDI_HR2_MSG_ITEM_NOT_HERE 4
+#define IDI_HR2_MSG_THANKS_FOR_PLAYING 239
+
+class HiRes2Engine : public AdlEngine_v2 {
+public:
+ HiRes2Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine_v2(syst, gd) { }
+
+private:
+ // AdlEngine
+ void runIntro() const;
+ void init();
+ void initGameState();
+};
+
void HiRes2Engine::runIntro() const {
// This only works for the 16-sector re-release. The original
// release is not supported at this time, because we don't have
// access to it.
- _disk->setMode13(false);
+ _disk->setSectorLimit(0);
StreamPtr stream(_disk->createReadStream(0x00, 0xd, 0x17, 1));
_display->setMode(DISPLAY_MODE_TEXT);
@@ -50,7 +76,7 @@ void HiRes2Engine::runIntro() const {
_display->printString(str);
delay(2000);
- _disk->setMode13(true);
+ _disk->setSectorLimit(13);
}
void HiRes2Engine::init() {
@@ -60,12 +86,10 @@ void HiRes2Engine::init() {
if (!_disk->open(IDS_HR2_DISK_IMAGE))
error("Failed to open disk image '" IDS_HR2_DISK_IMAGE "'");
- _disk->setMode13(true);
+ _disk->setSectorLimit(13);
StreamPtr stream(_disk->createReadStream(0x1f, 0x2, 0x00, 4));
-
- for (uint i = 0; i < IDI_HR2_NUM_MESSAGES; ++i)
- _messages.push_back(readDataBlockPtr(*stream));
+ loadMessages(*stream, IDI_HR2_NUM_MESSAGES);
// Read parser messages
stream.reset(_disk->createReadStream(0x1a, 0x1));
@@ -98,20 +122,11 @@ void HiRes2Engine::init() {
// Load global picture data
stream.reset(_disk->createReadStream(0x19, 0xa, 0x80, 0));
- byte picNr;
- while ((picNr = stream->readByte()) != 0xff) {
- if (stream->eos() || stream->err())
- error("Error reading global pic list");
-
- _pictures[picNr] = readDataBlockPtr(*stream);
- }
+ loadPictures(*stream);
// Load item picture data
stream.reset(_disk->createReadStream(0x1e, 0x9, 0x05));
- for (uint i = 0; i < IDI_HR2_NUM_ITEM_PICS; ++i) {
- stream->readByte(); // number
- _itemPics.push_back(readDataBlockPtr(*stream));
- }
+ loadItemPictures(*stream, IDI_HR2_NUM_ITEM_PICS);
// Load commands from executable
stream.reset(_disk->createReadStream(0x1d, 0x7, 0x00, 4));
@@ -122,12 +137,7 @@ void HiRes2Engine::init() {
// Load dropped item offsets
stream.reset(_disk->createReadStream(0x1b, 0x4, 0x15));
- for (uint i = 0; i < IDI_HR2_NUM_ITEM_OFFSETS; ++i) {
- Common::Point p;
- p.x = stream->readByte();
- p.y = stream->readByte();
- _itemOffsets.push_back(p);
- }
+ loadDroppedItemOffsets(*stream, IDI_HR2_NUM_ITEM_OFFSETS);
// Load verbs
stream.reset(_disk->createReadStream(0x19, 0x0, 0x00, 3));
@@ -142,46 +152,10 @@ void HiRes2Engine::initGameState() {
_state.vars.resize(IDI_HR2_NUM_VARS);
StreamPtr stream(_disk->createReadStream(0x21, 0x5, 0x0e, 7));
-
- for (uint i = 0; i < IDI_HR2_NUM_ROOMS; ++i) {
- Room room;
- stream->readByte(); // number
- for (uint j = 0; j < 6; ++j)
- room.connections[j] = stream->readByte();
- room.data = readDataBlockPtr(*stream);
- room.picture = stream->readByte();
- room.curPicture = stream->readByte();
- room.isFirstTime = stream->readByte();
- _state.rooms.push_back(room);
- }
+ loadRooms(*stream, IDI_HR2_NUM_ROOMS);
stream.reset(_disk->createReadStream(0x21, 0x0, 0x00, 2));
-
- byte id;
- while ((id = stream->readByte()) != 0xff) {
- Item item = Item();
- item.id = id;
- item.noun = stream->readByte();
- item.room = stream->readByte();
- item.picture = stream->readByte();
- item.isLineArt = stream->readByte(); // Is this still used in this way?
- item.position.x = stream->readByte();
- item.position.y = stream->readByte();
- item.state = stream->readByte();
- item.description = stream->readByte();
-
- stream->readByte(); // Struct size
-
- byte picListSize = stream->readByte();
-
- // Flag to keep track of what has been drawn on the screen
- stream->readByte();
-
- for (uint i = 0; i < picListSize; ++i)
- item.roomPictures.push_back(stream->readByte());
-
- _state.items.push_back(item);
- }
+ loadItems(*stream);
}
Engine *HiRes2Engine_create(OSystem *syst, const AdlGameDescription *gd) {
diff --git a/engines/adl/hires4.cpp b/engines/adl/hires4.cpp
new file mode 100644
index 0000000000..ddfc868e9a
--- /dev/null
+++ b/engines/adl/hires4.cpp
@@ -0,0 +1,271 @@
+/* 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/system.h"
+#include "common/debug.h"
+#include "common/error.h"
+#include "common/file.h"
+#include "common/stream.h"
+
+#include "adl/adl_v3.h"
+#include "adl/detection.h"
+#include "adl/display.h"
+#include "adl/graphics.h"
+#include "adl/disk.h"
+
+namespace Adl {
+
+#define IDI_HR4_NUM_ROOMS 164
+#define IDI_HR4_NUM_MESSAGES 255
+#define IDI_HR4_NUM_VARS 40
+#define IDI_HR4_NUM_ITEM_DESCS 44
+#define IDI_HR4_NUM_ITEM_PICS 41
+#define IDI_HR4_NUM_ITEM_OFFSETS 40
+
+// Messages used outside of scripts
+#define IDI_HR4_MSG_CANT_GO_THERE 110
+#define IDI_HR4_MSG_DONT_UNDERSTAND 112
+#define IDI_HR4_MSG_ITEM_DOESNT_MOVE 114
+#define IDI_HR4_MSG_ITEM_NOT_HERE 115
+#define IDI_HR4_MSG_THANKS_FOR_PLAYING 113
+
+class HiRes4Engine_Atari : public AdlEngine_v3 {
+public:
+ HiRes4Engine_Atari(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine_v3(syst, gd),
+ _boot(nullptr),
+ _curDisk(0) { }
+ ~HiRes4Engine_Atari();
+
+private:
+ // AdlEngine
+ void init();
+ void initGameState();
+ void loadRoom(byte roomNr);
+ Common::String formatVerbError(const Common::String &verb) const;
+ Common::String formatNounError(const Common::String &verb, const Common::String &noun) const;
+
+ // AdlEngine_v2
+ void adjustDataBlockPtr(byte &track, byte &sector, byte &offset, byte &size) const;
+
+ Common::SeekableReadStream *createReadStream(DiskImage *disk, byte track, byte sector, byte offset = 0, byte size = 0) const;
+ void loadCommonData();
+ void insertDisk(byte diskNr);
+ void rebindDisk();
+
+ DiskImage *_boot;
+ byte _curDisk;
+};
+
+static const char *const atariDisks[] = { "ULYS1A.XFD", "ULYS1B.XFD", "ULYS2C.XFD" };
+
+HiRes4Engine_Atari::~HiRes4Engine_Atari() {
+ delete _boot;
+}
+
+void HiRes4Engine_Atari::init() {
+ _graphics = new Graphics_v2(*_display);
+
+ _boot = new DiskImage();
+ if (!_boot->open(atariDisks[0]))
+ error("Failed to open disk image '%s'", atariDisks[0]);
+
+ insertDisk(1);
+ loadCommonData();
+
+ StreamPtr stream(createReadStream(_boot, 0x06, 0x2));
+ _strings.verbError = readStringAt(*stream, 0x4f);
+ _strings.nounError = readStringAt(*stream, 0x83);
+ _strings.enterCommand = readStringAt(*stream, 0xa6);
+
+ stream.reset(createReadStream(_boot, 0x05, 0xb, 0xd7));
+ _strings_v2.time = readString(*stream, 0xff);
+
+ stream.reset(createReadStream(_boot, 0x06, 0x7, 0x00, 2));
+ _strings_v2.saveInsert = readStringAt(*stream, 0x62);
+ _strings_v2.saveReplace = readStringAt(*stream, 0xdd);
+ _strings_v2.restoreInsert = readStringAt(*stream, 0x12a);
+ _strings_v2.restoreReplace = readStringAt(*stream, 0x1b8);
+ _strings.playAgain = readStringAt(*stream, 0x21b);
+ // TODO: restart sequence has "insert side a/b" strings
+
+ _messageIds.cantGoThere = IDI_HR4_MSG_CANT_GO_THERE;
+ _messageIds.dontUnderstand = IDI_HR4_MSG_DONT_UNDERSTAND;
+ _messageIds.itemDoesntMove = IDI_HR4_MSG_ITEM_DOESNT_MOVE;
+ _messageIds.itemNotHere = IDI_HR4_MSG_ITEM_NOT_HERE;
+ _messageIds.thanksForPlaying = IDI_HR4_MSG_THANKS_FOR_PLAYING;
+
+ stream.reset(createReadStream(_boot, 0x06, 0xd, 0x12, 2));
+ loadItemDescriptions(*stream, IDI_HR4_NUM_ITEM_DESCS);
+
+ stream.reset(createReadStream(_boot, 0x07, 0x1, 0xf4));
+ loadDroppedItemOffsets(*stream, IDI_HR4_NUM_ITEM_OFFSETS);
+
+ stream.reset(createReadStream(_boot, 0x08, 0xe, 0xa5, 5));
+ readCommands(*stream, _roomCommands);
+
+ stream.reset(createReadStream(_boot, 0x0a, 0x9, 0x00, 3));
+ readCommands(*stream, _globalCommands);
+
+ stream.reset(createReadStream(_boot, 0x05, 0x4, 0x00, 3));
+ loadWords(*stream, _verbs, _priVerbs);
+
+ stream.reset(createReadStream(_boot, 0x03, 0xb, 0x00, 6));
+ loadWords(*stream, _nouns, _priNouns);
+}
+
+void HiRes4Engine_Atari::loadRoom(byte roomNr) {
+ if (roomNr >= 59 && roomNr < 113) {
+ if (_curDisk != 2) {
+ insertDisk(2);
+ rebindDisk();
+ }
+ } else if (_curDisk != 1) {
+ insertDisk(1);
+ rebindDisk();
+ }
+
+ if (roomNr == 121) {
+ // Room 121 is not present in the Atari version. This causes
+ // problems when we're dumping scripts with the debugger, so
+ // we intercept this room load here.
+ // FIXME: Find out if the Apple II version does have this room
+ // FIXME: Implement more generic handling of invalid rooms?
+ debug("Warning: attempt to load non-existent room 121");
+ _roomData.description.clear();
+ _roomData.pictures.clear();
+ _roomData.commands.clear();
+ return;
+ }
+
+ AdlEngine_v3::loadRoom(roomNr);
+}
+
+Common::String HiRes4Engine_Atari::formatVerbError(const Common::String &verb) const {
+ Common::String err = _strings.verbError;
+ for (uint i = 0; i < verb.size(); ++i)
+ err.setChar(verb[i], i + 8);
+ return err;
+}
+
+Common::String HiRes4Engine_Atari::formatNounError(const Common::String &verb, const Common::String &noun) const {
+ Common::String err = _strings.nounError;
+ for (uint i = 0; i < verb.size(); ++i)
+ err.setChar(verb[i], i + 8);
+ for (uint i = 0; i < noun.size(); ++i)
+ err.setChar(noun[i], i + 19);
+ return err;
+}
+
+void HiRes4Engine_Atari::insertDisk(byte diskNr) {
+ if (_curDisk == diskNr)
+ return;
+
+ _curDisk = diskNr;
+
+ delete _disk;
+ _disk = new DiskImage();
+ if (!_disk->open(atariDisks[diskNr]))
+ error("Failed to open disk image '%s'", atariDisks[diskNr]);
+}
+
+void HiRes4Engine_Atari::rebindDisk() {
+ // As room.data is bound to the DiskImage, we need to rebind them here
+ // We cannot simply reload the rooms as that would reset their state
+
+ // FIXME: Remove DataBlockPtr-DiskImage coupling?
+
+ StreamPtr stream(createReadStream(_boot, 0x03, 0x1, 0x0e, 9));
+ for (uint i = 0; i < IDI_HR4_NUM_ROOMS; ++i) {
+ stream->skip(7);
+ _state.rooms[i].data = readDataBlockPtr(*stream);
+ stream->skip(3);
+ }
+
+ // Rebind data that is on both side B and C
+ loadCommonData();
+}
+
+void HiRes4Engine_Atari::loadCommonData() {
+ _messages.clear();
+ StreamPtr stream(createReadStream(_boot, 0x0a, 0x4, 0x00, 3));
+ loadMessages(*stream, IDI_HR4_NUM_MESSAGES);
+
+ _pictures.clear();
+ stream.reset(createReadStream(_boot, 0x05, 0xe, 0x80));
+ loadPictures(*stream);
+
+ _itemPics.clear();
+ stream.reset(createReadStream(_boot, 0x09, 0xe, 0x05));
+ loadItemPictures(*stream, IDI_HR4_NUM_ITEM_PICS);
+}
+
+void HiRes4Engine_Atari::initGameState() {
+ _state.vars.resize(IDI_HR4_NUM_VARS);
+
+ StreamPtr stream(createReadStream(_boot, 0x03, 0x1, 0x0e, 9));
+ loadRooms(*stream, IDI_HR4_NUM_ROOMS);
+
+ stream.reset(createReadStream(_boot, 0x02, 0xc, 0x00, 12));
+ loadItems(*stream);
+
+ // FIXME
+ _display->moveCursorTo(Common::Point(0, 23));
+}
+
+Common::SeekableReadStream *HiRes4Engine_Atari::createReadStream(DiskImage *disk, byte track, byte sector, byte offset, byte size) const {
+ adjustDataBlockPtr(track, sector, offset, size);
+ return disk->createReadStream(track, sector, offset, size);
+}
+
+void HiRes4Engine_Atari::adjustDataBlockPtr(byte &track, byte &sector, byte &offset, byte &size) const {
+ // Convert the Apple II disk offsets in the game, to Atari disk offsets
+ uint sectorIndex = (track * 16 + sector + 1) << 1;
+
+ // Atari uses 128 bytes per sector vs. 256 on the Apple II
+ // Note that size indicates *additional* sectors to read after reading one sector
+ size *= 2;
+
+ if (offset >= 128) {
+ // Offset in the second half of an Apple II sector, skip one sector and adjust offset
+ ++sectorIndex;
+ offset -= 128;
+ } else {
+ // Offset in the first half of an Apple II sector, we need to read one additional sector
+ ++size;
+ }
+
+ // Compute track/sector for Atari's 18 sectors per track (sectorIndex is 1-based)
+ track = (sectorIndex - 1) / 18;
+ sector = (sectorIndex - 1) % 18;
+}
+
+Engine *HiRes4Engine_create(OSystem *syst, const AdlGameDescription *gd) {
+ switch (gd->desc.platform) {
+ case Common::kPlatformAtariST:
+ return new HiRes4Engine_Atari(syst, gd);
+ default:
+ error("Unsupported platform");
+ }
+}
+
+} // End of namespace Adl
diff --git a/engines/adl/hires6.cpp b/engines/adl/hires6.cpp
index e9df7b513a..a1fea05f19 100644
--- a/engines/adl/hires6.cpp
+++ b/engines/adl/hires6.cpp
@@ -27,13 +27,65 @@
#include "common/stream.h"
#include "common/memstream.h"
-#include "adl/hires6.h"
+#include "adl/adl_v4.h"
#include "adl/display.h"
#include "adl/graphics.h"
#include "adl/disk.h"
namespace Adl {
+#define IDI_HR6_NUM_ROOMS 35
+#define IDI_HR6_NUM_MESSAGES 256
+#define IDI_HR6_NUM_VARS 40
+#define IDI_HR6_NUM_ITEM_DESCS 15
+#define IDI_HR6_NUM_ITEM_PICS 15
+#define IDI_HR6_NUM_ITEM_OFFSETS 16
+
+// Messages used outside of scripts
+#define IDI_HR6_MSG_CANT_GO_THERE 249
+#define IDI_HR6_MSG_DONT_UNDERSTAND 247
+#define IDI_HR6_MSG_ITEM_DOESNT_MOVE 253
+#define IDI_HR6_MSG_ITEM_NOT_HERE 254
+#define IDI_HR6_MSG_THANKS_FOR_PLAYING 252
+
+struct DiskDataDesc {
+ byte track;
+ byte sector;
+ byte offset;
+ byte volume;
+};
+
+class HiRes6Engine : public AdlEngine_v4 {
+public:
+ HiRes6Engine(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine_v4(syst, gd),
+ _boot(nullptr),
+ _currVerb(0),
+ _currNoun(0) {
+ }
+
+ ~HiRes6Engine() { delete _boot; }
+
+private:
+ // AdlEngine
+ void runIntro() const;
+ void init();
+ void initGameState();
+ void printRoomDescription();
+ void showRoom();
+ Common::String formatVerbError(const Common::String &verb) const;
+ Common::String formatNounError(const Common::String &verb, const Common::String &noun) const;
+
+ // AdlEngine_v2
+ void printString(const Common::String &str);
+
+ void loadDisk(byte disk);
+
+ DiskImage *_boot;
+ byte _currVerb, _currNoun;
+ Common::Array<DiskDataDesc> _diskDataDesc;
+};
+
static const char *disks[] = { "DARK1A.DSK", "DARK1B.NIB", "DARK2A.NIB", "DARK2B.NIB" };
#define SECTORS_PER_TRACK 16
@@ -141,18 +193,12 @@ void HiRes6Engine::init() {
// Item descriptions
stream.reset(loadSectors(_boot, 0x6, 0xb, 2));
- stream->seek(0x34);
- for (uint i = 0; i < IDI_HR6_NUM_ITEM_DESCS; ++i)
- _itemDesc.push_back(readString(*stream, 0xff));
+ stream->seek(0x16);
+ loadItemDescriptions(*stream, IDI_HR6_NUM_ITEM_DESCS);
// Load dropped item offsets
stream.reset(_boot->createReadStream(0x8, 0x9, 0x16));
- for (uint i = 0; i < IDI_HR6_NUM_ITEM_OFFSETS; ++i) {
- Common::Point p;
- p.x = stream->readByte();
- p.y = stream->readByte();
- _itemOffsets.push_back(p);
- }
+ loadDroppedItemOffsets(*stream, IDI_HR6_NUM_ITEM_OFFSETS);
// Location of game data for each disc
stream.reset(_boot->createReadStream(0x5, 0xa, 0x03));
@@ -187,10 +233,7 @@ void HiRes6Engine::loadDisk(byte disk) {
// Load item picture data (indexed on boot disk)
StreamPtr stream(_boot->createReadStream(0xb, 0xd, 0x08));
_itemPics.clear();
- for (uint i = 0; i < IDI_HR6_NUM_ITEM_PICS; ++i) {
- stream->readByte();
- _itemPics.push_back(readDataBlockPtr(*stream));
- }
+ loadItemPictures(*stream, IDI_HR6_NUM_ITEM_PICS);
_curDisk = disk;
@@ -214,19 +257,13 @@ void HiRes6Engine::loadDisk(byte disk) {
// Messages
_messages.clear();
uint count = size / 4;
- for (uint i = 0; i < count; ++i)
- _messages.push_back(readDataBlockPtr(*stream));
+ loadMessages(*stream, count);
break;
}
case 0x4a80: {
// Global pics
_pictures.clear();
- byte picNr;
- while ((picNr = stream->readByte()) != 0xff) {
- if (stream->eos() || stream->err())
- error("Error reading global pic list");
- _pictures[picNr] = readDataBlockPtr(*stream);
- }
+ loadPictures(*stream);
break;
}
case 0x4000:
@@ -243,17 +280,7 @@ void HiRes6Engine::loadDisk(byte disk) {
stream->skip(14); // Skip invalid room 0
_state.rooms.clear();
- for (uint i = 0; i < count; ++i) {
- Room room;
- stream->readByte(); // number
- for (uint j = 0; j < 6; ++j)
- room.connections[j] = stream->readByte();
- room.data = readDataBlockPtr(*stream);
- room.picture = stream->readByte();
- room.curPicture = stream->readByte();
- room.isFirstTime = stream->readByte();
- _state.rooms.push_back(room);
- }
+ loadRooms(*stream, count);
break;
}
case 0x7b00:
@@ -287,31 +314,7 @@ void HiRes6Engine::initGameState() {
StreamPtr stream(_boot->createReadStream(0x3, 0xe, 0x03));
- byte id;
- while ((id = stream->readByte()) != 0xff) {
- Item item = Item();
- item.id = id;
- item.noun = stream->readByte();
- item.room = stream->readByte();
- item.picture = stream->readByte();
- item.isLineArt = stream->readByte(); // Now seems to be disk number
- item.position.x = stream->readByte();
- item.position.y = stream->readByte();
- item.state = stream->readByte();
- item.description = stream->readByte();
-
- stream->readByte(); // Struct size
-
- byte picListSize = stream->readByte();
-
- // Flag to keep track of what has been drawn on the screen
- stream->readByte();
-
- for (uint i = 0; i < picListSize; ++i)
- item.roomPictures.push_back(stream->readByte());
-
- _state.items.push_back(item);
- }
+ loadItems(*stream);
_currVerb = _currNoun = 0;
}
diff --git a/engines/adl/hires6.h b/engines/adl/hires6.h
deleted file mode 100644
index 0f604d848c..0000000000
--- a/engines/adl/hires6.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* 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.
- *
- */
-
-#ifndef ADL_HIRES6_H
-#define ADL_HIRES6_H
-
-#include "common/str.h"
-
-#include "adl/adl_v3.h"
-#include "adl/disk.h"
-
-namespace Common {
-class ReadStream;
-struct Point;
-}
-
-namespace Adl {
-
-#define IDI_HR6_NUM_ROOMS 35
-#define IDI_HR6_NUM_MESSAGES 256
-#define IDI_HR6_NUM_VARS 40
-#define IDI_HR6_NUM_ITEM_DESCS 15
-#define IDI_HR6_NUM_ITEM_PICS 15
-#define IDI_HR6_NUM_ITEM_OFFSETS 16
-
-// Messages used outside of scripts
-#define IDI_HR6_MSG_CANT_GO_THERE 249
-#define IDI_HR6_MSG_DONT_UNDERSTAND 247
-#define IDI_HR6_MSG_ITEM_DOESNT_MOVE 253
-#define IDI_HR6_MSG_ITEM_NOT_HERE 254
-#define IDI_HR6_MSG_THANKS_FOR_PLAYING 252
-
-struct DiskDataDesc {
- byte track;
- byte sector;
- byte offset;
- byte volume;
-};
-
-class HiRes6Engine : public AdlEngine_v3 {
-public:
- HiRes6Engine(OSystem *syst, const AdlGameDescription *gd) :
- AdlEngine_v3(syst, gd),
- _boot(nullptr),
- _currVerb(0),
- _currNoun(0) {
- }
-
- ~HiRes6Engine() { delete _boot; }
-
-private:
- // AdlEngine
- void runIntro() const;
- void init();
- void initGameState();
- void printRoomDescription();
- void showRoom();
- Common::String formatVerbError(const Common::String &verb) const;
- Common::String formatNounError(const Common::String &verb, const Common::String &noun) const;
-
- // AdlEngine_v2
- void printString(const Common::String &str);
-
- void loadDisk(byte disk);
-
- DiskImage *_boot;
- byte _currVerb, _currNoun;
- Common::Array<DiskDataDesc> _diskDataDesc;
-};
-
-} // End of namespace Adl
-
-#endif
diff --git a/engines/adl/module.mk b/engines/adl/module.mk
index d17c8569b3..d1de2a6c02 100644
--- a/engines/adl/module.mk
+++ b/engines/adl/module.mk
@@ -4,6 +4,7 @@ MODULE_OBJS := \
adl.o \
adl_v2.o \
adl_v3.o \
+ adl_v4.o \
console.o \
detection.o \
disk.o \
@@ -14,6 +15,7 @@ MODULE_OBJS := \
hires0.o \
hires1.o \
hires2.o \
+ hires4.o \
hires6.o \
speaker.o