[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