SCI: Message: Added resource-internal recursion (currently untested).
svn-id: r40478
This commit is contained in:
parent
4aedfc75f8
commit
7f587a9d6b
3 changed files with 109 additions and 76 deletions
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
MessageTuple looking_at;
|
// Reset the cursor
|
||||||
|
initCursor();
|
||||||
|
_engineCursor.nextSeq = t->seq;
|
||||||
|
|
||||||
initIndexRecordCursor();
|
// Do a linear search for the message
|
||||||
_lastMessage.seq = t->seq - 1;
|
while (1) {
|
||||||
|
MessageTuple looking_at;
|
||||||
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;
|
||||||
|
parse(&_engineCursor, &mesg);
|
||||||
|
MessageTuple ref;
|
||||||
|
parseRef(&_engineCursor, &ref);
|
||||||
|
|
||||||
MessageTuple mesg;
|
if (_engineCursor.nextSeq == mesg.seq) {
|
||||||
parse(&_engineCursor, &mesg);
|
// We found the right sequence number, check for recursion
|
||||||
|
|
||||||
if (_lastMessage.seq == mesg.seq - 1)
|
if (ref.noun != 0) {
|
||||||
return 1;
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue