mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-01 15:55:45 +00:00
SCI: Message: Added a few more subfunctions; cleanup.
svn-id: r40529
This commit is contained in:
parent
f0182121f7
commit
e35b77e0a7
@ -722,107 +722,143 @@ reg_t kGetFarText(EngineState *s, int funct_nr, int argc, reg_t *argv) {
|
||||
return argv[2];
|
||||
}
|
||||
|
||||
#define DUMMY_MESSAGE "No MESSAGE support in SCI yet"
|
||||
#define DUMMY_MESSAGE "Message not found!"
|
||||
|
||||
static MessageState state;
|
||||
|
||||
enum kMessageFunc {
|
||||
K_MESSAGE_GET,
|
||||
K_MESSAGE_NEXT,
|
||||
K_MESSAGE_SIZE,
|
||||
K_MESSAGE_REFCOND,
|
||||
K_MESSAGE_REFVERB,
|
||||
K_MESSAGE_REFNOUN,
|
||||
K_MESSAGE_PUSH,
|
||||
K_MESSAGE_POP,
|
||||
K_MESSAGE_LASTMESSAGE
|
||||
};
|
||||
|
||||
reg_t kMessage(EngineState *s, int funct_nr, int argc, reg_t *argv) {
|
||||
MessageTuple tuple;
|
||||
int func;
|
||||
// For earlier version of of this function (GetMessage)
|
||||
bool isGetMessage = argc == 4;
|
||||
|
||||
if (isGetMessage) {
|
||||
func = K_MESSAGE_GET;
|
||||
|
||||
if (argc == 4) {
|
||||
// Earlier version of of this function (GetMessage)
|
||||
tuple.noun = UKPV(0);
|
||||
int module = UKPV(1);
|
||||
tuple.verb = UKPV(2);
|
||||
tuple.cond = 0;
|
||||
tuple.seq = 1;
|
||||
} else {
|
||||
func = UKPV(0);
|
||||
|
||||
if (state.loadRes(s->resmgr, module, true) && state.getMessage(&tuple)) {
|
||||
int len = state.getLength();
|
||||
char *buffer = kernel_dereference_char_pointer(s, argv[3], len + 1);
|
||||
if (argc >= 6) {
|
||||
tuple.noun = UKPV(2);
|
||||
tuple.verb = UKPV(3);
|
||||
tuple.cond = UKPV(4);
|
||||
tuple.seq = UKPV(5);
|
||||
}
|
||||
}
|
||||
|
||||
switch (func) {
|
||||
case K_MESSAGE_GET:
|
||||
case K_MESSAGE_NEXT: {
|
||||
reg_t bufferReg;
|
||||
char *buffer = NULL;
|
||||
const char *str;
|
||||
reg_t retval;
|
||||
|
||||
if (func == K_MESSAGE_GET) {
|
||||
state.loadRes(s->resmgr, UKPV(1), true);
|
||||
state.findTuple(tuple);
|
||||
|
||||
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 (state.getMessage()) {
|
||||
str = state.getText();
|
||||
if (isGetMessage)
|
||||
retval = bufferReg;
|
||||
else
|
||||
retval = make_reg(0, state.getTalker());
|
||||
} else {
|
||||
str = DUMMY_MESSAGE;
|
||||
retval = NULL_REG;
|
||||
}
|
||||
|
||||
if (!bufferReg.isNull()) {
|
||||
int len = strlen(str) + 1;
|
||||
buffer = kernel_dereference_char_pointer(s, bufferReg, len);
|
||||
|
||||
if (buffer) {
|
||||
state.getText(buffer);
|
||||
return argv[3];
|
||||
strcpy(buffer, str);
|
||||
} else {
|
||||
warning("Message: buffer "PREG" invalid or too small to hold the following text of %i bytes: '%s'", PRINT_REG(bufferReg), len, str);
|
||||
|
||||
// Set buffer to empty string if possible
|
||||
buffer = kernel_dereference_char_pointer(s, bufferReg, 1);
|
||||
if (buffer)
|
||||
*buffer = 0;
|
||||
}
|
||||
|
||||
state.gotoNext();
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
case K_MESSAGE_SIZE: {
|
||||
MessageState tempState;
|
||||
|
||||
if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.findTuple(tuple) && tempState.getMessage())
|
||||
return make_reg(0, strlen(tempState.getText()));
|
||||
else
|
||||
return NULL_REG;
|
||||
}
|
||||
case K_MESSAGE_REFCOND:
|
||||
case K_MESSAGE_REFVERB:
|
||||
case K_MESSAGE_REFNOUN: {
|
||||
MessageState tempState;
|
||||
|
||||
if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.findTuple(tuple)) {
|
||||
MessageTuple t = tempState.getRefTuple();
|
||||
switch (func) {
|
||||
case K_MESSAGE_REFCOND:
|
||||
return make_reg(0, t.cond);
|
||||
case K_MESSAGE_REFVERB:
|
||||
return make_reg(0, t.verb);
|
||||
case K_MESSAGE_REFNOUN:
|
||||
return make_reg(0, t.noun);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL_REG;
|
||||
}
|
||||
case K_MESSAGE_LASTMESSAGE: {
|
||||
MessageTuple msg = state.getLastTuple();
|
||||
int module = state.getLastModule();
|
||||
byte *buffer = kernel_dereference_bulk_pointer(s, argv[1], 10);
|
||||
|
||||
switch (UKPV(0)) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
tuple.noun = UKPV(2);
|
||||
tuple.verb = UKPV(3);
|
||||
tuple.cond = UKPV(4);
|
||||
tuple.seq = UKPV(5);
|
||||
}
|
||||
|
||||
switch (UKPV(0)) {
|
||||
case 0 :
|
||||
if (state.loadRes(s->resmgr, UKPV(1), true) && state.getMessage(&tuple)) {
|
||||
char *buffer = NULL;
|
||||
|
||||
if ((argc == 7) && (argv[6] != NULL_REG))
|
||||
buffer = kernel_dereference_char_pointer(s, argv[6], state.getLength() + 1);
|
||||
|
||||
int talker = state.getTalker();
|
||||
|
||||
if (buffer)
|
||||
state.getText(buffer);
|
||||
|
||||
// Talker id
|
||||
return make_reg(0, talker);
|
||||
if (buffer) {
|
||||
WRITE_LE_UINT16(buffer, module);
|
||||
WRITE_LE_UINT16(buffer + 2, msg.noun);
|
||||
WRITE_LE_UINT16(buffer + 4, msg.verb);
|
||||
WRITE_LE_UINT16(buffer + 6, msg.cond);
|
||||
WRITE_LE_UINT16(buffer + 8, msg.seq);
|
||||
} else {
|
||||
char *buffer = NULL;
|
||||
|
||||
if ((argc == 7) && (argv[6] != NULL_REG))
|
||||
buffer = kernel_dereference_char_pointer(s, argv[6], strlen(DUMMY_MESSAGE) + 1);
|
||||
|
||||
if (buffer)
|
||||
strcpy(buffer, DUMMY_MESSAGE);
|
||||
|
||||
return NULL_REG;
|
||||
warning("Message: buffer "PREG" invalid or too small to hold the tuple", PRINT_REG(argv[1]));
|
||||
}
|
||||
case 1 :
|
||||
if (state.getNext()) {
|
||||
char *buffer = NULL;
|
||||
|
||||
if ((argc == 2) && (argv[1] != NULL_REG))
|
||||
buffer = kernel_dereference_char_pointer(s, argv[1], state.getLength() + 1);
|
||||
|
||||
int talker = state.getTalker();
|
||||
|
||||
if (buffer)
|
||||
state.getText(buffer);
|
||||
|
||||
// Talker id
|
||||
return make_reg(0, talker);
|
||||
} else {
|
||||
char *buffer = NULL;
|
||||
|
||||
if ((argc == 2) && (argv[1] != NULL_REG))
|
||||
buffer = kernel_dereference_char_pointer(s, argv[1], strlen(DUMMY_MESSAGE) + 1);
|
||||
|
||||
if (buffer)
|
||||
strcpy(buffer, DUMMY_MESSAGE);
|
||||
|
||||
return NULL_REG;
|
||||
}
|
||||
case 2: {
|
||||
MessageState tempState;
|
||||
|
||||
if (tempState.loadRes(s->resmgr, UKPV(1), false) && tempState.getMessage(&tuple))
|
||||
return make_reg(0, tempState.getLength() + 1);
|
||||
else
|
||||
return NULL_REG;
|
||||
return NULL_REG;
|
||||
}
|
||||
default:
|
||||
warning("kMessage subfunction %i invoked (not implemented)", UKPV(0));
|
||||
warning("Message: subfunction %i invoked (not implemented)", func);
|
||||
}
|
||||
|
||||
return NULL_REG;
|
||||
|
@ -28,29 +28,37 @@
|
||||
|
||||
namespace Sci {
|
||||
|
||||
void MessageState::parse(IndexRecordCursor *cursor, MessageTuple *t) {
|
||||
t->noun = *(cursor->index_record + 0);
|
||||
t->verb = *(cursor->index_record + 1);
|
||||
MessageTuple MessageState::getTuple() {
|
||||
MessageTuple t;
|
||||
|
||||
t.noun = *(_engineCursor.index_record + 0);
|
||||
t.verb = *(_engineCursor.index_record + 1);
|
||||
if (_version == 2101) {
|
||||
t->cond = 0;
|
||||
t->seq = 1;
|
||||
t.cond = 0;
|
||||
t.seq = 1;
|
||||
} else {
|
||||
t->cond = *(cursor->index_record + 2);
|
||||
t->seq = *(cursor->index_record + 3);
|
||||
t.cond = *(_engineCursor.index_record + 2);
|
||||
t.seq = *(_engineCursor.index_record + 3);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void MessageState::parseRef(IndexRecordCursor *cursor, MessageTuple *t) {
|
||||
MessageTuple MessageState::getRefTuple() {
|
||||
MessageTuple t;
|
||||
|
||||
if (_version == 2101) {
|
||||
t->noun = 0;
|
||||
t->verb = 0;
|
||||
t->cond = 0;
|
||||
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.noun = *(_engineCursor.index_record + 7);
|
||||
t.verb = *(_engineCursor.index_record + 8);
|
||||
t.cond = *(_engineCursor.index_record + 9);
|
||||
}
|
||||
t->seq = 1;
|
||||
t.seq = 1;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void MessageState::initCursor() {
|
||||
@ -67,20 +75,22 @@ void MessageState::advanceCursor(bool increaseSeq) {
|
||||
_engineCursor.nextSeq++;
|
||||
}
|
||||
|
||||
int MessageState::getMessage(MessageTuple *t) {
|
||||
int MessageState::findTuple(MessageTuple &t) {
|
||||
if (_module == -1)
|
||||
return 0;
|
||||
|
||||
// Reset the cursor
|
||||
initCursor();
|
||||
_engineCursor.nextSeq = t->seq;
|
||||
_engineCursor.nextSeq = t.seq;
|
||||
|
||||
// Do a linear search for the message
|
||||
while (1) {
|
||||
MessageTuple looking_at;
|
||||
parse(&_engineCursor, &looking_at);
|
||||
MessageTuple looking_at = getTuple();
|
||||
|
||||
if (t->noun == looking_at.noun &&
|
||||
t->verb == looking_at.verb &&
|
||||
t->cond == looking_at.cond &&
|
||||
t->seq == looking_at.seq)
|
||||
if (t.noun == looking_at.noun &&
|
||||
t.verb == looking_at.verb &&
|
||||
t.cond == looking_at.cond &&
|
||||
t.seq == looking_at.seq)
|
||||
break;
|
||||
|
||||
advanceCursor(false);
|
||||
@ -90,15 +100,16 @@ int MessageState::getMessage(MessageTuple *t) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getNext();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int MessageState::getNext() {
|
||||
int MessageState::getMessage() {
|
||||
if (_module == -1)
|
||||
return 0;
|
||||
|
||||
if (_engineCursor.index != _recordCount) {
|
||||
MessageTuple mesg;
|
||||
parse(&_engineCursor, &mesg);
|
||||
MessageTuple ref;
|
||||
parseRef(&_engineCursor, &ref);
|
||||
MessageTuple mesg = getTuple();
|
||||
MessageTuple ref = getRefTuple();
|
||||
|
||||
if (_engineCursor.nextSeq == mesg.seq) {
|
||||
// We found the right sequence number, check for recursion
|
||||
@ -107,8 +118,8 @@ int MessageState::getNext() {
|
||||
// Recursion, advance the current cursor and load the reference
|
||||
advanceCursor(true);
|
||||
|
||||
if (getMessage(&ref))
|
||||
return getNext();
|
||||
if (findTuple(ref))
|
||||
return getMessage();
|
||||
else {
|
||||
// Reference not found
|
||||
return 0;
|
||||
@ -123,7 +134,7 @@ int MessageState::getNext() {
|
||||
// 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();
|
||||
return getMessage();
|
||||
}
|
||||
|
||||
// Stack is empty, no message available
|
||||
@ -134,10 +145,22 @@ int MessageState::getTalker() {
|
||||
return (_version == 2101) ? -1 : *(_engineCursor.index_record + 4);
|
||||
}
|
||||
|
||||
void MessageState::getText(char *buffer) {
|
||||
MessageTuple &MessageState::getLastTuple() {
|
||||
return _lastReturned;
|
||||
}
|
||||
|
||||
int MessageState::getLastModule() {
|
||||
return _lastReturnedModule;
|
||||
}
|
||||
|
||||
char *MessageState::getText() {
|
||||
int offset = READ_LE_UINT16(_engineCursor.index_record + ((_version == 2101) ? 2 : 5));
|
||||
char *stringptr = (char *)_currentResource->data + offset;
|
||||
strcpy(buffer, stringptr);
|
||||
return (char *)_currentResource->data + offset;
|
||||
}
|
||||
|
||||
void MessageState::gotoNext() {
|
||||
_lastReturned = getTuple();
|
||||
_lastReturnedModule = _module;
|
||||
advanceCursor(true);
|
||||
}
|
||||
|
||||
@ -148,24 +171,27 @@ int MessageState::getLength() {
|
||||
}
|
||||
|
||||
int MessageState::loadRes(ResourceManager *resmgr, int module, bool lock) {
|
||||
if (_module == module)
|
||||
return 1;
|
||||
if (_locked) {
|
||||
// We already have a locked resource
|
||||
if (_module == module) {
|
||||
// If it's the same resource, we are done
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Unlock old resource
|
||||
if (_module != -1) {
|
||||
// Otherwise, free the old resource
|
||||
resmgr->unlockResource(_currentResource, _module, kResourceTypeMessage);
|
||||
_module = -1;
|
||||
_locked = false;
|
||||
}
|
||||
|
||||
_currentResource = resmgr->findResource(kResourceTypeMessage, module, lock);
|
||||
|
||||
if (_currentResource == NULL || _currentResource->data == NULL) {
|
||||
warning("Message subsystem: failed to load %d.msg", module);
|
||||
warning("Message: failed to load %d.msg", module);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lock)
|
||||
_module = module;
|
||||
_module = module;
|
||||
_locked = lock;
|
||||
|
||||
_version = READ_LE_UINT16(_currentResource->data);
|
||||
|
||||
|
@ -48,30 +48,32 @@ typedef Common::Stack<IndexRecordCursor> CursorStack;
|
||||
|
||||
class MessageState {
|
||||
public:
|
||||
MessageState() : _module(-1) { }
|
||||
int getMessage(MessageTuple *t);
|
||||
int getNext();
|
||||
MessageState() : _module(-1), _locked(false) { }
|
||||
int findTuple(MessageTuple &t);
|
||||
MessageTuple getTuple();
|
||||
MessageTuple getRefTuple();
|
||||
int getMessage();
|
||||
void gotoNext();
|
||||
char *getText();
|
||||
int getTalker();
|
||||
int getLength();
|
||||
void getText(char *buffer);
|
||||
MessageTuple &getLastTuple();
|
||||
int getLastModule();
|
||||
int loadRes(ResourceManager *resmgr, int module, bool lock);
|
||||
int isInitialized() { return _initialized; }
|
||||
void initialize(ResourceManager *resmgr);
|
||||
void setVersion(int version) { _version = version; }
|
||||
|
||||
private:
|
||||
void parse(IndexRecordCursor *cursor, MessageTuple *t);
|
||||
void parseRef(IndexRecordCursor *cursor, MessageTuple *t);
|
||||
void initCursor();
|
||||
void advanceCursor(bool increaseSeq);
|
||||
|
||||
int _initialized;
|
||||
Resource *_currentResource;
|
||||
int _module;
|
||||
bool _locked;
|
||||
int _recordCount;
|
||||
byte *_indexRecords;
|
||||
CursorStack _cursorStack;
|
||||
IndexRecordCursor _engineCursor;
|
||||
MessageTuple _lastReturned;
|
||||
int _lastReturnedModule;
|
||||
int _version;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user