mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
This makes sure that the added field will be properly read when the minor version of nancy.dat is updated
652 lines
18 KiB
C++
652 lines
18 KiB
C++
/* 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/commontypes.h"
|
|
#include "engines/nancy/util.h"
|
|
#include "engines/nancy/nancy.h"
|
|
#include "engines/nancy/cif.h"
|
|
#include "engines/nancy/resource.h"
|
|
#include "engines/nancy/state/scene.h"
|
|
|
|
#include "common/memstream.h"
|
|
|
|
namespace Nancy {
|
|
|
|
void SceneChangeDescription::readData(Common::SeekableReadStream &stream, bool longFormat) {
|
|
sceneID = stream.readUint16LE();
|
|
frameID = stream.readUint16LE();
|
|
verticalOffset = stream.readUint16LE();
|
|
if (longFormat) {
|
|
paletteID = stream.readByte();
|
|
stream.skip(2);
|
|
}
|
|
|
|
continueSceneSound = stream.readUint16LE();
|
|
|
|
if (g_nancy->getGameType() >= kGameTypeNancy3) {
|
|
int32 x = stream.readSint32LE();
|
|
int32 y = stream.readSint32LE();
|
|
int32 z = stream.readSint32LE();
|
|
listenerFrontVector.set(x, y, z);
|
|
frontVectorFrameID = frameID;
|
|
}
|
|
}
|
|
|
|
void SceneChangeWithFlag::readData(Common::SeekableReadStream &stream, bool reverseFormat) {
|
|
_sceneChange.sceneID = stream.readUint16LE();
|
|
_sceneChange.frameID = stream.readUint16LE();
|
|
_sceneChange.verticalOffset = stream.readUint16LE();
|
|
_sceneChange.continueSceneSound = stream.readUint16LE();
|
|
|
|
if (reverseFormat) {
|
|
// NO shouldStopRendering
|
|
_flag.label = stream.readSint16LE();
|
|
_flag.flag = stream.readByte();
|
|
|
|
if (g_nancy->getGameType() >= kGameTypeNancy3) {
|
|
int32 x = stream.readSint32LE();
|
|
int32 y = stream.readSint32LE();
|
|
int32 z = stream.readSint32LE();
|
|
_sceneChange.listenerFrontVector.set(x, y, z);
|
|
_sceneChange.frontVectorFrameID = _sceneChange.frameID;
|
|
}
|
|
} else {
|
|
if (g_nancy->getGameType() >= kGameTypeNancy3) {
|
|
int32 x = stream.readSint32LE();
|
|
int32 y = stream.readSint32LE();
|
|
int32 z = stream.readSint32LE();
|
|
_sceneChange.listenerFrontVector.set(x, y, z);
|
|
_sceneChange.frontVectorFrameID = _sceneChange.frameID;
|
|
}
|
|
|
|
stream.skip(2); // shouldStopRendering
|
|
_flag.label = stream.readSint16LE();
|
|
_flag.flag = stream.readByte();
|
|
}
|
|
}
|
|
|
|
void SceneChangeWithFlag::execute() {
|
|
NancySceneState.changeScene(_sceneChange);
|
|
NancySceneState.setEventFlag(_flag);
|
|
}
|
|
|
|
void HotspotDescription::readData(Common::SeekableReadStream &stream) {
|
|
frameID = stream.readUint16LE();
|
|
readRect(stream, coords);
|
|
}
|
|
|
|
void FrameBlitDescription::readData(Common::SeekableReadStream &stream, bool longFormat) {
|
|
frameID = stream.readUint16LE();
|
|
|
|
if (longFormat) {
|
|
// In static mode Overlays, this is the id of the _srcRect to be used
|
|
staticRectID = stream.readUint16LE();
|
|
}
|
|
|
|
if (g_nancy->getGameType() >= kGameTypeNancy3 && longFormat) {
|
|
hasHotspot = stream.readUint16LE();
|
|
}
|
|
|
|
readRect(stream, src);
|
|
readRect(stream, dest);
|
|
}
|
|
|
|
void MultiEventFlagDescription::readData(Common::SeekableReadStream &stream) {
|
|
for (uint i = 0; i < 10; ++i) {
|
|
descs[i].label = stream.readSint16LE();
|
|
descs[i].flag = stream.readUint16LE();
|
|
}
|
|
}
|
|
|
|
void MultiEventFlagDescription::execute() {
|
|
for (uint i = 0; i < 10; ++i) {
|
|
NancySceneState.setEventFlag(descs[i]);
|
|
}
|
|
}
|
|
|
|
void SecondaryVideoDescription::readData(Common::SeekableReadStream &stream) {
|
|
frameID = stream.readUint16LE();
|
|
readRect(stream, srcRect);
|
|
readRect(stream, destRect);
|
|
stream.skip(0x20);
|
|
}
|
|
|
|
void SoundEffectDescription::readData(Common::SeekableReadStream &stream) {
|
|
minTimeDelay = stream.readUint32LE();
|
|
maxTimeDelay = stream.readUint32LE();
|
|
|
|
randomMoveMinX = stream.readSint32LE();
|
|
randomMoveMaxX = stream.readSint32LE();
|
|
randomMoveMinY = stream.readSint32LE();
|
|
randomMoveMaxY = stream.readSint32LE();
|
|
randomMoveMinZ = stream.readSint32LE();
|
|
randomMoveMaxZ = stream.readSint32LE();
|
|
|
|
fixedPosX = stream.readSint32LE();
|
|
fixedPosY = stream.readSint32LE();
|
|
fixedPosZ = stream.readSint32LE();
|
|
|
|
moveStepTime = stream.readUint32LE();
|
|
numMoveSteps = stream.readSint32LE();
|
|
|
|
linearMoveStartX = stream.readSint32LE();
|
|
linearMoveEndX = stream.readSint32LE();
|
|
linearMoveStartY = stream.readSint32LE();
|
|
linearMoveEndY = stream.readSint32LE();
|
|
linearMoveStartZ = stream.readSint32LE();
|
|
linearMoveEndX = stream.readSint32LE();
|
|
|
|
rotateMoveStartX = stream.readSint32LE();
|
|
rotateMoveStartY = stream.readSint32LE();
|
|
rotateMoveStartZ = stream.readSint32LE();
|
|
rotateMoveAxis = stream.readByte();
|
|
|
|
minDistance = stream.readUint32LE();
|
|
maxDistance = stream.readUint32LE();
|
|
}
|
|
|
|
void SoundDescription::readNormal(Common::SeekableReadStream &stream) {
|
|
Common::Serializer s(&stream, nullptr);
|
|
s.setVersion(g_nancy->getGameType());
|
|
|
|
readFilename(s, name);
|
|
|
|
s.syncAsUint16LE(channelID);
|
|
|
|
s.skip(2); // PLAY_SOUND_FROM_HD = 1, PLAY_SOUND_FROM_CDROM = 2
|
|
s.skip(2); // PLAY_SOUND_AS_DIGI = 1, PLAY_SOUND_AS_STREAM = 2
|
|
s.syncAsUint16LE(playCommands);
|
|
|
|
s.skip(2, kGameTypeVampire, kGameTypeNancy2);
|
|
|
|
s.syncAsUint32LE(numLoops);
|
|
|
|
s.skip(2, kGameTypeVampire, kGameTypeNancy2);
|
|
|
|
s.syncAsUint16LE(volume);
|
|
s.skip(2); // Second volume, always (?) same as the first
|
|
|
|
s.skip(4, kGameTypeVampire, kGameTypeNancy1); // Prior to nancy2 this field was used for something else
|
|
s.syncAsUint32LE(samplesPerSec, kGameTypeNancy2, kGameTypeNancy2);
|
|
}
|
|
|
|
void SoundDescription::readDIGI(Common::SeekableReadStream &stream) {
|
|
Common::Serializer s(&stream, nullptr);
|
|
s.setVersion(g_nancy->getGameType());
|
|
|
|
readFilename(s, name);
|
|
|
|
s.syncAsUint16LE(channelID);
|
|
|
|
s.skip(2); // PLAY_SOUND_FROM_HD = 1, PLAY_SOUND_FROM_CDROM = 2
|
|
s.skip(2, kGameTypeVampire, kGameTypeVampire);
|
|
s.syncAsUint16LE(playCommands, kGameTypeNancy1);
|
|
|
|
s.syncAsUint32LE(numLoops);
|
|
|
|
s.skip(2, kGameTypeVampire, kGameTypeNancy2);
|
|
s.syncAsUint16LE(volume);
|
|
s.skip(2); // Second volume, always (?) same as the first
|
|
|
|
s.syncAsUint16LE(panAnchorFrame, kGameTypeVampire, kGameTypeNancy2);
|
|
s.skip(2, kGameTypeVampire, kGameTypeNancy2);
|
|
}
|
|
|
|
void SoundDescription::readMenu(Common::SeekableReadStream &stream) {
|
|
Common::Serializer s(&stream, nullptr);
|
|
s.setVersion(g_nancy->getGameType());
|
|
|
|
readFilename(s, name);
|
|
|
|
s.syncAsUint16LE(channelID);
|
|
|
|
s.skip(2); // PLAY_SOUND_FROM_HD = 1, PLAY_SOUND_FROM_CDROM = 2
|
|
s.skip(2); // PLAY_SOUND_AS_DIGI = 1, PLAY_SOUND_AS_STREAM = 2
|
|
|
|
s.skip(2, kGameTypeVampire, kGameTypeNancy2);
|
|
|
|
s.syncAsUint32LE(numLoops);
|
|
|
|
s.skip(2, kGameTypeVampire, kGameTypeNancy2);
|
|
|
|
s.syncAsUint16LE(volume);
|
|
s.skip(2); // Second volume, always (?) same as the first
|
|
|
|
s.skip(4, kGameTypeVampire, kGameTypeNancy2);
|
|
}
|
|
|
|
void SoundDescription::readScene(Common::SeekableReadStream &stream) {
|
|
Common::Serializer s(&stream, nullptr);
|
|
s.setVersion(g_nancy->getGameType());
|
|
|
|
readFilename(s, name);
|
|
|
|
s.skip(2); // PLAY_SOUND_FROM_HD = 1, PLAY_SOUND_FROM_CDROM = 2
|
|
s.skip(2); // PLAY_SOUND_AS_DIGI = 1, PLAY_SOUND_AS_STREAM = 2
|
|
|
|
s.syncAsUint16LE(channelID);
|
|
s.syncAsUint16LE(playCommands);
|
|
|
|
s.skip(2, kGameTypeVampire, kGameTypeNancy2);
|
|
|
|
s.syncAsUint32LE(numLoops);
|
|
|
|
s.skip(2, kGameTypeVampire, kGameTypeNancy2);
|
|
|
|
s.syncAsUint16LE(volume);
|
|
s.skip(2); // Second volume, always (?) same as the first
|
|
s.skip(2, kGameTypeVampire, kGameTypeNancy2);
|
|
s.skip(4, kGameTypeVampire, kGameTypeNancy2); // Panning, always? at center
|
|
s.syncAsUint32LE(samplesPerSec, kGameTypeVampire, kGameTypeNancy2);
|
|
}
|
|
|
|
void SoundDescription::readTerse(Common::SeekableReadStream &stream) {
|
|
readFilename(stream, name);
|
|
channelID = stream.readUint16LE();
|
|
numLoops = stream.readUint32LE();
|
|
volume = stream.readUint16LE();
|
|
stream.skip(2);
|
|
}
|
|
|
|
void ConditionalDialogue::readData(Common::SeekableReadStream &stream) {
|
|
textID = stream.readByte();
|
|
sceneID = stream.readUint16LE();
|
|
soundID = stream.readString();
|
|
|
|
uint16 num = stream.readUint16LE();
|
|
conditions.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
conditions[i].type = stream.readByte();
|
|
conditions[i].label = stream.readSint16LE();
|
|
conditions[i].flag = stream.readByte();
|
|
}
|
|
}
|
|
|
|
void GoodbyeSceneChange::readData(Common::SeekableReadStream &stream) {
|
|
uint16 num = stream.readUint16LE();
|
|
sceneIDs.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
sceneIDs[i] = stream.readSint16LE();
|
|
}
|
|
|
|
num = stream.readUint16LE();
|
|
conditions.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
conditions[i].type = stream.readByte();
|
|
conditions[i].label = stream.readSint16LE();
|
|
conditions[i].flag = stream.readByte();
|
|
}
|
|
|
|
flagToSet.type = stream.readByte();
|
|
flagToSet.label = stream.readSint16LE();
|
|
flagToSet.flag = stream.readByte();
|
|
}
|
|
|
|
void Goodbye::readData(Common::SeekableReadStream &stream) {
|
|
soundID = stream.readString();
|
|
|
|
uint16 num = stream.readUint16LE();
|
|
sceneChanges.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
sceneChanges[i].readData(stream);
|
|
}
|
|
}
|
|
|
|
void Hint::readData(Common::SeekableReadStream &stream) {
|
|
textID = stream.readByte();
|
|
hintWeight = stream.readSint16LE();
|
|
soundIDs[0] = stream.readString();
|
|
soundIDs[1] = stream.readString();
|
|
soundIDs[2] = stream.readString();
|
|
|
|
uint16 num = stream.readUint16LE();
|
|
conditions.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
conditions[i].type = stream.readByte();
|
|
conditions[i].label = stream.readSint16LE();
|
|
conditions[i].flag = stream.readByte();
|
|
}
|
|
}
|
|
|
|
void SoundChannelInfo::readData(Common::SeekableReadStream &stream) {
|
|
numChannels = stream.readByte();
|
|
numSceneSpecificChannels = stream.readByte();
|
|
|
|
uint16 num = stream.readUint16LE();
|
|
speechChannels.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
speechChannels[i] = stream.readByte();
|
|
}
|
|
|
|
num = stream.readUint16LE();
|
|
musicChannels.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
musicChannels[i] = stream.readByte();
|
|
}
|
|
|
|
num = stream.readUint16LE();
|
|
sfxChannels.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
sfxChannels[i] = stream.readByte();
|
|
}
|
|
}
|
|
|
|
void StaticData::readData(Common::SeekableReadStream &stream, Common::Language language, uint32 endPos, int8 majorVersion, int8 minorVersion) {
|
|
uint16 num = 0;
|
|
int languageID = -1;
|
|
|
|
// Used for patch file reading
|
|
byte *patchBuf = nullptr;
|
|
uint32 patchBufSize = 0;
|
|
Common::Array<Common::Array<Common::String>> confManProps;
|
|
Common::Array<Common::Array<Common::Path>> fileIDs;
|
|
|
|
while (stream.pos() < endPos) {
|
|
uint32 nextSectionOffset = stream.readUint32LE();
|
|
|
|
switch(stream.readUint32LE()) {
|
|
case MKTAG('C', 'O', 'N', 'S') :
|
|
// Game constants
|
|
numItems = stream.readUint16LE();
|
|
numEventFlags = stream.readUint16LE();
|
|
|
|
// TODO remove once updated nancy.dat is pushed
|
|
if (minorVersion == 0) {
|
|
num = stream.readUint16LE();
|
|
mapAccessSceneIDs.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
mapAccessSceneIDs[i] = stream.readUint16LE();
|
|
}
|
|
}
|
|
|
|
num = stream.readUint16LE();
|
|
genericEventFlags.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
genericEventFlags[i] = stream.readUint16LE();
|
|
}
|
|
|
|
numCursorTypes = stream.readUint16LE();
|
|
if (minorVersion == 0) {
|
|
// TODO remove once updated nancy.dat is pushed
|
|
numCursorTypes /= (g_nancy->getGameType() == kGameTypeVampire ? 2 : 3);
|
|
stream.skip(2);
|
|
}
|
|
|
|
logoEndAfter = stream.readUint32LE();
|
|
if (minorVersion >= 1) {
|
|
wonGameFlagID = stream.readUint16LE();
|
|
}
|
|
|
|
break;
|
|
case MKTAG('M', 'A', 'P', 'A') :
|
|
num = stream.readUint16LE();
|
|
mapAccessSceneIDs.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
mapAccessSceneIDs[i] = stream.readUint16LE();
|
|
}
|
|
|
|
break;
|
|
case MKTAG('S', 'C', 'H', 'N') :
|
|
// Sound channels data
|
|
soundChannelInfo.readData(stream);
|
|
|
|
break;
|
|
case MKTAG('L', 'A', 'N', 'G') :
|
|
// Not used anymore
|
|
num = stream.readUint16LE();
|
|
languageID = -1;
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
if (stream.readByte() == language) {
|
|
languageID = i;
|
|
}
|
|
}
|
|
|
|
if (languageID == -1) {
|
|
error("Language not present in nancy.dat");
|
|
}
|
|
|
|
break;
|
|
case MKTAG('L', 'A', 'N', '2') : {
|
|
// Order of languages inside game data
|
|
enum GameLanguage : byte { kEnglish = 0, kRussian = 1, kGerman = 2, kFrench = 3 };
|
|
|
|
num = stream.readUint16LE();
|
|
languageID = -1;
|
|
GameLanguage expectedLang = kEnglish;
|
|
switch (language) {
|
|
case Common::Language::EN_ANY:
|
|
languageID = kEnglish;
|
|
break;
|
|
case Common::Language::RU_RUS:
|
|
languageID = kRussian;
|
|
break;
|
|
case Common::Language::DE_DEU:
|
|
languageID = kGerman;
|
|
break;
|
|
case Common::Language::FR_FRA:
|
|
languageID = kFrench;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
if (stream.readByte() == expectedLang) {
|
|
languageID = expectedLang;
|
|
}
|
|
}
|
|
|
|
if (languageID == -1) {
|
|
error("Language not present in nancy.dat");
|
|
}
|
|
|
|
break;
|
|
}
|
|
case MKTAG('C', 'D', 'L', 'G') :
|
|
// Conditional dialogue
|
|
num = stream.readUint16LE();
|
|
conditionalDialogue.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
uint16 num2 = stream.readUint16LE();
|
|
conditionalDialogue[i].resize(num2);
|
|
for (uint j = 0; j < num2; ++j) {
|
|
conditionalDialogue[i][j].readData(stream);
|
|
}
|
|
}
|
|
|
|
num = stream.readUint16LE();
|
|
if (num > 0) {
|
|
uint32 endOffset = stream.readUint32LE();
|
|
stream.skip(languageID * 4);
|
|
stream.seek(stream.readUint32LE());
|
|
num = stream.readUint16LE();
|
|
conditionalDialogueTexts.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
conditionalDialogueTexts[i] = stream.readString();
|
|
}
|
|
|
|
stream.seek(endOffset);
|
|
}
|
|
|
|
break;
|
|
case MKTAG('C', 'D', 'L', '2') :
|
|
// Conditional dialogue, no strings (nancy6 and up)
|
|
num = stream.readUint16LE();
|
|
conditionalDialogue.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
uint16 num2 = stream.readUint16LE();
|
|
conditionalDialogue[i].resize(num2);
|
|
for (uint j = 0; j < num2; ++j) {
|
|
conditionalDialogue[i][j].readData(stream);
|
|
}
|
|
}
|
|
|
|
break;
|
|
case MKTAG('G', 'D', 'B', 'Y') :
|
|
// Goodbyes
|
|
num = stream.readUint16LE();
|
|
goodbyes.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
goodbyes[i].readData(stream);
|
|
}
|
|
|
|
num = stream.readUint16LE();
|
|
if (num > 0) {
|
|
uint32 endOffset = stream.readUint32LE();
|
|
stream.skip(languageID * 4);
|
|
stream.seek(stream.readUint32LE());
|
|
num = stream.readUint16LE();
|
|
goodbyeTexts.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
goodbyeTexts[i] = stream.readString();
|
|
}
|
|
|
|
stream.seek(endOffset);
|
|
}
|
|
|
|
break;
|
|
case MKTAG('G', 'D', 'B', '2') :
|
|
// Goodbyes, no strings (nancy6 and up)
|
|
num = stream.readUint16LE();
|
|
goodbyes.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
goodbyes[i].readData(stream);
|
|
}
|
|
|
|
break;
|
|
case MKTAG('H', 'I', 'N', 'T') : {
|
|
// Hints (nancy1 only)
|
|
SceneChangeDescription sceneChange;
|
|
sceneChange.readData(stream, false);
|
|
|
|
num = stream.readUint16LE();
|
|
hints.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
uint16 num2 = stream.readUint16LE();
|
|
hints[i].resize(num2);
|
|
for (uint j = 0; j < num2; ++j) {
|
|
hints[i][j].readData(stream);
|
|
hints[i][j].sceneChange = sceneChange;
|
|
}
|
|
}
|
|
|
|
num = stream.readUint16LE();
|
|
if (num > 0) {
|
|
uint32 endOffset = stream.readUint32LE();
|
|
stream.skip(languageID * 4);
|
|
stream.seek(stream.readUint32LE());
|
|
num = stream.readUint16LE();
|
|
hintTexts.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
hintTexts[i] = stream.readString();
|
|
}
|
|
|
|
stream.seek(endOffset);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case MKTAG('R', 'I', 'N', 'G') :
|
|
// Ringing text (nancy1 and up)
|
|
num = stream.readUint16LE();
|
|
for (int i = 0; i < num; ++i) {
|
|
if (i == languageID) {
|
|
ringingText = stream.readString();
|
|
} else {
|
|
stream.readString();
|
|
}
|
|
}
|
|
|
|
break;
|
|
case MKTAG('E', 'S', 'A', 'V') :
|
|
num = stream.readUint16LE();
|
|
for (int i = 0; i < num; ++i) {
|
|
if (i == languageID) {
|
|
emptySaveText = stream.readString();
|
|
} else {
|
|
stream.readString();
|
|
}
|
|
}
|
|
|
|
break;
|
|
case MKTAG('E', 'F', 'L', 'G') :
|
|
// Event flag names
|
|
num = stream.readUint16LE();
|
|
eventFlagNames.resize(num);
|
|
for (uint16 i = 0; i < num; ++i) {
|
|
eventFlagNames[i] = stream.readString();
|
|
}
|
|
|
|
break;
|
|
case MKTAG('P', 'A', 'T', 'C') :
|
|
// Patch file
|
|
patchBufSize = nextSectionOffset - stream.pos();
|
|
patchBuf = (byte *)malloc(patchBufSize);
|
|
stream.read(patchBuf, patchBufSize);
|
|
break;
|
|
case MKTAG('P', 'A', 'S', 'S') :
|
|
// Patch file <-> ConfMan entries associations
|
|
num = stream.readUint16LE();
|
|
confManProps.resize(num);
|
|
fileIDs.resize(num);
|
|
for (uint i = 0; i < num; ++i) {
|
|
// 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] = Common::Path(stream.readString());
|
|
}
|
|
}
|
|
|
|
break;
|
|
default:
|
|
stream.seek(nextSectionOffset);
|
|
}
|
|
}
|
|
|
|
if (patchBuf) {
|
|
// Load the patch tree into the ResourceManager
|
|
Common::MemoryReadStream *patchStream = new Common::MemoryReadStream(patchBuf, patchBufSize, DisposeAfterUse::YES);
|
|
PatchTree *tree = g_nancy->_resource->readPatchTree(patchStream, "patchtree", 2);
|
|
assert(tree);
|
|
|
|
// Write the ConfMan associations
|
|
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]});
|
|
}
|
|
}
|
|
}
|
|
|
|
} // End of namespace Nancy
|