[Scummvm-git-logs] scummvm master -> 6f6625e3a2fffc656485f27d8dcab6dbcb368707
fracturehill
noreply at scummvm.org
Sun Nov 5 11:23:29 UTC 2023
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
934b99f116 DEVTOOLS: Fix typo in nancy2 data in create_nancy
8745974c86 DEVTOOLS: Build cif trees in-place in create_nancy
996a55abbe DEVTOOLS: Add nancy3 missing sound patch to nancy.dat
a37a4a7cfa NANCY: Add support for extra ConfMan checks in patches
d33adf5aee NANCY: Add support for images in loose .cifs
6f6625e3a2 NANCY: Add support for nancy5 Russian fonts
Commit: 934b99f116290ba215a1e0251aee5370ec422e1c
https://github.com/scummvm/scummvm/commit/934b99f116290ba215a1e0251aee5370ec422e1c
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-11-05T13:03:01+02:00
Commit Message:
DEVTOOLS: Fix typo in nancy2 data in create_nancy
Changed paths:
devtools/create_nancy/nancy2_data.h
diff --git a/devtools/create_nancy/nancy2_data.h b/devtools/create_nancy/nancy2_data.h
index 721e7e5f03b..03a2095422a 100644
--- a/devtools/create_nancy/nancy2_data.h
+++ b/devtools/create_nancy/nancy2_data.h
@@ -68,7 +68,7 @@ const Common::Array<Common::Array<ConditionalDialogue>> _nancy2ConditionalDialog
{ 8, 729, "NRD29",
{ { kEv, 115, kFalse }, { kEv, 68, kTrue } } },
{ 8, 729, "NRD29",
- { { kEv, 15, kFalse }, { kEv, 64, kTrue } } },
+ { { kEv, 115, kFalse }, { kEv, 64, kTrue } } },
{ 9, 728, "NRD28",
{ { kEv, 50, kTrue }, { kEv, 114, kFalse } } },
{ 10, 717, "NRD18",
Commit: 8745974c86b59b114a7544c6a70bdc735c655fcd
https://github.com/scummvm/scummvm/commit/8745974c86b59b114a7544c6a70bdc735c655fcd
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-11-05T13:03:01+02:00
Commit Message:
DEVTOOLS: Build cif trees in-place in create_nancy
Added code for reading .cif files, and combining them into
a ciftree, which is then to be written to nancy.dat. Removed
the nancy2_patchtree binary file, and added the four source
files in its place.
Changed paths:
A devtools/create_nancy/cif.cpp
A devtools/create_nancy/cif.h
A devtools/create_nancy/files/nancy2/S1160.cif
A devtools/create_nancy/files/nancy2/s1563.CIF
A devtools/create_nancy/files/nancy2/s1564.CIF
A devtools/create_nancy/files/nancy2/s1565.CIF
R devtools/create_nancy/files/nancy2_patchtree.dat
devtools/create_nancy/create_nancy.cpp
devtools/create_nancy/module.mk
devtools/create_nancy/nancy2_data.h
diff --git a/devtools/create_nancy/cif.cpp b/devtools/create_nancy/cif.cpp
new file mode 100644
index 00000000000..d56c39550a1
--- /dev/null
+++ b/devtools/create_nancy/cif.cpp
@@ -0,0 +1,223 @@
+/* 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 "cif.h"
+#include "common/endian.h"
+
+// Severely slimmed down version of the cif/ciftree code that's in the engine
+// Can only read .cif files, and only write ciftrees into memory
+byte *createCifTree(uint16 gameVersion, Common::Array<const char *> filenames, const char *folderName, uint32 &outSize) {
+ Common::Array<uint32> fileSizes(filenames.size(), 0);
+ Common::Array<byte *> cifInfos(filenames.size(), nullptr);
+ Common::Array<byte *> fileData(filenames.size(), nullptr);
+ Common::Array<bool> isCif(filenames.size(), false);
+
+ uint32 headerSize = 1024 * 2;
+ uint32 infoSizeTree = 0;
+ uint32 infoSizeCif = 0;
+ if (gameVersion <= 2) { // nancy1
+ headerSize += 30;
+ infoSizeTree = 38;
+ infoSizeCif = 21;
+ } else {
+ headerSize += 32;
+ if (gameVersion <= 3) {
+ // Format 1, short filenames
+ infoSizeTree = 70;
+ infoSizeCif = 53;
+ } else {
+ // Format 1 or 2*, with long filenames
+ infoSizeTree = 94;
+ infoSizeCif = 53;
+ }
+ }
+
+ // Read the .cif files
+ for (uint i = 0; i < filenames.size(); ++i) {
+ File f;
+ char *path = new char[256];
+ strcpy(path, folderName);
+ strcat(path, "/");
+ strcat(path, filenames[i]);
+ f.open(path, kFileReadMode);
+ delete[] path;
+
+ const char *c = filenames[i];
+ uint nameSize = 0;
+ while (*c != '\0') {
+ ++nameSize;
+ ++c;
+ }
+
+ if (nameSize > 4) {
+ // Check if file extension is .cif or not
+ if (tolower(*(c - 4)) == '.' && tolower(*(c - 3)) == 'c' && tolower(*(c - 2)) == 'i' && tolower(*(c - 1)) == 'f') {
+ isCif[i] = true;
+ }
+ }
+
+ if (isCif[i]) {
+ f.skip(20); // Skip header
+ f.skip(4); // Skip empty
+ f.skip(4); // Skip version
+
+ cifInfos[i] = new byte[infoSizeCif];
+ f.read(cifInfos[i], infoSizeCif);
+ }
+
+ fileSizes[i] = f.size() - f.pos(); // Assumes .cif files are well-behaved and don't have extra data at end
+ fileData[i] = new byte[fileSizes[i]];
+ f.read(fileData[i], fileSizes[i]);
+
+
+ f.close();
+ }
+
+ uint32 retSize = headerSize + filenames.size() * infoSizeTree;
+ for (uint i = 0; i < fileSizes.size(); ++i) {
+ retSize += fileSizes[i];
+ }
+
+ uint32 retPos = 0;
+ byte *ret = new byte[retSize];
+ memset(ret, 0, retSize);
+
+ memcpy(ret, "CIF TREE WayneSikes", 20);
+ retPos += 24;
+
+ WRITE_LE_UINT16(ret + retPos, 2);
+ retPos += 2;
+ if (gameVersion <= 2) { // nancy1
+ WRITE_LE_UINT16(ret + retPos, 0);
+ } else {
+ WRITE_LE_UINT16(ret + retPos, 1);
+ }
+ retPos += 2;
+
+ WRITE_LE_UINT16(ret + retPos, filenames.size());
+ retPos += 2;
+
+ if (gameVersion >= 3) { // nancy2
+ retPos += 2;
+ }
+
+ retPos += 1024 * 2; // Skip hash table
+
+ // Write the cif info structs
+ const uint nameSize = gameVersion <= 3 ? 9 : 33;
+ for (uint i = 0; i < filenames.size(); ++i) {
+ uint thisNameSize = 0;
+ char name[34];
+ memset(name, 0, 34);
+
+ const char *c = filenames[i];
+ while (*c != '\0' && thisNameSize <= nameSize && (isCif[i] ? *c != '.' : true)) { // Do not store the extension for .cif files
+ name[thisNameSize] = *c;
+ ++thisNameSize;
+ ++c;
+ }
+ name[nameSize] = '\0';
+
+ memcpy(ret + retPos, name, nameSize);
+ retPos += nameSize;
+
+ retPos += 2; // block index
+
+ uint32 dataOffset = headerSize + filenames.size() * infoSizeTree;
+ for (uint j = 0; j < i; ++j) {
+ dataOffset += fileSizes[j];
+ }
+
+ if (gameVersion >= 7) { // nancy6
+ WRITE_LE_UINT32(ret + retPos, dataOffset);
+ retPos += 6;
+ }
+
+ if (cifInfos[i]) {
+ // Write rects
+ uint32 pos = 0;
+ if (gameVersion >= 3) { // nancy2
+ memcpy(ret + retPos, cifInfos[i], 32);
+ retPos += 32;
+ pos += 32;
+ }
+
+ // width, pitch, height, depth, comp
+ memcpy(ret + retPos, cifInfos[i] + pos, 8);
+ retPos += 8;
+ pos += 8;
+
+ if (gameVersion <= 6) { // nancy5
+ WRITE_LE_UINT32(ret + retPos, dataOffset);
+ retPos += 4;
+ }
+
+ // uncompressed size, obsolete field, compressed size, data type
+ memcpy(ret + retPos, cifInfos[i] + pos, 13);
+ retPos += 13;
+ } else {
+ // Non-cif file
+
+ // Fill rects with zeroes
+ if (gameVersion >= 3) {
+ retPos += 32;
+ }
+
+ // width, pitch, height, depth
+ retPos += 7;
+
+ *(ret + retPos) = 1; // No compression
+ ++retPos;
+
+ if (gameVersion <= 6) { // nancy5
+ WRITE_LE_UINT32(ret + retPos, dataOffset);
+ retPos += 4;
+ }
+
+ WRITE_LE_UINT32(ret + retPos, fileSizes[i]);
+ WRITE_LE_UINT32(ret + retPos + 4, 0);
+ WRITE_LE_UINT32(ret + retPos + 8, fileSizes[i]);
+ retPos += 12;
+
+ *(ret + retPos) = 3; // data type
+ ++retPos;
+ }
+
+
+ if (gameVersion <= 6) { // nancy5
+ retPos += 2; // next id in chain
+ }
+ }
+
+ // Write the file datas
+ for (uint i = 0; i < fileData.size(); ++i) {
+ memcpy(ret + retPos, fileData[i], fileSizes[i]);
+ retPos += fileSizes[i];
+ }
+
+ for (uint i = 0; i < filenames.size(); ++i) {
+ delete[] fileData[i];
+ delete[] cifInfos[i];
+ }
+
+ outSize = retPos;
+ return ret;
+}
\ No newline at end of file
diff --git a/devtools/create_nancy/cif.h b/devtools/create_nancy/cif.h
new file mode 100644
index 00000000000..92a42efcac5
--- /dev/null
+++ b/devtools/create_nancy/cif.h
@@ -0,0 +1,29 @@
+/* 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 CREATE_NANCY_CIF_H
+#define CREATE_NANCY_CIF_H
+
+#include "file.h"
+
+byte *createCifTree(uint16 gameVersion, Common::Array<const char *> filenames, const char *folderName, uint32 &outSize);
+
+#endif // CREATE_NANCY_CIF_H
diff --git a/devtools/create_nancy/create_nancy.cpp b/devtools/create_nancy/create_nancy.cpp
index 3f046e3d6a1..eafd52de94a 100644
--- a/devtools/create_nancy/create_nancy.cpp
+++ b/devtools/create_nancy/create_nancy.cpp
@@ -20,6 +20,7 @@
*/
#include "file.h"
+#include "cif.h"
#include "tvd_data.h"
#include "nancy1_data.h"
#include "nancy2_data.h"
@@ -155,20 +156,17 @@ void writeEventFlagNames(File &output, const Common::Array<const char *> &eventF
writeToFile(output, eventFlagNames);
}
-void writePatchFile(File &output, const char *filename) {
- File file;
- if (!file.open(filename, AccessMode::kFileReadMode)) {
+void writePatchFile(File &output, uint gameVersion, Common::Array<const char *> filenames, const char *folderName) {
+ uint32 size;
+ byte *b = createCifTree(gameVersion, filenames, folderName, size);
+ if (!b) {
return;
}
-
- byte *buf = new byte[file.size()];
- file.read(buf, file.size());
output.writeUint32(MKTAG('P', 'A', 'T', 'C'));
- output.write(buf, file.size());
+ output.write(b, size);
- file.close();
- delete[] buf;
+ delete[] b;
}
void writePatchAssociations(File &output, const Common::Array<PatchAssociation> &patchAssociations) {
@@ -230,7 +228,7 @@ int main(int argc, char *argv[]) {
WRAPWITHOFFSET(writeRingingTexts(output, _nancy2TelephoneRinging))
WRAPWITHOFFSET(writeEmptySaveTexts(output, _nancy2EmptySaveStrings))
WRAPWITHOFFSET(writeEventFlagNames(output, _nancy2EventFlagNames))
- WRAPWITHOFFSET(writePatchFile(output, "files/nancy2_patchtree.dat"))
+ WRAPWITHOFFSET(writePatchFile(output, 3, nancy2PatchSrcFiles, "files/nancy2"))
WRAPWITHOFFSET(writePatchAssociations(output, nancy2PatchAssociations))
// Nancy Drew: Message in a Haunted Mansion data
diff --git a/devtools/create_nancy/files/nancy2/S1160.cif b/devtools/create_nancy/files/nancy2/S1160.cif
new file mode 100644
index 00000000000..df829a48cd0
Binary files /dev/null and b/devtools/create_nancy/files/nancy2/S1160.cif differ
diff --git a/devtools/create_nancy/files/nancy2/s1563.CIF b/devtools/create_nancy/files/nancy2/s1563.CIF
new file mode 100644
index 00000000000..3d3cdb03ee8
Binary files /dev/null and b/devtools/create_nancy/files/nancy2/s1563.CIF differ
diff --git a/devtools/create_nancy/files/nancy2/s1564.CIF b/devtools/create_nancy/files/nancy2/s1564.CIF
new file mode 100644
index 00000000000..5638c3447f5
Binary files /dev/null and b/devtools/create_nancy/files/nancy2/s1564.CIF differ
diff --git a/devtools/create_nancy/files/nancy2/s1565.CIF b/devtools/create_nancy/files/nancy2/s1565.CIF
new file mode 100644
index 00000000000..aff9e113cd1
Binary files /dev/null and b/devtools/create_nancy/files/nancy2/s1565.CIF differ
diff --git a/devtools/create_nancy/files/nancy2_patchtree.dat b/devtools/create_nancy/files/nancy2_patchtree.dat
deleted file mode 100644
index 5a1ffa064a4..00000000000
Binary files a/devtools/create_nancy/files/nancy2_patchtree.dat and /dev/null differ
diff --git a/devtools/create_nancy/module.mk b/devtools/create_nancy/module.mk
index 0db0310ae3c..032f5844879 100644
--- a/devtools/create_nancy/module.mk
+++ b/devtools/create_nancy/module.mk
@@ -2,6 +2,7 @@
MODULE := devtools/create_nancy
MODULE_OBJS := \
+ cif.o \
create_nancy.o \
file.o
diff --git a/devtools/create_nancy/nancy2_data.h b/devtools/create_nancy/nancy2_data.h
index 03a2095422a..d09f3352c50 100644
--- a/devtools/create_nancy/nancy2_data.h
+++ b/devtools/create_nancy/nancy2_data.h
@@ -617,6 +617,13 @@ const Common::Array<const char *> _nancy2EventFlagNames = {
"empty"
};
+const Common::Array<const char *> nancy2PatchSrcFiles {
+ "S1160.cif",
+ "S1563.cif",
+ "S1564.cif",
+ "S1565.cif"
+};
+
// Patch notes:
// - The patch that extends the final timer was originally distributed by HeR.
// - The softlock fix is custom, and works by adding a second inventory dependency
Commit: 996a55abbec5358376aadaca3d2af2f9fbcbab97
https://github.com/scummvm/scummvm/commit/996a55abbec5358376aadaca3d2af2f9fbcbab97
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-11-05T13:03:01+02:00
Commit Message:
DEVTOOLS: Add nancy3 missing sound patch to nancy.dat
Also slightly modified the format to allow for language
checks in the PatchAssociation struct
Changed paths:
A devtools/create_nancy/files/nancy3/han92b.his
devtools/create_nancy/create_nancy.cpp
devtools/create_nancy/file.cpp
devtools/create_nancy/nancy2_data.h
devtools/create_nancy/nancy3_data.h
devtools/create_nancy/types.h
diff --git a/devtools/create_nancy/create_nancy.cpp b/devtools/create_nancy/create_nancy.cpp
index eafd52de94a..fc1b467e97d 100644
--- a/devtools/create_nancy/create_nancy.cpp
+++ b/devtools/create_nancy/create_nancy.cpp
@@ -241,6 +241,8 @@ int main(int argc, char *argv[]) {
WRAPWITHOFFSET(writeRingingTexts(output, _nancy3TelephoneRinging))
WRAPWITHOFFSET(writeEmptySaveTexts(output, _nancy3EmptySaveStrings))
WRAPWITHOFFSET(writeEventFlagNames(output, _nancy3EventFlagNames))
+ WRAPWITHOFFSET(writePatchFile(output, 4, nancy3PatchSrcFiles, "files/nancy3"))
+ WRAPWITHOFFSET(writePatchAssociations(output, nancy3PatchAssociations))
// Nancy Drew: Treasure in the Royal Tower data
gameOffsets.push_back(output.pos());
diff --git a/devtools/create_nancy/file.cpp b/devtools/create_nancy/file.cpp
index 3842a31e2ed..9af72c5b2a2 100644
--- a/devtools/create_nancy/file.cpp
+++ b/devtools/create_nancy/file.cpp
@@ -219,7 +219,7 @@ void writeToFile(File &file, const Hint &obj) {
template<>
void writeToFile(File &file, const PatchAssociation &obj) {
- file.writeString(obj.confManID);
+ writeToFile(file, obj.confManProps);
writeToFile(file, obj.fileIDs);
}
diff --git a/devtools/create_nancy/files/nancy3/han92b.his b/devtools/create_nancy/files/nancy3/han92b.his
new file mode 100644
index 00000000000..848dada618d
Binary files /dev/null and b/devtools/create_nancy/files/nancy3/han92b.his differ
diff --git a/devtools/create_nancy/nancy2_data.h b/devtools/create_nancy/nancy2_data.h
index d09f3352c50..48e51408bbd 100644
--- a/devtools/create_nancy/nancy2_data.h
+++ b/devtools/create_nancy/nancy2_data.h
@@ -630,8 +630,8 @@ const Common::Array<const char *> nancy2PatchSrcFiles {
// to the last two ARs in scene S1160. This allows the player to re-enter the
// prop room when they've collected the door knob, but not the wire clippers.
const Common::Array<PatchAssociation> nancy2PatchAssociations {
- { "softlocks_fix", { "S1160" } },
- { "final_timer", { "S1563", "S1564", "S1565" } }
+ { { "softlocks_fix", "true" }, { "S1160" } },
+ { { "final_timer", "true" }, { "S1563", "S1564", "S1565" } }
};
#endif // NANCY2DATA
diff --git a/devtools/create_nancy/nancy3_data.h b/devtools/create_nancy/nancy3_data.h
index 28b96d55eb1..c95a8786fec 100644
--- a/devtools/create_nancy/nancy3_data.h
+++ b/devtools/create_nancy/nancy3_data.h
@@ -853,4 +853,14 @@ const Common::Array<const char *> _nancy3EventFlagNames = {
"empty",
};
+const Common::Array<const char *> nancy3PatchSrcFiles {
+ "han92b.his"
+};
+
+// Patch notes:
+// - The missing sound file is a patch from the original devs. Should only be enabled in the English version
+const Common::Array<PatchAssociation> nancy3PatchAssociations {
+ { { "language", "en" }, { "han92b.his" } }
+};
+
#endif // NANCY3DATA_H
diff --git a/devtools/create_nancy/types.h b/devtools/create_nancy/types.h
index 2b1ff7319c1..0529ebe2d21 100644
--- a/devtools/create_nancy/types.h
+++ b/devtools/create_nancy/types.h
@@ -91,7 +91,7 @@ struct SoundChannelInfo {
};
struct PatchAssociation {
- const char *confManID;
+ Common::Array<const char *> confManProps;
Common::Array<const char *> fileIDs;
};
Commit: a37a4a7cfa16092421c500fbe6d0ae146fd81cd8
https://github.com/scummvm/scummvm/commit/a37a4a7cfa16092421c500fbe6d0ae146fd81cd8
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-11-05T13:21:13+02:00
Commit Message:
NANCY: Add support for extra ConfMan checks in patches
ConfMan properties are now an array of key-value pairs, allowing
for checks against game language and other non-bool props
Changed paths:
engines/nancy/cif.cpp
engines/nancy/cif.h
engines/nancy/commontypes.cpp
diff --git a/engines/nancy/cif.cpp b/engines/nancy/cif.cpp
index 712aeee8cc9..961b367c50d 100644
--- a/engines/nancy/cif.cpp
+++ b/engines/nancy/cif.cpp
@@ -330,10 +330,25 @@ bool CifTree::sync(Common::Serializer &ser) {
bool PatchTree::hasFile(const Common::Path &path) const {
if (CifTree::hasFile(path)) {
+ // An association is just a Pair of two StringArrays
+ // The first member is an array of Pairs of Strings: a ConfMan property name, and the required value for that ConfMan property
+ // The second member is an array with the names of the files to be enabled if all the ConfMan property requirements are satisfied
for (auto &assoc : _associations) {
- for (const Common::String &s : assoc._value) {
+ auto &confManProps = assoc.first;
+ auto &filenames = assoc.second;
+ for (const Common::String &s : filenames) {
if (s == path.toString()) {
- return ConfMan.getBool(assoc._key, ConfMan.getActiveDomainName());
+ bool satisfied = true;
+
+ for (uint i = 0; i < confManProps.size(); ++i) {
+ // Check all
+ if (ConfMan.get(confManProps[i].first, ConfMan.getActiveDomainName()) != confManProps[i].second) {
+ satisfied = false;
+ break;
+ }
+ }
+
+ return satisfied;
}
}
}
diff --git a/engines/nancy/cif.h b/engines/nancy/cif.h
index b634bd4aad8..7a6751154a1 100644
--- a/engines/nancy/cif.h
+++ b/engines/nancy/cif.h
@@ -118,7 +118,7 @@ public:
bool hasFile(const Common::Path &path) const override;
- Common::HashMap<Common::String, Common::Array<Common::String>> _associations;
+ Common::Array<Common::Pair<Common::Array<Common::Pair<Common::String, Common::String>>, Common::StringArray>> _associations;
};
} // End of namespace Nancy
diff --git a/engines/nancy/commontypes.cpp b/engines/nancy/commontypes.cpp
index f10a8518a19..73bbe51ca63 100644
--- a/engines/nancy/commontypes.cpp
+++ b/engines/nancy/commontypes.cpp
@@ -356,7 +356,7 @@ void StaticData::readData(Common::SeekableReadStream &stream, Common::Language l
// Used for patch file reading
byte *patchBuf = nullptr;
uint32 patchBufSize = 0;
- Common::Array<Common::String> confManIDs;
+ Common::Array<Common::Array<Common::String>> confManProps;
Common::Array<Common::Array<Common::String>> fileIDs;
while (stream.pos() < endPos) {
@@ -550,12 +550,18 @@ void StaticData::readData(Common::SeekableReadStream &stream, Common::Language l
case MKTAG('P', 'A', 'S', 'S') :
// Patch file <-> ConfMan entries associations
num = stream.readUint16LE();
- confManIDs.resize(num);
+ confManProps.resize(num);
fileIDs.resize(num);
for (uint i = 0; i < num; ++i) {
- confManIDs[i] = stream.readString();
-
+ // Read ConfMan key-value pairs
uint16 num2 = stream.readUint16LE();
+ confManProps[i].resize(num2);
+ for (uint j = 0; j < num2; ++j) {
+ confManProps[i][j] = stream.readString();
+ }
+
+ // Read filenames
+ num2 = stream.readUint16LE();
fileIDs[i].resize(num2);
for (uint j = 0; j < num2; ++j) {
fileIDs[i][j] = stream.readString();
@@ -575,8 +581,15 @@ void StaticData::readData(Common::SeekableReadStream &stream, Common::Language l
assert(tree);
// Write the ConfMan associations
- for (uint i = 0; i < confManIDs.size(); ++i) {
- tree->_associations.setVal(confManIDs[i], fileIDs[i]);
+ for (uint i = 0; i < confManProps.size(); ++i) {
+ assert(confManProps[i].size() % 2 == 0);
+ // Separate the array of strings into an array of Pairs of strings
+ Common::Array<Common::Pair<Common::String, Common::String>> props;
+ for (uint j = 0; j < confManProps[i].size() / 2; ++j) {
+ props.push_back({confManProps[i][j * 2], confManProps[i][j * 2 + 1]});
+ }
+
+ tree->_associations.push_back({props, fileIDs[i]});
}
}
}
Commit: d33adf5aeeb43786f8b282ef334cc1e9d0b63a4d
https://github.com/scummvm/scummvm/commit/d33adf5aeeb43786f8b282ef334cc1e9d0b63a4d
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-11-05T13:21:13+02:00
Commit Message:
NANCY: Add support for images in loose .cifs
Fixed an oversight that would result in the Russian variants
of the games (which use loose image files instead of
patching the ciftree) to load wrong images. Also, walled off
the .bmp loading
Changed paths:
engines/nancy/resource.cpp
diff --git a/engines/nancy/resource.cpp b/engines/nancy/resource.cpp
index 90b026706af..7bcd61b10e9 100644
--- a/engines/nancy/resource.cpp
+++ b/engines/nancy/resource.cpp
@@ -20,6 +20,7 @@
*/
#include "common/memstream.h"
+#include "common/config-manager.h"
#include "image/bmp.h"
@@ -54,36 +55,59 @@ bool ResourceManager::loadImage(const Common::String &name, Graphics::ManagedSur
}
CifInfo info;
- bool external = false;
+ Common::SeekableReadStream *stream = nullptr;
- // First, check for external bitmap
- Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(name + ".bmp");
- if (stream) {
- // Found external image
- Image::BitmapDecoder bmpDec;
- bmpDec.loadStream(*stream);
- surf.copyFrom(*bmpDec.getSurface());
- surf.setPalette(bmpDec.getPalette(), bmpDec.getPaletteStartIndex(), MIN<uint>(256, bmpDec.getPaletteColorCount())); // LOGO.BMP reports 257 colors
- external = true;
- } else {
- // Then, search inside the ciftrees
- stream = SearchMan.createReadStreamForMember(name);
+ // First, check for external .bmp (TVD only; can also be enabled via a hidden ConfMan option)
+ if (g_nancy->getGameType() == kGameTypeVampire || ConfMan.getBool("external_bmp", ConfMan.getActiveDomainName())) {
+ stream = SearchMan.createReadStreamForMember(name + ".bmp");
+ if (stream) {
+ // Found external image
+ Image::BitmapDecoder bmpDec;
+ bmpDec.loadStream(*stream);
+ surf.copyFrom(*bmpDec.getSurface());
+ surf.setPalette(bmpDec.getPalette(), bmpDec.getPaletteStartIndex(), MIN<uint>(256, bmpDec.getPaletteColorCount())); // LOGO.BMP reports 257 colors
+ }
+ }
- if (!stream) {
- warning("Couldn't open image file %s", name.c_str());
- return false;
+ if (g_nancy->getGameType() == kGameTypeVampire) {
+ // .cifs/ciftrees were introduced with nancy1. We also don't need to flip endianness, since the BMP decoder should handle that by itself
+ return false;
+ }
+
+ // Check for loose .cif images. This bypasses tree search even with a provided treeName
+ if (!stream) {
+ stream = SearchMan.createReadStreamForMember(name + ".cif");
+ if (stream) {
+ // .cifs are compressed, so we need to extract
+ CifFile cifFile(stream, name); // cifFile takes ownership of the current stream
+ stream = cifFile.createReadStream();
+ info = cifFile._info;
}
}
- // Search for associated CifInfo struct
- if (!external || outSrc || outDest) {
- // First, get the correct tree
- const CifTree *tree = nullptr;
- if (treeName.size()) {
+ // Search inside the ciftrees
+ if (!stream) {
+ if (!treeName.empty()) {
+ // Tree name was provided, bypass SearchMan
Common::String upper = treeName;
upper.toUppercase();
- tree = (const CifTree *)SearchMan.getArchive(treePrefix + upper);
- } else {
+ const CifTree *tree = (const CifTree *)SearchMan.getArchive(treePrefix + upper);
+
+ stream = tree->createReadStreamForMember(name);
+ info = tree->getCifInfo(name);
+ }
+
+ if (!stream) {
+ // Tree name was not provided, or lookup failed. Use SearchMan
+ stream = SearchMan.createReadStreamForMember(name);
+
+ if (!stream) {
+ warning("Couldn't open image file %s", name.c_str());
+ return false;
+ }
+
+ // Search for the info struct in all ciftrees
+ const CifTree *tree = nullptr;
for (uint i = 0; i < _cifTreeNames.size(); ++i) {
// No provided tree name, check inside every loaded tree
Common::String upper = _cifTreeNames[i];
@@ -93,50 +117,50 @@ bool ResourceManager::loadImage(const Common::String &name, Graphics::ManagedSur
break;
}
}
- }
-
- if (!tree) {
- error("Couldn't find CifInfo struct inside loaded CifTrees");
- }
- // Now, get the info struct and read the data we need from it
- info = tree->getCifInfo(name);
- if (info.type != CifInfo::kResTypeImage) {
- warning("Resource '%s' is not an image", name.c_str());
- return false;
+ if (tree) {
+ info = tree->getCifInfo(name);
+ } else {
+ // Image was found inside ciftree, but its CifInfo wasn't. This _should_ be unreachable
+ error("Couldn't find CifInfo struct inside loaded CifTrees");
+ }
}
+ }
- if (info.depth != 16) {
- warning("Image '%s' has unsupported depth %i", name.c_str(), info.depth);
- return false;
- }
+ // Sanity checks
+ if (info.type != CifInfo::kResTypeImage) {
+ warning("Resource '%s' is not an image", name.c_str());
+ return false;
+ }
- if (outSrc) {
- *outSrc = info.src;
- }
+ if (info.depth != 16) {
+ warning("Image '%s' has unsupported depth %i", name.c_str(), info.depth);
+ return false;
+ }
- if (outDest) {
- *outDest = info.dest;
- }
+ // Load the src/dest rects when requested
+ if (outSrc) {
+ *outSrc = info.src;
+ }
- if (!external) {
- uint32 bufSize = info.pitch * info.height * (info.depth / 16);
- byte *buf = new byte[bufSize];
- stream->read(buf, bufSize);
+ if (outDest) {
+ *outDest = info.dest;
+ }
- #ifdef SCUMM_BIG_ENDIAN
- if (info.depth == 16) {
- for (uint i = 0; i < bufSize / 2; ++i) {
- ((uint16 *)buf)[i] = SWAP_BYTES_16(((uint16 *)buf)[i]);
- }
- }
- #endif
+ // Finally, copy the data into the surface
+ uint32 bufSize = info.pitch * info.height * (info.depth / 16);
+ byte *buf = new byte[bufSize];
+ stream->read(buf, bufSize);
- GraphicsManager::copyToManaged(buf, surf, info.width, info.height, g_nancy->_graphicsManager->getInputPixelFormat());
- delete[] buf;
- }
+ #ifdef SCUMM_BIG_ENDIAN
+ // Flip endianness on BE machines
+ for (uint i = 0; i < bufSize / 2; ++i) {
+ ((uint16 *)buf)[i] = SWAP_BYTES_16(((uint16 *)buf)[i]);
}
-
+ #endif
+
+ GraphicsManager::copyToManaged(buf, surf, info.width, info.height, g_nancy->_graphicsManager->getInputPixelFormat());
+ delete[] buf;
return true;
}
Commit: 6f6625e3a2fffc656485f27d8dcab6dbcb368707
https://github.com/scummvm/scummvm/commit/6f6625e3a2fffc656485f27d8dcab6dbcb368707
Author: Kaloyan Chehlarski (strahy at outlook.com)
Date: 2023-11-05T13:21:13+02:00
Commit Message:
NANCY: Add support for nancy5 Russian fonts
The Russian translations of nancy5 and up (except for
nancy6) switched to a Windows-1251 encoding for their
strings, and changed up the format of the FONT chunks.
Changed paths:
engines/nancy/font.cpp
engines/nancy/font.h
engines/nancy/nancy.cpp
engines/nancy/nancy.h
diff --git a/engines/nancy/font.cpp b/engines/nancy/font.cpp
index 34918b5c2f2..a4f458053e8 100644
--- a/engines/nancy/font.cpp
+++ b/engines/nancy/font.cpp
@@ -32,6 +32,7 @@ void Font::read(Common::SeekableReadStream &stream) {
_transColor = g_nancy->_graphicsManager->getTransColor();
_maxCharWidth = 0;
_fontHeight = 0;
+ uint16 numCharacters = 78;
Common::String imageName;
readFilename(stream, imageName);
@@ -72,39 +73,51 @@ void Font::read(Common::SeekableReadStream &stream) {
_semicolonOffset = stream.readUint16LE();
_slashOffset = stream.readUint16LE();
- if (g_nancy->getGameType() >= kGameTypeNancy6) {
- // Nancy6 added more characters to its fonts
- _aWithGraveOffset = stream.readUint16LE();
- _cWithCedillaOffset = stream.readUint16LE();
- _eWithGraveOffset = stream.readUint16LE();
- _eWithAcuteOffset = stream.readUint16LE();
- _eWithCircumflexOffset = stream.readUint16LE();
- _eWithDiaeresisOffset = stream.readUint16LE();
- _oWithCircumflexOffset = stream.readUint16LE();
- _uppercaseAWithGraveOffset = stream.readUint16LE();
- _aWithCircumflexOffset = stream.readUint16LE();
- _iWithCircumflexOffset = stream.readUint16LE();
- _uWithGraveOffset = stream.readUint16LE();
- _uppercaseAWithDiaeresisOffset = stream.readUint16LE();
- _aWithDiaeresisOffset = stream.readUint16LE();
- _uppercaseOWithDiaeresisOffset = stream.readUint16LE();
- _oWithDiaeresisOffset = stream.readUint16LE();
- _uppercaseUWithDiaeresisOffset = stream.readUint16LE();
- _uWithDiaeresisOffset = stream.readUint16LE();
- _invertedExclamationMarkOffset = stream.readUint16LE();
- _invertedQuestionMarkOffset = stream.readUint16LE();
- _uppercaseNWithTildeOffset = stream.readUint16LE();
- _nWithTildeOffset = stream.readUint16LE();
- _uppercaseEWithAcuteOffset = stream.readUint16LE();
- _aWithAcuteOffset = stream.readUint16LE();
- _iWithAcuteOffset = stream.readUint16LE();
- _oWithAcuteOffset = stream.readUint16LE();
- _uWithAcuteOffset = stream.readUint16LE();
- _eszettOffset = stream.readUint16LE();
+ if (g_nancy->getGameLanguage() == Common::RU_RUS && g_nancy->getGameType() >= kGameTypeNancy5 && g_nancy->getGameType() != kGameTypeNancy6) {
+ // Only extract the lowercase/uppercase offsets, since the letters are in order in the FONT data
+ _cyrillicLowercaseOffset = stream.readUint16LE();
+ stream.skip(72);
+ _cyrillicUppercaseOffset = stream.readUint16LE();
+ stream.skip(2);
+
+ numCharacters = 179;
+ } else {
+ if (g_nancy->getGameType() >= kGameTypeNancy6) {
+ // Nancy6 added more characters to its fonts
+ _aWithGraveOffset = stream.readUint16LE();
+ _cWithCedillaOffset = stream.readUint16LE();
+ _eWithGraveOffset = stream.readUint16LE();
+ _eWithAcuteOffset = stream.readUint16LE();
+ _eWithCircumflexOffset = stream.readUint16LE();
+ _eWithDiaeresisOffset = stream.readUint16LE();
+ _oWithCircumflexOffset = stream.readUint16LE();
+ _uppercaseAWithGraveOffset = stream.readUint16LE();
+ _aWithCircumflexOffset = stream.readUint16LE();
+ _iWithCircumflexOffset = stream.readUint16LE();
+ _uWithGraveOffset = stream.readUint16LE();
+ _uppercaseAWithDiaeresisOffset = stream.readUint16LE();
+ _aWithDiaeresisOffset = stream.readUint16LE();
+ _uppercaseOWithDiaeresisOffset = stream.readUint16LE();
+ _oWithDiaeresisOffset = stream.readUint16LE();
+ _uppercaseUWithDiaeresisOffset = stream.readUint16LE();
+ _uWithDiaeresisOffset = stream.readUint16LE();
+ _invertedExclamationMarkOffset = stream.readUint16LE();
+ _invertedQuestionMarkOffset = stream.readUint16LE();
+ _uppercaseNWithTildeOffset = stream.readUint16LE();
+ _nWithTildeOffset = stream.readUint16LE();
+ _uppercaseEWithAcuteOffset = stream.readUint16LE();
+ _aWithAcuteOffset = stream.readUint16LE();
+ _iWithAcuteOffset = stream.readUint16LE();
+ _oWithAcuteOffset = stream.readUint16LE();
+ _uWithAcuteOffset = stream.readUint16LE();
+ _eszettOffset = stream.readUint16LE();
+
+ numCharacters = 105;
+ }
}
- _characterRects.resize(g_nancy->getGameType() >= kGameTypeNancy6 ? 105 : 78);
- for (uint i = 0; i < _characterRects.size(); ++i) {
+ _characterRects.resize(numCharacters);
+ for (uint i = 0; i < numCharacters; ++i) {
Common::Rect &cur = _characterRects[i];
readRect(stream, cur);
@@ -185,101 +198,118 @@ Common::Rect Font::getCharacterSourceRect(char chr) const {
int offset = -1;
Common::Rect ret;
- if (chr < 0) {
- // Nancy6 introduced extended ASCII characters
- switch (chr) {
- case '\xe0':
- offset = _aWithGraveOffset;
- break;
- case '\xe7':
- offset = _cWithCedillaOffset;
- break;
- case '\xe8':
- offset = _eWithGraveOffset;
- break;
- case '\xe9':
- offset = _eWithAcuteOffset;
- break;
- case '\xea':
- offset = _eWithCircumflexOffset;
- break;
- case '\xeb':
- offset = _eWithDiaeresisOffset;
- break;
- case '\xf4':
- offset = _oWithCircumflexOffset;
- break;
- case '\xc0':
- offset = _uppercaseAWithGraveOffset;
- break;
- case '\xe2':
- offset = _aWithCircumflexOffset;
- break;
- case '\xee':
- offset = _iWithCircumflexOffset;
- break;
- case '\xf9':
- offset = _uWithGraveOffset;
- break;
- case '\xc4':
- offset = _uppercaseAWithDiaeresisOffset;
- break;
- case '\xe4':
- offset = _aWithDiaeresisOffset;
- break;
- case '\xd6':
- offset = _uppercaseOWithDiaeresisOffset;
- break;
- case '\xf6':
- offset = _oWithDiaeresisOffset;
- break;
- case '\xdc':
- offset = _uppercaseUWithDiaeresisOffset;
- break;
- case '\xfc':
- offset = _uWithDiaeresisOffset;
- break;
- case '\xa1':
- offset = _invertedExclamationMarkOffset;
- break;
- case '\xbf':
- offset = _invertedQuestionMarkOffset;
- break;
- case '\xd1':
- offset = _uppercaseNWithTildeOffset;
- break;
- case '\xf1':
- offset = _nWithTildeOffset;
- break;
- case '\xc9':
- offset = _uppercaseEWithAcuteOffset;
- break;
- case '\xe1':
- offset = _aWithAcuteOffset;
- break;
- case '\xed':
- offset = _iWithAcuteOffset;
- break;
- case '\xf3':
- offset = _oWithAcuteOffset;
- break;
- case '\xfa':
- offset = _uWithAcuteOffset;
- break;
- case '\xdf':
- offset = _eszettOffset;
- break;
- case '\x92':
- if (g_nancy->getGameType() == kGameTypeNancy4) {
- // Improvement: we fix a specific broken string in nancy4 ("It's too dark..." when entering a dark staircase)
- offset = _apostropheOffset;
- } else {
+ if ((uint8)chr > 127) {
+ bool selectedRussian = false;
+ if (g_nancy->getGameType() >= kGameTypeNancy5 && g_nancy->getGameType() != kGameTypeNancy6 && g_nancy->getGameLanguage() == Common::RU_RUS) {
+ // Handle Russian strings in nancy5 and up, which use Windows-1251 encoding
+ // (except for nancy6, which goes back to latinizing russian)
+ // We cannot rely on isUpper/isLower, since they use the C locale settings
+ if ((uint8)chr >= 0xC0 && (uint8)chr <= 0xDF) {
+ // capital letters
+ offset = (uint8)chr + _cyrillicUppercaseOffset - 0xC0;
+ selectedRussian = true;
+ } else if ((uint8)chr >= 0xE0) {
+ offset = (uint8)chr + _cyrillicLowercaseOffset - 0xE0;
+ selectedRussian = true;
+ }
+ }
+
+ if (!selectedRussian) {
+ // Nancy6 introduced extended ASCII characters
+ switch (chr) {
+ case '\xe0':
+ offset = _aWithGraveOffset;
+ break;
+ case '\xe7':
+ offset = _cWithCedillaOffset;
+ break;
+ case '\xe8':
+ offset = _eWithGraveOffset;
+ break;
+ case '\xe9':
+ offset = _eWithAcuteOffset;
+ break;
+ case '\xea':
+ offset = _eWithCircumflexOffset;
+ break;
+ case '\xeb':
+ offset = _eWithDiaeresisOffset;
+ break;
+ case '\xf4':
+ offset = _oWithCircumflexOffset;
+ break;
+ case '\xc0':
+ offset = _uppercaseAWithGraveOffset;
+ break;
+ case '\xe2':
+ offset = _aWithCircumflexOffset;
+ break;
+ case '\xee':
+ offset = _iWithCircumflexOffset;
+ break;
+ case '\xf9':
+ offset = _uWithGraveOffset;
+ break;
+ case '\xc4':
+ offset = _uppercaseAWithDiaeresisOffset;
+ break;
+ case '\xe4':
+ offset = _aWithDiaeresisOffset;
+ break;
+ case '\xd6':
+ offset = _uppercaseOWithDiaeresisOffset;
+ break;
+ case '\xf6':
+ offset = _oWithDiaeresisOffset;
+ break;
+ case '\xdc':
+ offset = _uppercaseUWithDiaeresisOffset;
+ break;
+ case '\xfc':
+ offset = _uWithDiaeresisOffset;
+ break;
+ case '\xa1':
+ offset = _invertedExclamationMarkOffset;
+ break;
+ case '\xbf':
+ offset = _invertedQuestionMarkOffset;
+ break;
+ case '\xd1':
+ offset = _uppercaseNWithTildeOffset;
+ break;
+ case '\xf1':
+ offset = _nWithTildeOffset;
+ break;
+ case '\xc9':
+ offset = _uppercaseEWithAcuteOffset;
+ break;
+ case '\xe1':
+ offset = _aWithAcuteOffset;
+ break;
+ case '\xed':
+ offset = _iWithAcuteOffset;
+ break;
+ case '\xf3':
+ offset = _oWithAcuteOffset;
+ break;
+ case '\xfa':
+ offset = _uWithAcuteOffset;
+ break;
+ case '\xdf':
+ offset = _eszettOffset;
+ break;
+ case '\x92':
+ if (g_nancy->getGameType() == kGameTypeNancy4) {
+ // Improvement: we fix a specific broken string in nancy4 ("It's too dark..." when entering a dark staircase)
+ offset = _apostropheOffset;
+ } else {
+ offset = -1;
+ }
+ break;
+ default:
offset = -1;
+ break;
}
- break;
- default:
- offset = -1;
- break;
}
} else if (isUpper(chr)) {
offset = chr + _uppercaseOffset - 0x41;
diff --git a/engines/nancy/font.h b/engines/nancy/font.h
index b3d8dfdba08..55e526e23f2 100644
--- a/engines/nancy/font.h
+++ b/engines/nancy/font.h
@@ -83,6 +83,11 @@ private:
uint16 _semicolonOffset = 0;
uint16 _slashOffset = 0;
+ // Specific offsets for Cyrillic characters. Introduced in nancy5, only used in Russian variants
+ // The original data references the letters one by one, out of order. We only keep the two offsets below
+ int16 _cyrillicUppercaseOffset = -1;
+ int16 _cyrillicLowercaseOffset = -1;
+
// More specific offsets for extended ASCII characters. Introduced in nancy6
int16 _aWithGraveOffset = -1;
int16 _cWithCedillaOffset = -1;
diff --git a/engines/nancy/nancy.cpp b/engines/nancy/nancy.cpp
index e10a394cff8..8558cee9541 100644
--- a/engines/nancy/nancy.cpp
+++ b/engines/nancy/nancy.cpp
@@ -183,6 +183,10 @@ GameType NancyEngine::getGameType() const {
return _gameDescription->gameType;
}
+Common::Language NancyEngine::getGameLanguage() const {
+ return _gameDescription->desc.language;
+}
+
Common::Platform NancyEngine::getPlatform() const {
return _gameDescription->desc.platform;
}
diff --git a/engines/nancy/nancy.h b/engines/nancy/nancy.h
index 87847ed22e2..c20dcd506fe 100644
--- a/engines/nancy/nancy.h
+++ b/engines/nancy/nancy.h
@@ -93,6 +93,7 @@ public:
uint32 getGameFlags() const;
const char *getGameId() const;
GameType getGameType() const;
+ Common::Language getGameLanguage() const;
Common::Platform getPlatform() const;
const StaticData &getStaticData() const;
More information about the Scummvm-git-logs
mailing list