mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-12 06:00:48 +00:00
821 lines
25 KiB
C++
821 lines
25 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/enginedata.h"
|
|
#include "engines/nancy/nancy.h"
|
|
#include "engines/nancy/util.h"
|
|
#include "engines/nancy/graphics.h"
|
|
|
|
#include "common/serializer.h"
|
|
|
|
namespace Nancy {
|
|
|
|
EngineData::EngineData(Common::SeekableReadStream *chunkStream) {
|
|
assert(chunkStream);
|
|
chunkStream->seek(0);
|
|
}
|
|
|
|
BSUM::BSUM(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
Common::Serializer s(chunkStream, nullptr);
|
|
s.setVersion(g_nancy->getGameType());
|
|
|
|
// The header is used to verify savegames
|
|
s.syncBytes(header, 90);
|
|
|
|
s.skip(0x17, kGameTypeVampire, kGameTypeVampire);
|
|
s.skip(0x49, kGameTypeNancy1, kGameTypeNancy1);
|
|
s.skip(0x43, kGameTypeNancy2);
|
|
|
|
readFilename(s, conversationTextsFilename, kGameTypeNancy6);
|
|
readFilename(s, autotextFilename, kGameTypeNancy6);
|
|
|
|
s.syncAsUint16LE(firstScene.sceneID);
|
|
s.skip(0xC, kGameTypeVampire, kGameTypeVampire); // Palette name + unknown 2 bytes
|
|
s.syncAsUint16LE(firstScene.frameID);
|
|
s.syncAsUint16LE(firstScene.verticalOffset);
|
|
s.syncAsUint16LE(startTimeHours);
|
|
s.syncAsUint16LE(startTimeMinutes);
|
|
|
|
s.syncAsUint16LE(adScene.sceneID, kGameTypeNancy7);
|
|
s.syncAsUint16LE(adScene.frameID, kGameTypeNancy7);
|
|
s.syncAsUint16LE(adScene.verticalOffset, kGameTypeNancy7);
|
|
|
|
s.skip(0xA4, kGameTypeVampire, kGameTypeNancy2);
|
|
s.skip(3); // Number of object, frame, and logo images
|
|
if (g_nancy->getEngineData("PLG0")) {
|
|
// Parner logos were introduced with nancy4, but at least one nancy3 release
|
|
// had one as well. For some reason they didn't port over the code from the
|
|
// later games, but implemented it the same way the other BSUM images work.
|
|
// Hence, we skip an extra byte indicating the number of partner logos.
|
|
s.skip(1);
|
|
}
|
|
|
|
s.skip(8, kGameTypeVampire, kGameTypeVampire);
|
|
readRect(s, extraButtonHotspot, kGameTypeVampire, kGameTypeVampire);
|
|
readRect(s, extraButtonHotspot, kGameTypeNancy2);
|
|
readRect(s, extraButtonHighlightDest, kGameTypeNancy1);
|
|
s.skip(0x10, kGameTypeVampire, kGameTypeVampire);
|
|
readRect(s, textboxScreenPosition);
|
|
readRect(s, inventoryBoxScreenPosition);
|
|
readRect(s, menuButtonSrc);
|
|
readRect(s, helpButtonSrc);
|
|
readRect(s, menuButtonDest);
|
|
readRect(s, helpButtonDest);
|
|
readRect(s, menuButtonHighlightSrc, kGameTypeNancy2);
|
|
readRect(s, helpButtonHighlightSrc, kGameTypeNancy2);
|
|
readRect(s, clockHighlightSrc, kGameTypeNancy2);
|
|
|
|
s.skip(0x2, kGameTypeVampire, kGameTypeVampire);
|
|
s.syncAsByte(paletteTrans, kGameTypeVampire, kGameTypeVampire);
|
|
s.skip(0x2, kGameTypeVampire, kGameTypeVampire);
|
|
s.syncAsByte(rTrans);
|
|
s.syncAsByte(gTrans);
|
|
s.syncAsByte(bTrans);
|
|
s.skip(6); // Black and white
|
|
|
|
s.syncAsUint16LE(horizontalEdgesSize);
|
|
s.syncAsUint16LE(verticalEdgesSize);
|
|
|
|
s.syncAsUint16LE(numFonts);
|
|
|
|
// Skip data for debug features (diagnostics, version...)
|
|
s.skip(0x18, kGameTypeVampire, kGameTypeVampire);
|
|
s.skip(0x1A, kGameTypeNancy1);
|
|
|
|
s.syncAsSint16LE(playerTimeMinuteLength);
|
|
s.syncAsUint16LE(buttonPressTimeDelay);
|
|
s.syncAsUint16LE(dayStartMinutes, kGameTypeNancy6);
|
|
s.syncAsUint16LE(dayEndMinutes, kGameTypeNancy6);
|
|
s.syncAsByte(overrideMovementTimeDeltas);
|
|
s.syncAsSint16LE(slowMovementTimeDelta);
|
|
s.syncAsSint16LE(fastMovementTimeDelta);
|
|
}
|
|
|
|
VIEW::VIEW(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
readRect(*chunkStream, screenPosition);
|
|
readRect(*chunkStream, bounds);
|
|
}
|
|
|
|
PCAL::PCAL(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
uint num = chunkStream->readUint16LE();
|
|
readFilenameArray(*chunkStream, calNames, num);
|
|
}
|
|
|
|
INV::INV(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
Common::Serializer s(chunkStream, nullptr);
|
|
s.setVersion(g_nancy->getGameType());
|
|
|
|
readRect(*chunkStream, scrollbarSrcBounds);
|
|
s.syncAsUint16LE(scrollbarDefaultPos.x);
|
|
s.syncAsUint16LE(scrollbarDefaultPos.y);
|
|
s.syncAsUint16LE(scrollbarMaxScroll);
|
|
|
|
readRectArray(s, ornamentSrcs, 6, 6, kGameTypeVampire, kGameTypeNancy1);
|
|
readRectArray(s, ornamentDests, 6, 6, kGameTypeVampire, kGameTypeNancy1);
|
|
|
|
uint numFrames = g_nancy->getGameType() == kGameTypeVampire ? 10 : 7;
|
|
|
|
readRectArray(s, curtainAnimationSrcs, numFrames * 2);
|
|
|
|
readRect(s, curtainsScreenPosition);
|
|
s.syncAsUint16LE(curtainsFrameTime);
|
|
|
|
s.syncAsUint16LE(captionAutoClearTime, kGameTypeNancy3);
|
|
|
|
readFilename(s, inventoryBoxIconsImageName);
|
|
readFilename(s, inventoryCursorsImageName);
|
|
|
|
s.skip(0x4, kGameTypeVampire, kGameTypeNancy1); // inventory box icons surface w/h
|
|
s.skip(0x4, kGameTypeVampire, kGameTypeNancy1); // inventory cursors surface w/h
|
|
|
|
s.skip(0x10); // unknown rect, same size as a hotspot
|
|
|
|
byte textBuf[60];
|
|
|
|
if (s.getVersion() >= kGameTypeNancy2) {
|
|
cantSound.readNormal(*chunkStream);
|
|
s.syncBytes(textBuf, 60);
|
|
textBuf[59] = '\0';
|
|
cantText = (char *)textBuf;
|
|
}
|
|
|
|
uint itemNameLength;
|
|
switch (s.getVersion()) {
|
|
case kGameTypeVampire :
|
|
itemNameLength = 15;
|
|
break;
|
|
case kGameTypeNancy1 :
|
|
itemNameLength = 20;
|
|
break;
|
|
case kGameTypeNancy2 :
|
|
// fall through
|
|
default:
|
|
itemNameLength = 48;
|
|
break;
|
|
}
|
|
|
|
uint16 numItems = g_nancy->getStaticData().numItems;
|
|
itemDescriptions.resize(numItems);
|
|
for (uint i = 0; i < numItems; ++i) {
|
|
ItemDescription &item = itemDescriptions[i];
|
|
|
|
s.syncBytes(textBuf, itemNameLength);
|
|
textBuf[itemNameLength - 1] = '\0';
|
|
item.name = (char *)textBuf;
|
|
|
|
s.syncAsUint16LE(item.keepItem);
|
|
s.syncAsUint16LE(item.sceneID, kGameTypeNancy7);
|
|
s.syncAsUint16LE(item.sceneSoundFlag, kGameTypeNancy7);
|
|
readRect(s, item.sourceRect);
|
|
readRect(s, item.highlightedSourceRect, kGameTypeNancy2);
|
|
|
|
if (s.getVersion() == kGameTypeNancy2) {
|
|
s.syncBytes(textBuf, 60);
|
|
textBuf[59] = '\0';
|
|
assembleTextLine((char *)textBuf, item.cantText, 60);
|
|
|
|
s.syncBytes(textBuf, 60);
|
|
textBuf[59] = '\0';
|
|
assembleTextLine((char *)textBuf, item.cantTextNotHolding, 60);
|
|
|
|
item.cantSound.readNormal(*chunkStream);
|
|
item.cantSoundNotHolding.readNormal(*chunkStream);
|
|
} else if (s.getVersion() >= kGameTypeNancy3) {
|
|
s.syncBytes(textBuf, 60);
|
|
textBuf[59] = '\0';
|
|
assembleTextLine((char *)textBuf, item.cantText, 60);
|
|
|
|
item.cantSound.readNormal(*chunkStream);
|
|
}
|
|
}
|
|
}
|
|
|
|
TBOX::TBOX(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
bool isVampire = g_nancy->getGameType() == Nancy::GameType::kGameTypeVampire;
|
|
|
|
readRect(*chunkStream, scrollbarSrcBounds);
|
|
|
|
chunkStream->seek(0x20);
|
|
readRect(*chunkStream, innerBoundingBox);
|
|
|
|
scrollbarDefaultPos.x = chunkStream->readUint16LE() - (isVampire ? 1 : 0);
|
|
scrollbarDefaultPos.y = chunkStream->readUint16LE();
|
|
scrollbarMaxScroll = chunkStream->readUint16LE();
|
|
|
|
upOffset = chunkStream->readUint16LE() + 1;
|
|
downOffset = chunkStream->readUint16LE();
|
|
leftOffset = chunkStream->readUint16LE() - 1;
|
|
rightOffset = chunkStream->readUint16LE();
|
|
|
|
readRectArray(*chunkStream, ornamentSrcs, 14);
|
|
readRectArray(*chunkStream, ornamentDests, 14);
|
|
|
|
defaultFontID = chunkStream->readUint16LE();
|
|
defaultTextColor = chunkStream->readUint16LE();
|
|
|
|
if (g_nancy->getGameType() >= kGameTypeNancy2) {
|
|
conversationFontID = chunkStream->readUint16LE();
|
|
highlightConversationFontID = chunkStream->readUint16LE();
|
|
} else {
|
|
conversationFontID = defaultFontID;
|
|
highlightConversationFontID = defaultFontID;
|
|
}
|
|
|
|
tabWidth = chunkStream->readUint16LE();
|
|
pageScrollPercent = chunkStream->readUint16LE(); // Not implemented yet
|
|
|
|
Graphics::PixelFormat format = g_nancy->_graphics->getInputPixelFormat();
|
|
if (g_nancy->getGameType() >= kGameTypeNancy2) {
|
|
byte r, g, b;
|
|
r = chunkStream->readByte();
|
|
g = chunkStream->readByte();
|
|
b = chunkStream->readByte();
|
|
|
|
textBackground = (r << format.rShift) |
|
|
(g << format.gShift) |
|
|
(b << format.bShift);
|
|
|
|
r = chunkStream->readByte();
|
|
g = chunkStream->readByte();
|
|
b = chunkStream->readByte();
|
|
|
|
highlightTextBackground = (r << format.rShift) |
|
|
(g << format.gShift) |
|
|
(b << format.bShift);
|
|
} else {
|
|
textBackground = highlightTextBackground = 0;
|
|
}
|
|
}
|
|
|
|
MAP::MAP(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
Common::Serializer s(chunkStream, nullptr);
|
|
s.setVersion(g_nancy->getGameType());
|
|
uint numLocations = s.getVersion() == kGameTypeVampire ? 7 : 4;
|
|
uint numMaps = s.getVersion() == kGameTypeVampire ? 4 : 2;
|
|
|
|
readFilenameArray(s, mapNames, numMaps);
|
|
readFilenameArray(s, mapPaletteNames, numMaps, kGameTypeVampire, kGameTypeVampire);
|
|
|
|
s.skip(4);
|
|
|
|
sounds.resize(numMaps);
|
|
for (uint i = 0; i < numMaps; ++i) {
|
|
sounds[i].readMenu(*chunkStream);
|
|
}
|
|
|
|
s.skip(0x20);
|
|
|
|
s.syncAsUint16LE(globeFrameTime, kGameTypeVampire, kGameTypeVampire);
|
|
readRectArray(s, globeSrcs, 8, 8, kGameTypeVampire, kGameTypeVampire);
|
|
readRect(s, globeDest, kGameTypeVampire, kGameTypeVampire);
|
|
|
|
s.skip(2, kGameTypeNancy1);
|
|
readRect(s, buttonSrc, kGameTypeNancy1);
|
|
readRect(s, buttonDest, kGameTypeNancy1);
|
|
|
|
locations.resize(numLocations);
|
|
|
|
for (uint i = 0; i < numLocations; ++i) {
|
|
readRect(*chunkStream, locations[i].labelSrc);
|
|
}
|
|
|
|
readRect(s, closedLabelSrc);
|
|
|
|
readRect(s, globeGargoyleSrc, kGameTypeVampire, kGameTypeVampire);
|
|
readRect(s, globeGargoyleDest, kGameTypeVampire, kGameTypeVampire);
|
|
|
|
char buf[30];
|
|
|
|
for (uint i = 0; i < numLocations; ++i) {
|
|
s.syncBytes((byte *)buf, 30);
|
|
buf[29] = '\0';
|
|
locations[i].description = buf;
|
|
}
|
|
|
|
for (uint i = 0; i < numLocations; ++i) {
|
|
readRect(*chunkStream, locations[i].hotspot);
|
|
}
|
|
|
|
s.skip(numLocations * 2);
|
|
s.skip(0x10);
|
|
|
|
s.syncAsUint16LE(cursorPosition.x);
|
|
s.syncAsUint16LE(cursorPosition.y);
|
|
|
|
for (uint j = 0; j < 2; ++j) {
|
|
for (uint i = 0; i < numLocations; ++i) {
|
|
SceneChangeDescription &sc = locations[i].scenes[j];
|
|
s.syncAsUint16LE(sc.sceneID);
|
|
s.syncAsUint16LE(sc.frameID);
|
|
s.syncAsUint16LE(sc.verticalOffset);
|
|
s.syncAsUint16LE(sc.paletteID, kGameTypeVampire, kGameTypeVampire);
|
|
}
|
|
}
|
|
}
|
|
|
|
HELP::HELP(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
readFilename(*chunkStream, imageName);
|
|
chunkStream->skip(20);
|
|
|
|
if (g_nancy->getGameType() <= kGameTypeNancy1) {
|
|
buttonDest.left = chunkStream->readUint16LE();
|
|
buttonDest.top = chunkStream->readUint16LE();
|
|
buttonDest.right = chunkStream->readUint16LE();
|
|
buttonDest.bottom = chunkStream->readUint16LE();
|
|
buttonSrc.left = chunkStream->readUint16LE();
|
|
buttonSrc.top = chunkStream->readUint16LE();
|
|
buttonSrc.right = chunkStream->readUint16LE();
|
|
buttonSrc.bottom = chunkStream->readUint16LE();
|
|
} else {
|
|
readRect(*chunkStream, buttonDest);
|
|
readRect(*chunkStream, buttonSrc);
|
|
readRect(*chunkStream, buttonHoverSrc);
|
|
}
|
|
}
|
|
|
|
CRED::CRED(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
bool isVampire = g_nancy->getGameType() == kGameTypeVampire;
|
|
readFilename(*chunkStream, imageName);
|
|
|
|
textNames.resize(isVampire ? 7 : 1);
|
|
for (Common::Path &str : textNames) {
|
|
readFilename(*chunkStream, str);
|
|
}
|
|
|
|
chunkStream->skip(0x20);
|
|
readRect(*chunkStream, textScreenPosition);
|
|
chunkStream->skip(0x10);
|
|
|
|
updateTime = chunkStream->readUint16LE();
|
|
pixelsToScroll = chunkStream->readUint16LE();
|
|
sound.readMenu(*chunkStream);
|
|
}
|
|
|
|
MENU::MENU(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
Common::Serializer ser(chunkStream, nullptr);
|
|
ser.setVersion(g_nancy->getGameType());
|
|
readFilename(ser, _imageName);
|
|
|
|
ser.skip(22);
|
|
|
|
uint numOptions = g_nancy->getGameType() <= kGameTypeNancy6 ? 8 : 9;
|
|
|
|
readRectArray16(ser, _buttonDests, numOptions, numOptions, kGameTypeVampire, kGameTypeNancy1);
|
|
readRectArray16(ser, _buttonDownSrcs, numOptions, numOptions, kGameTypeVampire, kGameTypeNancy1);
|
|
|
|
readRectArray(ser, _buttonDests, numOptions, numOptions, kGameTypeNancy2);
|
|
readRectArray(ser, _buttonDownSrcs, numOptions, numOptions, kGameTypeNancy2);
|
|
readRectArray(ser, _buttonDisabledSrcs, numOptions, numOptions, kGameTypeNancy2);
|
|
readRectArray(ser, _buttonHighlightSrcs, numOptions, numOptions, kGameTypeNancy2);
|
|
}
|
|
|
|
SET::SET(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
readFilename(*chunkStream, _imageName);
|
|
chunkStream->skip(20); // image info
|
|
chunkStream->skip(16); // bounds for all scrollbars
|
|
|
|
uint numButtons;
|
|
if (g_nancy->getGameType() == kGameTypeVampire) {
|
|
numButtons = 5;
|
|
} else if (g_nancy->getGameType() <= kGameTypeNancy5) {
|
|
numButtons = 4;
|
|
} else {
|
|
numButtons = 3;
|
|
}
|
|
|
|
readRectArray(*chunkStream, _scrollbarBounds, 3);
|
|
readRectArray(*chunkStream, _buttonDests, numButtons);
|
|
readRectArray(*chunkStream, _buttonDownSrcs, numButtons);
|
|
|
|
if (g_nancy->getGameType() >= kGameTypeNancy2) {
|
|
readRect(*chunkStream, _doneButtonHighlightSrc);
|
|
}
|
|
|
|
readRectArray(*chunkStream, _scrollbarSrcs, 3);
|
|
|
|
_scrollbarsCenterYPos.resize(3);
|
|
_scrollbarsCenterXPosL.resize(3);
|
|
_scrollbarsCenterXPosR.resize(3);
|
|
for (uint i = 0; i < 3; ++i) {
|
|
_scrollbarsCenterYPos[i] = chunkStream->readUint16LE();
|
|
_scrollbarsCenterXPosL[i] = chunkStream->readUint16LE();
|
|
_scrollbarsCenterXPosR[i] = chunkStream->readUint16LE();
|
|
}
|
|
|
|
_sounds.resize(3);
|
|
for (uint i = 0; i < 3; ++i) {
|
|
_sounds[i].readMenu(*chunkStream);
|
|
}
|
|
}
|
|
|
|
LOAD::LOAD(Common::SeekableReadStream *chunkStream) :
|
|
EngineData(chunkStream),
|
|
_highlightFontID(-1),
|
|
_disabledFontID(-1),
|
|
_blinkingTimeDelay(0) {
|
|
Common::Serializer s(chunkStream, nullptr);
|
|
s.setVersion(g_nancy->getGameType());
|
|
|
|
if (s.getVersion() <= kGameTypeNancy7) {
|
|
// v1
|
|
readFilename(s, _image1Name);
|
|
|
|
s.skip(0x1F, kGameTypeVampire, kGameTypeVampire);
|
|
s.skip(0x23, kGameTypeNancy1);
|
|
s.skip(4);
|
|
|
|
s.syncAsSint16LE(_mainFontID);
|
|
s.syncAsSint16LE(_highlightFontID, kGameTypeNancy2);
|
|
s.syncAsSint16LE(_disabledFontID, kGameTypeNancy2);
|
|
s.syncAsSint16LE(_fontXOffset);
|
|
s.syncAsSint16LE(_fontYOffset);
|
|
|
|
s.skip(16);
|
|
|
|
if (s.getVersion() <= kGameTypeNancy1) {
|
|
readRectArray16(s, _saveButtonDests, 7);
|
|
readRectArray16(s, _loadButtonDests, 7);
|
|
readRectArray16(s, _textboxBounds, 7);
|
|
readRect16(s, _doneButtonDest);
|
|
readRectArray16(s, _saveButtonDownSrcs, 7);
|
|
readRectArray16(s, _loadButtonDownSrcs, 7);
|
|
s.skip(8 * 7);
|
|
readRect16(s, _doneButtonDownSrc);
|
|
readRect(s, _blinkingCursorSrc);
|
|
s.syncAsUint16LE(_blinkingTimeDelay, kGameTypeNancy1);
|
|
readRectArray(s, _cancelButtonSrcs, 7);
|
|
readRectArray(s, _cancelButtonDests, 7);
|
|
readRect(s, _cancelButtonDownSrc);
|
|
} else {
|
|
readRectArray(s, _saveButtonDests, 7);
|
|
readRectArray(s, _loadButtonDests, 7);
|
|
readRectArray(s, _textboxBounds, 7);
|
|
readRect(s, _doneButtonDest);
|
|
readRectArray(s, _saveButtonDownSrcs, 7);
|
|
readRectArray(s, _loadButtonDownSrcs, 7);
|
|
s.skip(16 * 7);
|
|
readRect(s, _doneButtonDownSrc);
|
|
readRectArray(s, _saveButtonHighlightSrcs, 7);
|
|
readRectArray(s, _loadButtonHighlightSrcs, 7);
|
|
s.skip(16 * 7);
|
|
readRect(s, _doneButtonHighlightSrc);
|
|
readRectArray(s, _saveButtonDisabledSrcs, 7);
|
|
readRectArray(s, _loadButtonDisabledSrcs, 7);
|
|
s.skip(16 * 7);
|
|
readRect(s, _doneButtonDisabledSrc);
|
|
readRect(s, _blinkingCursorSrc);
|
|
s.syncAsUint16LE(_blinkingTimeDelay);
|
|
readRectArray(s, _cancelButtonSrcs, 7);
|
|
readRectArray(s, _cancelButtonDests, 7);
|
|
readRect(s, _cancelButtonDownSrc);
|
|
readRect(s, _cancelButtonHighlightSrc);
|
|
readRect(s, _cancelButtonDisabledSrc);
|
|
|
|
readFilename(s, _gameSavedPopup, kGameTypeNancy3);
|
|
readFilename(s, _emptySaveText, kGameTypeNancy7);
|
|
readFilename(s, _defaultSaveNamePrefix, kGameTypeNancy7);
|
|
s.skip(16, kGameTypeNancy3);
|
|
}
|
|
} else {
|
|
// v2
|
|
readFilename(*chunkStream, _image1Name);
|
|
readFilename(*chunkStream, _image2Name);
|
|
readFilename(*chunkStream, _imageButtonsName);
|
|
|
|
readRectArray(*chunkStream, _unpressedButtonSrcs, 5);
|
|
readRectArray(*chunkStream, _pressedButtonSrcs, 5);
|
|
readRectArray(*chunkStream, _highlightedButtonSrcs, 5);
|
|
readRectArray(*chunkStream, _disabledButtonSrcs, 5);
|
|
|
|
readRectArray(*chunkStream, _buttonDests, 5);
|
|
readRectArray(*chunkStream, _textboxBounds, 10);
|
|
|
|
chunkStream->skip(25); // prefixes and suffixes for filenames
|
|
|
|
_mainFontID = chunkStream->readSint16LE();
|
|
_highlightFontID = chunkStream->readSint16LE();
|
|
_fontXOffset = chunkStream->readSint16LE();
|
|
_fontYOffset = chunkStream->readSint16LE();
|
|
|
|
chunkStream->skip(16); // src rect for dash in font
|
|
_blinkingTimeDelay = chunkStream->readUint16LE();
|
|
|
|
readFilename(*chunkStream, _gameSavedPopup);
|
|
readFilename(*chunkStream, _emptySaveText);
|
|
}
|
|
}
|
|
|
|
SDLG::SDLG(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
while (chunkStream->pos() < chunkStream->size()) {
|
|
dialogs.push_back(Dialog(chunkStream));
|
|
}
|
|
}
|
|
|
|
SDLG::Dialog::Dialog(Common::SeekableReadStream *chunkStream) {
|
|
readFilename(*chunkStream, imageName);
|
|
chunkStream->skip(16);
|
|
|
|
readRect(*chunkStream, yesDest);
|
|
readRect(*chunkStream, noDest);
|
|
readRect(*chunkStream, cancelDest);
|
|
|
|
chunkStream->skip(16);
|
|
|
|
readRect(*chunkStream, yesHighlightSrc);
|
|
readRect(*chunkStream, noHighlightSrc);
|
|
readRect(*chunkStream, cancelHighlightSrc);
|
|
|
|
readRect(*chunkStream, yesDownSrc);
|
|
readRect(*chunkStream, noDownSrc);
|
|
readRect(*chunkStream, cancelDownSrc);
|
|
}
|
|
|
|
HINT::HINT(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
uint size = chunkStream->size();
|
|
numHints.resize(size);
|
|
for (uint i = 0; i < size; ++i) {
|
|
numHints[i] = chunkStream->readByte();
|
|
}
|
|
}
|
|
|
|
SPUZ::SPUZ(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
tileOrder.resize(3);
|
|
|
|
for (uint difficulty = 0; difficulty < 3; ++difficulty) {
|
|
tileOrder[difficulty].resize(6);
|
|
for (uint y = 0; y < 6; ++y) {
|
|
tileOrder[difficulty][y].resize(6);
|
|
for (uint x = 0; x < 6; ++x) {
|
|
tileOrder[difficulty][y][x] = chunkStream->readSint16LE();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CLOK::CLOK(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
Common::Serializer s(chunkStream, nullptr);
|
|
s.setVersion(g_nancy->getGameType());
|
|
|
|
uint numFrames = s.getVersion() == kGameTypeVampire? 8 : 7;
|
|
|
|
readRectArray(s, animSrcs, numFrames);
|
|
readRectArray(s, animDests, numFrames, numFrames, kGameTypeNancy2);
|
|
|
|
readRect(s, staticImageSrc, kGameTypeNancy2);
|
|
readRect(s, staticImageDest, kGameTypeNancy2);
|
|
|
|
readRectArray(s, hoursHandSrcs, 12);
|
|
readRectArray(s, hoursHandDests, 12, 12, kGameTypeNancy2);
|
|
|
|
readRectArray(s, minutesHandSrcs, 4);
|
|
readRectArray(s, minutesHandDests, 4, 4, kGameTypeNancy2);
|
|
|
|
readRect(s, screenPosition, kGameTypeVampire, kGameTypeVampire);
|
|
|
|
readRectArray(s, hoursHandDests, 12, 12, kGameTypeVampire, kGameTypeVampire);
|
|
readRectArray(s, minutesHandDests, 4, 4, kGameTypeVampire, kGameTypeVampire);
|
|
|
|
readRect(s, staticImageSrc, kGameTypeVampire, kGameTypeVampire);
|
|
readRect(s, staticImageDest, kGameTypeVampire, kGameTypeVampire);
|
|
|
|
s.syncAsUint32LE(timeToKeepOpen);
|
|
s.syncAsUint16LE(frameTime);
|
|
|
|
s.syncAsByte(clockIsDisabled, kGameTypeNancy5);
|
|
s.syncAsByte(clockIsDay, kGameTypeNancy5);
|
|
s.syncAsUint32LE(countdownTime, kGameTypeNancy5);
|
|
s.skip(2, kGameTypeNancy5);
|
|
readRectArray(s, daySrcs, 3, 3, kGameTypeNancy5);
|
|
readRectArray(s, countdownSrcs, 13, 13, kGameTypeNancy5);
|
|
readRect(s, disabledSrc, kGameTypeNancy5);
|
|
}
|
|
|
|
SPEC::SPEC(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
fadeToBlackNumFrames = chunkStream->readByte();
|
|
fadeToBlackFrameTime = chunkStream->readUint16LE();
|
|
crossDissolveNumFrames = chunkStream->readUint16LE();
|
|
}
|
|
|
|
RCLB::RCLB(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
lightSwitchID = chunkStream->readUint16LE();
|
|
unk2 = chunkStream->readUint16LE();
|
|
|
|
char buf[100];
|
|
|
|
while (chunkStream->pos() < chunkStream->size()) {
|
|
themes.push_back(Theme());
|
|
Theme &theme = themes.back();
|
|
|
|
chunkStream->read(buf, 100);
|
|
theme.themeName = buf;
|
|
|
|
for (uint i = 0; i < 10; ++i) {
|
|
int32 val = chunkStream->readSint32LE();
|
|
if (val != -1) {
|
|
theme.wallIDs.push_back(val);
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < 10; ++i) {
|
|
int16 val = chunkStream->readUint16LE();
|
|
if (val != -1) {
|
|
theme.floorIDs.push_back(val);
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < 10; ++i) {
|
|
int16 val = chunkStream->readSint16LE();
|
|
if (val != -1) {
|
|
theme.exitFloorIDs.push_back(val);
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < 10; ++i) {
|
|
int16 val = chunkStream->readSint16LE();
|
|
if (val != -1) {
|
|
theme.ceilingIDs.push_back(val);
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < 10; ++i) {
|
|
int32 val = chunkStream->readSint32LE();
|
|
if (val != -1) {
|
|
theme.doorIDs.push_back(val);
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < 10; ++i) {
|
|
int32 val = chunkStream->readSint32LE();
|
|
if (val != -1) {
|
|
theme.transparentwallIDs.push_back(val);
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < 10; ++i) {
|
|
int32 val = chunkStream->readSint32LE();
|
|
if (val != -1) {
|
|
theme.objectwallIDs.push_back(val);
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < 10; ++i) {
|
|
int16 val = chunkStream->readSint16LE();
|
|
if (val != -1) {
|
|
theme.objectWallHeights.push_back(val);
|
|
}
|
|
}
|
|
|
|
theme.generalLighting = chunkStream->readUint16LE();
|
|
theme.hasLightSwitch = chunkStream->readUint16LE();
|
|
theme.transparentWallDensity = chunkStream->readSint16LE();
|
|
theme.objectWallDensity = chunkStream->readSint16LE();
|
|
theme.doorDensity = chunkStream->readSint16LE();
|
|
}
|
|
}
|
|
|
|
RCPR::RCPR(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
readRectArray(*chunkStream, screenViewportSizes, 6);
|
|
viewportSizeUsed = chunkStream->readUint16LE();
|
|
|
|
wallColor[0] = chunkStream->readByte();
|
|
wallColor[1] = chunkStream->readByte();
|
|
wallColor[2] = chunkStream->readByte();
|
|
|
|
playerColor[0] = chunkStream->readByte();
|
|
playerColor[1] = chunkStream->readByte();
|
|
playerColor[2] = chunkStream->readByte();
|
|
|
|
doorColor[0] = chunkStream->readByte();
|
|
doorColor[1] = chunkStream->readByte();
|
|
doorColor[2] = chunkStream->readByte();
|
|
|
|
lightSwitchColor[0] = chunkStream->readByte();
|
|
lightSwitchColor[1] = chunkStream->readByte();
|
|
lightSwitchColor[2] = chunkStream->readByte();
|
|
|
|
exitColor[0] = chunkStream->readByte();
|
|
exitColor[1] = chunkStream->readByte();
|
|
exitColor[2] = chunkStream->readByte();
|
|
|
|
uColor6[0] = chunkStream->readByte();
|
|
uColor6[1] = chunkStream->readByte();
|
|
uColor6[2] = chunkStream->readByte();
|
|
|
|
uColor7[0] = chunkStream->readByte();
|
|
uColor7[1] = chunkStream->readByte();
|
|
uColor7[2] = chunkStream->readByte();
|
|
|
|
uColor8[0] = chunkStream->readByte();
|
|
uColor8[1] = chunkStream->readByte();
|
|
uColor8[2] = chunkStream->readByte();
|
|
|
|
transparentWallColor[0] = chunkStream->readByte();
|
|
transparentWallColor[1] = chunkStream->readByte();
|
|
transparentWallColor[2] = chunkStream->readByte();
|
|
|
|
uColor10[0] = chunkStream->readByte();
|
|
uColor10[1] = chunkStream->readByte();
|
|
uColor10[2] = chunkStream->readByte();
|
|
|
|
Common::Path tmp;
|
|
while (chunkStream->pos() < chunkStream->size()) {
|
|
readFilename(*chunkStream, tmp);
|
|
Common::String baseName(tmp.baseName());
|
|
if (baseName.hasPrefixIgnoreCase("Wall")) {
|
|
wallNames.push_back(tmp);
|
|
} else if (baseName.hasPrefixIgnoreCase("SpW")) {
|
|
specialWallNames.push_back(tmp);
|
|
} else if (baseName.hasPrefixIgnoreCase("Ceil")) {
|
|
ceilingNames.push_back(tmp);
|
|
} else if (baseName.hasPrefixIgnoreCase("Floor")) {
|
|
floorNames.push_back(tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
ImageChunk::ImageChunk(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
readFilename(*chunkStream, imageName);
|
|
width = chunkStream->readUint16LE();
|
|
height = chunkStream->readUint16LE();
|
|
}
|
|
|
|
CVTX::CVTX(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
uint16 numEntries = chunkStream->readUint16LE();
|
|
|
|
char *buf = nullptr;
|
|
uint bufSize = 0;
|
|
Common::String keyName;
|
|
|
|
for (uint i = 0; i < numEntries; ++i) {
|
|
readFilename(*chunkStream, keyName);
|
|
uint16 stringSize = chunkStream->readUint16LE();
|
|
if (stringSize > bufSize) {
|
|
delete[] buf;
|
|
buf = new char[stringSize * 2];
|
|
bufSize = stringSize * 2;
|
|
}
|
|
|
|
if (buf) {
|
|
chunkStream->read(buf, stringSize);
|
|
buf[stringSize] = '\0';
|
|
texts.setVal(keyName, buf);
|
|
} else {
|
|
texts.setVal(keyName, Common::String());
|
|
}
|
|
}
|
|
|
|
delete[] buf;
|
|
}
|
|
|
|
TABL::TABL(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
uint numEntries = chunkStream->readUint16LE();
|
|
|
|
readFilename(*chunkStream, soundBaseName);
|
|
|
|
startIDs.resize(numEntries);
|
|
for (uint i = 0; i < numEntries; ++i) {
|
|
startIDs[i] = chunkStream->readUint16LE();
|
|
}
|
|
chunkStream->skip((20 - numEntries) * 2);
|
|
|
|
correctIDs.resize(numEntries);
|
|
for (uint i = 0; i < numEntries; ++i) {
|
|
correctIDs[i] = chunkStream->readUint16LE();
|
|
}
|
|
chunkStream->skip((20 - numEntries) * 2);
|
|
|
|
readRectArray(*chunkStream, srcRects, numEntries, 20);
|
|
|
|
char buf[1000];
|
|
strings.resize(numEntries);
|
|
for (uint i = 0; i < numEntries; ++i) {
|
|
chunkStream->read(buf, 1000);
|
|
assembleTextLine(buf, strings[i], 1000);
|
|
}
|
|
chunkStream->skip((20 - numEntries) * 1000);
|
|
}
|
|
|
|
MARK::MARK(Common::SeekableReadStream *chunkStream) : EngineData(chunkStream) {
|
|
readRectArray(*chunkStream, _markSrcs, 5);
|
|
}
|
|
|
|
} // End of namespace Nancy
|