aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/kstring.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/kstring.cpp')
-rw-r--r--engines/sci/engine/kstring.cpp89
1 files changed, 63 insertions, 26 deletions
diff --git a/engines/sci/engine/kstring.cpp b/engines/sci/engine/kstring.cpp
index c4db0b891c..15a9f54996 100644
--- a/engines/sci/engine/kstring.cpp
+++ b/engines/sci/engine/kstring.cpp
@@ -155,30 +155,47 @@ reg_t kReadNumber(EngineState *s, int argc, reg_t *argv) {
source++; /* Skip whitespace */
int16 result = 0;
+ int16 sign = 1;
+ if (*source == '-') {
+ sign = -1;
+ source++;
+ }
if (*source == '$') {
// Hexadecimal input
- result = (int16)strtol(source + 1, NULL, 16);
+ source++;
+ char c;
+ while ((c = *source++) != 0) {
+ int16 x = 0;
+ if ((c >= '0') && (c <= '9'))
+ x = c - '0';
+ else if ((c >= 'a') && (c <= 'f'))
+ x = c - 'a' + 10;
+ else if ((c >= 'A') && (c <= 'F'))
+ x = c - 'A' + 10;
+ else
+ // Stop if we encounter anything other than a digit (like atoi)
+ break;
+ result *= 16;
+ result += x;
+ }
} else {
// Decimal input. We can not use strtol/atoi in here, because while
// Sierra used atoi, it was a non standard compliant atoi, that didn't
// do clipping. In SQ4 we get the door code in here and that's even
// larger than uint32!
- if (*source == '-') {
- // FIXME: Setting result to -1 does _not_ negate the output.
- result = -1;
- source++;
- }
- while (*source) {
- if ((*source < '0') || (*source > '9'))
+ char c;
+ while ((c = *source++) != 0) {
+ if ((c < '0') || (c > '9'))
// Stop if we encounter anything other than a digit (like atoi)
break;
result *= 10;
- result += *source - 0x30;
- source++;
+ result += c - '0';
}
}
+ result *= sign;
+
return make_reg(0, result);
}
@@ -471,9 +488,9 @@ enum kMessageFunc {
K_MESSAGE_GET,
K_MESSAGE_NEXT,
K_MESSAGE_SIZE,
- K_MESSAGE_REFCOND,
- K_MESSAGE_REFVERB,
K_MESSAGE_REFNOUN,
+ K_MESSAGE_REFVERB,
+ K_MESSAGE_REFCOND,
K_MESSAGE_PUSH,
K_MESSAGE_POP,
K_MESSAGE_LASTMESSAGE
@@ -489,20 +506,15 @@ reg_t kGetMessage(EngineState *s, int argc, reg_t *argv) {
reg_t kMessage(EngineState *s, int argc, reg_t *argv) {
uint func = argv[0].toUint16();
+ uint16 module = (argc >= 2) ? argv[1].toUint16() : 0;
#ifdef ENABLE_SCI32
if (getSciVersion() >= SCI_VERSION_2) {
// In complete weirdness, SCI32 bumps up subops 3-8 to 4-9 and stubs off subop 3.
- // In addition, SCI32 reorders the REF* subops.
if (func == 3)
error("SCI32 kMessage(3)");
- else if (func > 3) {
+ else if (func > 3)
func--;
- if (func == K_MESSAGE_REFCOND)
- func = K_MESSAGE_REFNOUN;
- else if (func == K_MESSAGE_REFNOUN || func == K_MESSAGE_REFVERB)
- func--;
- }
}
#endif
@@ -518,19 +530,44 @@ reg_t kMessage(EngineState *s, int argc, reg_t *argv) {
if (argc >= 6)
tuple = MessageTuple(argv[2].toUint16(), argv[3].toUint16(), argv[4].toUint16(), argv[5].toUint16());
+ // WORKAROUND for a script bug in Pepper. When using objects together,
+ // there is code inside script 894 that shows appropriate messages.
+ // In the case of the jar of cabbage (noun 26), the relevant message
+ // shown when using any object with it is missing. This leads to the
+ // script code being triggered, which modifies the jar's noun and
+ // message selectors, and renders it useless. Thus, when using any
+ // object with the jar of cabbage, it's effectively corrupted, and
+ // can't be used on the goat to empty it, therefore the game reaches
+ // an unsolvable state. It's almost impossible to patch the offending
+ // script, as it is used in many cases. But we can prevent the
+ // corruption of the jar here: if the message is found, the offending
+ // code is never reached and the jar is never corrupted. To do this,
+ // we substitute all verbs on the cabbage jar with the default verb,
+ // which shows the "Cannot use this object with the jar" message, and
+ // never triggers the offending script code that corrupts the object.
+ // This only affects the jar of cabbage - any other object, including
+ // the empty jar has a different noun, thus it's unaffected.
+ // Fixes bug #3601090.
+ // NOTE: To fix a corrupted jar object, type "send Glass_Jar message 52"
+ // in the debugger.
+ if (g_sci->getGameId() == GID_PEPPER && func == 0 && argc >= 6 && module == 894 &&
+ tuple.noun == 26 && tuple.cond == 0 && tuple.seq == 1 &&
+ !s->_msgState->getMessage(module, tuple, NULL_REG))
+ tuple.verb = 0;
+
switch (func) {
case K_MESSAGE_GET:
- return make_reg(0, s->_msgState->getMessage(argv[1].toUint16(), tuple, (argc == 7 ? argv[6] : NULL_REG)));
+ return make_reg(0, s->_msgState->getMessage(module, 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));
+ return make_reg(0, s->_msgState->messageSize(module, tuple));
case K_MESSAGE_REFCOND:
case K_MESSAGE_REFVERB:
case K_MESSAGE_REFNOUN: {
MessageTuple t;
- if (s->_msgState->messageRef(argv[1].toUint16(), tuple, t)) {
+ if (s->_msgState->messageRef(module, tuple, t)) {
switch (func) {
case K_MESSAGE_REFCOND:
return make_reg(0, t.cond);
@@ -545,9 +582,9 @@ reg_t kMessage(EngineState *s, int argc, reg_t *argv) {
}
case K_MESSAGE_LASTMESSAGE: {
MessageTuple msg;
- int module;
+ int lastModule;
- s->_msgState->lastQuery(module, msg);
+ s->_msgState->lastQuery(lastModule, msg);
bool ok = false;
@@ -556,7 +593,7 @@ reg_t kMessage(EngineState *s, int argc, reg_t *argv) {
if (buffer) {
ok = true;
- WRITE_LE_UINT16(buffer, module);
+ WRITE_LE_UINT16(buffer, lastModule);
WRITE_LE_UINT16(buffer + 2, msg.noun);
WRITE_LE_UINT16(buffer + 4, msg.verb);
WRITE_LE_UINT16(buffer + 6, msg.cond);
@@ -567,7 +604,7 @@ reg_t kMessage(EngineState *s, int argc, reg_t *argv) {
if (buffer) {
ok = true;
- buffer[0] = make_reg(0, module);
+ buffer[0] = make_reg(0, lastModule);
buffer[1] = make_reg(0, msg.noun);
buffer[2] = make_reg(0, msg.verb);
buffer[3] = make_reg(0, msg.cond);