[Scummvm-cvs-logs] SF.net SVN: scummvm:[44860] scummvm/trunk/engines/sci

waltervn at users.sourceforge.net waltervn at users.sourceforge.net
Sat Oct 10 04:16:23 CEST 2009


Revision: 44860
          http://scummvm.svn.sourceforge.net/scummvm/?rev=44860&view=rev
Author:   waltervn
Date:     2009-10-10 02:16:23 +0000 (Sat, 10 Oct 2009)

Log Message:
-----------
SCI: kMessage() rewrite

Modified Paths:
--------------
    scummvm/trunk/engines/sci/engine/game.cpp
    scummvm/trunk/engines/sci/engine/kernel.cpp
    scummvm/trunk/engines/sci/engine/kernel.h
    scummvm/trunk/engines/sci/engine/kstring.cpp
    scummvm/trunk/engines/sci/engine/message.cpp
    scummvm/trunk/engines/sci/engine/message.h
    scummvm/trunk/engines/sci/engine/savegame.cpp
    scummvm/trunk/engines/sci/engine/state.cpp
    scummvm/trunk/engines/sci/engine/state.h
    scummvm/trunk/engines/sci/gui/gui_gfx.cpp
    scummvm/trunk/engines/sci/gui/gui_picture.cpp

Modified: scummvm/trunk/engines/sci/engine/game.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/game.cpp	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/engine/game.cpp	2009-10-10 02:16:23 UTC (rev 44860)
@@ -32,6 +32,7 @@
 #include "sci/engine/kernel.h"
 #include "sci/engine/kernel_types.h"
 #include "sci/gui/gui.h"
+#include "sci/engine/message.h"
 #include "sci/gfx/gfx_widgets.h"
 #include "sci/gfx/gfx_state_internal.h"	// required for GfxPort, GfxVisual
 #include "sci/gfx/menubar.h"
@@ -318,6 +319,7 @@
 // Architectural stuff: Init/Unintialize engine
 int script_init_engine(EngineState *s) {
 	s->_segMan = new SegManager(s->resMan);
+	s->_msgState = new MessageState(s->_segMan);
 	s->gc_countdown = GC_INTERVAL - 1;
 
 	SegmentId script_000_segment = s->_segMan->getScriptSegment(0, SCRIPT_GET_LOCK);

Modified: scummvm/trunk/engines/sci/engine/kernel.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/kernel.cpp	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/engine/kernel.cpp	2009-10-10 02:16:23 UTC (rev 44860)
@@ -160,7 +160,7 @@
 	/*0x79*/ "ATan",
 	/*0x7a*/ "Lock",
 	/*0x7b*/ "StrSplit",
-	/*0x7c*/ "Message",
+	/*0x7c*/ "GetMessage",
 	/*0x7d*/ "IsItSkip",
 	/*0x7e*/ "MergePoly",
 	/*0x7f*/ "ResCheck",
@@ -325,6 +325,7 @@
 	/*(?)*/	DEFUN("TimesCot", kTimesCot, "ii"),
 	/*(?)*/	DEFUN("TimesTan", kTimesTan, "ii"),
 	DEFUN("Message", kMessage, ".*"),
+	DEFUN("GetMessage", kGetMessage, "iiir"),
 	DEFUN("DoAudio", kDoAudio, ".*"),
 	DEFUN("DoSync", kDoSync, ".*"),
 	DEFUN("ResCheck", kResCheck, "iii*"),
@@ -700,6 +701,7 @@
 		// KQ6CD calls unimplemented function 0x26
 		_kernelNames[0x26] = "Dummy";
 		_kernelNames[0x71] = "PalVary";
+		_kernelNames[0x7c] = "Message";
 		break;
 
 	default:

Modified: scummvm/trunk/engines/sci/engine/kernel.h
===================================================================
--- scummvm/trunk/engines/sci/engine/kernel.h	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/engine/kernel.h	2009-10-10 02:16:23 UTC (rev 44860)
@@ -414,6 +414,7 @@
 reg_t kGetSaveDir(EngineState *s, int argc, reg_t *argv);
 reg_t kTextSize(EngineState *s, int argc, reg_t *argv);
 reg_t kIsItSkip(EngineState *s, int argc, reg_t *argv);
+reg_t kGetMessage(EngineState *s, int argc, reg_t *argv);
 reg_t kMessage(EngineState *s, int argc, reg_t *argv);
 reg_t kDoAudio(EngineState *s, int argc, reg_t *argv);
 reg_t kDoSync(EngineState *s, int argc, reg_t *argv);

Modified: scummvm/trunk/engines/sci/engine/kstring.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/kstring.cpp	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/engine/kstring.cpp	2009-10-10 02:16:23 UTC (rev 44860)
@@ -618,92 +618,40 @@
 	K_MESSAGE_LASTMESSAGE
 };
 
-reg_t kMessage(EngineState *s, int argc, reg_t *argv) {
-	MessageTuple tuple;
-	int func;
-	// For earlier version of of this function (GetMessage)
-	bool isGetMessage = argc == 4;
+reg_t kGetMessage(EngineState *s, int argc, reg_t *argv) {
+	MessageTuple tuple = MessageTuple(argv[0].toUint16(), argv[2].toUint16());
 
-	if (isGetMessage) {
-		func = K_MESSAGE_GET;
+	s->_msgState->getMessage(argv[1].toUint16(), tuple, argv[3]);
 
-		tuple.noun = argv[0].toUint16();
-		tuple.verb = argv[2].toUint16();
-		tuple.cond = 0;
-		tuple.seq = 1;
-	} else {
-		func = argv[0].toUint16();
+	return argv[3];
+}
 
-		if (argc >= 6) {
-			tuple.noun = argv[2].toUint16();
-			tuple.verb = argv[3].toUint16();
-			tuple.cond = argv[4].toUint16();
-			tuple.seq = argv[5].toUint16();
-		}
+reg_t kMessage(EngineState *s, int argc, reg_t *argv) {
+	uint func = argv[0].toUint16();
+
+	if ((func != K_MESSAGE_NEXT) && (argc < 2)) {
+		warning("Message: not enough arguments passed to subfunction %d", func);
+		return NULL_REG;
 	}
 
-	switch (func) {
-	case K_MESSAGE_GET:
-	case K_MESSAGE_NEXT: {
-		reg_t bufferReg;
-		Common::String str;
-		reg_t retval;
+	MessageTuple tuple;
 
-		if (func == K_MESSAGE_GET) {
-			s->_msgState.loadRes(s->resMan, argv[1].toUint16(), true);
-			s->_msgState.findTuple(tuple);
+	if (argc >= 6)
+		tuple = MessageTuple(argv[2].toUint16(), argv[3].toUint16(), argv[4].toUint16(), argv[5].toUint16());
 
-			if (isGetMessage)
-				bufferReg = (argc == 4 ? argv[3] : NULL_REG);
-			else
-				bufferReg = (argc == 7 ? argv[6] : NULL_REG);
-		} else {
-			bufferReg = (argc == 2 ? argv[1] : NULL_REG);
-		}
-
-		if (s->_msgState.getMessage()) {
-			str = s->_msgState.getText();
-			if (isGetMessage)
-				retval = bufferReg;
-			else
-				retval = make_reg(0, s->_msgState.getTalker());
-		} else {
-			str = Common::String(DUMMY_MESSAGE);
-			retval = NULL_REG;
-		}
-
-		if (!bufferReg.isNull()) {
-			int len = str.size() + 1;
-			SegmentRef buffer_r = s->_segMan->dereference(bufferReg);
-			if (buffer_r.maxSize < len) {
-				warning("Message: buffer %04x:%04x invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(bufferReg), len, str.c_str());
-
-				// Set buffer to empty string if possible
-				if (buffer_r.maxSize > 0)
-					s->_segMan->strcpy(bufferReg, "");
-			} else
-				s->_segMan->strcpy(bufferReg, str.c_str());
-
-			s->_msgState.gotoNext();
-		}
-
-		return retval;
-	}
-	case K_MESSAGE_SIZE: {
-		MessageState tempState;
-
-		if (tempState.loadRes(s->resMan, argv[1].toUint16(), false) && tempState.findTuple(tuple) && tempState.getMessage())
-			return make_reg(0, tempState.getText().size() + 1);
-		else
-			return NULL_REG;
-	}
+	switch (func) {
+	case K_MESSAGE_GET:
+		return make_reg(0, s->_msgState->getMessage(argv[1].toUint16(), tuple, (argc == 7 ? argv[6] : NULL_REG)));
+	case K_MESSAGE_NEXT:
+		return make_reg(0, s->_msgState->nextMessage((argc == 2 ? argv[1] : NULL_REG)));
+	case K_MESSAGE_SIZE:
+		return make_reg(0, s->_msgState->messageSize(argv[1].toUint16(), tuple));
 	case K_MESSAGE_REFCOND:
 	case K_MESSAGE_REFVERB:
 	case K_MESSAGE_REFNOUN: {
-		MessageState tempState;
+		MessageTuple t;
 
-		if (tempState.loadRes(s->resMan, argv[1].toUint16(), false) && tempState.findTuple(tuple)) {
-			MessageTuple t = tempState.getRefTuple();
+		if (s->_msgState->messageRef(argv[1].toUint16(), tuple, t)) {
 			switch (func) {
 			case K_MESSAGE_REFCOND:
 				return make_reg(0, t.cond);
@@ -714,16 +662,17 @@
 			}
 		}
 
-		return NULL_REG;
+		return make_reg(0, -1);
 	}
 	case K_MESSAGE_LASTMESSAGE: {
-		MessageTuple msg = s->_msgState.getLastTuple();
-		int module = s->_msgState.getLastModule();
+		MessageTuple msg;
+		int module;
+
+		s->_msgState->lastQuery(module, msg);
+
 		byte *buffer = s->_segMan->derefBulkPtr(argv[1], 10);
 
 		if (buffer) {
-			// FIXME: Is this correct? I.e., do we really write into a "raw" segment
-			// here? Or maybe we want to write 4 reg_t instead?
 			assert(s->_segMan->dereference(argv[1]).isRaw);
 
 			WRITE_LE_UINT16(buffer, module);

Modified: scummvm/trunk/engines/sci/engine/message.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/message.cpp	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/engine/message.cpp	2009-10-10 02:16:23 UTC (rev 44860)
@@ -24,264 +24,361 @@
  */
 
 #include "sci/engine/message.h"
+#include "sci/engine/kernel.h"
+#include "sci/engine/seg_manager.h"
 #include "sci/tools.h"
 
 namespace Sci {
 
-MessageTuple MessageState::getTuple() {
-	MessageTuple t;
+struct MessageRecord {
+	MessageTuple tuple;
+	MessageTuple refTuple;
+	const char *string;
+	byte talker;
+};
 
-	t.noun = _engineCursor.index_record[0];
-	t.verb = _engineCursor.index_record[1];
-	if (_offsetCondSeq == -1) {
-		t.cond = 0;
-		t.seq = 1;
-	} else {
-		t.cond = _engineCursor.index_record[_offsetCondSeq];
-		t.seq = _engineCursor.index_record[_offsetCondSeq + 1];
+class MessageReader {
+public:
+	bool init() {
+		if (_headerSize > _size)
+			return false;
+
+		// Read message count from last word in header
+		_messageCount = READ_LE_UINT16(_data + _headerSize - 2);
+
+		if (_messageCount * _recordSize + _headerSize > _size)
+			return false;
+
+		return true;
 	}
 
-	return t;
-}
+	virtual bool findRecord(const MessageTuple &tuple, MessageRecord &record) = 0;
 
-MessageTuple MessageState::getRefTuple() {
-	MessageTuple t;
+	virtual ~MessageReader() { };
 
-	if (_offsetRef == -1) {
-		t.noun = 0;
-		t.verb = 0;
-		t.cond = 0;
-	} else {
-		t.noun = _engineCursor.index_record[_offsetRef];
-		t.verb = _engineCursor.index_record[_offsetRef + 1];
-		t.cond = _engineCursor.index_record[_offsetRef + 2];
+protected:
+	MessageReader(const byte *data, uint size, uint headerSize, uint recordSize)
+		: _data(data), _size(size), _headerSize(headerSize), _recordSize(recordSize) { }
+
+	const byte *_data;
+	const uint _size;
+	const uint _headerSize;
+	const uint _recordSize;
+	uint _messageCount;
+};
+
+class MessageReaderV2 : public MessageReader {
+public:
+	MessageReaderV2(byte *data, uint size) : MessageReader(data, size, 6, 4) { }
+
+	bool findRecord(const MessageTuple &tuple, MessageRecord &record) {
+		const byte *recordPtr = _data + _headerSize;
+
+		for (uint i = 0; i < _messageCount; i++) {
+			if ((recordPtr[0] == tuple.noun) && (recordPtr[1] == tuple.verb)) {
+				record.tuple = tuple;
+				record.refTuple = MessageTuple();
+				record.talker = 0;
+				record.string = (const char *)_data + READ_LE_UINT16(recordPtr + 2);
+				return true;
+			}
+			recordPtr += _recordSize;
+		}
+
+		return false;
 	}
-	t.seq = 1;
+};
 
-	return t;
-}
+class MessageReaderV3 : public MessageReader {
+public:
+	MessageReaderV3(byte *data, uint size) : MessageReader(data, size, 8, 10) { }
 
-void MessageState::initCursor() {
-	_engineCursor.index_record = _indexRecords;
-	_engineCursor.index = 0;
-	_engineCursor.nextSeq = 0;
-}
+	bool findRecord(const MessageTuple &tuple, MessageRecord &record) {
+		const byte *recordPtr = _data + _headerSize;
 
-void MessageState::advanceCursor(bool increaseSeq) {
-	_engineCursor.index_record += _recordSize;
-	_engineCursor.index++;
+		for (uint i = 0; i < _messageCount; i++) {
+			if ((recordPtr[0] == tuple.noun) && (recordPtr[1] == tuple.verb)
+				&& (recordPtr[2] == tuple.cond) && (recordPtr[3] == tuple.seq)) {
+				record.tuple = tuple;
+				record.refTuple = MessageTuple();
+				record.talker = recordPtr[4];
+				record.string = (const char *)_data + READ_LE_UINT16(recordPtr + 5);
+				return true;
+			}
+			recordPtr += _recordSize;
+		}
 
-	if (increaseSeq)
-		_engineCursor.nextSeq++;
-}
+		return false;
+	}
+};
 
-int MessageState::findTuple(MessageTuple &t) {
-	if (_module == -1)
-		return 0;
+class MessageReaderV4 : public MessageReader {
+public:
+	MessageReaderV4(byte *data, uint size) : MessageReader(data, size, 10, 11) { }
 
-	// Reset the cursor
-	initCursor();
-	_engineCursor.nextSeq = t.seq;
+	bool findRecord(const MessageTuple &tuple, MessageRecord &record) {
+		const byte *recordPtr = _data + _headerSize;
 
-	// Do a linear search for the message
-	while (1) {
-		MessageTuple looking_at = getTuple();
+		for (uint i = 0; i < _messageCount; i++) {
+			if ((recordPtr[0] == tuple.noun) && (recordPtr[1] == tuple.verb)
+				&& (recordPtr[2] == tuple.cond) && (recordPtr[3] == tuple.seq)) {
+				record.tuple = tuple;
+				record.refTuple = MessageTuple(recordPtr[7], recordPtr[8], recordPtr[9]);
+				record.talker = recordPtr[4];
+				record.string = (const char *)_data + READ_LE_UINT16(recordPtr + 5);
+				return true;
+			}
+			recordPtr += _recordSize;
+		}
 
-		if (t.noun == looking_at.noun &&
-			t.verb == looking_at.verb &&
-			t.cond == looking_at.cond &&
-			t.seq == looking_at.seq)
-			break;
+		return false;
+	}
+};
 
-		advanceCursor(false);
+bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &record) {
+	Resource *res = ((SciEngine *)g_engine)->getResourceManager()->findResource(ResourceId(kResourceTypeMessage, stack.getModule()), 0);
 
-		// Message tuple is not present
-		if (_engineCursor.index == _recordCount)
-			return 0;
+	if (!res) {
+		warning("Failed to open message resource %d", stack.getModule());
+		return NULL;
 	}
 
-	return 1;
-}
+	MessageReader *reader;
+	int version = READ_LE_UINT16(res->data) / 1000;
 
-int MessageState::getMessage() {
-	if (_module == -1)
-		return 0;
+	switch (version) {
+	case 2:
+		reader = new MessageReaderV2(res->data, res->size);
+		break;
+	case 3:
+		reader = new MessageReaderV3(res->data, res->size);
+		break;
+	case 4:
+		reader = new MessageReaderV4(res->data, res->size);
+		break;
+	default:
+		warning("Message: unsupported resource version");
+		return NULL;
+	}
 
-	if (_engineCursor.index != _recordCount) {
-		MessageTuple mesg = getTuple();
-		MessageTuple ref = getRefTuple();
+	if (!reader->init()) {
+		warning("Message: failed to read resource header");
+		return NULL;
+	}
 
-		if (_engineCursor.nextSeq == mesg.seq) {
-			// We found the right sequence number, check for recursion
+	while (1) {
+		MessageTuple &t = stack.top();
 
-			if (ref.noun != 0) {
-				// Recursion, advance the current cursor and load the reference
-				advanceCursor(true);
+		if (!reader->findRecord(t, record)) {
+			// Tuple not found
+			if (recurse && (stack.size() > 1)) {
+				stack.pop();
+				continue;
+			}
 
-				_cursorStack.push(_engineCursor);
+			return false;
+		}
 
-				if (findTuple(ref))
-					return getMessage();
-				else {
-					// Reference not found
-					return 0;
-				}
-			} else {
-				// No recursion, we are done
-				return 1;
+		if (recurse) {
+			MessageTuple &ref = record.refTuple;
+
+			if ((ref.noun != 0) && (ref.verb != 0) && (ref.cond != 0)) {
+				t.seq++;
+				stack.push(MessageTuple(ref.noun, ref.verb, ref.cond));
+				continue;
 			}
 		}
+
+		return true;
 	}
+}
 
-	// We either ran out of records, or found an incorrect sequence number. Go to previous stack frame.
-	if (!_cursorStack.empty()) {
-		_engineCursor = _cursorStack.pop();
-		return getMessage();
+int MessageState::getMessage(int module, MessageTuple &t, reg_t buf) {
+	_cursorStack.init(module, t);
+	return nextMessage(buf);
+}
+
+int MessageState::nextMessage(reg_t buf) {
+	MessageRecord record;
+
+	if (!buf.isNull()) {
+		MessageTuple &t = _cursorStack.top();
+		Common::String finalStr;
+
+		if (getRecord(_cursorStack, true, record)) {
+			outputString(buf, processString(record.string));
+			_lastReturned = record.tuple;
+			_lastReturnedModule = _cursorStack.getModule();
+			t.seq++;
+			return record.talker;
+		} else {
+			outputString(buf, Common::String::printf("Msg %d: %d %d %d %d not found", _cursorStack.getModule(), t.noun, t.verb, t.cond, t.seq));
+			return 0;
+		}
+	} else {
+		CursorStack stack = _cursorStack;
+
+		if (getRecord(stack, true, record))
+			return record.talker;
+		else
+			return 0;
 	}
+}
 
-	// Stack is empty, no message available
-	return 0;
+int MessageState::messageSize(int module, MessageTuple &t) {
+	CursorStack stack;
+	MessageRecord record;
+
+	stack.init(module, t);
+	if (getRecord(stack, true, record))
+		return strlen(record.string);
+	else
+		return 0;
 }
 
-int MessageState::getTalker() {
-	return (_offsetTalker == -1) ? -1 : _engineCursor.index_record[_offsetTalker];
+bool MessageState::messageRef(int module, const MessageTuple &t, MessageTuple &ref) {
+	CursorStack stack;
+	MessageRecord record;
+
+	stack.init(module, t);
+	if (getRecord(stack, false, record)) {
+		ref = record.refTuple;
+		return true;
+	}
+
+	return false;
 }
 
-MessageTuple &MessageState::getLastTuple() {
-	return _lastReturned;
+void MessageState::pushCursorStack() {
+	_cursorStackStack.push(_cursorStack);
 }
 
-int MessageState::getLastModule() {
-	return _lastReturnedModule;
+void MessageState::popCursorStack() {
+	if (!_cursorStackStack.empty())
+		_cursorStack = _cursorStackStack.pop();
+	else
+		warning("Message: attempt to pop from empty stack");
 }
 
-Common::String MessageState::getText() {
-	char *str = (char *)_currentResource->data + READ_LE_UINT16(_engineCursor.index_record + _offsetText);
+int MessageState::hexDigitToInt(char h) {
+	if ((h >= 'A') && (h <= 'F'))
+		return h - 'A' + 10;
 
-	Common::String strippedStr;
-	Common::String skippedSubstr;
-	bool skipping = false;
+	if ((h >= 'a') && (h <= 'f'))
+		return h - 'a' + 10;
 
-	for (uint i = 0; i < strlen(str); i++) {
-		if (skipping) {
-			// Skip stage direction
-			skippedSubstr += str[i];
+	if ((h >= '0') && (h <= '9'))
+		return h - '0';
 
-			// Hopefully these locale-dependant functions are good enough
-			if (islower((unsigned char)str[i]) || isdigit((unsigned char)str[i])) {
-				// Lowercase or digit found, this is not a stage direction
-				strippedStr += skippedSubstr;
-				skipping = false;
-			} else if (str[i] == ')') {
-				// End of stage direction, skip trailing white space
-				while ((i + 1 < strlen(str)) && isspace(str[i + 1]))
-					i++;
-				skipping = false;
-			}
-		} else {
-			if (str[i] == '(') {
-				// Start skipping stage direction
-				skippedSubstr = str[i];
-				skipping = true;
-			} else if (str[i] == '\\') {
-				// Escape sequence
-				if ((i + 2 < strlen(str)) && isdigit(str[i + 1]) && isdigit(str[i + 2])) {
-					// Hex escape sequence
-					char hexStr[3];
+	return -1;
+}
 
-					hexStr[0] = str[++i];
-					hexStr[1] = str[++i];
-					hexStr[2] = 0;
+bool MessageState::stringHex(Common::String &outStr, const Common::String &inStr, uint &index) {
+	// Hex escape sequences of the form \nn, where n is a hex digit
+	if (inStr[index] != '\\')
+		return false;
 
-					char *endptr;
-					int hexNr = strtol(hexStr, &endptr, 16);
-					if (*endptr == 0)
-						strippedStr += hexNr;
-				} else if (i + 1 < strlen(str)) {
-					// Literal escape sequence
-					strippedStr += str[++i];
-				}
-			} else {
-				strippedStr += str[i];
-			}
-		}
-	}
+	// Check for enough room for a hex escape sequence
+	if (index + 2 >= inStr.size())
+		return false;
 
-	return strippedStr;
-}
+	int digit1 = hexDigitToInt(inStr[index + 1]);
+	int digit2 = hexDigitToInt(inStr[index + 2]);
 
-void MessageState::gotoNext() {
-	_lastReturned = getTuple();
-	_lastReturnedModule = _module;
-	advanceCursor(true);
+	// Check for hex
+	if ((digit1 == -1) || (digit2 == -1))
+		return false;
+
+	outStr += digit1 * 16 + digit2;
+	index += 3;
+
+	return true;
 }
 
-int MessageState::getLength() {
-	int offset = READ_LE_UINT16(_engineCursor.index_record + _offsetText);
-	char *stringptr = (char *)_currentResource->data + offset;
-	return strlen(stringptr);
+bool MessageState::stringLit(Common::String &outStr, const Common::String &inStr, uint &index) {
+	// Literal escape sequences of the form \n
+	if (inStr[index] != '\\')
+		return false;
+
+	// Check for enough room for a literal escape sequence
+	if (index + 1 >= inStr.size())
+		return false;
+
+	outStr += inStr[index + 1];
+	index += 2;
+
+	return true;
 }
 
-int MessageState::loadRes(ResourceManager *resMan, int module, bool lock) {
-	_cursorStack.clear();
+bool MessageState::stringStage(Common::String &outstr, const Common::String &inStr, uint &index) {
+	// Stage directions of the form (n*), where n is anything but a digit or a lowercase character
+	if (inStr[index] != '(')
+		return false;
 
-	if (_locked) {
-		// We already have a locked resource
-		if (_module == module) {
-			// If it's the same resource, we are done
-			return 1;
+	for (uint i = index + 1; i < inStr.size(); i++) {
+		if (inStr[i] == ')') {
+			// Stage direction found, skip it
+			index = i + 1;
+
+			// Skip trailing white space
+			while ((index < inStr.size()) && ((inStr[index] == '\n') || (inStr[index] == '\r') || (inStr[index] == ' ')))
+				index++;
+
+			return true;
 		}
 
-		// Otherwise, free the old resource
-		resMan->unlockResource(_currentResource);
-		_locked = false;
+		// If we find a lowercase character or a digit, it's not a stage direction
+		if (((inStr[i] >= 'a') && (inStr[i] <= 'z')) || ((inStr[i] >= '0') && (inStr[i] <= '9')))
+			return false;
 	}
 
-	_currentResource = resMan->findResource(ResourceId(kResourceTypeMessage, module), lock);
+	// We ran into the end of the string without finding a closing bracket
+	return false;
+}
 
-	if (_currentResource == NULL || _currentResource->data == NULL) {
-		warning("Message: failed to load %d.msg", module);
-		return 0;
-	}
+Common::String MessageState::processString(const char *s) {
+	Common::String outStr;
+	Common::String inStr = Common::String(s);
 
-	_module = module;
-	_locked = lock;
+	uint index = 0;
 
-	int version = READ_LE_UINT16(_currentResource->data);
-	debug(5, "Message: reading resource %d.msg, version %d.%03d", _module, version / 1000, version % 1000);
+	while (index < inStr.size()) {
+		// Check for hex escape sequence
+		if (stringHex(outStr, inStr, index))
+			continue;
 
-	int offsetCount;
+		// Check for literal escape sequence
+		if (stringLit(outStr, inStr, index))
+			continue;
 
-	// FIXME: Correct/extend this data by examining more games
-	if (version < 3000) {
-		_offsetCondSeq = -1;
-		_offsetTalker = -1;
-		_offsetRef = -1;
-		_offsetText = 2;
-		_recordSize = 4;
-		offsetCount = 4;
-	} else if (version < 4000) {
-		_offsetCondSeq = 2;
-		_offsetTalker = 4;
-		_offsetRef = -1;
-		_offsetText = 5;
-		_recordSize = 10;
-		offsetCount = 6;
-	} else {
-		_offsetCondSeq = 2;
-		_offsetTalker = 4;
-		_offsetRef = 7;
-		_offsetText = 5;
-		_recordSize = 11;
-		offsetCount = 8;
+		// Check for stage direction
+		if (stringStage(outStr, inStr, index))
+			continue;
+
+		// None of the above, copy char
+		outStr += inStr[index++];
 	}
 
-	_recordCount = READ_LE_UINT16(_currentResource->data + offsetCount);
-	_indexRecords = _currentResource->data + offsetCount + 2;
+	return outStr;
+}
 
-	initCursor();
+void MessageState::outputString(reg_t buf, const Common::String &str) {
+	SegmentRef buffer_r = _segMan->dereference(buf);
 
-	return 1;
+	if ((unsigned)buffer_r.maxSize >= str.size()) {
+		_segMan->strcpy(buf, str.c_str());
+	} else {
+		warning("Message: buffer %04x:%04x invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(buf), str.size() + 1, str.c_str());
+
+		// Set buffer to empty string if possible
+		if (buffer_r.maxSize > 0)
+			_segMan->strcpy(buf, "");
+	}
 }
 
+void MessageState::lastQuery(int &module, MessageTuple &tuple) {
+	module = _lastReturnedModule;
+	tuple = _lastReturned;
+}
+
 } // End of namespace Sci

Modified: scummvm/trunk/engines/sci/engine/message.h
===================================================================
--- scummvm/trunk/engines/sci/engine/message.h	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/engine/message.h	2009-10-10 02:16:23 UTC (rev 44860)
@@ -27,59 +27,66 @@
 #define SCI_ENGINE_MESSAGE_H
 
 #include "sci/resource.h"
+#include "sci/engine/vm_types.h"
 #include "common/stack.h"
 
 namespace Sci {
 
+class SegManager;
+class MessageRecord;
+
 struct MessageTuple {
-	int noun;
-	int verb;
-	int cond;
-	int seq;
+	byte noun;
+	byte verb;
+	byte cond;
+	byte seq;
+
+	MessageTuple(byte noun_ = 0, byte verb_ = 0, byte cond_ = 0, byte seq_ = 1)
+		: noun(noun_), verb(verb_), cond(cond_), seq(seq_) { }
 };
 
-struct IndexRecordCursor {
-	byte *index_record;
-	int index;
-	int nextSeq;
+class CursorStack : public Common::Stack<MessageTuple> {
+public:
+	void init(int module, MessageTuple t) {
+		clear();
+		push(t);
+		_module = module;
+	}
+
+	int getModule() const { return _module; }
+
+private:
+	int _module;
 };
 
-typedef Common::Stack<IndexRecordCursor> CursorStack;
+typedef Common::Stack<CursorStack> CursorStackStack;
 
-// FIXME: Documentation
 class MessageState {
 public:
-	MessageState() : _module(-1), _locked(false) { }
-	int findTuple(MessageTuple &t);
-	MessageTuple getTuple();
-	MessageTuple getRefTuple();
-	int getMessage();
-	void gotoNext();
-	Common::String getText();
-	int getTalker();
-	int getLength();
-	MessageTuple &getLastTuple();
-	int getLastModule();
-	int loadRes(ResourceManager *resMan, int module, bool lock);
+	MessageState(SegManager *segMan) : _segMan(segMan) { }
+	int getMessage(int module, MessageTuple &t, reg_t buf);
+	int nextMessage(reg_t buf);
+	int messageSize(int module, MessageTuple &t);
+	bool messageRef(int module, const MessageTuple &t, MessageTuple &ref);
+	void lastQuery(int &module, MessageTuple &tuple);
+	void pushCursorStack();
+	void popCursorStack();
 
 private:
-	void initCursor();
-	void advanceCursor(bool increaseSeq);
+	bool getRecord(CursorStack &stack, bool recurse, MessageRecord &record);
+	void outputString(reg_t buf, const Common::String &str);
+	Common::String processString(const char *s);
+	int hexDigitToInt(char h);
+	bool stringHex(Common::String &outStr, const Common::String &inStr, uint &index);
+	bool stringLit(Common::String &outStr, const Common::String &inStr, uint &index);
+	bool stringStage(Common::String &outStr, const Common::String &inStr, uint &index);
 
-	Resource *_currentResource;
-	int _module;
-	bool _locked;
-	int _recordCount;
-	byte *_indexRecords;
 	CursorStack _cursorStack;
-	IndexRecordCursor _engineCursor;
+	CursorStackStack _cursorStackStack;
 	MessageTuple _lastReturned;
 	int _lastReturnedModule;
-	int _offsetCondSeq;
-	int _offsetRef;
-	int _offsetTalker;
-	int _offsetText;
-	int _recordSize;
+
+	SegManager *_segMan;
 };
 
 } // End of namespace Sci

Modified: scummvm/trunk/engines/sci/engine/savegame.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/savegame.cpp	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/engine/savegame.cpp	2009-10-10 02:16:23 UTC (rev 44860)
@@ -35,6 +35,7 @@
 #include "sci/sfx/core.h"
 #include "sci/sfx/iterator.h"
 #include "sci/engine/state.h"
+#include "sci/engine/message.h"
 #include "sci/engine/savegame.h"
 #include "sci/gui/gui.h"
 
@@ -775,7 +776,7 @@
 	reconstruct_sounds(retval);
 
 	// Message state:
-	retval->_msgState = s->_msgState;
+	retval->_msgState = new MessageState(retval->_segMan);
 
 	retval->_gui->resetEngineState(retval);
 

Modified: scummvm/trunk/engines/sci/engine/state.cpp
===================================================================
--- scummvm/trunk/engines/sci/engine/state.cpp	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/engine/state.cpp	2009-10-10 02:16:23 UTC (rev 44860)
@@ -26,6 +26,7 @@
 #include "sci/engine/state.h"
 #include "sci/engine/vm.h"
 #include "sci/engine/script.h"
+#include "sci/engine/message.h"
 
 namespace Sci {
 
@@ -116,6 +117,7 @@
 
 EngineState::~EngineState() {
 	delete speedThrottler;
+	delete _msgState;
 }
 
 uint16 EngineState::currentRoomNumber() const {

Modified: scummvm/trunk/engines/sci/engine/state.h
===================================================================
--- scummvm/trunk/engines/sci/engine/state.h	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/engine/state.h	2009-10-10 02:16:23 UTC (rev 44860)
@@ -39,7 +39,6 @@
 #include "sci/vocabulary.h"
 #include "sci/resource.h"
 #include "sci/engine/kernel.h"	// for kfunct_sig_pair_t
-#include "sci/engine/message.h"		// for MessageState
 #include "sci/engine/script.h"
 #include "sci/engine/seg_manager.h"
 #include "sci/gfx/gfx_system.h"
@@ -50,6 +49,7 @@
 class Menubar;
 class SciGui;
 class SciGuiCursor;
+class MessageState;
 
 struct GfxState;
 struct GfxPort;
@@ -320,7 +320,7 @@
 	SegManager *_segMan;
 	int gc_countdown; /**< Number of kernel calls until next gc */
 
-	MessageState _msgState;
+	MessageState *_msgState;
 
 	SpeedThrottler *speedThrottler;
 

Modified: scummvm/trunk/engines/sci/gui/gui_gfx.cpp
===================================================================
--- scummvm/trunk/engines/sci/gui/gui_gfx.cpp	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/gui/gui_gfx.cpp	2009-10-10 02:16:23 UTC (rev 44860)
@@ -24,6 +24,7 @@
  */
 
 #include "common/util.h"
+#include "common/stack.h"
 #include "graphics/primitives.h"
 
 #include "sci/sci.h"

Modified: scummvm/trunk/engines/sci/gui/gui_picture.cpp
===================================================================
--- scummvm/trunk/engines/sci/gui/gui_picture.cpp	2009-10-10 01:38:45 UTC (rev 44859)
+++ scummvm/trunk/engines/sci/gui/gui_picture.cpp	2009-10-10 02:16:23 UTC (rev 44860)
@@ -23,6 +23,7 @@
  *
  */
 
+#include "common/stack.h"
 #include "sci/sci.h"
 #include "sci/engine/state.h"
 #include "sci/tools.h"


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list