From 70588aecdc9df737821dc37c466b4274b5f76549 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Sat, 27 Aug 2016 20:20:29 +0200 Subject: ADL: Load hires4 verbs, nouns and items --- engines/adl/adl_v2.cpp | 33 ++++++++++++++++++++++++ engines/adl/adl_v2.h | 2 ++ engines/adl/adl_v3.cpp | 24 ++++++++++++++++++ engines/adl/adl_v3.h | 2 ++ engines/adl/adl_v4.cpp | 15 +---------- engines/adl/adl_v4.h | 2 +- engines/adl/hires0.cpp | 26 +------------------ engines/adl/hires2.cpp | 26 +------------------ engines/adl/hires4.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++++++++-- engines/adl/hires4.h | 25 ++++++++++++++++-- engines/adl/hires6.cpp | 31 +++-------------------- 11 files changed, 158 insertions(+), 97 deletions(-) diff --git a/engines/adl/adl_v2.cpp b/engines/adl/adl_v2.cpp index e18f3339f8..2b9a1b061a 100644 --- a/engines/adl/adl_v2.cpp +++ b/engines/adl/adl_v2.cpp @@ -359,9 +359,42 @@ 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::SeekableReadStream &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"); +} + 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 327b36e913..e8894b5e87 100644 --- a/engines/adl/adl_v2.h +++ b/engines/adl/adl_v2.h @@ -52,6 +52,8 @@ protected: void takeItem(byte noun); virtual DataBlockPtr readDataBlockPtr(Common::ReadStream &f) const; + virtual void adjustDataBlockPtr(byte &track, byte §or, byte &offset, byte &size) const { } + void loadItems(Common::SeekableReadStream &stream); void checkTextOverflow(char c); diff --git a/engines/adl/adl_v3.cpp b/engines/adl/adl_v3.cpp index 6b93acde61..6551524c9e 100644 --- a/engines/adl/adl_v3.cpp +++ b/engines/adl/adl_v3.cpp @@ -32,6 +32,30 @@ Common::String AdlEngine_v3::getItemDescription(const Item &item) const { return _itemDesc[item.description - 1]; } +void AdlEngine_v3::loadItemDescriptions(Common::SeekableReadStream &stream, byte count) { + int32 startPos = stream.pos(); + uint16 baseAddr = stream.readUint16LE(); +debug("%04x", baseAddr); + // This code assumes that the first pointer points to a string that + // directly follows the pointer table + assert(baseAddr != 0); + baseAddr -= count * 2; + + for (uint i = 0; i < count; ++i) { + stream.seek(startPos + i * 2); + uint16 offset = stream.readUint16LE(); + + if (offset > 0) { + stream.seek(startPos + offset - baseAddr); + _itemDesc.push_back(readString(stream, 0xff)); + } else + _itemDesc.push_back(Common::String()); + } + + if (stream.eos() || stream.err()) + error("Error loading item descriptions"); +} + typedef Common::Functor1Mem OpcodeV3; void AdlEngine_v3::setupOpcodeTables() { diff --git a/engines/adl/adl_v3.h b/engines/adl/adl_v3.h index 759b17cc6f..b0d40f3993 100644 --- a/engines/adl/adl_v3.h +++ b/engines/adl/adl_v3.h @@ -38,6 +38,8 @@ protected: virtual void setupOpcodeTables(); Common::String getItemDescription(const Item &item) const; + void loadItemDescriptions(Common::SeekableReadStream &stream, byte count); + int o3_isNounNotInRoom(ScriptEnv &e); int o3_listInv(ScriptEnv &e); diff --git a/engines/adl/adl_v4.cpp b/engines/adl/adl_v4.cpp index 602ee25683..ed20c82513 100644 --- a/engines/adl/adl_v4.cpp +++ b/engines/adl/adl_v4.cpp @@ -59,21 +59,8 @@ void AdlEngine_v4::applyDiskOffset(byte &track, byte §or) const { track += _diskOffsets[_curDisk].track; } -DataBlockPtr AdlEngine_v4::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"); - - if (track == 0 && sector == 0 && offset == 0 && size == 0) - return DataBlockPtr(); - +void AdlEngine_v4::adjustDataBlockPtr(byte &track, byte §or, byte &offset, byte &size) const { applyDiskOffset(track, sector); - - return _disk->getDataBlock(track, sector, offset, size); } typedef Common::Functor1Mem OpcodeV4; diff --git a/engines/adl/adl_v4.h b/engines/adl/adl_v4.h index dc9a27501e..79aa824d92 100644 --- a/engines/adl/adl_v4.h +++ b/engines/adl/adl_v4.h @@ -49,7 +49,7 @@ protected: Common::String getItemDescription(const Item &item) const; // AdlEngine_v2 - virtual DataBlockPtr readDataBlockPtr(Common::ReadStream &f) const; + virtual void adjustDataBlockPtr(byte &track, byte §or, byte &offset, byte &size) const; void applyDiskOffset(byte &track, byte §or) const; diff --git a/engines/adl/hires0.cpp b/engines/adl/hires0.cpp index 875a06c73d..5bfe482c7c 100644 --- a/engines/adl/hires0.cpp +++ b/engines/adl/hires0.cpp @@ -134,31 +134,7 @@ void HiRes0Engine::initGameState() { 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); - } + loadItems(*stream); } Engine *HiRes0Engine_create(OSystem *syst, const AdlGameDescription *gd) { diff --git a/engines/adl/hires2.cpp b/engines/adl/hires2.cpp index d0e459c96c..34de51885a 100644 --- a/engines/adl/hires2.cpp +++ b/engines/adl/hires2.cpp @@ -157,31 +157,7 @@ void HiRes2Engine::initGameState() { 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 index 22fd9c2f81..1ce2a44c4a 100644 --- a/engines/adl/hires4.cpp +++ b/engines/adl/hires4.cpp @@ -27,24 +27,89 @@ #include "common/stream.h" #include "adl/hires4.h" +#include "adl/detection.h" #include "adl/display.h" #include "adl/graphics.h" #include "adl/disk.h" namespace Adl { -void HiRes4Engine::runIntro() const { +HiRes4Engine::~HiRes4Engine() { + delete _disk2; + delete _disk3; } void HiRes4Engine::init() { _graphics = new Graphics_v2(*_display); + + const char *const *names = getDiskImageNames(); + + _disk = new DiskImage(); + if (!_disk->open(names[0])) + error("Failed to open disk image '%s'", names[0]); + + _disk2 = new DiskImage(); + if (!_disk2->open(names[1])) + error("Failed to open disk image '%s'", names[1]); + + _disk3 = new DiskImage(); + if (!_disk3->open(names[2])) + error("Failed to open disk image '%s'", names[2]); + + StreamPtr stream(createReadStream(_disk, 0x06, 0xd, 0x12, 2)); + loadItemDescriptions(*stream, IDI_HR4_NUM_ITEM_DESCS); + + stream.reset(createReadStream(_disk, 0x05, 0x4, 0x00, 3)); + loadWords(*stream, _verbs, _priVerbs); + + stream.reset(createReadStream(_disk, 0x03, 0xb, 0x00, 6)); + loadWords(*stream, _nouns, _priNouns); } void HiRes4Engine::initGameState() { + StreamPtr stream(createReadStream(_disk, 0x02, 0xc, 0x00, 12)); + loadItems(*stream); +} + +Common::SeekableReadStream *HiRes4Engine::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 §or, 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; +} + +const char *const *HiRes4Engine_Atari::getDiskImageNames() const { + static const char *const disks[] = { "ULYS1A.XFD", "ULYS1B.XFD", "ULYS2C.XFD" }; + return disks; } Engine *HiRes4Engine_create(OSystem *syst, const AdlGameDescription *gd) { - return new HiRes4Engine(syst, 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/hires4.h b/engines/adl/hires4.h index f1c429ce38..a578080857 100644 --- a/engines/adl/hires4.h +++ b/engines/adl/hires4.h @@ -29,15 +29,36 @@ namespace Adl { +#define IDI_HR4_NUM_ITEM_DESCS 44 + class HiRes4Engine : public AdlEngine_v3 { public: + ~HiRes4Engine(); + +protected: HiRes4Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine_v3(syst, gd) { } -private: // AdlEngine - void runIntro() const; void init(); void initGameState(); + + Common::SeekableReadStream *createReadStream(DiskImage *disk, byte track, byte sector, byte offset = 0, byte size = 0) const; + virtual const char *const *getDiskImageNames() const = 0; + + // FIXME: use an array? + DiskImage *_disk2, *_disk3; +}; + +class HiRes4Engine_Atari : public HiRes4Engine { +public: + HiRes4Engine_Atari(OSystem *syst, const AdlGameDescription *gd) : HiRes4Engine(syst, gd) { } + +private: + // AdlEngine_v2 + virtual void adjustDataBlockPtr(byte &track, byte §or, byte &offset, byte &size) const; + + // HiRes4Engine + virtual const char *const *getDiskImageNames() const; }; } // End of namespace Adl diff --git a/engines/adl/hires6.cpp b/engines/adl/hires6.cpp index e9df7b513a..cf06591f6d 100644 --- a/engines/adl/hires6.cpp +++ b/engines/adl/hires6.cpp @@ -141,9 +141,8 @@ 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)); @@ -287,31 +286,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; } -- cgit v1.2.3