aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWalter van Niftrik2016-12-11 13:35:15 +0100
committerWalter van Niftrik2016-12-11 13:36:22 +0100
commit6b132706d309f0b62bd2af36ad8b956a5db652f7 (patch)
tree267bf2576b95e7a3546ef0cb03399cb5f84ac8fa
parentc4bf56960d24cc9d1403eda00568056c09fcf2d0 (diff)
downloadscummvm-rg350-6b132706d309f0b62bd2af36ad8b956a5db652f7.tar.gz
scummvm-rg350-6b132706d309f0b62bd2af36ad8b956a5db652f7.tar.bz2
scummvm-rg350-6b132706d309f0b62bd2af36ad8b956a5db652f7.zip
ADL: Load hires5 data
-rw-r--r--engines/adl/adl.h19
-rw-r--r--engines/adl/adl_v4.cpp199
-rw-r--r--engines/adl/adl_v4.h37
-rw-r--r--engines/adl/detection.cpp24
-rw-r--r--engines/adl/hires1.cpp4
-rw-r--r--engines/adl/hires2.cpp4
-rw-r--r--engines/adl/hires5.cpp90
-rw-r--r--engines/adl/hires6.cpp4
8 files changed, 357 insertions, 24 deletions
diff --git a/engines/adl/adl.h b/engines/adl/adl.h
index fc696f074f..06be0e072d 100644
--- a/engines/adl/adl.h
+++ b/engines/adl/adl.h
@@ -159,18 +159,30 @@ struct Time {
Time() : hours(12), minutes(0) { }
};
+struct RoomState {
+ byte picture;
+ byte isFirstTime;
+};
+
+struct Region {
+ Common::Array<byte> vars;
+ Common::Array<RoomState> rooms;
+};
+
struct State {
+ Common::Array<Region> regions;
Common::Array<Room> rooms;
Common::List<Item> items;
Common::Array<byte> vars;
+ byte region;
byte room;
byte curPicture;
uint16 moves;
bool isDark;
Time time;
- State() : room(1), curPicture(0), moves(1), isDark(false) { }
+ State() : region(0), room(1), curPicture(0), moves(1), isDark(false) { }
};
typedef Common::List<Command> Commands;
@@ -362,8 +374,10 @@ protected:
bool _isRestarting, _isRestoring, _isQuitting;
bool _skipOneCommand;
+ const AdlGameDescription *_gameDescription;
+
private:
- virtual void runIntro() const { }
+ virtual void runIntro() { }
virtual void init() = 0;
virtual void initGameState() = 0;
virtual void drawItems() = 0;
@@ -385,7 +399,6 @@ private:
Console *_console;
GUI::Debugger *getDebugger() { return _console; }
- const AdlGameDescription *_gameDescription;
byte _saveVerb, _saveNoun, _restoreVerb, _restoreNoun;
bool _canSaveNow, _canRestoreNow;
};
diff --git a/engines/adl/adl_v4.cpp b/engines/adl/adl_v4.cpp
index 5fc15169c5..6a74881db5 100644
--- a/engines/adl/adl_v4.cpp
+++ b/engines/adl/adl_v4.cpp
@@ -21,11 +21,208 @@
*/
#include "adl/adl_v4.h"
+#include "adl/detection.h"
namespace Adl {
AdlEngine_v4::AdlEngine_v4(OSystem *syst, const AdlGameDescription *gd) :
- AdlEngine_v3(syst, gd) {
+ AdlEngine_v3(syst, gd),
+ _currentVolume(0),
+ _itemPicIndex(nullptr) {
+
+}
+
+AdlEngine_v4::~AdlEngine_v4() {
+ delete _itemPicIndex;
+}
+
+Common::String AdlEngine_v4::loadMessage(uint idx) const {
+ Common::String str = AdlEngine_v3::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];
+}
+
+DiskImage *AdlEngine_v4::loadDisk(byte volume) const {
+ const ADGameFileDescription *ag;
+
+ for (ag = _gameDescription->desc.filesDescriptions; ag->fileName; ag++) {
+ if (ag->fileType == volume) {
+ DiskImage *disk = new DiskImage();
+ if (!disk->open(ag->fileName))
+ error("Failed to open %s", ag->fileName);
+ return disk;
+ }
+ }
+
+ error("Disk volume %d not found", volume);
+}
+
+void AdlEngine_v4::insertDisk(byte volume) {
+ delete _disk;
+ _disk = loadDisk(volume);
+ _currentVolume = volume;
+}
+
+void AdlEngine_v4::loadRegionLocations(Common::ReadStream &stream, uint regions) {
+ for (uint r = 0; r < regions; ++r) {
+ RegionLocation loc;
+ loc.track = stream.readByte();
+ loc.sector = stream.readByte();
+
+ if (stream.eos() || stream.err())
+ error("Failed to read region locations");
+
+ _regionLocations.push_back(loc);
+ }
+}
+
+void AdlEngine_v4::loadRegionInitDataOffsets(Common::ReadStream &stream, uint regions) {
+ for (uint r = 0; r < regions; ++r) {
+ RegionInitDataOffset init;
+ init.track = stream.readByte();
+ init.sector = stream.readByte();
+ init.offset = stream.readByte();
+ init.volume = stream.readByte();
+
+ if (stream.eos() || stream.err())
+ error("Failed to read region init data offsets");
+
+ _regionInitDataOffsets.push_back(init);
+ }
+}
+
+void AdlEngine_v4::initRegions(const byte *roomsPerRegion, uint regions) {
+ _state.regions.resize(regions);
+
+ for (uint r = 0; r < regions; ++r) {
+ Region &regn = _state.regions[r];
+ // Each region has 24 variables
+ regn.vars.resize(24);
+
+ regn.rooms.resize(roomsPerRegion[r]);
+ for (uint rm = 0; rm < roomsPerRegion[r]; ++rm) {
+ // TODO: hires6 uses 0xff and has slightly different
+ // code working on these values
+ regn.rooms[rm].picture = 1;
+ regn.rooms[rm].isFirstTime = 1;
+ }
+ }
+}
+
+void AdlEngine_v4::fixupDiskOffset(byte &track, byte &sector) const {
+ if (_state.region == 0)
+ return;
+
+ sector += _regionLocations[_state.region - 1].sector;
+ if (sector >= 16) {
+ sector -= 16;
+ ++track;
+ }
+
+ track += _regionLocations[_state.region - 1].track;
+}
+
+void AdlEngine_v4::adjustDataBlockPtr(byte &track, byte &sector, byte &offset, byte &size) const {
+ fixupDiskOffset(track, sector);
+}
+
+void AdlEngine_v4::loadRegion(byte region) {
+ if (_currentVolume != _regionInitDataOffsets[region - 1].volume) {
+ insertDisk(_regionInitDataOffsets[region - 1].volume);
+
+ // FIXME: This shouldn't be needed, but currently is, due to
+ // implementation choices made earlier on for DataBlockPtr and DiskImage.
+ _state.region = 0; // To avoid region offset being applied
+ _itemPics.clear();
+ loadItemPictures(*_itemPicIndex, _itemPicIndex->size() / 5);
+ }
+
+ _state.region = region;
+
+ byte track = _regionInitDataOffsets[region - 1].track;
+ byte sector = _regionInitDataOffsets[region - 1].sector;
+ uint offset = _regionInitDataOffsets[region - 1].offset;
+
+ fixupDiskOffset(track, sector);
+
+ for (uint block = 0; block < 7; ++block) {
+ StreamPtr stream(_disk->createReadStream(track, sector, offset, 1));
+
+ uint16 addr = stream->readUint16LE();
+ uint16 size = stream->readUint16LE();
+
+ stream.reset(_disk->createReadStream(track, sector, offset, size / 256 + 1));
+ stream->skip(4);
+
+ switch (addr) {
+ case 0x9000: {
+ // Messages
+ _messages.clear();
+ uint count = size / 4;
+ loadMessages(*stream, count);
+ break;
+ }
+ case 0x4a80: {
+ // Global pics
+ _pictures.clear();
+ loadPictures(*stream);
+ break;
+ }
+ case 0x4000:
+ // Verbs
+ loadWords(*stream, _verbs, _priVerbs);
+ break;
+ case 0x1800:
+ // Nouns
+ loadWords(*stream, _nouns, _priNouns);
+ break;
+ case 0x0e00: {
+ // Rooms
+ uint count = size / 14 - 1;
+ stream->skip(14); // Skip invalid room 0
+
+ _state.rooms.clear();
+ loadRooms(*stream, count);
+ break;
+ }
+ case 0x7b00:
+ // Global commands
+ readCommands(*stream, _globalCommands);
+ break;
+ case 0x9500:
+ // Room commands
+ readCommands(*stream, _roomCommands);
+ break;
+ default:
+ error("Unknown data block found (addr %04x; size %04x)", addr, size);
+ }
+
+ offset += 4 + size;
+ while (offset >= 256) {
+ offset -= 256;
+ ++sector;
+ if (sector >= 16) {
+ sector = 0;
+ ++track;
+ }
+ }
+ }
+}
+
+void AdlEngine_v4::loadItemPicIndex(Common::ReadStream &stream, uint items) {
+ _itemPicIndex = stream.readStream(items * 5);
+
+ if (stream.eos() || stream.err())
+ error("Error reading item index");
}
} // End of namespace Adl
diff --git a/engines/adl/adl_v4.h b/engines/adl/adl_v4.h
index b3465cb10a..2a5ceb422d 100644
--- a/engines/adl/adl_v4.h
+++ b/engines/adl/adl_v4.h
@@ -27,12 +27,47 @@
namespace Adl {
+// Base track/sector for a region
+struct RegionLocation {
+ byte track;
+ byte sector;
+};
+
+// Location of the 7 initial data blocks, relative to RegionLocation
+struct RegionInitDataOffset {
+ byte track;
+ byte sector;
+ byte offset;
+ byte volume;
+};
+
class AdlEngine_v4 : public AdlEngine_v3 {
public:
- virtual ~AdlEngine_v4() { }
+ virtual ~AdlEngine_v4();
protected:
AdlEngine_v4(OSystem *syst, const AdlGameDescription *gd);
+
+ // AdlEngine
+ virtual Common::String loadMessage(uint idx) const;
+ virtual Common::String getItemDescription(const Item &item) const;
+
+ // AdlEngine_v2
+ virtual void adjustDataBlockPtr(byte &track, byte &sector, byte &offset, byte &size) const;
+
+ DiskImage *loadDisk(byte volume) const;
+ void insertDisk(byte volume);
+ void loadRegionLocations(Common::ReadStream &stream, uint regions);
+ void loadRegionInitDataOffsets(Common::ReadStream &stream, uint regions);
+ void initRegions(const byte *roomsPerRegion, uint regions);
+ void fixupDiskOffset(byte &track, byte &sector) const;
+ void loadRegion(byte region);
+ void loadItemPicIndex(Common::ReadStream &stream, uint items);
+
+ byte _currentVolume;
+ Common::Array<RegionLocation> _regionLocations;
+ Common::Array<RegionInitDataOffset> _regionInitDataOffsets;
+ Common::SeekableReadStream *_itemPicIndex;
};
} // End of namespace Adl
diff --git a/engines/adl/detection.cpp b/engines/adl/detection.cpp
index 6c1085a127..cba66faca9 100644
--- a/engines/adl/detection.cpp
+++ b/engines/adl/detection.cpp
@@ -162,18 +162,18 @@ static const AdlGameDescription gameDescriptions[] = {
{
"hires5", 0,
{
- { "TZONE1A.NIB", 0, "475dedb7396fdcea81c1a2a4046caebe", 232960 },
- { "TZONE1B.NIB", 0, "f8aaea094ebbe41cf4354d9fe2c30d9a", 232960 },
- { "TZONE2C.NIB", 0, "b351a367dc48e776bf08e42a3f50ae74", 232960 },
- { "TZONE2D.NIB", 0, "9583b287a5c95960f5335878102bb8b1", 232960 },
- { "TZONE3E.NIB", 0, "502e42a0cb69ffe4a48cd51c1ff210cf", 232960 },
- { "TZONE3F.NIB", 0, "3d6e0aae15f590b72b6759535b6b7d3c", 232960 },
- { "TZONE4G.NIB", 0, "ede4113a9c9e17745faf71d099808a18", 232960 },
- { "TZONE4H.NIB", 0, "f95dae4aae1155a27f7120230464d4e1", 232960 },
- { "TZONE5I.NIB", 0, "92b3b376877f81a7b7ae426bf1e65456", 232960 },
- { "TZONE5J.NIB", 0, "c9ef796fa596548dbf8f085901f0bac3", 232960 },
- { "TZONE6K.NIB", 0, "2e5323be637002efce1d4c813ae20a3f", 232960 },
- { "TZONE6L.NIB", 0, "7c9268f0ea2d02120c77a46337b3d975", 232960 },
+ { "TZONE1A.NIB", 2, "475dedb7396fdcea81c1a2a4046caebe", 232960 },
+ { "TZONE1B.NIB", 3, "f8aaea094ebbe41cf4354d9fe2c30d9a", 232960 },
+ { "TZONE2C.NIB", 4, "b351a367dc48e776bf08e42a3f50ae74", 232960 },
+ { "TZONE2D.NIB", 5, "9583b287a5c95960f5335878102bb8b1", 232960 },
+ { "TZONE3E.NIB", 6, "502e42a0cb69ffe4a48cd51c1ff210cf", 232960 },
+ { "TZONE3F.NIB", 7, "3d6e0aae15f590b72b6759535b6b7d3c", 232960 },
+ { "TZONE4G.NIB", 8, "ede4113a9c9e17745faf71d099808a18", 232960 },
+ { "TZONE4H.NIB", 9, "f95dae4aae1155a27f7120230464d4e1", 232960 },
+ { "TZONE5I.NIB", 10, "92b3b376877f81a7b7ae426bf1e65456", 232960 },
+ { "TZONE5J.NIB", 11, "c9ef796fa596548dbf8f085901f0bac3", 232960 },
+ { "TZONE6K.NIB", 12, "2e5323be637002efce1d4c813ae20a3f", 232960 },
+ { "TZONE6L.NIB", 13, "7c9268f0ea2d02120c77a46337b3d975", 232960 },
AD_LISTEND
},
Common::EN_ANY,
diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp
index 217a9013ba..8bd49c75b4 100644
--- a/engines/adl/hires1.cpp
+++ b/engines/adl/hires1.cpp
@@ -98,7 +98,7 @@ public:
private:
// AdlEngine
- void runIntro() const;
+ void runIntro();
void init();
void initGameState();
void restartGame();
@@ -126,7 +126,7 @@ private:
} _gameStrings;
};
-void HiRes1Engine::runIntro() const {
+void HiRes1Engine::runIntro() {
StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_0));
stream->seek(IDI_HR1_OFS_LOGO_0);
diff --git a/engines/adl/hires2.cpp b/engines/adl/hires2.cpp
index 199f457b4f..9562095ec9 100644
--- a/engines/adl/hires2.cpp
+++ b/engines/adl/hires2.cpp
@@ -54,12 +54,12 @@ public:
private:
// AdlEngine
- void runIntro() const;
+ void runIntro();
void init();
void initGameState();
};
-void HiRes2Engine::runIntro() const {
+void HiRes2Engine::runIntro() {
// 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.
diff --git a/engines/adl/hires5.cpp b/engines/adl/hires5.cpp
index 4f1d5a28b8..4d52d2822c 100644
--- a/engines/adl/hires5.cpp
+++ b/engines/adl/hires5.cpp
@@ -36,19 +36,107 @@ namespace Adl {
class HiRes5Engine : public AdlEngine_v4 {
public:
- HiRes5Engine(OSystem *syst, const AdlGameDescription *gd) : AdlEngine_v4(syst, gd) { }
+ HiRes5Engine(OSystem *syst, const AdlGameDescription *gd) :
+ AdlEngine_v4(syst, gd) { }
private:
// AdlEngine
+ void runIntro();
void init();
void initGameState();
+
+ static const uint kRegions = 41;
+ static const uint kItems = 69;
};
+void HiRes5Engine::runIntro() {
+ insertDisk(2);
+
+ StreamPtr stream(_disk->createReadStream(0x10, 0x0, 0x00, 31));
+
+ _display->setMode(DISPLAY_MODE_HIRES);
+ _display->loadFrameBuffer(*stream);
+ _display->updateHiResScreen();
+
+ inputKey();
+
+ _display->home();
+ _display->setMode(DISPLAY_MODE_TEXT);
+
+ stream.reset(_disk->createReadStream(0x03, 0xc, 0x34, 1));
+ Common::String menu(readString(*stream));
+
+ while (!g_engine->shouldQuit()) {
+ _display->home();
+ _display->printString(menu);
+
+ Common::String cmd(inputString());
+
+ // We ignore the backup and format menu options
+ if (!cmd.empty() && cmd[0] == APPLECHAR('1'))
+ break;
+ };
+}
+
void HiRes5Engine::init() {
_graphics = new Graphics_v2(*_display);
+
+ insertDisk(2);
+
+ StreamPtr stream(_disk->createReadStream(0x5, 0x0, 0x02));
+ loadRegionLocations(*stream, kRegions);
+
+ stream.reset(_disk->createReadStream(0xd, 0x2, 0x04));
+ loadRegionInitDataOffsets(*stream, kRegions);
+
+ stream.reset(_disk->createReadStream(0x7, 0xe));
+ _strings.verbError = readStringAt(*stream, 0x4f);
+ _strings.nounError = readStringAt(*stream, 0x8e);
+ _strings.enterCommand = readStringAt(*stream, 0xbc);
+
+ stream.reset(_disk->createReadStream(0x7, 0xc));
+ _strings.lineFeeds = readString(*stream);
+
+ // TODO: opcode strings
+
+ _messageIds.cantGoThere = 110;
+ _messageIds.dontUnderstand = 112;
+ _messageIds.itemDoesntMove = 114;
+ _messageIds.itemNotHere = 115;
+ _messageIds.thanksForPlaying = 113;
+
+ stream.reset(_disk->createReadStream(0xe, 0x1, 0x13, 4));
+ loadItemDescriptions(*stream, kItems);
+
+ stream.reset(_disk->createReadStream(0xb, 0xa, 0x05, 1));
+ loadItemPicIndex(*stream, kItems);
+
+ if (stream->eos() || stream->err())
+ error("Error reading item index");
}
void HiRes5Engine::initGameState() {
+ _state.vars.resize(40);
+
+ insertDisk(2);
+
+ StreamPtr stream(_disk->createReadStream(0x5, 0x1, 0x00, 3));
+ loadItems(*stream);
+
+ // A combined total of 1213 rooms
+ static const byte rooms[kRegions] = {
+ 6, 16, 24, 57, 40, 30, 76, 40,
+ 54, 38, 44, 21, 26, 42, 49, 32,
+ 59, 69, 1, 1, 1, 1, 1, 18,
+ 25, 13, 28, 28, 11, 23, 9, 31,
+ 6, 29, 29, 34, 9, 10, 95, 86,
+ 1
+ };
+
+ initRegions(rooms, kRegions);
+
+ loadRegion(1);
+ _state.room = 5;
}
Engine *HiRes5Engine_create(OSystem *syst, const AdlGameDescription *gd) {
diff --git a/engines/adl/hires6.cpp b/engines/adl/hires6.cpp
index 2cf37d4c37..c07493f5bd 100644
--- a/engines/adl/hires6.cpp
+++ b/engines/adl/hires6.cpp
@@ -68,7 +68,7 @@ public:
private:
// AdlEngine
- void runIntro() const;
+ void runIntro();
void init();
void initGameState();
void printRoomDescription();
@@ -120,7 +120,7 @@ static Common::MemoryReadStream *loadSectors(DiskImage *disk, byte track, byte s
return new Common::MemoryReadStream(buf, bufSize, DisposeAfterUse::YES);
}
-void HiRes6Engine::runIntro() const {
+void HiRes6Engine::runIntro() {
DiskImage *boot(new DiskImage());
if (!boot->open(disks[0]))