aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsluicebox2019-11-20 13:57:41 -0800
committersluicebox2019-11-20 14:12:54 -0800
commit11065630c0f7913d6023c92035641ffde1cb6a5f (patch)
treeb54cf175c014c2fd943cc1ba3e73f0958e1353b3
parent7423320e9d57554c5f0e156eb8e6e3b79fb087ad (diff)
downloadscummvm-rg350-11065630c0f7913d6023c92035641ffde1cb6a5f.tar.gz
scummvm-rg350-11065630c0f7913d6023c92035641ffde1cb6a5f.tar.bz2
scummvm-rg350-11065630c0f7913d6023c92035641ffde1cb6a5f.zip
SCI: Fix CAMELOT menu items when restoring
-rw-r--r--engines/sci/engine/savegame.cpp41
-rw-r--r--engines/sci/engine/selector.cpp1
-rw-r--r--engines/sci/engine/selector.h1
3 files changed, 43 insertions, 0 deletions
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 6d0abf75af..3423a0126a 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -1194,6 +1194,47 @@ extern void showScummVMDialog(const Common::String &message);
void gamestate_afterRestoreFixUp(EngineState *s, int savegameId) {
switch (g_sci->getGameId()) {
+ case GID_CAMELOT: {
+ // WORKAROUND: CAMELOT depends on its dynamic menu state persisting. The menu items'
+ // enabled states determines when the player can draw or sheathe their sword and
+ // open a purse. If these aren't updated then the player may be unable to perform
+ // necessary actions, or may be able to perform unexpected ones that break the game.
+ // Since we don't persist menu state (yet) we need to recreate it from game state.
+ //
+ // - Action \ Open Purse: Enabled while one of the purses is in inventory.
+ // - Action \ Draw Sword: Enabled while flag 3 is set, unless disabled by room scripts.
+ // * The text "Draw Sword" toggles to "Sheathe Sword" depending on global 124,
+ // but this is only cosmetic. Exported proc #1 in script 997 refreshes this
+ // when the sword status or room changes.
+ //
+ // After evaluating all the scripts that disable the sword, we enforce the few
+ // that prevent breaking the game: room 50 under the aqueduct and sitting with
+ // the scholar while in room 82 (ego view 84).
+ //
+ // FIXME: Save and restore full menu state as SSCI did and don't apply these
+ // workarounds when restoring saves that contain menu state.
+
+ // Action \ Open Purse
+ reg_t enablePurse = NULL_REG;
+ Common::Array<reg_t> purses = s->_segMan->findObjectsByName("purse");
+ reg_t ego = s->variables[VAR_GLOBAL][0];
+ for (uint i = 0; i < purses.size(); ++i) {
+ reg_t purseOwner = readSelector(s->_segMan, purses[i], SELECTOR(owner));
+ if (purseOwner == ego) {
+ enablePurse = TRUE_REG;
+ break;
+ }
+ }
+ g_sci->_gfxMenu->kernelSetAttribute(1281 >> 8, 1281 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, enablePurse);
+
+ // Action \ Draw Sword
+ bool hasSword = (s->variables[VAR_GLOBAL][250].getOffset() & 0x1000); // flag 3
+ bool underAqueduct = (s->variables[VAR_GLOBAL][11].getOffset() == 50);
+ bool sittingWithScholar = (readSelectorValue(s->_segMan, ego, SELECTOR(view)) == 84);
+ reg_t enableSword = (hasSword && !underAqueduct && !sittingWithScholar) ? TRUE_REG : NULL_REG;
+ g_sci->_gfxMenu->kernelSetAttribute(1283 >> 8, 1283 & 0xFF, SCI_MENU_ATTRIBUTE_ENABLED, enableSword);
+ break;
+ }
case GID_MOTHERGOOSE:
// WORKAROUND: Mother Goose SCI0
// Script 200 / rm200::newRoom will set global C5h directly right after creating a child to the
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index 6fbccb81a3..6196495954 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -169,6 +169,7 @@ void Kernel::mapSelectors() {
FIND_SELECTOR(setStep);
FIND_SELECTOR(setMotion);
FIND_SELECTOR(cycleSpeed);
+ FIND_SELECTOR(owner);
#ifdef ENABLE_SCI32
FIND_SELECTOR(data);
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index fa2df8ced6..68b36b3bc2 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -135,6 +135,7 @@ struct SelectorCache {
Selector setStep;
Selector setMotion;
Selector cycleSpeed;
+ Selector owner;
#ifdef ENABLE_SCI32
Selector data; // Used by Array()/String()