aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/message.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/message.cpp')
-rw-r--r--engines/sci/engine/message.cpp237
1 files changed, 49 insertions, 188 deletions
diff --git a/engines/sci/engine/message.cpp b/engines/sci/engine/message.cpp
index 88aa73541a..0688b1ad12 100644
--- a/engines/sci/engine/message.cpp
+++ b/engines/sci/engine/message.cpp
@@ -25,6 +25,7 @@
#include "sci/engine/kernel.h"
#include "sci/engine/seg_manager.h"
#include "sci/engine/state.h"
+#include "sci/engine/workarounds.h"
#include "sci/util.h"
namespace Sci {
@@ -183,10 +184,17 @@ public:
#endif
bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &record) {
- Resource *res = g_sci->getResMan()->findResource(ResourceId(kResourceTypeMessage, stack.getModule()), false);
+ // find a workaround for the requested message and use the prescribed module
+ int module = stack.getModule();
+ MessageTuple &tuple = stack.top();
+ SciMessageWorkaroundSolution workaround = findMessageWorkaround(module, tuple.noun, tuple.verb, tuple.cond, tuple.seq);
+ if (workaround.type != MSG_WORKAROUND_NONE) {
+ module = workaround.module;
+ }
+ Resource *res = g_sci->getResMan()->findResource(ResourceId(kResourceTypeMessage, module), false);
if (!res) {
- warning("Failed to open message resource %d", stack.getModule());
+ warning("Failed to open message resource %d", module);
return false;
}
@@ -224,198 +232,51 @@ bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &re
return false;
}
- while (1) {
- MessageTuple &t = stack.top();
-
- // Fix known incorrect message tuples
- // TODO: Add a more generic mechanism, like the one we have for
- // script workarounds, for cases with incorrect sync resources,
- // like the ones below.
- if (g_sci->getGameId() == GID_QFG1VGA && stack.getModule() == 322 &&
- t.noun == 14 && t.verb == 1 && t.cond == 19 && t.seq == 1) {
- // Talking to Kaspar the shopkeeper - bug #3604944
- t.verb = 2;
- }
-
- if (g_sci->getGameId() == GID_PQ1 && stack.getModule() == 38 &&
- t.noun == 10 && t.verb == 4 && t.cond == 8 && t.seq == 1) {
- // Using the hand icon on Keith in the Blue Room - bug #3605654
- t.cond = 9;
- }
-
- if (g_sci->getGameId() == GID_PQ1 && stack.getModule() == 38 &&
- t.noun == 10 && t.verb == 1 && t.cond == 0 && t.seq == 1) {
- // Using the eye icon on Keith in the Blue Room - bug #3605654
- t.cond = 13;
- }
-
- if (g_sci->getGameId() == GID_QFG4 && stack.getModule() == 16 &&
- t.noun == 49 && t.verb == 1 && t.cond == 0 && t.seq == 2) {
- // Examining the statue inventory item from the monastery - bug #10770
- // The description says "squid-like monster", yet the icon is
- // clearly an insect. It turned Chief into "an enormous beetle". We
- // change the phrase to "monstrous insect".
- //
- // Note: The German string contains accented characters.
- // 0x84 "a with diaeresis"
- // 0x94 "o with diaeresis"
- //
- // Values were pulled from SCI Companion's raw message data. They
- // are escaped that way here, as encoded bytes.
- record.tuple = t;
- record.refTuple = MessageTuple();
- record.talker = 99;
- if (g_sci->getSciLanguage() == K_LANG_GERMAN) {
- record.string = "Die groteske Skulptur eines schrecklichen, monstr\x94sen insekts ist sorgf\x84ltig in die Einkaufstasche eingewickelt.";
- record.length = 112;
- } else {
- record.string = "Carefully wrapped in a shopping bag is the grotesque sculpture of a horrible, monstrous insect.";
- record.length = 95;
- }
- delete reader;
- return true;
- }
-
- if (g_sci->getGameId() == GID_QFG4 && stack.getModule() == 579 &&
- t.noun == 0 && t.verb == 0 && t.cond == 0 && t.seq == 1) {
- // Talking with the Leshy and telling him about "bush in goo" - bug #10137
- t.verb = 1;
- }
-
- if (g_sci->getGameId() == GID_QFG4 && g_sci->isCD() && stack.getModule() == 520 &&
- t.noun == 2 && t.verb == 59 && t.cond == 0) {
- // The CD edition mangled the Rusalka flowers dialogue. - bug #10849
- // In the floppy edition, there are 3 lines, the first from
- // the narrator, then two from Rusalka. The CD edition omits
- // narration and only has the 3rd text, with the 2nd audio! The
- // 3rd audio is orphaned but available.
- //
- // We only restore Rusalka's lines, providing the correct text
- // for seq:1 to match the audio. We respond to seq:2 requests
- // with Rusalka's last text. The orphaned audio (seq:3) has its
- // tuple adjusted to seq:2 in resource_audio.cpp.
- if (t.seq == 1) {
- record.tuple = t;
- record.refTuple = MessageTuple();
- record.talker = 28;
- record.string = "Thank you for the beautiful flowers. No one has been so nice to me since I can remember.";
- record.length = 89;
- delete reader;
- return true;
- } else if (t.seq == 2) {
- // The CD edition ships with this text at seq:1.
- // Look it up instead of hardcoding.
- t.seq = 1;
- if (!reader->findRecord(t, record)) {
- delete reader;
- return false;
- }
- t.seq = 2; // Prevent an endless 2=1 -> 2=1 -> 2=1... loop.
- record.tuple.seq = 2; // Make the record seq:2 to get the seq:2 audio.
+ // apply the message workaround
+ if (workaround.type == MSG_WORKAROUND_REMAP) {
+ // remap the request to a different message record.
+ // this alters the stack, nextMessage() will return the next
+ // record in the sequence following the returned record.
+ stack.setModule(module);
+ tuple.noun = workaround.noun;
+ tuple.verb = workaround.verb;
+ tuple.cond = workaround.cond;
+ tuple.seq = workaround.seq;
+ } else if (workaround.type == MSG_WORKAROUND_FAKE) {
+ // return a fake message record hard-coded in the workaround.
+ // this leaves the stack unchanged.
+ record.tuple = stack.top();
+ record.refTuple = MessageTuple();
+ record.string = workaround.text;
+ record.length = strlen(workaround.text);
+ record.talker = workaround.talker;
+ delete reader;
+ return true;
+ } else if (workaround.type == MSG_WORKAROUND_EXTRACT) {
+ // extract and return text from a different message record.
+ // use the talker provided by the workaround since the correct value
+ // could be in either, or neither, of the records.
+ // this leaves the stack unchanged.
+ MessageTuple textTuple(workaround.noun, workaround.verb, workaround.cond, workaround.seq);
+ MessageRecord textRecord;
+ if (reader->findRecord(textTuple, textRecord)) {
+ uint32 textLength = (workaround.substringLength == 0) ? textRecord.length : workaround.substringLength;
+ if (workaround.substringIndex + textLength <= textRecord.length) {
+ record.tuple = stack.top();
record.refTuple = MessageTuple();
+ record.string = textRecord.string + workaround.substringIndex;
+ record.length = textLength;
+ record.talker = workaround.talker;
delete reader;
return true;
}
}
+ }
- if (g_sci->getGameId() == GID_LAURABOW2 && !g_sci->isCD() && stack.getModule() == 1885 &&
- t.noun == 1 && t.verb == 6 && t.cond == 16 && t.seq == 4 &&
- (g_sci->getEngineState()->currentRoomNumber() == 350 ||
- g_sci->getEngineState()->currentRoomNumber() == 360 ||
- g_sci->getEngineState()->currentRoomNumber() == 370)) {
- // Asking Yvette about Tut in act 2 party - bug #10723
- // Skip the last two lines of dialogue about a murder that hasn't occurred yet.
- // Sierra fixed this in cd version by creating a copy of this message without those lines.
- // Room-specific as the message is used again later where it should display in full.
- t.seq += 2;
- }
-
- // Fill in known missing message tuples
- if (g_sci->getGameId() == GID_SQ4 && stack.getModule() == 16 &&
- t.noun == 7 && t.verb == 0 && t.cond == 3 && t.seq == 1) {
- // This fixes the error message shown when speech and subtitles are
- // enabled simultaneously in SQ4 - the (very) long dialog when Roger
- // is talking with the aliens is missing - bug #3538416.
- record.tuple = t;
- record.refTuple = MessageTuple();
- record.talker = 7; // Roger
- // The missing text is just too big to fit in one speech bubble, and
- // if it's added here manually and drawn on screen, it's painted over
- // the entrance in the back where the Sequel Police enters, so it
- // looks very ugly. Perhaps this is why this particular text is missing,
- // as the text shown in this screen is very short (one-liners).
- // Just output an empty string here instead of showing an error.
- record.string = "";
- record.length = 0;
- delete reader;
- return true;
- }
-
- // FPFP CD has several message sequences where audio and text were left
- // out of sync. This is probably because this version didn't formally
- // support text mode. Most of these texts just say "Dummy Msg". All the
- // real text is there but it's either concatenated or in a different
- // tuple. We extract and return the correct text. Fixes #10964
- if (g_sci->getGameId() == GID_FREDDYPHARKAS && g_sci->isCD() &&
- g_sci->getLanguage() == Common::EN_ANY && !g_sci->isDemo()) {
- byte textSeq = 0;
- uint32 substringIndex = 0;
- uint32 substringLength = 0;
-
- // lever brothers' introduction
- if (stack.getModule() == 220 && t.noun == 24 && t.verb == 0 && t.cond == 0) {
- switch (t.seq) {
- case 1: textSeq = 1; substringIndex = 0; substringLength = 25; break;
- case 2: textSeq = 1; substringIndex = 26; substringLength = 20; break;
- case 3: textSeq = 1; substringIndex = 47; substringLength = 58; break;
- case 4: textSeq = 1; substringIndex = 106; substringLength = 34; break;
- case 5: textSeq = 1; substringIndex = 141; substringLength = 27; break;
- case 6: textSeq = 1; substringIndex = 169; substringLength = 29; break;
- case 7: textSeq = 1; substringIndex = 199; substringLength = 52; break;
- case 8: textSeq = 1; substringIndex = 252; substringLength = 37; break;
- }
- }
-
- // kenny's introduction
- if (stack.getModule() == 220 && t.noun == 30 && t.verb == 0 && t.cond == 0) {
- switch (t.seq) {
- case 3: textSeq = 3; substringIndex = 0; substringLength = 14; break;
- case 4: textSeq = 3; substringIndex = 15; substringLength = 245; break;
- case 5: textSeq = 4; break;
- }
- }
-
- // helen swatting flies
- if (stack.getModule() == 660 && t.noun == 35 && t.verb == 0 && t.cond == 0) {
- switch (t.seq) {
- case 1: textSeq = 1; substringIndex = 0; substringLength = 42; break;
- case 2: textSeq = 1; substringIndex = 43; substringLength = 93; break;
- case 3: textSeq = 1; substringIndex = 137; substringLength = 72; break;
- case 4: textSeq = 2; break;
- case 5: textSeq = 1; substringIndex = 210; substringLength = 57; break;
- case 6: textSeq = 3; break;
- }
- }
-
- // find the original message record and the record that contains the
- // correct text, then use the correct substring. the original must
- // be used to preserve its correct talker and tuple values.
- if (textSeq != 0 && reader->findRecord(t, record)) {
- MessageTuple textTuple(t.noun, t.verb, t.cond, textSeq);
- MessageRecord textRecord;
- if (reader->findRecord(textTuple, textRecord)) {
- uint32 textLength = (substringLength == 0) ? textRecord.length : substringLength;
- if (substringIndex + textLength <= textRecord.length) {
- record.string = textRecord.string + substringIndex;
- record.length = textLength;
- delete reader;
- return true;
- }
- }
- }
- }
+ while (1) {
+ tuple = stack.top();
- if (!reader->findRecord(t, record)) {
+ if (!reader->findRecord(tuple, record)) {
// Tuple not found
if (recurse && (stack.size() > 1)) {
stack.pop();
@@ -430,7 +291,7 @@ bool MessageState::getRecord(CursorStack &stack, bool recurse, MessageRecord &re
MessageTuple &ref = record.refTuple;
if (ref.noun || ref.verb || ref.cond) {
- t.seq++;
+ tuple.seq++;
stack.push(ref);
continue;
}