[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