[Scummvm-git-logs] scummvm master -> ebdc4ec3faf509625ac94948cbbb0996d440c37e
dreammaster
paulfgilbert at gmail.com
Tue Jun 11 04:09:51 CEST 2019
This automated email contains information about 5 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
d5d801d1cb GLK: ADVSYS: Adding opcodes and message decoding
8bb7c893f1 GLK: ADVSYS: String printing
75da8ddd06 GLK: ADVSYS: Subroutine call & return opcodes
1de8c3d730 GLK: ADVSYS: More opcodes
ebdc4ec3fa GLK: ADVSYS: Created dedicated function pointer class, cleanup method opcodes
Commit: d5d801d1cba3ee95a9be48bd2a505f2e2906ead8
https://github.com/scummvm/scummvm/commit/d5d801d1cba3ee95a9be48bd2a505f2e2906ead8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-10T19:08:58-07:00
Commit Message:
GLK: ADVSYS: Adding opcodes and message decoding
Changed paths:
engines/glk/advsys/advsys.cpp
engines/glk/advsys/detection.cpp
engines/glk/advsys/game.cpp
engines/glk/advsys/game.h
engines/glk/advsys/glk_interface.cpp
engines/glk/advsys/glk_interface.h
engines/glk/advsys/vm.cpp
engines/glk/advsys/vm.h
diff --git a/engines/glk/advsys/advsys.cpp b/engines/glk/advsys/advsys.cpp
index b745222..fe02e25 100644
--- a/engines/glk/advsys/advsys.cpp
+++ b/engines/glk/advsys/advsys.cpp
@@ -80,7 +80,7 @@ bool AdvSys::initialize() {
return false;
// Load the game's header
- if (!Game::init(_gameFile))
+ if (!Game::init(&_gameFile))
return false;
return true;
diff --git a/engines/glk/advsys/detection.cpp b/engines/glk/advsys/detection.cpp
index 921be4e..d3b376f 100644
--- a/engines/glk/advsys/detection.cpp
+++ b/engines/glk/advsys/detection.cpp
@@ -65,7 +65,7 @@ bool AdvSysMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &
if (!gameFile.open(*file))
continue;
- Header hdr(gameFile);
+ Header hdr(&gameFile);
if (!hdr._valid)
continue;
diff --git a/engines/glk/advsys/game.cpp b/engines/glk/advsys/game.cpp
index 17a4104..fe1221b 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
diff --git a/engines/glk/advsys/game.h b/engines/glk/advsys/game.h
index a5c7f41..99cfe26 100644
--- a/engines/glk/advsys/game.h
+++ b/engines/glk/advsys/game.h
@@ -30,6 +30,8 @@ namespace Glk {
namespace AdvSys {
#define NIL 0
+#define MESSAGE_CACHE_SIZE 8
+#define MESSAGE_BLOCK_SIZE 512
/**
* Actions
@@ -118,22 +120,36 @@ public:
/**
* Constructor
*/
- Header(Common::ReadStream &s) {
+ Header(Common::SeekableReadStream *s) {
init(s);
}
/**
* init the header
*/
- bool init(Common::ReadStream &s);
+ bool init(Common::SeekableReadStream *s);
};
/**
* Game abstraction class
*/
class Game : public Header {
+ struct CacheEntry {
+ int _blockNum;
+ char _data[MESSAGE_BLOCK_SIZE];
+
+ /**
+ * Constructor
+ */
+ CacheEntry() : _blockNum(-1) {
+ Common::fill(&_data[0], &_data[MESSAGE_BLOCK_SIZE], '\0');
+ }
+ };
private:
bool _restartFlag;
+ Common::SeekableReadStream *_stream;
+ Common::Array<CacheEntry *> _msgCache;
+ int _msgBlockNum, _msgBlockOffset;
private:
/**
* Find an object property field
@@ -166,6 +182,16 @@ private:
* Check if a word is in an element of a given list
*/
bool inList(int link, int word) const;
+
+ /**
+ * Reads in a message block from the game file
+ */
+ void readMsgBlock();
+
+ /**
+ * Read the next character for a string
+ */
+ char readMsgChar();
public:
Common::Array<byte> _data;
int _residentOffset;
@@ -187,20 +213,22 @@ public:
/**
* Constructor
*/
- Game() : Header(), _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) {}
+ Game();
+
+ /**
+ * Destructor
+ */
+ ~Game();
/**
* init data for the game
*/
- bool init(Common::SeekableReadStream &s);
+ bool init(Common::SeekableReadStream *s);
/**
* Restore savegame data from the game to it's initial state
*/
- void restart(Common::SeekableReadStream &s);
+ void restart();
/**
* Returns true if the game is restarting, and resets the flag
@@ -330,6 +358,11 @@ public:
void writeWord(int offset, int val) {
WRITE_LE_UINT16(_residentBase + offset, val);
}
+
+ /**
+ * Read a string from the messages section
+ */
+ Common::String readString(int msg);
};
} // End of namespace AdvSys
diff --git a/engines/glk/advsys/glk_interface.cpp b/engines/glk/advsys/glk_interface.cpp
index 3bc6800..fff6bd1 100644
--- a/engines/glk/advsys/glk_interface.cpp
+++ b/engines/glk/advsys/glk_interface.cpp
@@ -25,6 +25,13 @@
namespace Glk {
namespace AdvSys {
+void GlkInterface::printString(int offset) {
+ // TODO
+}
+
+void GlkInterface::printNumber(int number) {
+ // TODO
+}
} // End of namespace AdvSys
} // End of namespace Glk
diff --git a/engines/glk/advsys/glk_interface.h b/engines/glk/advsys/glk_interface.h
index 58ff831..b54a35b 100644
--- a/engines/glk/advsys/glk_interface.h
+++ b/engines/glk/advsys/glk_interface.h
@@ -33,6 +33,18 @@ namespace AdvSys {
* input and output
*/
class GlkInterface : public GlkAPI {
+protected:
+ /**
+ * Print a string
+ * @param offset String offset
+ */
+ void printString(int offset);
+
+ /**
+ * Print a number
+ * @param number Number to print
+ */
+ void printNumber(int number);
public:
/**
* Constructor
diff --git a/engines/glk/advsys/vm.cpp b/engines/glk/advsys/vm.cpp
index 754a86a..be2fed9 100644
--- a/engines/glk/advsys/vm.cpp
+++ b/engines/glk/advsys/vm.cpp
@@ -108,23 +108,23 @@ void VM::executeOpcode() {
if (opcode >= OP_BRT && opcode <= OP_VOWEL) {
(this->*_METHODS[(int)opcode - 1])();
} else if (opcode >= OP_XVAR && opcode < OP_XSET) {
- _stack.back() = getVariable((int)opcode - OP_XVAR);
+ _stack.top() = getVariable((int)opcode - OP_XVAR);
} else if (opcode >= OP_XSET && opcode < OP_XPLIT) {
- setVariable((int)opcode - OP_XSET, _stack.back());
+ setVariable((int)opcode - OP_XSET, _stack.top());
} else if (opcode >= OP_XPLIT && opcode < OP_XNLIT) {
- _stack.back() = (int)opcode - OP_XPLIT;
+ _stack.top() = (int)opcode - OP_XPLIT;
} else if (opcode >= OP_XNLIT && (int)opcode < 256) {
- _stack.back() = OP_XNLIT - opcode;
+ _stack.top() = OP_XNLIT - opcode;
} else {
error("Unknown opcode %x at offset %d", opcode, _pc);
}
}
void VM::opBRT() {
- _pc = _stack.back() ? readCodeWord() : _pc + 2;
+ _pc = _stack.top() ? readCodeWord() : _pc + 2;
}
void VM::opBRF() {
- _pc = !_stack.back() ? readCodeWord() : _pc + 2;
+ _pc = !_stack.top() ? readCodeWord() : _pc + 2;
}
void VM::opBR() {
@@ -132,11 +132,11 @@ void VM::opBR() {
}
void VM::opT() {
- _stack.back() = TRUE;
+ _stack.top() = TRUE;
}
void VM::opNIL() {
- _stack.back() = NIL;
+ _stack.top() = NIL;
}
void VM::opPUSH() {
@@ -144,83 +144,84 @@ void VM::opPUSH() {
}
void VM::opNOT() {
- _stack.back() = _stack.back() ? NIL : TRUE;
+ _stack.top() = _stack.top() ? NIL : TRUE;
}
void VM::opADD() {
int v = _stack.pop();
- _stack.back() += v;
+ _stack.top() += v;
}
void VM::opSUB() {
int v = _stack.pop();
- _stack.back() -= v;
+ _stack.top() -= v;
}
void VM::opMUL() {
int v = _stack.pop();
- _stack.back() *= v;
+ _stack.top() *= v;
}
void VM::opDIV() {
int v = _stack.pop();
- _stack.back() = (v == 0) ? 0 : _stack.back() / v;
+ _stack.top() = (v == 0) ? 0 : _stack.top() / v;
}
void VM::opREM() {
int v = _stack.pop();
- _stack.back() = (v == 0) ? 0 : _stack.back() % v;
+ _stack.top() = (v == 0) ? 0 : _stack.top() % v;
}
void VM::opBAND() {
int v = _stack.pop();
- _stack.back() &= v;
+ _stack.top() &= v;
}
void VM::opBOR() {
int v = _stack.pop();
- _stack.back() |= v;
+ _stack.top() |= v;
}
void VM::opBNOT() {
- _stack.back() = ~_stack.back();
+ _stack.top() = ~_stack.top();
}
void VM::opLT() {
int v = _stack.pop();
- _stack.back() = (_stack.back() < v) ? TRUE : NIL;
+ _stack.top() = (_stack.top() < v) ? TRUE : NIL;
}
void VM::opEQ() {
int v = _stack.pop();
- _stack.back() = (_stack.back() == v) ? TRUE : NIL;
+ _stack.top() = (_stack.top() == v) ? TRUE : NIL;
}
void VM::opGT() {
int v = _stack.pop();
- _stack.back() = (_stack.back() > v) ? TRUE : NIL;
+ _stack.top() = (_stack.top() > v) ? TRUE : NIL;
}
void VM::opLIT() {
- _stack.back() = readCodeWord();
+ _stack.top() = readCodeWord();
}
void VM::opVAR() {
- _stack.back() = getVariable(readCodeWord());
+ _stack.top() = getVariable(readCodeWord());
}
void VM::opGETP() {
int v = _stack.pop();
- _stack.back() = getObjectProperty(_stack.back(), v);
+ _stack.top() = getObjectProperty(_stack.top(), v);
}
void VM::opSETP() {
int v3 = _stack.pop();
int v2 = _stack.pop();
- _stack.back() = setObjectProperty(_stack.back(), v2, v3);
+ _stack.top() = setObjectProperty(_stack.top(), v2, v3);
}
void VM::opSET() {
+ setVariable(readCodeWord(), _stack.top());
}
void VM::opPRINT() {
@@ -251,7 +252,7 @@ void VM::opCALL() {
}
void VM::opSVAR() {
- _stack.back() = getVariable(readCodeByte());
+ _stack.top() = getVariable(readCodeByte());
}
void VM::opSSET() {
diff --git a/engines/glk/advsys/vm.h b/engines/glk/advsys/vm.h
index e1b217f..9718b04 100644
--- a/engines/glk/advsys/vm.h
+++ b/engines/glk/advsys/vm.h
@@ -127,6 +127,11 @@ class VM : public GlkInterface, public Game {
pop_back();
return v;
}
+
+ /**
+ * Returns the top of the stack (the most recently added value
+ */
+ int &top() { return back(); }
};
private:
static OpcodeMethod _METHODS[0x34];
Commit: 8bb7c893f1bd7a884ef55e8a8213fd03889238ad
https://github.com/scummvm/scummvm/commit/8bb7c893f1bd7a884ef55e8a8213fd03889238ad
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-10T19:08:58-07:00
Commit Message:
GLK: ADVSYS: String printing
Changed paths:
engines/glk/advsys/advsys.cpp
engines/glk/advsys/advsys.h
engines/glk/advsys/glk_interface.cpp
engines/glk/advsys/glk_interface.h
engines/glk/advsys/vm.cpp
diff --git a/engines/glk/advsys/advsys.cpp b/engines/glk/advsys/advsys.cpp
index fe02e25..0c63ff8 100644
--- a/engines/glk/advsys/advsys.cpp
+++ b/engines/glk/advsys/advsys.cpp
@@ -26,10 +26,6 @@
namespace Glk {
namespace AdvSys {
-void execute(int offset) {
- // TODO: Stub
-}
-
bool getInput() {
// TODO: Stub
return false;
@@ -75,8 +71,7 @@ void AdvSys::runGame() {
bool AdvSys::initialize() {
// Create a Glk window for the game
- _window = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
- if (!_window)
+ if (!GlkInterface::initialize())
return false;
// Load the game's header
@@ -89,10 +84,6 @@ bool AdvSys::initialize() {
void AdvSys::deinitialize() {
}
-void AdvSys::print(const char *msg) {
- glk_put_string_stream(glk_window_get_stream(_window), msg);
-}
-
Common::Error AdvSys::loadGameData(strid_t save) {
return Common::kNoError;
}
diff --git a/engines/glk/advsys/advsys.h b/engines/glk/advsys/advsys.h
index a6e9a5b..50977a6 100644
--- a/engines/glk/advsys/advsys.h
+++ b/engines/glk/advsys/advsys.h
@@ -34,8 +34,6 @@ namespace AdvSys {
*/
class AdvSys : public VM {
private:
- winid_t _window;
-private:
/**
* Engine initialization
*/
@@ -45,11 +43,6 @@ private:
* Engine cleanup
*/
void deinitialize();
-
- /**
- * Print a string to the window
- */
- void print(const char *msg);
public:
/**
* Constructor
diff --git a/engines/glk/advsys/glk_interface.cpp b/engines/glk/advsys/glk_interface.cpp
index fff6bd1..c83f0c1 100644
--- a/engines/glk/advsys/glk_interface.cpp
+++ b/engines/glk/advsys/glk_interface.cpp
@@ -25,12 +25,18 @@
namespace Glk {
namespace AdvSys {
-void GlkInterface::printString(int offset) {
- // TODO
+bool GlkInterface::initialize() {
+ _window = glk_window_open(0, 0, 0, wintype_TextBuffer, 1);
+ return !_window;
}
-void GlkInterface::printNumber(int number) {
- // TODO
+void GlkInterface::print(const Common::String &msg) {
+ glk_put_string_stream(glk_window_get_stream(_window), msg.c_str());
+}
+
+void GlkInterface::print(int number) {
+ Common::String s = Common::String::format("%d", number);
+ print(s);
}
} // End of namespace AdvSys
diff --git a/engines/glk/advsys/glk_interface.h b/engines/glk/advsys/glk_interface.h
index b54a35b..b316f1f 100644
--- a/engines/glk/advsys/glk_interface.h
+++ b/engines/glk/advsys/glk_interface.h
@@ -33,18 +33,25 @@ namespace AdvSys {
* input and output
*/
class GlkInterface : public GlkAPI {
+private:
+ winid_t _window;
protected:
/**
+ * GLK initialization
+ */
+ bool initialize();
+
+ /**
* Print a string
- * @param offset String offset
+ * @param msg String
*/
- void printString(int offset);
+ void print(const Common::String &msg);
/**
* Print a number
- * @param number Number to print
+ * @param number Number to print
*/
- void printNumber(int number);
+ void print(int number);
public:
/**
* Constructor
diff --git a/engines/glk/advsys/vm.cpp b/engines/glk/advsys/vm.cpp
index be2fed9..0e59fe3 100644
--- a/engines/glk/advsys/vm.cpp
+++ b/engines/glk/advsys/vm.cpp
@@ -225,12 +225,16 @@ void VM::opSET() {
}
void VM::opPRINT() {
+ Common::String msg = readString(_stack.top());
+ print(msg);
}
void VM::opTERPRI() {
+ print("\n");
}
void VM::opPNUMBER() {
+ print(_stack.top());
}
void VM::opFINISH() {
Commit: 75da8ddd06a08e26fd006ff0033ee911e5bd5411
https://github.com/scummvm/scummvm/commit/75da8ddd06a08e26fd006ff0033ee911e5bd5411
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-10T19:08:58-07:00
Commit Message:
GLK: ADVSYS: Subroutine call & return opcodes
Changed paths:
engines/glk/advsys/vm.cpp
engines/glk/advsys/vm.h
diff --git a/engines/glk/advsys/vm.cpp b/engines/glk/advsys/vm.cpp
index 0e59fe3..ef943e6 100644
--- a/engines/glk/advsys/vm.cpp
+++ b/engines/glk/advsys/vm.cpp
@@ -83,7 +83,7 @@ OpcodeMethod VM::_METHODS[0x34] = {
};
VM::VM(OSystem *syst, const GlkGameDescription &gameDesc) : GlkInterface(syst, gameDesc), Game(),
- _pc(0), _status(IN_PROGRESS) {
+ _pc(0), _fp(-1), _status(IN_PROGRESS) {
}
ExecutionResult VM::execute(int offset) {
@@ -238,21 +238,46 @@ void VM::opPNUMBER() {
}
void VM::opFINISH() {
+ _status = FINISH;
}
void VM::opCHAIN() {
+ _status = CHAIN;
}
void VM::opABORT() {
+ _status = ABORT;
}
void VM::opEXIT() {
+ quitGame();
+ _status = ABORT;
}
void VM::opRETURN() {
+ if (_stack.empty()) {
+ _status = CHAIN;
+ } else {
+ int val = _stack.top();
+ _stack.resize(_fp);
+ _fp = _stack.pop();
+ _pc = _stack.pop();
+
+ int varsSize = _stack.pop();
+ _stack.resize(_stack.size() - varsSize);
+ _stack.top() = val;
+ }
}
void VM::opCALL() {
+ int varSize = readCodeByte();
+ int topIndex = _stack.size() - 1;
+
+ _stack.push(varSize);
+ _stack.push(_pc);
+ _stack.push(_fp);
+ _fp = _stack.size();
+ _pc = getActionField(_stack[topIndex - varSize], A_CODE);
}
void VM::opSVAR() {
@@ -311,6 +336,26 @@ void VM::opRNDMIZE() {
}
void VM::opSEND() {
+ int varSize = readCodeByte();
+ int topIndex = _stack.size() - 1;
+
+ _stack.push(varSize);
+ _stack.push(_pc);
+ _stack.push(_fp);
+ _fp = _stack.size();
+
+ int val = _stack[topIndex - varSize];
+ if (val)
+ val = getObjectField(val, O_CLASS);
+ else
+ val = _stack[topIndex - varSize + 1];
+
+ if (val && (val = getObjectProperty(val, _stack[topIndex - varSize + 2])) != 0) {
+ _pc = getActionField(val, A_CODE);
+ } else {
+ // Return NIL if there's no action for the given message
+ opRETURN();
+ }
}
void VM::opVOWEL() {
diff --git a/engines/glk/advsys/vm.h b/engines/glk/advsys/vm.h
index 9718b04..e5432d3 100644
--- a/engines/glk/advsys/vm.h
+++ b/engines/glk/advsys/vm.h
@@ -25,7 +25,7 @@
#include "glk/advsys/glk_interface.h"
#include "glk/advsys/game.h"
-#include "common/array.h"
+#include "common/stack.h"
namespace Glk {
namespace AdvSys {
@@ -110,34 +110,19 @@ typedef void (VM::*OpcodeMethod)();
* Main VM for AdvSys
*/
class VM : public GlkInterface, public Game {
- class ArrayStack : public Common::Array<int> {
+ class FixedStack : public Common::FixedStack<int, 500> {
public:
- /**
- * Push a value onto the stack
- */
- void push(int v) {
- push_back(v);
+ void resize(size_t newSize) {
+ assert(newSize <= _size);
+ _size = newSize;
}
-
- /**
- * Pop a value from the stack
- */
- int pop() {
- int v = back();
- pop_back();
- return v;
- }
-
- /**
- * Returns the top of the stack (the most recently added value
- */
- int &top() { return back(); }
};
private:
static OpcodeMethod _METHODS[0x34];
int _pc;
ExecutionResult _status;
- ArrayStack _stack;
+ FixedStack _stack;
+ int _fp;
private:
/**
* Execute a single opcode within the script
Commit: 1de8c3d7308512b4eae556511a468d9b59d26f90
https://github.com/scummvm/scummvm/commit/1de8c3d7308512b4eae556511a468d9b59d26f90
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-10T19:08:58-07:00
Commit Message:
GLK: ADVSYS: More opcodes
Changed paths:
engines/glk/advsys/glk_interface.cpp
engines/glk/advsys/glk_interface.h
engines/glk/advsys/vm.cpp
diff --git a/engines/glk/advsys/glk_interface.cpp b/engines/glk/advsys/glk_interface.cpp
index c83f0c1..800d708 100644
--- a/engines/glk/advsys/glk_interface.cpp
+++ b/engines/glk/advsys/glk_interface.cpp
@@ -39,5 +39,10 @@ void GlkInterface::print(int number) {
print(s);
}
+Common::String GlkInterface::getLine() {
+ // TODO: Stub
+ return "";
+}
+
} // End of namespace AdvSys
} // End of namespace Glk
diff --git a/engines/glk/advsys/glk_interface.h b/engines/glk/advsys/glk_interface.h
index b316f1f..44f3db9 100644
--- a/engines/glk/advsys/glk_interface.h
+++ b/engines/glk/advsys/glk_interface.h
@@ -52,6 +52,11 @@ protected:
* @param number Number to print
*/
void print(int number);
+
+ /**
+ * Get an input line
+ */
+ Common::String getLine();
public:
/**
* Constructor
diff --git a/engines/glk/advsys/vm.cpp b/engines/glk/advsys/vm.cpp
index ef943e6..a06cd28 100644
--- a/engines/glk/advsys/vm.cpp
+++ b/engines/glk/advsys/vm.cpp
@@ -285,30 +285,51 @@ void VM::opSVAR() {
}
void VM::opSSET() {
+ setVariable(getCodeByte(), _stack.top());
}
void VM::opSPLIT() {
+ _stack.top() = readCodeByte();
}
void VM::opSNLIT() {
+ _stack.top() = readCodeByte();
}
void VM::opYORN() {
+ Common::String line = getLine();
+ _stack.top() = line[0] == 'Y' || line[0] == 'y' ? TRUE : NIL;
}
void VM::opSAVE() {
+ if (saveGame().getCode() != Common::kNoError)
+ print("Sorry, the savegame couldn't be created");
}
void VM::opRESTORE() {
+ if (saveGame().getCode() != Common::kNoError)
+ print("Sorry, the savegame couldn't be restored");
}
void VM::opARG() {
+ int argNum = readCodeByte();
+ int varsSize = _stack[_fp - 3];
+ if (argNum >= varsSize)
+ error("Invalid argument number");
+ _stack.top() = _stack[_fp - 4 - argNum];
}
void VM::opASET() {
+ int argNum = readCodeByte();
+ int varsSize = _stack[_fp - 3];
+ if (argNum >= varsSize)
+ error("Invalid argument number");
+ _stack[_fp - 4 - argNum] = _stack.top();
}
void VM::opTMP() {
+ int val = readCodeByte();
+
}
void VM::opTSET() {
Commit: ebdc4ec3faf509625ac94948cbbb0996d440c37e
https://github.com/scummvm/scummvm/commit/ebdc4ec3faf509625ac94948cbbb0996d440c37e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2019-06-10T19:08:58-07:00
Commit Message:
GLK: ADVSYS: Created dedicated function pointer class, cleanup method opcodes
Changed paths:
engines/glk/advsys/vm.cpp
engines/glk/advsys/vm.h
diff --git a/engines/glk/advsys/vm.cpp b/engines/glk/advsys/vm.cpp
index a06cd28..dbfe0ad 100644
--- a/engines/glk/advsys/vm.cpp
+++ b/engines/glk/advsys/vm.cpp
@@ -83,7 +83,7 @@ OpcodeMethod VM::_METHODS[0x34] = {
};
VM::VM(OSystem *syst, const GlkGameDescription &gameDesc) : GlkInterface(syst, gameDesc), Game(),
- _pc(0), _fp(-1), _status(IN_PROGRESS) {
+ _fp(_stack), _pc(0), _status(IN_PROGRESS) {
}
ExecutionResult VM::execute(int offset) {
@@ -263,21 +263,21 @@ void VM::opRETURN() {
_fp = _stack.pop();
_pc = _stack.pop();
- int varsSize = _stack.pop();
- _stack.resize(_stack.size() - varsSize);
+ int argsSize = _stack.pop();
+ _stack.resize(_stack.size() - argsSize);
_stack.top() = val;
}
}
void VM::opCALL() {
- int varSize = readCodeByte();
- int topIndex = _stack.size() - 1;
+ int argsSize = readCodeByte();
- _stack.push(varSize);
+ _stack.push(argsSize);
_stack.push(_pc);
_stack.push(_fp);
- _fp = _stack.size();
- _pc = getActionField(_stack[topIndex - varSize], A_CODE);
+
+ _fp.set();
+ _pc = getActionField(_fp[_fp[FP_ARGS_SIZE] + FP_ARGS], A_CODE);
}
void VM::opSVAR() {
@@ -285,7 +285,7 @@ void VM::opSVAR() {
}
void VM::opSSET() {
- setVariable(getCodeByte(), _stack.top());
+ setVariable(readCodeByte(), _stack.top());
}
void VM::opSPLIT() {
@@ -328,8 +328,6 @@ void VM::opASET() {
}
void VM::opTMP() {
- int val = readCodeByte();
-
}
void VM::opTSET() {
@@ -357,21 +355,19 @@ void VM::opRNDMIZE() {
}
void VM::opSEND() {
- int varSize = readCodeByte();
- int topIndex = _stack.size() - 1;
-
- _stack.push(varSize);
+ int argsSize = readCodeByte();
+ _stack.push(argsSize);
_stack.push(_pc);
_stack.push(_fp);
- _fp = _stack.size();
+ _fp.set();
- int val = _stack[topIndex - varSize];
+ int val = _fp[_fp[FP_ARGS_SIZE] + FP_ARGS];
if (val)
val = getObjectField(val, O_CLASS);
else
- val = _stack[topIndex - varSize + 1];
+ val = _fp[_fp[FP_ARGS_SIZE] + FP_ARGS];
- if (val && (val = getObjectProperty(val, _stack[topIndex - varSize + 2])) != 0) {
+ if (val && (val = getObjectProperty(val, _fp[_fp[FP_ARGS_SIZE] + 1])) != 0) {
_pc = getActionField(val, A_CODE);
} else {
// Return NIL if there's no action for the given message
diff --git a/engines/glk/advsys/vm.h b/engines/glk/advsys/vm.h
index e5432d3..e7477b9 100644
--- a/engines/glk/advsys/vm.h
+++ b/engines/glk/advsys/vm.h
@@ -103,26 +103,84 @@ enum Opcode {
OP_XNLIT = 0xC0 ///< Extra short load a negative literal
};
+/**
+ * Indexes useable in function pointer array offsets
+ */
+enum FPOffset {
+ FP_FP = 0,
+ FP_PC = 1,
+ FP_ARGS_SIZE = 2,
+ FP_ARGS = 3
+};
+
class VM;
typedef void (VM::*OpcodeMethod)();
/**
+ * Fixed stack
+ */
+class FixedStack : public Common::FixedStack<int, 500> {
+public:
+ void resize(size_t newSize) {
+ assert(newSize <= _size);
+ _size = newSize;
+ }
+};
+
+/**
+ * Implements a function pointer reference into the stack. It also allows
+ * positive array indexing to reference the following:
+ * 0 = Previous function pointer
+ * 1 = Return PC
+ * 2 = Size of argument block
+ * 3+ = Any function call arguments
+ */
+class FunctionPointer {
+private:
+ FixedStack &_stack;
+ int _index;
+public:
+ /**
+ * Constructor
+ */
+ FunctionPointer(FixedStack &s) : _stack(s), _index(-1) {}
+
+ /**
+ * Array indexing
+ */
+ int &operator[](int idx) { return _stack[_index - idx - 1]; }
+
+ /**
+ * Sets the index in the stack of the function pointer
+ */
+ FunctionPointer &operator=(int index) {
+ _index = index;
+ return *this;
+ }
+
+ /**
+ * Returns the index in the stack of the function pointer
+ */
+ operator int() const { return _index; }
+
+ /**
+ * Sets the function pointer to the top of the stack
+ */
+ void set() {
+ _index = _stack.size();
+ }
+};
+
+/**
* Main VM for AdvSys
*/
class VM : public GlkInterface, public Game {
- class FixedStack : public Common::FixedStack<int, 500> {
- public:
- void resize(size_t newSize) {
- assert(newSize <= _size);
- _size = newSize;
- }
- };
private:
static OpcodeMethod _METHODS[0x34];
int _pc;
ExecutionResult _status;
FixedStack _stack;
- int _fp;
+ FunctionPointer _fp;
private:
/**
* Execute a single opcode within the script
More information about the Scummvm-git-logs
mailing list