aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/advsys/game.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/glk/advsys/game.cpp')
-rw-r--r--engines/glk/advsys/game.cpp99
1 files changed, 90 insertions, 9 deletions
diff --git a/engines/glk/advsys/game.cpp b/engines/glk/advsys/game.cpp
index 17a4104404..fe1221baf7 100644
--- a/engines/glk/advsys/game.cpp
+++ b/engines/glk/advsys/game.cpp
@@ -36,12 +36,12 @@ void Decrypter::decrypt(byte *data, size_t size) {
#define HEADER_SIZE 62
-bool Header::init(Common::ReadStream &s) {
+bool Header::init(Common::SeekableReadStream *s) {
_valid = false;
byte data[HEADER_SIZE];
// Read in the data
- if (s.read(data, HEADER_SIZE) != HEADER_SIZE)
+ if (s->read(data, HEADER_SIZE) != HEADER_SIZE)
return false;
decrypt(data, HEADER_SIZE);
Common::MemoryReadStream ms(data, HEADER_SIZE, DisposeAfterUse::NO);
@@ -98,9 +98,26 @@ enum LinkField {
L_SIZE = 4
};
-bool Game::init(Common::SeekableReadStream &s) {
+Game::Game() : Header(), _stream(nullptr), _restartFlag(false), _residentOffset(0), _wordCount(0),
+ _objectCount(0), _actionCount(0), _variableCount(0), _residentBase(nullptr),
+ _wordTable(nullptr), _wordTypeTable(nullptr), _objectTable(nullptr), _actionTable(nullptr),
+ _variableTable(nullptr), _saveArea(nullptr), _msgBlockNum(-1), _msgBlockOffset(0) {
+ _msgCache.resize(MESSAGE_CACHE_SIZE);
+ for (int idx = 0; idx < MESSAGE_CACHE_SIZE; ++idx)
+ _msgCache[idx] = new CacheEntry();
+}
+
+Game::~Game() {
+ for (int idx = 0; idx < MESSAGE_CACHE_SIZE; ++idx)
+ delete _msgCache[idx];
+}
+
+bool Game::init(Common::SeekableReadStream *s) {
+ // Store a copy of the game file stream
+ _stream = s;
+
// Load the header
- s.seek(0);
+ s->seek(0);
if (!Header::init(s))
return false;
@@ -109,10 +126,10 @@ bool Game::init(Common::SeekableReadStream &s) {
// Load the needed resident game data and decrypt it
_residentOffset = _dataBlockOffset * 512;
- s.seek(_residentOffset);
+ s->seek(_residentOffset);
_data.resize(_size);
- if (!s.read(&_data[0], _size))
+ if (!s->read(&_data[0], _size))
return false;
decrypt(&_data[0], _size);
@@ -136,9 +153,9 @@ bool Game::init(Common::SeekableReadStream &s) {
return true;
}
-void Game::restart(Common::SeekableReadStream &s) {
- s.seek(_residentOffset + _saveAreaOffset);
- s.read(_saveArea, _saveSize);
+void Game::restart() {
+ _stream->seek(_residentOffset + _saveAreaOffset);
+ _stream->read(_saveArea, _saveSize);
decrypt(_saveArea, _saveSize);
setVariable(V_OCOUNT, _objectCount);
@@ -316,5 +333,69 @@ bool Game::inList(int link, int word) const {
return false;
}
+Common::String Game::readString(int msg) {
+ // Get the block to use, and ensure it's loaded
+ _msgBlockNum = msg >> 7;
+ _msgBlockOffset = (msg & 0x7f) << 2;
+ readMsgBlock();
+
+ // Read the string
+ Common::String result;
+ char c;
+
+ while ((c = readMsgChar()) != '\0')
+ result += c;
+
+ return result;
+}
+
+char Game::readMsgChar() {
+ if (_msgBlockOffset >= MESSAGE_BLOCK_SIZE) {
+ // Move to the next block
+ ++_msgBlockNum;
+ _msgBlockOffset = 0;
+ readMsgBlock();
+ }
+
+ // Return next character
+ return _msgCache[0]->_data[_msgBlockOffset++];
+}
+
+void Game::readMsgBlock() {
+ CacheEntry *ce;
+
+ // Check to see if the specified block is in the cache
+ for (int idx = 0; idx < MESSAGE_CACHE_SIZE; ++idx) {
+ if (_msgCache[idx]->_blockNum == _msgBlockNum) {
+ // If it's not already at the top of the list, move it there to ensure
+ // it'll be last to be unloaded as new blocks are loaded in
+ if (idx != 0) {
+ ce = _msgCache[idx];
+ _msgCache.remove_at(idx);
+ _msgCache.insert_at(0, ce);
+ }
+
+ return;
+ }
+ }
+
+ // At this point we need to load a new block in. Discard the block at the end
+ // and move it to the start for storing the new block to load
+ ce = _msgCache.back();
+ _msgCache.remove_at(_msgCache.size() - 1);
+ _msgCache.insert_at(0, ce);
+
+ // Load the new block
+ ce->_blockNum = _msgBlockNum;
+ _stream->seek((_messageBlockOffset + _msgBlockNum) << 9);
+ if (_stream->read(&ce->_data[0], MESSAGE_BLOCK_SIZE) != MESSAGE_BLOCK_SIZE)
+ error("Error reading message block");
+
+ // Decode the loaded block
+ for (int idx = 0; idx < MESSAGE_BLOCK_SIZE; ++idx)
+ ce->_data[idx] = (ce->_data[idx] + 30) & 0xff;
+}
+
+
} // End of namespace AdvSys
} // End of namespace Glk