mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 05:38:56 +00:00
SCI: Create message workaround system
Adds a new workaround system for known broken messages and their corresponding audio and sync resources. This replaces all special cases in c++ and several script patches with data structures and generic handling. Common message bugs: - Wrong tuple requested by game script - Wrong tuple in message resource - Wrong message text that exists in another record - Missing message text - Audio or sync resource with different tuple than message
This commit is contained in:
parent
9326f2f31d
commit
56ea963cea
@ -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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
MessageTuple &t = stack.top();
|
||||
tuple = 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.
|
||||
record.refTuple = MessageTuple();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
}
|
||||
|
||||
int getModule() const { return _module; }
|
||||
void setModule(int module) { _module = module; }
|
||||
|
||||
private:
|
||||
int _module;
|
||||
|
@ -2091,28 +2091,6 @@ static const uint16 gk1Day5MoselyVevePointsPatch[] = {
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// GK1 english pc floppy has a missing message when showing certain items to
|
||||
// Magentia in room 290 such as the flashlight. This triggers an error message.
|
||||
// We fix this by passing GkMessager:say the correct cond as later versions do.
|
||||
//
|
||||
// Applies to: English PC Floppy 1.0
|
||||
// Responsible method: magentia:doVerb
|
||||
// Fixes bug: #10782
|
||||
static const uint16 gk1ShowMagentiaItemSignature[] = {
|
||||
SIG_MAGICDWORD,
|
||||
0x76, // push0
|
||||
0x39, 0x23, // pushi 23 [ invalid message cond ]
|
||||
0x76, // push0
|
||||
0x81, 0x5b, // lag global[5b] [ GkMessager ]
|
||||
SIG_END
|
||||
};
|
||||
|
||||
static const uint16 gk1ShowMagentiaItemPatch[] = {
|
||||
PATCH_ADDTOOFFSET(+1),
|
||||
0x39, 0x00, // pushi 0 [ "Does this mean anything to you?" ]
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// The day 5 snake attack has speed, audio, and graphics problems.
|
||||
// These occur in all versions and also in Sierra's interpreter.
|
||||
//
|
||||
@ -2459,85 +2437,6 @@ static const uint16 gk1GranRoomInitPatch[] = {
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// Using the money on the fortune teller Lorelei is scripted to respond with
|
||||
// a different message depending on whether she's sitting or dancing. This
|
||||
// feature manages to have three bugs which all occur in Sierra's interpreter.
|
||||
//
|
||||
// Bug 1: The script transposes the sitting and dancing responses.
|
||||
// We reverse the test so that the right messages are attempted.
|
||||
//
|
||||
// Bug 2: The script passes the wrong message tuple when Lorelei is sitting
|
||||
// and so a missing message error occurs. We pass the right tuple.
|
||||
//
|
||||
// Bug 3: The audio36 resource for message 420 2 32 0 1 has the wrong tuple and
|
||||
// so no audio plays when using the money on Lorelei while dancing.
|
||||
// This is a CD resource bug which we fix in the audio loader.
|
||||
//
|
||||
// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
|
||||
// Responsible method: lorelei:doVerb(32)
|
||||
// Fixes bug: #10819
|
||||
static const uint16 gk1LoreleiMoneySignature[] = {
|
||||
0x30, SIG_UINT16(0x000d), // bnt 000d [ lorelei is sitting ]
|
||||
SIG_ADDTOOFFSET(+19),
|
||||
SIG_MAGICDWORD,
|
||||
0x7a, // push2 [ noun ]
|
||||
0x8f, 0x01, // lsp param[1] [ verb (32d) ]
|
||||
0x39, 0x03, // pushi 03 [ cond ]
|
||||
SIG_END
|
||||
};
|
||||
|
||||
static const uint16 gk1LoreleiMoneyPatch[] = {
|
||||
0x2e, PATCH_UINT16(0x000d), // bt 000d [ lorelei is dancing ]
|
||||
PATCH_ADDTOOFFSET(+22),
|
||||
0x39, 0x02, // pushi 02 [ correct cond ]
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// Using "Operate" on the fortune teller Lorelei's right chair causes a
|
||||
// missing message error when she's standing in english pc floppy.
|
||||
// We fix the message tuple as Sierra did in later versions.
|
||||
//
|
||||
// Applies to: English PC Floppy 1.0
|
||||
// Responsible method: chair2:doVerb(8)
|
||||
// Fixes bug: #10820
|
||||
static const uint16 gk1OperateLoreleiChairSignature[] = {
|
||||
// we have to reach far ahead of the doVerb method for a unique byte
|
||||
// sequence to base a signature off of. chair2:doVerb has no unique bytes
|
||||
// and is surrounded by doVerb methods which are duplicates of others.
|
||||
SIG_MAGICDWORD,
|
||||
0x72, SIG_UINT16(0x023a), // lofsa sPickupVeil
|
||||
0x36, // push
|
||||
SIG_ADDTOOFFSET(+913),
|
||||
0x39, 0x03, // pushi 03 [ cond ]
|
||||
0x81, 0x5b, // lag global[5b] [ gkMessager ]
|
||||
SIG_END
|
||||
};
|
||||
|
||||
static const uint16 gk1OperateLoreleiChairPatch[] = {
|
||||
PATCH_ADDTOOFFSET(+917),
|
||||
0x39, 0x07, // pushi 07 [ correct cond ]
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// Using the photocopy of the veve on the artist causes a missing message error
|
||||
// after giving the sketch from the lake and then the original veve file.
|
||||
// This is due to using the wrong verb in the message tuple, which we fix.
|
||||
//
|
||||
// Applies to: All PC Floppy and CD versions. TODO: Test Mac, should apply
|
||||
// Responsible method: artist:doVerb(24)
|
||||
// Fixes bug: #10818
|
||||
static const uint16 gk1ArtistVeveCopySignature[] = {
|
||||
SIG_MAGICDWORD,
|
||||
0x39, 0x30, // pushi 30 [ verb: original veve file ]
|
||||
0x39, 0x1f, // pushi 1f [ cond ]
|
||||
SIG_END
|
||||
};
|
||||
|
||||
static const uint16 gk1ArtistVeveCopyPatch[] = {
|
||||
0x39, 0x18, // pushi 18 [ verb: veve photocopy ]
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// After phoning Wolfgang on day 7, Gabriel is placed beyond room 220's obstacle
|
||||
// boundary and can walk through walls and behind the room. This also occurs in
|
||||
// the original. The script inconsistently uses accessible and inaccessible
|
||||
@ -2577,12 +2476,8 @@ static const SciScriptPatcherEntry gk1Signatures[] = {
|
||||
{ true, 260, "fix day 5 snake attack (1/2)", 1, gk1Day5SnakeAttackSignature1, gk1Day5SnakeAttackPatch1 },
|
||||
{ true, 260, "fix day 5 snake attack (2/2)", 1, gk1Day5SnakeAttackSignature2, gk1Day5SnakeAttackPatch2 },
|
||||
{ true, 280, "fix pathfinding in Madame Cazanoux's house", 1, gk1CazanouxPathfindingSignature, gk1CazanouxPathfindingPatch },
|
||||
{ true, 290, "fix magentia missing message", 1, gk1ShowMagentiaItemSignature, gk1ShowMagentiaItemPatch },
|
||||
{ true, 380, "fix Gran's room obstacles and ego flicker", 1, gk1GranRoomInitSignature, gk1GranRoomInitPatch },
|
||||
{ true, 410, "fix day 2 binoculars lockup", 1, gk1Day2BinocularsLockupSignature, gk1Day2BinocularsLockupPatch },
|
||||
{ true, 410, "fix artist veve photocopy missing message", 1, gk1ArtistVeveCopySignature, gk1ArtistVeveCopyPatch },
|
||||
{ true, 420, "fix lorelei chair missing message", 1, gk1OperateLoreleiChairSignature, gk1OperateLoreleiChairPatch },
|
||||
{ true, 420, "fix lorelei money messages", 1, gk1LoreleiMoneySignature, gk1LoreleiMoneyPatch },
|
||||
{ true, 710, "fix day 9 vine swing speech playing", 1, gk1Day9VineSwingSignature, gk1Day9VineSwingPatch },
|
||||
{ true, 710, "fix day 9 mummy animation (floppy)", 1, gk1MummyAnimateFloppySignature, gk1MummyAnimateFloppyPatch },
|
||||
{ true, 710, "fix day 9 mummy animation (cd)", 1, gk1MummyAnimateCDSignature, gk1MummyAnimateCDPatch },
|
||||
@ -5824,33 +5719,6 @@ static const uint16 laurabow2PatchFixAct4Initialization[] = {
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// LB2 Floppy 1.0 attempts to show a non-existent message when using the
|
||||
// carbon paper on the desk lamp in room 550.
|
||||
//
|
||||
// deskLamp:<noname300>(39), which is really doVerb, attempts to show a message
|
||||
// for its own noun (5) instead of the expected noun (45) when the lamp is off.
|
||||
// This results in "<Messager> 550: 5, 39, 6, 1 not found".
|
||||
//
|
||||
// We fix this the way Sierra did in version 1.1 by passing the correct noun.
|
||||
//
|
||||
// Applies to: English floppy 1.000
|
||||
// Responsible method: deskLamp:<noname300>(39), which is really doVerb
|
||||
// Fixes bug: #10706
|
||||
static const uint16 laurabow2SignatureMissingDeskLampMessage[] = {
|
||||
SIG_MAGICDWORD,
|
||||
0x33, 0x1a, // jmp 1a
|
||||
0x38, SIG_UINT16(0x0127), // pushi 127h [ say, hardcoded as we only patch one floppy version ]
|
||||
0x39, 0x03, // pushi 3
|
||||
0x67, 0x1a, // pTos 1a [ deskLamp noun (5) ]
|
||||
SIG_END
|
||||
};
|
||||
|
||||
static const uint16 laurabow2PatchMissingDeskLampMessage[] = {
|
||||
PATCH_ADDTOOFFSET(+7),
|
||||
0x39, 0x2d, // pushi 45d [ correct message noun ]
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// The armor exhibit rooms (440 and 448) have event handlers that fail to handle
|
||||
// all events, preventing messages from being displayed.
|
||||
//
|
||||
@ -6196,7 +6064,6 @@ static const SciScriptPatcherEntry laurabow2Signatures[] = {
|
||||
{ true, 550, "CD/Floppy: fix back rub east entrance lockup", 1, laurabow2SignatureFixBackRubEastEntranceLockup, laurabow2PatchFixBackRubEastEntranceLockup },
|
||||
{ true, 550, "CD/Floppy: fix disappearing desk items", 1, laurabow2SignatureFixDisappearingDeskItems, laurabow2PatchFixDisappearingDeskItems },
|
||||
{ true, 26, "Floppy: fix act 4 initialization", 1, laurabow2SignatureFixAct4Initialization, laurabow2PatchFixAct4Initialization },
|
||||
{ true, 550, "Floppy: missing desk lamp message", 1, laurabow2SignatureMissingDeskLampMessage, laurabow2PatchMissingDeskLampMessage },
|
||||
{ true, 440, "CD/Floppy: handle armor room events", 1, laurabow2SignatureHandleArmorRoomEvents, laurabow2PatchHandleArmorRoomEvents },
|
||||
{ true, 448, "CD/Floppy: handle armor hall room events", 1, laurabow2SignatureHandleArmorRoomEvents, laurabow2PatchHandleArmorRoomEvents },
|
||||
{ true, 600, "Floppy: fix bugs with meat", 1, laurabow2FloppySignatureFixBugsWithMeat, laurabow2FloppyPatchFixBugsWithMeat },
|
||||
@ -11873,27 +11740,6 @@ static const uint16 sq4PatchEgaIntroDelay[] = {
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// Talking in room 520 results in a missing message due to passing the wrong
|
||||
// modNum to the narrator.
|
||||
//
|
||||
// Applies to: English PC CD
|
||||
// Responsible method: rm520:doVerb(2)
|
||||
// Fixes bug #10915
|
||||
static const uint16 sq4CdSignatureMazeTalkMessage[] = {
|
||||
0x38, SIG_SELECTOR16(modNum), // pushi modNum
|
||||
SIG_MAGICDWORD,
|
||||
0x78, // push1
|
||||
0x38, SIG_UINT16(0x01fe), // pushi 01fe [ incorrect modNum: 510 ]
|
||||
0x38, SIG_SELECTOR16(say), // pushi say
|
||||
SIG_END,
|
||||
};
|
||||
|
||||
static const uint16 sq4CdPatchMazeTalkMessage[] = {
|
||||
PATCH_ADDTOOFFSET(+4),
|
||||
0x38, PATCH_UINT16(0x01f4), // pushi 01f4 [ correct modNum: 500 ]
|
||||
PATCH_END
|
||||
};
|
||||
|
||||
// Talking to the red shopper in the mall has a 5% chance of a funny message but
|
||||
// this script is broken in the CD version. After the first time the wrong
|
||||
// message tuple is attempted by the narrator as its modNum value is cleared.
|
||||
@ -12613,7 +12459,6 @@ static const SciScriptPatcherEntry sq4Signatures[] = {
|
||||
{ true, 406, "CD/Floppy: zero gravity blast fix", 1, sq4SignatureZeroGravityBlast, sq4PatchZeroGravityBlast },
|
||||
{ true, 410, "CD/Floppy: zero gravity blast fix", 1, sq4SignatureZeroGravityBlast, sq4PatchZeroGravityBlast },
|
||||
{ true, 411, "CD/Floppy: zero gravity blast fix", 1, sq4SignatureZeroGravityBlast, sq4PatchZeroGravityBlast },
|
||||
{ true, 520, "CD: maze talk message fix", 1, sq4CdSignatureMazeTalkMessage, sq4CdPatchMazeTalkMessage },
|
||||
{ true, 545, "CD: vohaul pocketpal text+speech fix", 1, sq4CdSignatureVohaulPocketPalTextSpeech, sq4CdPatchVohaulPocketPalTextSpeech },
|
||||
{ true, 610, "CD: biker bar door fix", 1, sq4CdSignatureBikerBarDoor, sq4CdPatchBikerBarDoor },
|
||||
{ true, 610, "CD: biker hands-on fix", 3, sq4CdSignatureBikerHandsOn, sq4CdPatchBikerHandsOn },
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "sci/engine/workarounds.h"
|
||||
|
||||
#define SCI_WORKAROUNDENTRY_TERMINATOR { (SciGameId)0, -1, -1, 0, NULL, NULL, NULL, 0, 0, { WORKAROUND_NONE, 0 } }
|
||||
#define SCI_MESSAGEWORKAROUNDENTRY_TERMINATOR { (SciGameId)0, (SciMedia)0, (kLanguage)0, -1, -1, 0, 0, 0, 0, { MSG_WORKAROUND_NONE, -1, 0, 0, 0, 0, 0, 0, 0, NULL } }
|
||||
|
||||
namespace Sci {
|
||||
|
||||
@ -1135,4 +1136,203 @@ SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroun
|
||||
return noneFound;
|
||||
}
|
||||
|
||||
// Workarounds for known broken messages
|
||||
//
|
||||
// The most common message bug is a script passing the wrong tuple or a message
|
||||
// having the wrong tuple. This results in a "missing message" message. These
|
||||
// requests just need to be remapped to the right message. In some cases the
|
||||
// message text is incorrect, or missing, in which case it can be extracted
|
||||
// from another record or faked with a hard-coded response.
|
||||
//
|
||||
// Workarounds can be optionally scoped to media (floppy vs cd), language, and
|
||||
// room number. If a message is remapped, this will also remap any audio36 and
|
||||
// sync36 resources with the same tuple, unless those resources have their own
|
||||
// remapping workarounds due to their tuples being out of sync with their
|
||||
// already broken messages, which we've seen twice.
|
||||
//
|
||||
// The one kind of broken message that we don't handle yet is when the audio is
|
||||
// completely missing from the game. QFG4 has most of those. In speech-only
|
||||
// mode this means no audio or text and in dual mode the text disappears
|
||||
// quickly as most games use audio length for the message delay. That logic is
|
||||
// in each game's Messager/Narrator/Talker scripts.
|
||||
static const SciMessageWorkaroundEntry messageWorkarounds[] = {
|
||||
// game media language room mod n v c s workaround-type mod n v c s tlk idx len text
|
||||
// FPFP CD has several message sequences where audio and text were left out of sync - bug #10964
|
||||
// Some of the texts just say "Dummy Msg" and the real values are concatenated in the first record.
|
||||
// Lever Brothers' intro
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 24, 0, 0, 1, { MSG_WORKAROUND_EXTRACT, 220, 24, 0, 0, 1, 99, 0, 25, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 24, 0, 0, 2, { MSG_WORKAROUND_EXTRACT, 220, 24, 0, 0, 1, 99, 26, 20, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 24, 0, 0, 3, { MSG_WORKAROUND_EXTRACT, 220, 24, 0, 0, 1, 99, 47, 58, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 24, 0, 0, 4, { MSG_WORKAROUND_EXTRACT, 220, 24, 0, 0, 1, 99, 106, 34, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 24, 0, 0, 5, { MSG_WORKAROUND_EXTRACT, 220, 24, 0, 0, 1, 99, 141, 27, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 24, 0, 0, 6, { MSG_WORKAROUND_EXTRACT, 220, 24, 0, 0, 1, 99, 169, 29, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 24, 0, 0, 7, { MSG_WORKAROUND_EXTRACT, 220, 24, 0, 0, 1, 99, 199, 52, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 24, 0, 0, 8, { MSG_WORKAROUND_EXTRACT, 220, 24, 0, 0, 1, 99, 252, 37, NULL } },
|
||||
// Kenny's intro
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 30, 0, 0, 3, { MSG_WORKAROUND_EXTRACT, 220, 30, 0, 0, 3, 99, 0, 14, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 30, 0, 0, 4, { MSG_WORKAROUND_EXTRACT, 220, 30, 0, 0, 3, 99, 15, 245, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 220, 30, 0, 0, 5, { MSG_WORKAROUND_EXTRACT, 220, 30, 0, 0, 4, 99, 0, 0, NULL } },
|
||||
// Helen swatting flies
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 660, 35, 0, 0, 1, { MSG_WORKAROUND_EXTRACT, 660, 35, 0, 0, 1, 53, 0, 42, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 660, 35, 0, 0, 2, { MSG_WORKAROUND_EXTRACT, 660, 35, 0, 0, 1, 53, 43, 93, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 660, 35, 0, 0, 3, { MSG_WORKAROUND_EXTRACT, 660, 35, 0, 0, 1, 53, 137, 72, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 660, 35, 0, 0, 4, { MSG_WORKAROUND_EXTRACT, 660, 35, 0, 0, 2, 53, 0, 0, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 660, 35, 0, 0, 5, { MSG_WORKAROUND_EXTRACT, 660, 35, 0, 0, 1, 53, 210, 57, NULL } },
|
||||
{ GID_FREDDYPHARKAS, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 660, 35, 0, 0, 6, { MSG_WORKAROUND_EXTRACT, 660, 35, 0, 0, 3, 12, 0, 0, NULL } },
|
||||
// Missing message when clicking flashlight and other items on Magentia in room 290, floppy 1.0 - bug #10782
|
||||
{ GID_GK1, SCI_MEDIA_FLOPPY, K_LANG_NONE, -1, 290, 8, 0, 35, 1, { MSG_WORKAROUND_REMAP, 290, 8, 0, 0, 1, 0, 0, 0, NULL } },
|
||||
// Missing message when clicking photocopy of the veve on the artist after giving sketch and original veve in room 410 - bug #10818
|
||||
{ GID_GK1, SCI_MEDIA_ALL, K_LANG_NONE, -1, 410, 3, 48, 31, 1, { MSG_WORKAROUND_REMAP, 410, 3, 24, 31, 1, 0, 0, 0, NULL } },
|
||||
// Missing message when clicking operate on Loreli's right chair in room 420, floppy 1.0 - bug #10820
|
||||
{ GID_GK1, SCI_MEDIA_FLOPPY, K_LANG_NONE, -1, 420, 4, 8, 3, 1, { MSG_WORKAROUND_REMAP, 420, 4, 8, 7, 1, 0, 0, 0, NULL } },
|
||||
// Clicking money on Loreli when sitting or dancing in room 420 - bug #10819
|
||||
// The script transposes sitting vs dancing responses, passes an invalid cond for one of them, and the
|
||||
// audio36 for the the other has the wrong tuple, which we fix in the audio36 workarounds.
|
||||
{ GID_GK1, SCI_MEDIA_ALL, K_LANG_NONE, -1, 420, 2, 32, 3, 1, { MSG_WORKAROUND_REMAP, 420, 2, 32, 0, 1, 0, 0, 0, NULL } },
|
||||
{ GID_GK1, SCI_MEDIA_ALL, K_LANG_NONE, -1, 420, 2, 32, 0, 1, { MSG_WORKAROUND_REMAP, 420, 2, 32, 2, 1, 0, 0, 0, NULL } },
|
||||
// Asking Yvette about Tut in act 2 party in floppy version - bug #10723
|
||||
// The last two sequences in this five part message reveal a murder that hasn't occurred yet.
|
||||
// We skip these as to not spoil the plot, but only in the act 2 rooms, as the message is used
|
||||
// in later acts where all five parts are appropriate. Sierra fixed this in the CD version by
|
||||
// creating a new three-sequence message for act 2 to accomplish the same thing.
|
||||
{ GID_LAURABOW2, SCI_MEDIA_FLOPPY, K_LANG_NONE, 350, 1885, 1, 6, 16, 4, { MSG_WORKAROUND_REMAP, 1885, 1, 6, 16, 6, 0, 0, 0, NULL } },
|
||||
{ GID_LAURABOW2, SCI_MEDIA_FLOPPY, K_LANG_NONE, 360, 1885, 1, 6, 16, 4, { MSG_WORKAROUND_REMAP, 1885, 1, 6, 16, 6, 0, 0, 0, NULL } },
|
||||
{ GID_LAURABOW2, SCI_MEDIA_FLOPPY, K_LANG_NONE, 370, 1885, 1, 6, 16, 4, { MSG_WORKAROUND_REMAP, 1885, 1, 6, 16, 6, 0, 0, 0, NULL } },
|
||||
// Missing message when clicking carbon paper on desk lamp in room 550, floppy 1.0 - bug #10706
|
||||
{ GID_LAURABOW2, SCI_MEDIA_FLOPPY, K_LANG_NONE, -1, 550, 5, 39, 6, 1, { MSG_WORKAROUND_REMAP, 550, 45, 39, 6, 1, 0, 0, 0, NULL } },
|
||||
// Using the hand icon on Keith in the Blue Room (missing message) - bug #6253
|
||||
{ GID_PQ1, SCI_MEDIA_ALL, K_LANG_NONE, -1, 38, 10, 4, 8, 1, { MSG_WORKAROUND_REMAP, 38, 10, 4, 9, 1, 0, 0, 0, NULL } },
|
||||
// Using the eye icon on Keith in the Blue Room (no message and wrong talker) - bug #6253
|
||||
{ GID_PQ1, SCI_MEDIA_ALL, K_LANG_NONE, -1, 38, 10, 1, 0, 1, { MSG_WORKAROUND_EXTRACT, 38, 10, 1, 13, 1, 99, 0, 0, NULL } },
|
||||
// Talking to Kaspar the shopkeeper - bug #6250
|
||||
{ GID_QFG1VGA, SCI_MEDIA_ALL, K_LANG_NONE, -1, 322, 14, 1, 19, 1, { MSG_WORKAROUND_REMAP, 322, 14, 2, 19, 1, 0, 0, 0, NULL } },
|
||||
// Talking with the Leshy and telling him about "bush in goo" - bug #10137
|
||||
{ GID_QFG4, SCI_MEDIA_ALL, K_LANG_NONE, -1, 579, 0, 0, 0, 1, { MSG_WORKAROUND_REMAP, 579, 0, 1, 0, 1, 0, 0, 0, NULL } },
|
||||
// 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". This message is text-only.
|
||||
// Note: The German string contains accented characters.
|
||||
// 0x84 "a with diaeresis"
|
||||
// 0x94 "o with diaeresis"
|
||||
{ GID_QFG4, SCI_MEDIA_ALL, K_LANG_ENGLISH, -1, 16, 49, 1, 0, 2, { MSG_WORKAROUND_FAKE, 16, 49, 1, 0, 2, 99, 0, 0, "Carefully wrapped in a shopping bag is the grotesque sculpture of a horrible, monstrous insect." } },
|
||||
{ GID_QFG4, SCI_MEDIA_ALL, K_LANG_GERMAN, -1, 16, 49, 1, 0, 2, { MSG_WORKAROUND_FAKE, 16, 49, 1, 0, 2, 99, 0, 0, "Die groteske Skulptur eines schrecklichen, monstr\x94sen insekts ist sorgf\x84ltig in die Einkaufstasche eingewickelt." } },
|
||||
// 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 remapped to seq:2 in an audio workaround below.
|
||||
{ GID_QFG4, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 520, 2, 59, 0, 1, { MSG_WORKAROUND_FAKE, 520, 2, 59, 0, 1, 28, 0, 0, "Thank you for the beautiful flowers. No one has been so nice to me since I can remember." } },
|
||||
{ GID_QFG4, SCI_MEDIA_CD, K_LANG_ENGLISH, -1, 520, 2, 59, 0, 2, { MSG_WORKAROUND_EXTRACT, 520, 2, 59, 0, 1, 28, 0, 0, NULL } },
|
||||
// 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 #6067.
|
||||
// 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.
|
||||
{ GID_SQ4, SCI_MEDIA_CD, K_LANG_NONE, -1, 16, 7, 0, 3, 1, { MSG_WORKAROUND_FAKE, 16, 7, 0, 3, 1, 7, 0, 0, "" } },
|
||||
// Missing message when clicking talk in room 520 - bug #10915
|
||||
{ GID_SQ4, SCI_MEDIA_CD, K_LANG_NONE, -1, 510, 99, 0, 3, 1, { MSG_WORKAROUND_REMAP, 500, 99, 0, 3, 1, 0, 0, 0, NULL } },
|
||||
SCI_MESSAGEWORKAROUNDENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
// Audio36 workarounds are for when an audio36 resource's tuple is out of sync
|
||||
// with its corresponding message, in which case it can be remapped. Any sync36
|
||||
// resource with the same tuple will also be remapped. Remapping is the only
|
||||
// workaround type available to this table. If a tuple is remapped both here
|
||||
// and in message workarounds, this remapping is used.
|
||||
static const SciMessageWorkaroundEntry audio36Workarounds[] = {
|
||||
// game media language room mod n v c s workaround-type mod n v c s tlk idx len text
|
||||
// Clicking money on Lorelei when dancing - bug #10819 (see message workarounds above)
|
||||
{ GID_GK1, SCI_MEDIA_CD, K_LANG_NONE, -1, 420, 2, 32, 0, 1, { MSG_WORKAROUND_REMAP, 420, 2, 32, 3, 1, 0, 0, 0, NULL } },
|
||||
// Clicking Look on floor grate in room 510 - bug #10848
|
||||
{ GID_QFG4, SCI_MEDIA_CD, K_LANG_NONE, -1, 510, 23, 1, 0, 1, { MSG_WORKAROUND_REMAP, 510, 199, 1, 0, 1, 0, 0, 0, NULL } },
|
||||
// Clicking flowers on Rusalka - bug #10849 (see message workarounds above)
|
||||
{ GID_QFG4, SCI_MEDIA_CD, K_LANG_NONE, -1, 520, 2, 59, 0, 2, { MSG_WORKAROUND_REMAP, 520, 2, 59, 0, 3, 0, 0, 0, NULL } },
|
||||
SCI_MESSAGEWORKAROUNDENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
// Sync36 workarounds are for when a sync36 resource's tuple is out of sync with
|
||||
// its corresponding message, in which case it can be remapped. This hasn't
|
||||
// been encountered yet, but remapping solves a similar LB2 sync bug.
|
||||
static const SciMessageWorkaroundEntry sync36Workarounds[] = {
|
||||
// game media language room mod n v c s workaround-type mod n v c s tlk idx len text
|
||||
// Asking yvette about tut in act 2 is missing a sync resource but a duplicate message has a sync resource - bug #9956
|
||||
{ GID_LAURABOW2, SCI_MEDIA_CD, K_LANG_NONE, -1, 1885, 1, 6, 30, 2, { MSG_WORKAROUND_REMAP, 1885, 1, 6, 10, 2, 0, 0, 0, NULL } },
|
||||
SCI_MESSAGEWORKAROUNDENTRY_TERMINATOR
|
||||
};
|
||||
|
||||
static SciMessageWorkaroundSolution findMessageWorkaround(int module, byte noun, byte verb, byte cond, byte seq, const SciMessageWorkaroundEntry *workaroundList) {
|
||||
const SciMessageWorkaroundEntry *workaround = workaroundList;
|
||||
while (workaround->solution.type != MSG_WORKAROUND_NONE) {
|
||||
if (workaround->gameId == g_sci->getGameId() &&
|
||||
(workaround->media == SCI_MEDIA_ALL ||
|
||||
(workaround->media == SCI_MEDIA_FLOPPY && !g_sci->isCD()) ||
|
||||
(workaround->media == SCI_MEDIA_CD && g_sci->isCD())) &&
|
||||
(workaround->language == K_LANG_NONE ||
|
||||
workaround->language == g_sci->getSciLanguage()) &&
|
||||
(workaround->roomNumber == -1 ||
|
||||
workaround->roomNumber == g_sci->getEngineState()->currentRoomNumber()) &&
|
||||
workaround->module == module &&
|
||||
workaround->noun == noun &&
|
||||
workaround->verb == verb &&
|
||||
workaround->cond == cond &&
|
||||
workaround->seq == seq) {
|
||||
break;
|
||||
}
|
||||
workaround++;
|
||||
}
|
||||
return workaround->solution;
|
||||
}
|
||||
|
||||
SciMessageWorkaroundSolution findMessageWorkaround(int module, byte noun, byte verb, byte cond, byte seq) {
|
||||
return findMessageWorkaround(module, noun, verb, cond, seq, messageWorkarounds);
|
||||
}
|
||||
|
||||
ResourceId remapAudio36ResourceId(const ResourceId &resourceId) {
|
||||
int module = resourceId.getNumber();
|
||||
byte noun = resourceId.getTuple() >> 24;
|
||||
byte verb = (resourceId.getTuple() >> 16) & 0xff;
|
||||
byte cond = (resourceId.getTuple() >> 8) & 0xff;
|
||||
byte seq = resourceId.getTuple() & 0xff;
|
||||
|
||||
SciMessageWorkaroundSolution workaround = findMessageWorkaround(module, noun, verb, cond, seq, audio36Workarounds);
|
||||
if (workaround.type != MSG_WORKAROUND_REMAP) {
|
||||
workaround = findMessageWorkaround(module, noun, verb, cond, seq, messageWorkarounds);
|
||||
}
|
||||
|
||||
if (workaround.type == MSG_WORKAROUND_REMAP) {
|
||||
return ResourceId(resourceId.getType(), workaround.module, workaround.noun, workaround.verb, workaround.cond, workaround.seq);
|
||||
}
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
ResourceId remapSync36ResourceId(const ResourceId &resourceId) {
|
||||
int module = resourceId.getNumber();
|
||||
byte noun = resourceId.getTuple() >> 24;
|
||||
byte verb = (resourceId.getTuple() >> 16) & 0xff;
|
||||
byte cond = (resourceId.getTuple() >> 8) & 0xff;
|
||||
byte seq = resourceId.getTuple() & 0xff;
|
||||
|
||||
SciMessageWorkaroundSolution workaround = findMessageWorkaround(module, noun, verb, cond, seq, sync36Workarounds);
|
||||
if (workaround.type != MSG_WORKAROUND_REMAP) {
|
||||
workaround = findMessageWorkaround(module, noun, verb, cond, seq, audio36Workarounds);
|
||||
}
|
||||
if (workaround.type != MSG_WORKAROUND_REMAP) {
|
||||
workaround = findMessageWorkaround(module, noun, verb, cond, seq, messageWorkarounds);
|
||||
}
|
||||
|
||||
if (workaround.type == MSG_WORKAROUND_REMAP) {
|
||||
return ResourceId(resourceId.getType(), workaround.module, workaround.noun, workaround.verb, workaround.cond, workaround.seq);
|
||||
}
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
} // End of namespace Sci
|
||||
|
@ -113,6 +113,49 @@ extern const SciWorkaroundEntry kScrollWindowAdd_workarounds[];
|
||||
|
||||
extern SciWorkaroundSolution trackOriginAndFindWorkaround(int index, const SciWorkaroundEntry *workaroundList, SciCallOrigin *trackOrigin);
|
||||
|
||||
enum SciMessageWorkaroundType {
|
||||
MSG_WORKAROUND_NONE, // only used by terminator or when no workaround was found
|
||||
MSG_WORKAROUND_REMAP, // use a different tuple instead
|
||||
MSG_WORKAROUND_FAKE, // use a hard-coded response
|
||||
MSG_WORKAROUND_EXTRACT // use text from a different record, optionally a substring
|
||||
};
|
||||
|
||||
enum SciMedia {
|
||||
SCI_MEDIA_ALL,
|
||||
SCI_MEDIA_FLOPPY,
|
||||
SCI_MEDIA_CD
|
||||
};
|
||||
|
||||
struct SciMessageWorkaroundSolution {
|
||||
SciMessageWorkaroundType type;
|
||||
int module;
|
||||
byte noun;
|
||||
byte verb;
|
||||
byte cond;
|
||||
byte seq;
|
||||
byte talker;
|
||||
uint32 substringIndex;
|
||||
uint32 substringLength;
|
||||
const char *text;
|
||||
};
|
||||
|
||||
struct SciMessageWorkaroundEntry {
|
||||
SciGameId gameId;
|
||||
SciMedia media;
|
||||
kLanguage language;
|
||||
int roomNumber;
|
||||
int module;
|
||||
byte noun;
|
||||
byte verb;
|
||||
byte cond;
|
||||
byte seq;
|
||||
SciMessageWorkaroundSolution solution;
|
||||
};
|
||||
|
||||
extern SciMessageWorkaroundSolution findMessageWorkaround(int module, byte noun, byte verb, byte cond, byte seq);
|
||||
extern ResourceId remapAudio36ResourceId(const ResourceId &resourceId);
|
||||
extern ResourceId remapSync36ResourceId(const ResourceId &resourceId);
|
||||
|
||||
} // End of namespace Sci
|
||||
|
||||
#endif // SCI_ENGINE_WORKAROUNDS_H
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "common/memstream.h"
|
||||
#endif
|
||||
|
||||
#include "sci/engine/workarounds.h"
|
||||
#include "sci/parser/vocabulary.h"
|
||||
#include "sci/resource.h"
|
||||
#include "sci/resource_intern.h"
|
||||
@ -1134,6 +1135,12 @@ Common::List<ResourceId> ResourceManager::listResources(ResourceType type, int m
|
||||
}
|
||||
|
||||
Resource *ResourceManager::findResource(ResourceId id, bool lock) {
|
||||
// remap known incorrect audio36 and sync36 resource ids
|
||||
if (id.getType() == kResourceTypeAudio36) {
|
||||
id = remapAudio36ResourceId(id);
|
||||
} else if (id.getType() == kResourceTypeSync36) {
|
||||
id = remapSync36ResourceId(id);
|
||||
}
|
||||
Resource *retval = testResource(id);
|
||||
|
||||
if (!retval)
|
||||
|
@ -455,28 +455,6 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
|
||||
break;
|
||||
}
|
||||
|
||||
// GK1CD has a message whose audio36 resource has the wrong tuple and never plays.
|
||||
// The message tuple is 420 2 32 0 1 but the audio36 tuple is 420 2 32 3 1. bug #10819
|
||||
if (g_sci->getGameId() == GID_GK1 && g_sci->isCD() &&
|
||||
map->_mapNumber == 420 && n == 0x02200301) {
|
||||
n = 0x02200001;
|
||||
}
|
||||
|
||||
// QFG4CD has a message whose audio36 resource has the wrong tuple and never plays.
|
||||
// The message tuple is 510 23 1 0 1 but the audio36 tuple is 510 199 1 0 1. bug #10848
|
||||
if (g_sci->getGameId() == GID_QFG4 && g_sci->isCD() &&
|
||||
map->_mapNumber == 510 && n == 0xc7010001) {
|
||||
n = 0x17010001;
|
||||
}
|
||||
|
||||
// QFG4CD has an orphaned audio36 resource that additionally has the wrong tuple.
|
||||
// The audio36 tuple is 520 2 59 0 3. The message would be 520 2 59 0 2. bug #10849
|
||||
// We restore the missing message in message.cpp.
|
||||
if (g_sci->getGameId() == GID_QFG4 && g_sci->isCD() &&
|
||||
map->_mapNumber == 520 && n == 0x023b0003) {
|
||||
n = 0x023b0002;
|
||||
}
|
||||
|
||||
if (isEarly) {
|
||||
offset = ptr.getUint32LE();
|
||||
ptr += 4;
|
||||
@ -492,14 +470,6 @@ int ResourceManager::readAudioMapSCI11(IntMapResourceSource *map) {
|
||||
// FIXME: The sync36 resource seems to be two bytes too big in KQ6CD
|
||||
// (bytes taken from the RAVE resource right after it)
|
||||
if (syncSize > 0) {
|
||||
// TODO: Add a mechanism to handle cases with missing resources like the ones below
|
||||
//
|
||||
// LB2CD is missing the sync resource for message 1885 1 6 30 2 but it's a duplicate
|
||||
// of 1885 1 6 16 2 which does have a sync resource so use that for both. bug #9956
|
||||
if (g_sci->getGameId() == GID_LAURABOW2 && map->_mapNumber == 1885 && n == 0x01061002) {
|
||||
addResource(ResourceId(kResourceTypeSync36, map->_mapNumber, 0x01061e02), src, offset, syncSize, map->getLocationName());
|
||||
}
|
||||
|
||||
addResource(ResourceId(kResourceTypeSync36, map->_mapNumber, n & 0xffffff3f), src, offset, syncSize, map->getLocationName());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user