SCI: Message: Added resource-internal recursion (currently untested).

svn-id: r40478
This commit is contained in:
Walter van Niftrik 2009-05-12 11:28:15 +00:00
parent 4aedfc75f8
commit 7f587a9d6b
3 changed files with 109 additions and 76 deletions

View file

@ -727,9 +727,6 @@ reg_t kGetFarText(EngineState *s, int funct_nr, int argc, reg_t *argv) {
static MessageState state; static MessageState state;
reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
if (!state.isInitialized())
message_state_initialize(s->resmgr, &state);
MessageTuple tuple; MessageTuple tuple;
switch (UKPV(0)) { switch (UKPV(0)) {
@ -738,9 +735,6 @@ reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
case 3: case 3:
case 4: case 4:
case 5: case 5:
if (!state.loadRes(UKPV(1)))
return NULL_REG;
tuple.noun = UKPV(2); tuple.noun = UKPV(2);
tuple.verb = UKPV(3); tuple.verb = UKPV(3);
tuple.cond = UKPV(4); tuple.cond = UKPV(4);
@ -749,7 +743,7 @@ reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
switch (UKPV(0)) { switch (UKPV(0)) {
case 0 : case 0 :
if (state.getMessage(&tuple)) { if (state.loadRes(s->resmgr, UKPV(1), true) && state.getMessage(&tuple)) {
char *buffer = NULL; char *buffer = NULL;
if ((argc == 7) && (argv[6] != NULL_REG)) if ((argc == 7) && (argv[6] != NULL_REG))
@ -759,6 +753,7 @@ reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
if (buffer) if (buffer)
state.getText(buffer); state.getText(buffer);
// Talker id // Talker id
return make_reg(0, talker); return make_reg(0, talker);
} else { } else {
@ -783,6 +778,7 @@ reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
if (buffer) if (buffer)
state.getText(buffer); state.getText(buffer);
// Talker id // Talker id
return make_reg(0, talker); return make_reg(0, talker);
} else { } else {
@ -796,11 +792,14 @@ reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
return NULL_REG; return NULL_REG;
} }
case 2: case 2: {
if (state.getMessage(&tuple)) MessageState tempState;
return make_reg(0, state.getLength() + 1);
if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.getMessage(&tuple))
return make_reg(0, tempState.getLength() + 1);
else else
return NULL_REG; return NULL_REG;
}
default: default:
warning("kMessage subfunction %i invoked (not implemented)", UKPV(0)); warning("kMessage subfunction %i invoked (not implemented)", UKPV(0));
} }
@ -809,9 +808,6 @@ reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
} }
reg_t kGetMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) { reg_t kGetMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
if (!state.isInitialized())
message_state_initialize(s->resmgr, &state);
MessageTuple tuple; MessageTuple tuple;
tuple.noun = UKPV(0); tuple.noun = UKPV(0);
int module = UKPV(1); int module = UKPV(1);
@ -819,7 +815,7 @@ reg_t kGetMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
tuple.cond = 0; tuple.cond = 0;
tuple.seq = 0; tuple.seq = 0;
if (state.loadRes(module) && state.getMessage(&tuple)) { if (state.loadRes(s->resmgr, module, true) && state.getMessage(&tuple)) {
int len = state.getLength(); int len = state.getLength();
char *buffer = kernel_dereference_char_pointer(s, argv[3], len + 1); char *buffer = kernel_dereference_char_pointer(s, argv[3], len + 1);

View file

@ -28,13 +28,6 @@
namespace Sci { namespace Sci {
void MessageState::initIndexRecordCursor() {
_engineCursor.resource_beginning = _currentResource->data;
_engineCursor.index_record = _indexRecords;
_engineCursor.index = 0;
_lastMessage.seq = 0;
}
void MessageState::parse(IndexRecordCursor *cursor, MessageTuple *t) { void MessageState::parse(IndexRecordCursor *cursor, MessageTuple *t) {
t->noun = *(cursor->index_record + 0); t->noun = *(cursor->index_record + 0);
t->verb = *(cursor->index_record + 1); t->verb = *(cursor->index_record + 1);
@ -47,39 +40,93 @@ void MessageState::parse(IndexRecordCursor *cursor, MessageTuple *t) {
} }
} }
void MessageState::parseRef(IndexRecordCursor *cursor, MessageTuple *t) {
if (_version == 2101) {
t->noun = 0;
t->verb = 0;
t->cond = 0;
} else {
t->noun = *(cursor->index_record + 7);
t->verb = *(cursor->index_record + 8);
t->cond = *(cursor->index_record + 9);
}
t->seq = 1;
}
void MessageState::initCursor() {
_engineCursor.index_record = _indexRecords;
_engineCursor.index = 0;
_engineCursor.nextSeq = 0;
}
void MessageState::advanceCursor(bool increaseSeq) {
_engineCursor.index_record += ((_version == 2101) ? 4 : 11);
_engineCursor.index++;
if (increaseSeq)
_engineCursor.nextSeq++;
}
int MessageState::getMessage(MessageTuple *t) { int MessageState::getMessage(MessageTuple *t) {
// Reset the cursor
initCursor();
_engineCursor.nextSeq = t->seq;
// Do a linear search for the message
while (1) {
MessageTuple looking_at; MessageTuple looking_at;
initIndexRecordCursor();
_lastMessage.seq = t->seq - 1;
while (_engineCursor.index != _recordCount) {
parse(&_engineCursor, &looking_at); parse(&_engineCursor, &looking_at);
if (t->noun == looking_at.noun && if (t->noun == looking_at.noun &&
t->verb == looking_at.verb && t->verb == looking_at.verb &&
t->cond == looking_at.cond && t->cond == looking_at.cond &&
t->seq == looking_at.seq) t->seq == looking_at.seq)
return 1; break;
_engineCursor.index_record += ((_version == 2101) ? 4 : 11); advanceCursor(false);
_engineCursor.index++;
// Message tuple is not present
if (_engineCursor.index == _recordCount)
return 0;
} }
// FIXME: Recursion not handled yet return getNext();
return 0;
} }
int MessageState::getNext() { int MessageState::getNext() {
if (_engineCursor.index == _recordCount) if (_engineCursor.index != _recordCount) {
return 0;
MessageTuple mesg; MessageTuple mesg;
parse(&_engineCursor, &mesg); parse(&_engineCursor, &mesg);
MessageTuple ref;
parseRef(&_engineCursor, &ref);
if (_lastMessage.seq == mesg.seq - 1) if (_engineCursor.nextSeq == mesg.seq) {
// We found the right sequence number, check for recursion
if (ref.noun != 0) {
// Recursion, advance the current cursor and load the reference
advanceCursor(true);
if (getMessage(&ref))
return getNext();
else {
// Reference not found
return 0;
}
} else {
// No recursion, we are done
return 1; return 1;
}
}
}
// We either ran out of records, or found an incorrect sequence number. Go to previous stack frame.
if (!_cursorStack.empty()) {
_engineCursor = _cursorStack.pop();
return getNext();
}
// Stack is empty, no message available
return 0; return 0;
} }
@ -89,60 +136,47 @@ int MessageState::getTalker() {
void MessageState::getText(char *buffer) { void MessageState::getText(char *buffer) {
int offset = READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5)); int offset = READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5));
char *stringptr = (char *)_engineCursor.resource_beginning + offset; char *stringptr = (char *)_currentResource->data + offset;
parse(&_engineCursor, &_lastMessage);
strcpy(buffer, stringptr); strcpy(buffer, stringptr);
_engineCursor.index_record += ((_version == 2101) ? 4 : 11); advanceCursor(true);
_engineCursor.index++;
} }
int MessageState::getLength() { int MessageState::getLength() {
int offset = READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5)); int offset = READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5));
char *stringptr = (char *)_engineCursor.resource_beginning + offset; char *stringptr = (char *)_currentResource->data + offset;
return strlen(stringptr); return strlen(stringptr);
} }
int MessageState::loadRes(int module) { int MessageState::loadRes(ResourceManager *resmgr, int module, bool lock) {
if (_module == module) if (_module == module)
return 1; return 1;
// Unlock old resource // Unlock old resource
if (_module != -1) if (_module != -1) {
_resmgr->unlockResource(_currentResource, _module, kResourceTypeMessage); resmgr->unlockResource(_currentResource, _module, kResourceTypeMessage);
_module = -1;
}
_module = module; _currentResource = resmgr->findResource(kResourceTypeMessage, module, lock);
_currentResource = _resmgr->findResource(kResourceTypeMessage, module, 1);
if (_currentResource == NULL || _currentResource->data == NULL) { if (_currentResource == NULL || _currentResource->data == NULL) {
sciprintf("Message subsystem: Failed to load %d.MSG\n", module); warning("Message subsystem: failed to load %d.msg", module);
_module = -1;
return 0; return 0;
} }
if (lock)
_module = module;
_version = READ_LE_UINT16(_currentResource->data);
int offs = (_version == 2101) ? 0 : 4; int offs = (_version == 2101) ? 0 : 4;
_recordCount = READ_LE_UINT16(_currentResource->data + 4 + offs); _recordCount = READ_LE_UINT16(_currentResource->data + 4 + offs);
_indexRecords = _currentResource->data + 6 + offs; _indexRecords = _currentResource->data + 6 + offs;
initIndexRecordCursor(); _cursorStack.clear();
initCursor();
return 1; return 1;
} }
void MessageState::initialize(ResourceManager *resmgr) {
_module = -1;
_resmgr = resmgr;
_currentResource = NULL;
_recordCount = 0;
_initialized = 1;
}
void message_state_initialize(ResourceManager *resmgr, MessageState *state) {
Resource *tester = resmgr->findResource(kResourceTypeMessage, 0, 0);
if (tester) {
int version = READ_LE_UINT16(tester->data);
state->initialize(resmgr);
state->setVersion(version);
}
}
} // End of namespace Sci } // End of namespace Sci

View file

@ -27,6 +27,7 @@
#define SCI_ENGINE_MESSAGE_H #define SCI_ENGINE_MESSAGE_H
#include "sci/scicore/resource.h" #include "sci/scicore/resource.h"
#include "common/stack.h"
namespace Sci { namespace Sci {
@ -40,38 +41,40 @@ struct MessageTuple {
struct IndexRecordCursor { struct IndexRecordCursor {
byte *index_record; byte *index_record;
int index; int index;
byte *resource_beginning; int nextSeq;
}; };
typedef Common::Stack<IndexRecordCursor> CursorStack;
class MessageState { class MessageState {
public: public:
MessageState() : _module(-1) { }
int getMessage(MessageTuple *t); int getMessage(MessageTuple *t);
int getNext(); int getNext();
int getTalker(); int getTalker();
int getLength(); int getLength();
void getText(char *buffer); void getText(char *buffer);
int loadRes(int module); int loadRes(ResourceManager *resmgr, int module, bool lock);
int isInitialized() { return _initialized; } int isInitialized() { return _initialized; }
void initialize(ResourceManager *resmgr); void initialize(ResourceManager *resmgr);
void setVersion(int version) { _version = version; } void setVersion(int version) { _version = version; }
private: private:
void initIndexRecordCursor();
void parse(IndexRecordCursor *cursor, MessageTuple *t); void parse(IndexRecordCursor *cursor, MessageTuple *t);
void parseRef(IndexRecordCursor *cursor, MessageTuple *t);
void initCursor();
void advanceCursor(bool increaseSeq);
int _initialized; int _initialized;
ResourceManager *_resmgr;
Resource *_currentResource; Resource *_currentResource;
int _module; int _module;
int _recordCount; int _recordCount;
byte *_indexRecords; byte *_indexRecords;
CursorStack _cursorStack;
IndexRecordCursor _engineCursor; IndexRecordCursor _engineCursor;
MessageTuple _lastMessage;
int _version; int _version;
}; };
void message_state_initialize(ResourceManager *resmgr, MessageState *state);
} // End of namespace Sci } // End of namespace Sci
#endif // SCI_ENGINE_MESSAGE_H #endif // SCI_ENGINE_MESSAGE_H