[Scummvm-git-logs] scummvm master -> 8745a64dfc4fa8625ebce372cde5ff2e9b9c21ae
fracturehill
noreply at scummvm.org
Wed Feb 7 22:32:49 UTC 2024
This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
a45a521ff5 NANCY: Disambiguate detection entries
7682560cc7 NANCY: Add detection for nancy10 & 11
f5311cfe87 NANCY: Expand TableData struct
af2ff22907 NANCY: Split data-related records to separate file
1369449374 NANCY: Implement SetValue
a8dcc387a4 NANCY: Implement SetValueCombo
8745a64dfc NANCY: Implement ValueTest
Commit: a45a521ff5f839e976a2dbe08b3e58146a66a8ef
https://github.com/scummvm/scummvm/commit/a45a521ff5f839e976a2dbe08b3e58146a66a8ef
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-07T23:15:23+01:00
Commit Message:
NANCY: Disambiguate detection entries
Added more rigid entries for some game variants where
the ciftree.dat file is not present inside the cabfiles. Now,
those entries require a second file that can only be found
when the cabs are extracted.
Changed paths:
engines/nancy/detection.cpp
diff --git a/engines/nancy/detection.cpp b/engines/nancy/detection.cpp
index 91c37833ea4..6b52f1ebd94 100644
--- a/engines/nancy/detection.cpp
+++ b/engines/nancy/detection.cpp
@@ -28,6 +28,8 @@ const char *const directoryGlobs[] = {
"iff",
"cifTree",
"datafiles",
+ "cdvideo", // used to test for unpacked variants
+ "hdvideo", // used to test for unpacked variants
nullptr
};
@@ -431,7 +433,11 @@ static const Nancy::NancyGameDescription gameDescriptions[] = {
{ // MD5 by Strangerke
{
"nancy6", nullptr,
- AD_ENTRY1s("ciftree.dat", "a97b848651fdcf38f5cad7092d98e4a1", 28888006),
+ {
+ { "ciftree.dat", 0, "a97b848651fdcf38f5cad7092d98e4a1", 28888006 },
+ { "amfid.avf", 0, "5f39a351a9fdd13fc24efbcb841cb059", 207695 },
+ AD_LISTEND
+ },
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_UNSTABLE | ADGF_DROPPLATFORM,
@@ -616,7 +622,11 @@ static const Nancy::NancyGameDescription gameDescriptions[] = {
{ // MD5 by fracturehill
{
"nancy9", nullptr,
- AD_ENTRY1s("ciftree.dat", "3a756e09631f4a2c8f48bf316e77b5d5", 26610718),
+ {
+ { "ciftree.dat", 0, "3a756e09631f4a2c8f48bf316e77b5d5", 26610718 },
+ { "andyfid.avf", 0, "4e11e5237e6776e342df6262fc930142", 1171821 },
+ AD_LISTEND
+ },
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_UNSTABLE | ADGF_DROPPLATFORM,
Commit: 7682560cc76f35d3b1f8e39b6db8d7489272c690
https://github.com/scummvm/scummvm/commit/7682560cc76f35d3b1f8e39b6db8d7489272c690
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-07T23:15:23+01:00
Commit Message:
NANCY: Add detection for nancy10 & 11
The games absolutely will not run yet, but they're useful
to have around so their data can be inspected.
Changed paths:
engines/nancy/detection.cpp
engines/nancy/detection.h
engines/nancy/nancy.cpp
diff --git a/engines/nancy/detection.cpp b/engines/nancy/detection.cpp
index 6b52f1ebd94..7dc711aff66 100644
--- a/engines/nancy/detection.cpp
+++ b/engines/nancy/detection.cpp
@@ -45,15 +45,17 @@ static const DebugChannelDef debugFlagList[] = {
static const PlainGameDescriptor nancyGames[] = {
// Games
{ "vampirediaries", "The Vampire Diaries" },
- { "nancy1", "Nancy Drew: Secrets Can Kill" },
- { "nancy2", "Nancy Drew: Stay Tuned for Danger" },
- { "nancy3", "Nancy Drew: Message in a Haunted Mansion" },
- { "nancy4", "Nancy Drew: Treasure in the Royal Tower" },
- { "nancy5", "Nancy Drew: The Final Scene" },
- { "nancy6", "Nancy Drew: Secret of the Scarlet Hand" },
- { "nancy7", "Nancy Drew: Ghost Dogs of Moon Lake" },
- { "nancy8", "Nancy Drew: The Haunted Carousel" },
- { "nancy9", "Nancy Drew: Danger on Deception Island" },
+ { "nancy1", "Nancy Drew: Secrets Can Kill" },
+ { "nancy2", "Nancy Drew: Stay Tuned for Danger" },
+ { "nancy3", "Nancy Drew: Message in a Haunted Mansion" },
+ { "nancy4", "Nancy Drew: Treasure in the Royal Tower" },
+ { "nancy5", "Nancy Drew: The Final Scene" },
+ { "nancy6", "Nancy Drew: Secret of the Scarlet Hand" },
+ { "nancy7", "Nancy Drew: Ghost Dogs of Moon Lake" },
+ { "nancy8", "Nancy Drew: The Haunted Carousel" },
+ { "nancy9", "Nancy Drew: Danger on Deception Island" },
+ { "nancy10", "Nancy Drew: The Secret of Shadow Ranch" },
+ { "nancy11", "Nancy Drew: Curse of Blackmoor Manor" },
{ nullptr, nullptr }
};
@@ -651,6 +653,70 @@ static const Nancy::NancyGameDescription gameDescriptions[] = {
},
Nancy::kGameTypeNancy9
},
+ {
+ {
+ "nancy10", nullptr,
+ {
+ { "ciftree.dat", 0, "270133c5e89b8538caef08041598d049", 29413095 },
+ { "den_cal_back16.avf", 0, "ee6c779d1bc61a6483f9166aa20e4545", 324644 },
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE | ADGF_DROPPLATFORM,
+ GUIO1(GAMEOPTION_AUTO_MOVE)
+ },
+ Nancy::kGameTypeNancy10
+ },
+ {
+ {
+ "nancy10", nullptr,
+ {
+ { "data1.hdr", 0, "fb73756ee951627e97f859ff27182e6f", 394467 },
+ { "data1.cab", 0, "d72b503642cb2533bcc6ce2b0ca463ac", 7510894 },
+ { "data2.cab", 0, "63b9d6400a241fc0777ec8ad3e3c4076", 150997862 },
+ { "ciftree.dat", 0, "270133c5e89b8538caef08041598d049", 29413095 }, // ciftree is outside of cabfiles
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE | ADGF_DROPPLATFORM | Nancy::GF_COMPRESSED,
+ GUIO1(GAMEOPTION_AUTO_MOVE)
+ },
+ Nancy::kGameTypeNancy10
+ },
+ {
+ {
+ "nancy11", nullptr,
+ {
+ { "ciftree.dat", 0, "3c406d4f391b6536982c6081f2dd1f4e", 55960641 },
+ { "gre_oil_cinematic.bik", 0, "28a2b6f939f1c7795e47a99337d7343a", 21514180 },
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE | ADGF_DROPPLATFORM,
+ GUIO1(GAMEOPTION_AUTO_MOVE)
+ },
+ Nancy::kGameTypeNancy11
+ },
+ {
+ {
+ "nancy11", nullptr,
+ {
+ { "data1.hdr", 0, "ac8c62e5db77edff6265d80238c0f2c5", 375104 },
+ { "data1.cab", 0, "17aed043f3f1247a97f32ce950ec1cab", 8055234 },
+ { "data2.cab", 0, "42756dd5c89779d03bfcf4636912ef73", 149200126 },
+ { "ciftree.dat", 0, "3c406d4f391b6536982c6081f2dd1f4e", 55960641 }, // ciftree is outside of cabfiles
+ AD_LISTEND
+ },
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE | ADGF_DROPPLATFORM | Nancy::GF_COMPRESSED,
+ GUIO1(GAMEOPTION_AUTO_MOVE)
+ },
+ Nancy::kGameTypeNancy11
+ },
// Do not delete
{ AD_TABLE_END_MARKER, Nancy::kGameTypeNone }
diff --git a/engines/nancy/detection.h b/engines/nancy/detection.h
index d4d2afb271f..e88de519828 100644
--- a/engines/nancy/detection.h
+++ b/engines/nancy/detection.h
@@ -27,17 +27,19 @@
namespace Nancy {
enum GameType {
- kGameTypeNone = 0,
+ kGameTypeNone = 0,
kGameTypeVampire = 1,
- kGameTypeNancy1 = 2,
- kGameTypeNancy2 = 3,
- kGameTypeNancy3 = 4,
- kGameTypeNancy4 = 5,
- kGameTypeNancy5 = 6,
- kGameTypeNancy6 = 7,
- kGameTypeNancy7 = 8,
- kGameTypeNancy8 = 9,
- kGameTypeNancy9 = 10
+ kGameTypeNancy1 = 2,
+ kGameTypeNancy2 = 3,
+ kGameTypeNancy3 = 4,
+ kGameTypeNancy4 = 5,
+ kGameTypeNancy5 = 6,
+ kGameTypeNancy6 = 7,
+ kGameTypeNancy7 = 8,
+ kGameTypeNancy8 = 9,
+ kGameTypeNancy9 = 10,
+ kGameTypeNancy10 = 11,
+ kGameTypeNancy11 = 12,
};
enum NancyGameFlags {
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index 30514192d1e..af0074afc6b 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -101,7 +101,7 @@ NancyEngine::~NancyEngine() {
}
NancyEngine *NancyEngine::create(GameType type, OSystem *syst, const NancyGameDescription *gd) {
- if (type >= kGameTypeVampire && type <= kGameTypeNancy9) {
+ if (type >= kGameTypeVampire && type <= kGameTypeNancy11) {
return new NancyEngine(syst, gd);
}
@@ -408,6 +408,10 @@ void NancyEngine::bootGameEngine() {
// Setup mixer
syncSoundSettings();
+ if (getGameType() >= kGameTypeNancy10) {
+ error("Game not supported; Use console to inspect game data");
+ }
+
IFF *iff = _resource->loadIFF("boot");
if (!iff)
error("Failed to load boot script");
Commit: f5311cfe87e6ef6079faed192095405bf0f29cc3
https://github.com/scummvm/scummvm/commit/f5311cfe87e6ef6079faed192095405bf0f29cc3
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-07T23:15:23+01:00
Commit Message:
NANCY: Expand TableData struct
>From nancy8 on, a new method of writing and evaluating
data started being used. This commit expands the existing
TableData struct to accommodate it.
Changed paths:
engines/nancy/action/miscrecords.cpp
engines/nancy/action/overlay.cpp
engines/nancy/action/soundrecords.cpp
engines/nancy/commontypes.h
engines/nancy/puzzledata.cpp
engines/nancy/puzzledata.h
diff --git a/engines/nancy/action/miscrecords.cpp b/engines/nancy/action/miscrecords.cpp
index 29e2f56699c..14cf611bca2 100644
--- a/engines/nancy/action/miscrecords.cpp
+++ b/engines/nancy/action/miscrecords.cpp
@@ -136,15 +136,15 @@ void TableIndexSetValueHS::execute() {
case kNoChangeTableValue:
break;
case kIncrementTableValue:
- ++playerTable->currentIDs[_tableIndex - 1];
- if (playerTable->currentIDs[_tableIndex - 1] >= playerTable->currentIDs.size() + 1) {
- playerTable->currentIDs[_tableIndex - 1] = 1;
+ ++playerTable->singleValues[_tableIndex - 1];
+ if (playerTable->singleValues[_tableIndex - 1] >= playerTable->singleValues.size() + 1) {
+ playerTable->singleValues[_tableIndex - 1] = 1;
}
break;
case kDecrementTableValue:
- --playerTable->currentIDs[_tableIndex - 1];
- if (playerTable->currentIDs[_tableIndex - 1] == 0) {
- playerTable->currentIDs[_tableIndex - 1] = playerTable->currentIDs.size();
+ --playerTable->singleValues[_tableIndex - 1];
+ if (playerTable->singleValues[_tableIndex - 1] == 0) {
+ playerTable->singleValues[_tableIndex - 1] = playerTable->singleValues.size();
}
break;
@@ -153,7 +153,7 @@ void TableIndexSetValueHS::execute() {
// Check for correctness...
// ...of current index only...
- if (playerTable->currentIDs[_tableIndex] == tabl->correctIDs[_tableIndex]) {
+ if (playerTable->singleValues[_tableIndex] == tabl->correctIDs[_tableIndex]) {
NancySceneState.setEventFlag(_entryCorrectFlagID, g_nancy->_true);
} else {
NancySceneState.setEventFlag(_entryCorrectFlagID, g_nancy->_false);
@@ -162,7 +162,7 @@ void TableIndexSetValueHS::execute() {
// ..and of all indices
bool allCorrect = true;
for (uint i = 0; i < tabl->correctIDs.size(); ++i) {
- if (playerTable->currentIDs[i] != tabl->correctIDs[i]) {
+ if (playerTable->singleValues[i] != tabl->correctIDs[i]) {
allCorrect = false;
break;
}
diff --git a/engines/nancy/action/overlay.cpp b/engines/nancy/action/overlay.cpp
index 33b16429053..327debb637a 100644
--- a/engines/nancy/action/overlay.cpp
+++ b/engines/nancy/action/overlay.cpp
@@ -425,8 +425,8 @@ void TableIndexOverlay::execute() {
auto *tabl = GetEngineData(TABL);
assert(tabl);
- if (_lastIndexVal != playerTable->currentIDs[_tableIndex - 1]) {
- _lastIndexVal = playerTable->currentIDs[_tableIndex - 1];
+ if (_lastIndexVal != playerTable->singleValues[_tableIndex - 1]) {
+ _lastIndexVal = playerTable->singleValues[_tableIndex - 1];
_srcRects.clear();
_srcRects.push_back(tabl->srcRects[_lastIndexVal - 1]);
_currentViewportFrame = -1; // Force redraw
diff --git a/engines/nancy/action/soundrecords.cpp b/engines/nancy/action/soundrecords.cpp
index 63cc699e76d..c65cfd4ede6 100644
--- a/engines/nancy/action/soundrecords.cpp
+++ b/engines/nancy/action/soundrecords.cpp
@@ -309,12 +309,12 @@ void TableIndexPlaySound::execute() {
auto *tabl = GetEngineData(TABL);
assert(tabl);
- if (_lastIndexVal != playerTable->currentIDs[_tableIndex - 1]) {
+ if (_lastIndexVal != playerTable->singleValues[_tableIndex - 1]) {
g_nancy->_sound->stopSound(_sound);
NancySceneState.getTextbox().clear();
- _lastIndexVal = playerTable->currentIDs[_tableIndex - 1];
- _sound.name = Common::String::format("%s%u", tabl->soundBaseName.c_str(), playerTable->currentIDs[_tableIndex - 1]);
- _ccText = tabl->strings[playerTable->currentIDs[_tableIndex - 1] - 1];
+ _lastIndexVal = playerTable->singleValues[_tableIndex - 1];
+ _sound.name = Common::String::format("%s%u", tabl->soundBaseName.c_str(), playerTable->singleValues[_tableIndex - 1]);
+ _ccText = tabl->strings[playerTable->singleValues[_tableIndex - 1] - 1];
}
PlaySoundCC::execute();
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index f1265640d2c..55d2da36809 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -117,6 +117,7 @@ static const byte kPlayOverlayNoHotspot = 2;
static const byte kNoChangeTableValue = 0;
static const byte kIncrementTableValue = 1;
static const byte kDecrementTableValue = 2;
+static const int16 kNoChangeTableValue = 9999;
// 3D sound rotation
static const byte kRotateAroundX = 0;
diff --git a/engines/nancy/puzzledata.cpp b/engines/nancy/puzzledata.cpp
index 4cdfb6f8072..4709f70ce68 100644
--- a/engines/nancy/puzzledata.cpp
+++ b/engines/nancy/puzzledata.cpp
@@ -145,21 +145,63 @@ void JournalData::synchronize(Common::Serializer &ser) {
}
TableData::TableData() {
- auto *tabl = GetEngineData(TABL);
- assert(tabl);
+ if (g_nancy->getGameType() == kGameTypeNancy6) {
+ auto *tabl = GetEngineData(TABL);
+ assert(tabl);
- currentIDs = tabl->startIDs;
+ singleValues.resize(tabl->startIDs.size());
+ for (uint i = 0; i < tabl->startIDs.size(); ++i) {
+ singleValues[i] = tabl->startIDs[i];
+ }
+ }
}
void TableData::synchronize(Common::Serializer &ser) {
- byte num = currentIDs.size();
+ byte num = singleValues.size();
ser.syncAsByte(num);
if (ser.isLoading()) {
- currentIDs.resize(num);
+ singleValues.resize(num);
+ }
+
+ ser.syncArray(singleValues.data(), num, Common::Serializer::Sint16LE);
+
+ if (g_nancy->getGameType() < kGameTypeNancy8) {
+ return;
+ }
+
+ num = comboValues.size();
+ ser.syncAsByte(num);
+
+ if (ser.isLoading()) {
+ comboValues.resize(num);
+ }
+
+ ser.syncArray(comboValues.data(), num, Common::Serializer::FloatLE);
+}
+
+void TableData::setSingleValue(uint16 index, int16 value) {
+ if (singleValues.size() <= index) {
+ singleValues.resize(index, kNoTableValue);
}
- ser.syncArray(currentIDs.data(), num, Common::Serializer::Uint16LE);
+ singleValues[index] = value;
+}
+
+int16 TableData::getSingleValue(uint16 index) const {
+ return index < singleValues.size() ? singleValues[index] : kNoTableValue;
+}
+
+void TableData::setComboValue(uint16 index, float value) {
+ if (comboValues.size() < index) {
+ comboValues.resize(index, kNoTableValue);
+ }
+
+ comboValues[index] = value;
+}
+
+float TableData::getComboValue(uint16 index) const {
+ return index < comboValues.size() ? comboValues[index] : kNoTableValue;
}
PuzzleData *makePuzzleData(const uint32 tag) {
diff --git a/engines/nancy/puzzledata.h b/engines/nancy/puzzledata.h
index 6f28e995363..039117e2905 100644
--- a/engines/nancy/puzzledata.h
+++ b/engines/nancy/puzzledata.h
@@ -117,8 +117,11 @@ struct JournalData : public PuzzleData {
Common::HashMap<uint16, Common::Array<Common::String>> journalEntries;
};
-// Contains data related to nancy6's exhibit puzzle, which
-// spans multiple scenes and uses several special-purpose AR types
+// Contains variables that can be read and modified through action records.
+// Mixes two separate things:
+// - the exhibit data table in nancy6
+// - the general variable storage in nancy8 and up
+// The exhibit data was only ever used in nancy6, so mixing these should be ok.
struct TableData : public PuzzleData {
TableData();
virtual ~TableData() {}
@@ -126,7 +129,14 @@ struct TableData : public PuzzleData {
static constexpr uint32 getTag() { return MKTAG('T', 'A', 'B', 'L'); }
virtual void synchronize(Common::Serializer &ser);
- Common::Array<uint16> currentIDs;
+ void setSingleValue(uint16 index, int16 value);
+ int16 getSingleValue(uint16 index) const;
+
+ void setComboValue(uint16 index, float value);
+ float getComboValue(uint16 index) const;
+
+ Common::Array<int16> singleValues;
+ Common::Array<float> comboValues;
};
PuzzleData *makePuzzleData(const uint32 tag);
Commit: af2ff22907751fc09d14f5b50f512408840d860b
https://github.com/scummvm/scummvm/commit/af2ff22907751fc09d14f5b50f512408840d860b
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-07T23:15:23+01:00
Commit Message:
NANCY: Split data-related records to separate file
Created a new header file for action records that mainly
serve to manipulate data. This is done in preparation for the
addition of SetValue, SetValueCombo, and ValueTest.
Changed paths:
A engines/nancy/action/datarecords.cpp
A engines/nancy/action/datarecords.h
engines/nancy/action/arfactory.cpp
engines/nancy/action/miscrecords.cpp
engines/nancy/action/miscrecords.h
engines/nancy/module.mk
diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 4c47f0327b4..70e8f8a9456 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "engines/nancy/action/datarecords.h"
#include "engines/nancy/action/inventoryrecords.h"
#include "engines/nancy/action/navigationrecords.h"
#include "engines/nancy/action/soundrecords.h"
diff --git a/engines/nancy/action/datarecords.cpp b/engines/nancy/action/datarecords.cpp
new file mode 100644
index 00000000000..8f8c93bc8ce
--- /dev/null
+++ b/engines/nancy/action/datarecords.cpp
@@ -0,0 +1,192 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "engines/nancy/nancy.h"
+#include "engines/nancy/util.h"
+
+#include "engines/nancy/action/datarecords.h"
+
+#include "engines/nancy/state/scene.h"
+
+namespace Nancy {
+namespace Action {
+
+void TableIndexSetValueHS::readData(Common::SeekableReadStream &stream) {
+ _tableIndex = stream.readUint16LE();
+ _valueChangeType = stream.readByte();
+ _entryCorrectFlagID = stream.readSint16LE();
+ _allEntriesCorrectFlagID = stream.readSint16LE();
+
+ _flags.readData(stream);
+ _cursorType = stream.readUint16LE();
+ uint16 numHotspots = stream.readUint16LE();
+ _hotspots.resize(numHotspots);
+ for (uint i = 0; i < numHotspots; ++i) {
+ _hotspots[i].readData(stream);
+ }
+}
+
+void TableIndexSetValueHS::execute() {
+ switch (_state) {
+ case kBegin:
+ _state = kRun;
+ // fall through
+ case kRun:
+ _hasHotspot = false;
+ for (uint i = 0; i < _hotspots.size(); ++i) {
+ if (_hotspots[i].frameID == NancySceneState.getSceneInfo().frameID) {
+ _hasHotspot = true;
+ _hotspot = _hotspots[i].coords;
+ }
+ }
+ break;
+ case kActionTrigger: {
+ TableData *playerTable = (TableData *)NancySceneState.getPuzzleData(TableData::getTag());
+ assert(playerTable);
+ auto *tabl = GetEngineData(TABL);
+ assert(tabl);
+
+ // Edit table. Values start from 1!
+ switch (_valueChangeType) {
+ case kNoChangeTableValue:
+ break;
+ case kIncrementTableValue:
+ ++playerTable->singleValues[_tableIndex - 1];
+ if (playerTable->singleValues[_tableIndex - 1] >= playerTable->singleValues.size() + 1) {
+ playerTable->singleValues[_tableIndex - 1] = 1;
+ }
+ break;
+ case kDecrementTableValue:
+ --playerTable->singleValues[_tableIndex - 1];
+ if (playerTable->singleValues[_tableIndex - 1] == 0) {
+ playerTable->singleValues[_tableIndex - 1] = playerTable->singleValues.size();
+ }
+
+ break;
+ }
+
+ // Check for correctness...
+
+ // ...of current index only...
+ if (playerTable->singleValues[_tableIndex] == tabl->correctIDs[_tableIndex]) {
+ NancySceneState.setEventFlag(_entryCorrectFlagID, g_nancy->_true);
+ } else {
+ NancySceneState.setEventFlag(_entryCorrectFlagID, g_nancy->_false);
+ }
+
+ // ..and of all indices
+ bool allCorrect = true;
+ for (uint i = 0; i < tabl->correctIDs.size(); ++i) {
+ if (playerTable->singleValues[i] != tabl->correctIDs[i]) {
+ allCorrect = false;
+ break;
+ }
+ }
+
+ if (allCorrect) {
+ NancySceneState.setEventFlag(_allEntriesCorrectFlagID, g_nancy->_true);
+ } else {
+ NancySceneState.setEventFlag(_allEntriesCorrectFlagID, g_nancy->_false);
+ }
+
+ _flags.execute();
+ finishExecution();
+ }
+ }
+}
+
+void EventFlags::readData(Common::SeekableReadStream &stream) {
+ if (!_isTerse) {
+ _flags.readData(stream);
+ } else {
+ // Terse version only has 2 flags
+ _flags.descs[0].label = stream.readSint16LE();
+ _flags.descs[0].flag = stream.readUint16LE();
+ _flags.descs[1].label = stream.readSint16LE();
+ _flags.descs[1].flag = stream.readUint16LE();
+ }
+}
+
+void EventFlags::execute() {
+ _flags.execute();
+ _isDone = true;
+}
+
+void EventFlagsMultiHS::readData(Common::SeekableReadStream &stream) {
+ EventFlags::readData(stream);
+
+ if (_isCursor) {
+ _hoverCursor = (CursorManager::CursorType)stream.readUint16LE();
+ }
+
+ uint16 numHotspots = stream.readUint16LE();
+
+ _hotspots.reserve(numHotspots);
+ for (uint16 i = 0; i < numHotspots; ++i) {
+ _hotspots.push_back(HotspotDescription());
+ HotspotDescription &newDesc = _hotspots[i];
+ newDesc.readData(stream);
+ }
+}
+
+void EventFlagsMultiHS::execute() {
+ switch (_state) {
+ case kBegin:
+ // turn main rendering on
+ _state = kRun;
+ // fall through
+ case kRun:
+ _hasHotspot = false;
+
+ for (uint i = 0; i < _hotspots.size(); ++i) {
+ if (_hotspots[i].frameID == NancySceneState.getSceneInfo().frameID) {
+ _hasHotspot = true;
+ _hotspot = _hotspots[i].coords;
+ }
+ }
+
+ break;
+ case kActionTrigger:
+ if (_hoverCursor != CursorManager::kCustom1 && _hoverCursor != CursorManager::kCustom2) {
+ _hasHotspot = false;
+ EventFlags::execute();
+ finishExecution();
+ break;
+ } else {
+ _state = kRun;
+ }
+ }
+}
+
+void DifficultyLevel::readData(Common::SeekableReadStream &stream) {
+ _difficulty = stream.readUint16LE();
+ _flag.label = stream.readSint16LE();
+ _flag.flag = stream.readUint16LE();
+}
+
+void DifficultyLevel::execute() {
+ NancySceneState.setDifficulty(_difficulty);
+ NancySceneState.setEventFlag(_flag);
+ _isDone = true;
+}
+
+} // End of namespace Action
+} // End of namespace Nancy
diff --git a/engines/nancy/action/datarecords.h b/engines/nancy/action/datarecords.h
new file mode 100644
index 00000000000..720b830b52e
--- /dev/null
+++ b/engines/nancy/action/datarecords.h
@@ -0,0 +1,110 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef NANCY_ACTION_DATARECORDS_H
+#define NANCY_ACTION_DATARECORDS_H
+
+#include "engines/nancy/action/actionrecord.h"
+
+namespace Nancy {
+
+class NancyEngine;
+
+namespace Action {
+
+// Changes the selected value inside the TableData. Value can be incremented, decremented, or not changed.
+// Also responsible for checking whether all values are correct (as described in the TABL chunk). nancy6 only.
+class TableIndexSetValueHS : public ActionRecord {
+public:
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+ CursorManager::CursorType getHoverCursor() const override { return (CursorManager::CursorType)_cursorType; }
+
+protected:
+ Common::String getRecordTypeName() const override { return "TableIndexSetValueHS"; }
+
+ uint16 _tableIndex = 0;
+ byte _valueChangeType = kNoChangeTableValue;
+ int16 _entryCorrectFlagID = -1;
+ int16 _allEntriesCorrectFlagID = -1;
+
+ MultiEventFlagDescription _flags;
+ uint16 _cursorType = 1;
+ Common::Array<HotspotDescription> _hotspots;
+};
+
+// Sets up to 10 flags at once.
+class EventFlags : public ActionRecord {
+public:
+ EventFlags(bool terse = false) : _isTerse(terse) {}
+ virtual ~EventFlags() {}
+
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+ MultiEventFlagDescription _flags;
+ bool _isTerse;
+
+protected:
+ Common::String getRecordTypeName() const override { return _isTerse ? "EventFlagsTerse" : "EventFlags"; }
+};
+
+// Sets up to 10 flags when clicked. Hotspot can move alongside background frame.
+class EventFlagsMultiHS : public EventFlags {
+public:
+ EventFlagsMultiHS(bool isCursor, bool terse = false) : EventFlags(terse), _isCursor(isCursor) {}
+ virtual ~EventFlagsMultiHS() {}
+
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+ CursorManager::CursorType getHoverCursor() const override { return _hoverCursor; }
+
+ CursorManager::CursorType _hoverCursor = CursorManager::kHotspot;
+ Common::Array<HotspotDescription> _hotspots;
+
+ bool _isCursor;
+
+protected:
+ bool canHaveHotspot() const override { return true; }
+ Common::String getRecordTypeName() const override { return _isCursor ? (_isTerse ? "EventFlagsHSTerse" : "EventFlagsCursorHS") : "EventFlagsMultiHS"; }
+};
+
+// Sets the difficulty level for the current save. Only appears at the start of the game.
+// First appears in nancy1. Nancy1 and nancy2 have three difficulty values, while later games
+// only have two: 0 and 2.
+class DifficultyLevel : public ActionRecord {
+public:
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+ uint16 _difficulty = 0;
+ FlagDescription _flag;
+
+protected:
+ Common::String getRecordTypeName() const override { return "DifficultyLevel"; }
+};
+
+} // End of namespace Action
+} // End of namespace Nancy
+
+#endif // NANCY_ACTION_DATARECORDS_H
diff --git a/engines/nancy/action/miscrecords.cpp b/engines/nancy/action/miscrecords.cpp
index 14cf611bca2..49b06464742 100644
--- a/engines/nancy/action/miscrecords.cpp
+++ b/engines/nancy/action/miscrecords.cpp
@@ -96,90 +96,6 @@ void SpecialEffect::execute() {
_isDone = true;
}
-void TableIndexSetValueHS::readData(Common::SeekableReadStream &stream) {
- _tableIndex = stream.readUint16LE();
- _valueChangeType = stream.readByte();
- _entryCorrectFlagID = stream.readSint16LE();
- _allEntriesCorrectFlagID = stream.readSint16LE();
-
- _flags.readData(stream);
- _cursorType = stream.readUint16LE();
- uint16 numHotspots = stream.readUint16LE();
- _hotspots.resize(numHotspots);
- for (uint i = 0; i < numHotspots; ++i) {
- _hotspots[i].readData(stream);
- }
-}
-
-void TableIndexSetValueHS::execute() {
- switch (_state) {
- case kBegin:
- _state = kRun;
- // fall through
- case kRun:
- _hasHotspot = false;
- for (uint i = 0; i < _hotspots.size(); ++i) {
- if (_hotspots[i].frameID == NancySceneState.getSceneInfo().frameID) {
- _hasHotspot = true;
- _hotspot = _hotspots[i].coords;
- }
- }
- break;
- case kActionTrigger: {
- TableData *playerTable = (TableData *)NancySceneState.getPuzzleData(TableData::getTag());
- assert(playerTable);
- auto *tabl = GetEngineData(TABL);
- assert(tabl);
-
- // Edit table. Values start from 1!
- switch (_valueChangeType) {
- case kNoChangeTableValue:
- break;
- case kIncrementTableValue:
- ++playerTable->singleValues[_tableIndex - 1];
- if (playerTable->singleValues[_tableIndex - 1] >= playerTable->singleValues.size() + 1) {
- playerTable->singleValues[_tableIndex - 1] = 1;
- }
- break;
- case kDecrementTableValue:
- --playerTable->singleValues[_tableIndex - 1];
- if (playerTable->singleValues[_tableIndex - 1] == 0) {
- playerTable->singleValues[_tableIndex - 1] = playerTable->singleValues.size();
- }
-
- break;
- }
-
- // Check for correctness...
-
- // ...of current index only...
- if (playerTable->singleValues[_tableIndex] == tabl->correctIDs[_tableIndex]) {
- NancySceneState.setEventFlag(_entryCorrectFlagID, g_nancy->_true);
- } else {
- NancySceneState.setEventFlag(_entryCorrectFlagID, g_nancy->_false);
- }
-
- // ..and of all indices
- bool allCorrect = true;
- for (uint i = 0; i < tabl->correctIDs.size(); ++i) {
- if (playerTable->singleValues[i] != tabl->correctIDs[i]) {
- allCorrect = false;
- break;
- }
- }
-
- if (allCorrect) {
- NancySceneState.setEventFlag(_allEntriesCorrectFlagID, g_nancy->_true);
- } else {
- NancySceneState.setEventFlag(_allEntriesCorrectFlagID, g_nancy->_false);
- }
-
- _flags.execute();
- finishExecution();
- }
- }
-}
-
void LightningOn::execute() {
NancySceneState.beginLightning(_distance, _pulseTime, _rgbPercent);
_isDone = true;
@@ -264,69 +180,6 @@ void StopTimer::execute() {
_isDone = true;
}
-void EventFlags::readData(Common::SeekableReadStream &stream) {
- if (!_isTerse) {
- _flags.readData(stream);
- } else {
- // Terse version only has 2 flags
- _flags.descs[0].label = stream.readSint16LE();
- _flags.descs[0].flag = stream.readUint16LE();
- _flags.descs[1].label = stream.readSint16LE();
- _flags.descs[1].flag = stream.readUint16LE();
- }
-}
-
-void EventFlags::execute() {
- _flags.execute();
- _isDone = true;
-}
-
-void EventFlagsMultiHS::readData(Common::SeekableReadStream &stream) {
- EventFlags::readData(stream);
-
- if (_isCursor) {
- _hoverCursor = (CursorManager::CursorType)stream.readUint16LE();
- }
-
- uint16 numHotspots = stream.readUint16LE();
-
- _hotspots.reserve(numHotspots);
- for (uint16 i = 0; i < numHotspots; ++i) {
- _hotspots.push_back(HotspotDescription());
- HotspotDescription &newDesc = _hotspots[i];
- newDesc.readData(stream);
- }
-}
-
-void EventFlagsMultiHS::execute() {
- switch (_state) {
- case kBegin:
- // turn main rendering on
- _state = kRun;
- // fall through
- case kRun:
- _hasHotspot = false;
-
- for (uint i = 0; i < _hotspots.size(); ++i) {
- if (_hotspots[i].frameID == NancySceneState.getSceneInfo().frameID) {
- _hasHotspot = true;
- _hotspot = _hotspots[i].coords;
- }
- }
-
- break;
- case kActionTrigger:
- if (_hoverCursor != CursorManager::kCustom1 && _hoverCursor != CursorManager::kCustom2) {
- _hasHotspot = false;
- EventFlags::execute();
- finishExecution();
- break;
- } else {
- _state = kRun;
- }
- }
-}
-
void GotoMenu::readData(Common::SeekableReadStream &stream) {
stream.skip(1);
}
@@ -392,18 +245,6 @@ void WinGame::execute() {
_isDone = true;
}
-void DifficultyLevel::readData(Common::SeekableReadStream &stream) {
- _difficulty = stream.readUint16LE();
- _flag.label = stream.readSint16LE();
- _flag.flag = stream.readUint16LE();
-}
-
-void DifficultyLevel::execute() {
- NancySceneState.setDifficulty(_difficulty);
- NancySceneState.setEventFlag(_flag);
- _isDone = true;
-}
-
void HintSystem::readData(Common::SeekableReadStream &stream) {
_characterID = stream.readByte();
_genericSound.readNormal(stream);
diff --git a/engines/nancy/action/miscrecords.h b/engines/nancy/action/miscrecords.h
index a16691d71d0..39afe0e0ad3 100644
--- a/engines/nancy/action/miscrecords.h
+++ b/engines/nancy/action/miscrecords.h
@@ -87,28 +87,6 @@ protected:
Common::String getRecordTypeName() const override { return "SpecialEffect"; }
};
-// Changes the selected value inside the TableData. Value can be incremented, decremented, or not changed.
-// Also responsible for checking whether all values are correct (as described in the TABL chunk). Nancy6 and up.
-class TableIndexSetValueHS : public ActionRecord {
-public:
- void readData(Common::SeekableReadStream &stream) override;
- void execute() override;
-
- CursorManager::CursorType getHoverCursor() const override { return (CursorManager::CursorType)_cursorType; }
-
-protected:
- Common::String getRecordTypeName() const override { return "TableIndexSetValueHS"; }
-
- uint16 _tableIndex = 0;
- byte _valueChangeType = kNoChangeTableValue;
- int16 _entryCorrectFlagID = -1;
- int16 _allEntriesCorrectFlagID = -1;
-
- MultiEventFlagDescription _flags;
- uint16 _cursorType = 1;
- Common::Array<HotspotDescription> _hotspots;
-};
-
// Adds a caption to the textbox.
class TextBoxWrite : public ActionRecord {
public:
@@ -196,43 +174,6 @@ protected:
Common::String getRecordTypeName() const override { return "StopTimer"; }
};
-// Sets up to 10 flags at once.
-class EventFlags : public ActionRecord {
-public:
- EventFlags(bool terse = false) : _isTerse(terse) {}
- virtual ~EventFlags() {}
-
- void readData(Common::SeekableReadStream &stream) override;
- void execute() override;
-
- MultiEventFlagDescription _flags;
- bool _isTerse;
-
-protected:
- Common::String getRecordTypeName() const override { return _isTerse ? "EventFlagsTerse" : "EventFlags"; }
-};
-
-// Sets up to 10 flags when clicked. Hotspot can move alongside background frame.
-class EventFlagsMultiHS : public EventFlags {
-public:
- EventFlagsMultiHS(bool isCursor, bool terse = false) : EventFlags(terse), _isCursor(isCursor) {}
- virtual ~EventFlagsMultiHS() {}
-
- void readData(Common::SeekableReadStream &stream) override;
- void execute() override;
-
- CursorManager::CursorType getHoverCursor() const override { return _hoverCursor; }
-
- CursorManager::CursorType _hoverCursor = CursorManager::kHotspot;
- Common::Array<HotspotDescription> _hotspots;
-
- bool _isCursor;
-
-protected:
- bool canHaveHotspot() const override { return true; }
- Common::String getRecordTypeName() const override { return _isCursor ? (_isTerse ? "EventFlagsHSTerse" : "EventFlagsCursorHS") : "EventFlagsMultiHS"; }
-};
-
// Returns the player back to the main menu
class GotoMenu : public ActionRecord {
public:
@@ -289,21 +230,6 @@ protected:
Common::String getRecordTypeName() const override { return "WinGame"; }
};
-// Sets the difficulty level for the current save. Only appears at the start of the game.
-// First appears in nancy1. Nancy1 and nancy2 have three difficulty values, while later games
-// only have two: 0 and 2.
-class DifficultyLevel : public ActionRecord {
-public:
- void readData(Common::SeekableReadStream &stream) override;
- void execute() override;
-
- uint16 _difficulty = 0;
- FlagDescription _flag;
-
-protected:
- Common::String getRecordTypeName() const override { return "DifficultyLevel"; }
-};
-
// Checks how many hints the player is allowed to get. If they are still allowed hints,
// it selects an appropriate one and plays its sound/displays its caption in the Textbox.
// The hint system was _only_ used in nancy1, since it's pretty limited and overly punishing.
@@ -327,4 +253,4 @@ protected:
} // End of namespace Action
} // End of namespace Nancy
-#endif // NANCY_ACTION_RECORDTYPES_H
+#endif // NANCY_ACTION_MISCRECORDS_H
diff --git a/engines/nancy/module.mk b/engines/nancy/module.mk
index 57ea5fb711e..288a1a80e5f 100644
--- a/engines/nancy/module.mk
+++ b/engines/nancy/module.mk
@@ -5,6 +5,7 @@ MODULE_OBJS = \
action/actionrecord.o \
action/arfactory.o \
action/autotext.o \
+ action/datarecords.o \
action/inventoryrecords.o \
action/navigationrecords.o \
action/soundrecords.o \
Commit: 136944937474c1d04f6771837b36416432ba5e2d
https://github.com/scummvm/scummvm/commit/136944937474c1d04f6771837b36416432ba5e2d
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-07T23:15:23+01:00
Commit Message:
NANCY: Implement SetValue
Added support for the simplest of the data access action
records. This simply sets or adds to a value inside the
TableData struct.
Changed paths:
engines/nancy/action/arfactory.cpp
engines/nancy/action/datarecords.cpp
engines/nancy/action/datarecords.h
engines/nancy/commontypes.h
engines/nancy/puzzledata.cpp
diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 70e8f8a9456..1768ea3ef8c 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -185,6 +185,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
return new TextBoxWrite();
case 76:
return new TextboxClear();
+ case 77:
+ return new SetValue();
case 97:
return new EventFlags(true);
case 98:
diff --git a/engines/nancy/action/datarecords.cpp b/engines/nancy/action/datarecords.cpp
index 8f8c93bc8ce..cad9897d768 100644
--- a/engines/nancy/action/datarecords.cpp
+++ b/engines/nancy/action/datarecords.cpp
@@ -70,7 +70,7 @@ void TableIndexSetValueHS::execute() {
break;
case kIncrementTableValue:
++playerTable->singleValues[_tableIndex - 1];
- if (playerTable->singleValues[_tableIndex - 1] >= playerTable->singleValues.size() + 1) {
+ if (playerTable->singleValues[_tableIndex - 1] >= (int)playerTable->singleValues.size() + 1) {
playerTable->singleValues[_tableIndex - 1] = 1;
}
break;
@@ -113,6 +113,40 @@ void TableIndexSetValueHS::execute() {
}
}
+void SetValue::readData(Common::SeekableReadStream &stream) {
+ _index = stream.readByte();
+ _shouldSet = stream.readByte();
+ _value = stream.readSint16LE();
+}
+
+void SetValue::execute() {
+ TableData *playerTable = (TableData *)NancySceneState.getPuzzleData(TableData::getTag());
+ assert(playerTable);
+
+ // nancy8 has 20 single & 20 combo values, later games have 30/10
+ uint numSingleValues = g_nancy->getGameType() <= kGameTypeNancy8 ? 20 : 30;
+
+ if (_index < numSingleValues) {
+ // Single values
+ int16 curValue = playerTable->getSingleValue(_index);
+ if (_shouldSet || curValue == kNoTableValue) {
+ playerTable->setSingleValue(_index, _value);
+ } else {
+ playerTable->setSingleValue(_index, curValue + _value);
+ }
+ } else {
+ // Combo values
+ float curValue = playerTable->getComboValue(_index - numSingleValues);
+ if (_shouldSet || curValue == (float)kNoTableValue) {
+ playerTable->setComboValue(_index - numSingleValues, _value);
+ } else {
+ playerTable->setComboValue(_index - numSingleValues, curValue + _value);
+ }
+ }
+
+ finishExecution();
+}
+
void EventFlags::readData(Common::SeekableReadStream &stream) {
if (!_isTerse) {
_flags.readData(stream);
diff --git a/engines/nancy/action/datarecords.h b/engines/nancy/action/datarecords.h
index 720b830b52e..fe6e626b891 100644
--- a/engines/nancy/action/datarecords.h
+++ b/engines/nancy/action/datarecords.h
@@ -52,6 +52,20 @@ protected:
Common::Array<HotspotDescription> _hotspots;
};
+// Sets (or adds to) a value inside the TableData struct
+class SetValue : public ActionRecord {
+public:
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+protected:
+ Common::String getRecordTypeName() const override { return "SetValue"; }
+
+ byte _index = 0;
+ bool _shouldSet = false;
+ int16 _value = kNoTableValue;
+};
+
// Sets up to 10 flags at once.
class EventFlags : public ActionRecord {
public:
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index 55d2da36809..840cb5af9f3 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -117,7 +117,7 @@ static const byte kPlayOverlayNoHotspot = 2;
static const byte kNoChangeTableValue = 0;
static const byte kIncrementTableValue = 1;
static const byte kDecrementTableValue = 2;
-static const int16 kNoChangeTableValue = 9999;
+static const int16 kNoTableValue = 9999;
// 3D sound rotation
static const byte kRotateAroundX = 0;
diff --git a/engines/nancy/puzzledata.cpp b/engines/nancy/puzzledata.cpp
index 4709f70ce68..310968f73ac 100644
--- a/engines/nancy/puzzledata.cpp
+++ b/engines/nancy/puzzledata.cpp
@@ -182,7 +182,7 @@ void TableData::synchronize(Common::Serializer &ser) {
void TableData::setSingleValue(uint16 index, int16 value) {
if (singleValues.size() <= index) {
- singleValues.resize(index, kNoTableValue);
+ singleValues.resize(index + 1, kNoTableValue);
}
singleValues[index] = value;
@@ -194,7 +194,7 @@ int16 TableData::getSingleValue(uint16 index) const {
void TableData::setComboValue(uint16 index, float value) {
if (comboValues.size() < index) {
- comboValues.resize(index, kNoTableValue);
+ comboValues.resize(index + 1, kNoTableValue);
}
comboValues[index] = value;
Commit: a8dcc387a45bc5a3d3f1c236dbc9d21af87c0b89
https://github.com/scummvm/scummvm/commit/a8dcc387a45bc5a3d3f1c236dbc9d21af87c0b89
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-07T23:15:23+01:00
Commit Message:
NANCY: Implement SetValueCombo
Implemented the action record type that computes a
sum of values, each one with an attached percentage
weight. The values themselves can be either supplied
verbatim, or extracted from the TableData struct.
This was implemented in nancy8, but only started getting
used in nancy9.
Changed paths:
engines/nancy/action/arfactory.cpp
engines/nancy/action/datarecords.cpp
engines/nancy/action/datarecords.h
engines/nancy/commontypes.h
diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 1768ea3ef8c..9f6760e6b22 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -187,6 +187,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
return new TextboxClear();
case 77:
return new SetValue();
+ case 78:
+ return new SetValueCombo();
case 97:
return new EventFlags(true);
case 98:
diff --git a/engines/nancy/action/datarecords.cpp b/engines/nancy/action/datarecords.cpp
index cad9897d768..96df6a1d9b6 100644
--- a/engines/nancy/action/datarecords.cpp
+++ b/engines/nancy/action/datarecords.cpp
@@ -147,6 +147,55 @@ void SetValue::execute() {
finishExecution();
}
+void SetValueCombo::readData(Common::SeekableReadStream &stream) {
+ _valueIndex = stream.readByte();
+
+ _indices.resize(10);
+ _percentages.resize(10);
+ for (uint i = 0; i < 10; ++i) {
+ _indices[i] = stream.readByte();
+ _percentages[i] = stream.readSint16LE();
+ }
+}
+
+void SetValueCombo::execute() {
+ TableData *playerTable = (TableData *)NancySceneState.getPuzzleData(TableData::getTag());
+ assert(playerTable);
+
+ // nancy8 has 20 single & 20 combo values, later games have 30/10
+ uint numSingleValues = g_nancy->getGameType() <= kGameTypeNancy8 ? 20 : 30;
+
+ playerTable->setComboValue(_valueIndex - numSingleValues, 0);
+
+ for (uint i = 0; i < _indices.size(); ++i) {
+ if (_indices[i] != kNoTableIndex) {
+ float valueToAdd = 0;
+
+ if (_indices[i] == 100) { // ACTUAL_VALUE
+ valueToAdd = _percentages[i];
+ } else {
+ if (_indices[i] < numSingleValues) {
+ // Add a single value
+ if (playerTable->singleValues[_indices[i]] != kNoTableValue) {
+ valueToAdd = playerTable->singleValues[_indices[i]];
+ valueToAdd = valueToAdd * ((float)_percentages[i] / 100.f);
+ }
+ } else {
+ // Add another combo value
+ if (playerTable->comboValues[_indices[i] - numSingleValues] != kNoTableValue) {
+ valueToAdd = playerTable->comboValues[_indices[i] - numSingleValues];
+ valueToAdd = valueToAdd * ((float)_percentages[i] / 100.f);
+ }
+ }
+ }
+
+ playerTable->setComboValue(_valueIndex - numSingleValues, playerTable->getComboValue(_valueIndex - numSingleValues) + valueToAdd);
+ }
+ }
+
+ finishExecution();
+}
+
void EventFlags::readData(Common::SeekableReadStream &stream) {
if (!_isTerse) {
_flags.readData(stream);
diff --git a/engines/nancy/action/datarecords.h b/engines/nancy/action/datarecords.h
index fe6e626b891..eb383945f88 100644
--- a/engines/nancy/action/datarecords.h
+++ b/engines/nancy/action/datarecords.h
@@ -66,6 +66,19 @@ protected:
int16 _value = kNoTableValue;
};
+class SetValueCombo : public ActionRecord {
+public:
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+protected:
+ Common::String getRecordTypeName() const override { return "SetValueCombo"; }
+
+ byte _valueIndex = 0;
+ Common::Array<byte> _indices;
+ Common::Array<int16> _percentages;
+};
+
// Sets up to 10 flags at once.
class EventFlags : public ActionRecord {
public:
diff --git a/engines/nancy/commontypes.h b/engines/nancy/commontypes.h
index 840cb5af9f3..7463b5ec66c 100644
--- a/engines/nancy/commontypes.h
+++ b/engines/nancy/commontypes.h
@@ -117,6 +117,7 @@ static const byte kPlayOverlayNoHotspot = 2;
static const byte kNoChangeTableValue = 0;
static const byte kIncrementTableValue = 1;
static const byte kDecrementTableValue = 2;
+static const uint16 kNoTableIndex = 99;
static const int16 kNoTableValue = 9999;
// 3D sound rotation
Commit: 8745a64dfc4fa8625ebce372cde5ff2e9b9c21ae
https://github.com/scummvm/scummvm/commit/8745a64dfc4fa8625ebce372cde5ff2e9b9c21ae
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2024-02-07T23:15:23+01:00
Commit Message:
NANCY: Implement ValueTest
Implemented the record type responsible for actually
checking the values inside TableData.
Changed paths:
engines/nancy/action/arfactory.cpp
engines/nancy/action/datarecords.cpp
engines/nancy/action/datarecords.h
diff --git a/engines/nancy/action/arfactory.cpp b/engines/nancy/action/arfactory.cpp
index 9f6760e6b22..185a11f5feb 100644
--- a/engines/nancy/action/arfactory.cpp
+++ b/engines/nancy/action/arfactory.cpp
@@ -189,6 +189,8 @@ ActionRecord *ActionManager::createActionRecord(uint16 type, Common::SeekableRea
return new SetValue();
case 78:
return new SetValueCombo();
+ case 79:
+ return new ValueTest();
case 97:
return new EventFlags(true);
case 98:
diff --git a/engines/nancy/action/datarecords.cpp b/engines/nancy/action/datarecords.cpp
index 96df6a1d9b6..641ec2ff534 100644
--- a/engines/nancy/action/datarecords.cpp
+++ b/engines/nancy/action/datarecords.cpp
@@ -196,6 +196,137 @@ void SetValueCombo::execute() {
finishExecution();
}
+void ValueTest::readData(Common::SeekableReadStream &stream) {
+ _valueIndex = stream.readByte();
+ _testType = stream.readByte();
+ _condition = stream.readByte();
+
+ _indicesToTest.resize(5);
+ for (uint i = 0; i < 5; ++i) {
+ _indicesToTest[i] = stream.readByte();
+ }
+
+ _flagToSet = stream.readSint16LE();
+}
+
+static const byte kTestAllCombo = 0;
+static const byte kTestAllSingle = 1;
+static const byte kTestSome = 2;
+static const byte kTestActualValue = 3;
+
+static const byte kTestEqualTo = 0;
+static const byte kTestLessThan = 1;
+static const byte kTestGreaterThan = 2;
+static const byte kTestGreaterThanOrEqual = 3;
+static const byte kTestLessThanOrEqual = 4;
+
+void ValueTest::execute() {
+ TableData *playerTable = (TableData *)NancySceneState.getPuzzleData(TableData::getTag());
+ assert(playerTable);
+
+ // nancy8 has 20 single & 20 combo values, later games have 30/10
+ uint numSingleValues = g_nancy->getGameType() <= kGameTypeNancy8 ? 20 : 30;
+
+ float testedValue;
+ if (_valueIndex < numSingleValues) {
+ // Test a single value
+ testedValue = playerTable->getSingleValue(_valueIndex);
+ } else {
+ // Test a combo value
+ testedValue = playerTable->getComboValue(_valueIndex - numSingleValues);
+ }
+
+ // Pick which values we will test against, depending on the _testType param
+ Common::Array<byte> testedIndices;
+ switch (_testType) {
+ case kTestAllSingle:
+ testedIndices.resize(numSingleValues);
+ for (uint i = 0; i < numSingleValues; ++i) {
+ testedIndices[i] = i;
+ }
+
+ break;
+ case kTestAllCombo:
+ testedIndices.resize(g_nancy->getGameType() == kGameTypeNancy8 ? 20 : 10);
+ for (uint i = 0; i < testedIndices.size(); ++i) {
+ testedIndices[i] = i + numSingleValues;
+ }
+
+ break;
+ case kTestSome:
+ case kTestActualValue:
+ testedIndices = _indicesToTest;
+ break;
+ }
+
+ bool satisfied = false;
+ for (uint i = 0; i < testedIndices.size(); ++i) {
+ if (testedIndices[i] == kNoTableIndex) {
+ continue;
+ }
+
+ float otherValue = 0;
+ if (_testType == kTestActualValue) {
+ otherValue = testedIndices[i];
+ } else {
+ if (testedIndices[i] < numSingleValues) {
+ // Test against single value
+ otherValue = playerTable->getSingleValue(testedIndices[i]);
+ } else {
+ // Test against combo value
+ otherValue = playerTable->getComboValue(testedIndices[i] - numSingleValues);
+ }
+
+ if (otherValue == (float)kNoTableValue) {
+ continue;
+ }
+ }
+
+ switch (_condition) {
+ case kTestEqualTo:
+ if (testedValue == otherValue) {
+ satisfied = true;
+ }
+
+ break;
+ case kTestLessThan:
+ if (testedValue < otherValue) {
+ satisfied = true;
+ }
+
+ break;
+ case kTestGreaterThan:
+ if (testedValue > otherValue) {
+ satisfied = true;
+ }
+
+ break;
+ case kTestGreaterThanOrEqual:
+ if (testedValue >= otherValue) {
+ satisfied = true;
+ }
+
+ break;
+ case kTestLessThanOrEqual:
+ if (testedValue <= otherValue) {
+ satisfied = true;
+ }
+
+ break;
+ }
+
+ if (satisfied) {
+ break;
+ }
+ }
+
+ if (satisfied) {
+ NancySceneState.setEventFlag(_flagToSet, g_nancy->_true);
+ }
+
+ finishExecution();
+}
+
void EventFlags::readData(Common::SeekableReadStream &stream) {
if (!_isTerse) {
_flags.readData(stream);
diff --git a/engines/nancy/action/datarecords.h b/engines/nancy/action/datarecords.h
index eb383945f88..7848423be1e 100644
--- a/engines/nancy/action/datarecords.h
+++ b/engines/nancy/action/datarecords.h
@@ -79,6 +79,22 @@ protected:
Common::Array<int16> _percentages;
};
+class ValueTest : public ActionRecord {
+public:
+ void readData(Common::SeekableReadStream &stream) override;
+ void execute() override;
+
+protected:
+ Common::String getRecordTypeName() const override { return "ValueTest"; }
+
+ byte _valueIndex = 0;
+ byte _testType = 0;
+ byte _condition = 0;
+ Common::Array<byte> _indicesToTest;
+
+ int16 _flagToSet = kFlagNoLabel;
+};
+
// Sets up to 10 flags at once.
class EventFlags : public ActionRecord {
public:
More information about the Scummvm-git-logs
mailing list