2012-10-06 16:26:16 +02:00
|
|
|
/* 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 2
|
|
|
|
* 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, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2021-02-19 02:17:41 +02:00
|
|
|
#include "engines/nancy/state/logo.h"
|
|
|
|
#include "engines/nancy/state/scene.h"
|
2021-03-07 12:58:55 +02:00
|
|
|
#include "engines/nancy/state/help.h"
|
|
|
|
#include "engines/nancy/state/map.h"
|
2021-03-08 16:43:02 +02:00
|
|
|
#include "engines/nancy/state/credits.h"
|
2021-02-19 02:17:41 +02:00
|
|
|
|
2021-03-10 14:26:02 +02:00
|
|
|
#include "engines/nancy/action/sliderpuzzle.h"
|
|
|
|
#include "engines/nancy/action/primaryvideo.h"
|
|
|
|
#include "engines/nancy/action/secondarymovie.h"
|
|
|
|
|
2021-01-04 23:16:23 +02:00
|
|
|
#include "engines/nancy/nancy.h"
|
|
|
|
#include "engines/nancy/resource.h"
|
|
|
|
#include "engines/nancy/iff.h"
|
2021-02-20 20:22:13 +02:00
|
|
|
#include "engines/nancy/sound.h"
|
2021-01-07 22:41:11 +02:00
|
|
|
#include "engines/nancy/input.h"
|
2021-02-20 20:22:13 +02:00
|
|
|
#include "engines/nancy/sound.h"
|
2021-02-19 02:17:41 +02:00
|
|
|
#include "engines/nancy/graphics.h"
|
|
|
|
#include "engines/nancy/cursor.h"
|
2021-03-06 12:23:15 +02:00
|
|
|
#include "engines/nancy/cheat.h"
|
2021-01-04 23:16:23 +02:00
|
|
|
|
2012-10-06 16:26:16 +02:00
|
|
|
#include "common/system.h"
|
|
|
|
#include "common/random.h"
|
|
|
|
#include "common/error.h"
|
|
|
|
#include "common/events.h"
|
|
|
|
#include "common/debug-channels.h"
|
|
|
|
#include "common/config-manager.h"
|
|
|
|
#include "common/textconsole.h"
|
2012-10-22 13:12:42 +02:00
|
|
|
#include "common/memstream.h"
|
2015-06-12 14:45:59 +02:00
|
|
|
#include "common/installshield_cab.h"
|
2021-01-04 23:16:23 +02:00
|
|
|
#include "common/str.h"
|
2021-03-10 14:26:02 +02:00
|
|
|
#include "common/savefile.h"
|
|
|
|
#include "common/serializer.h"
|
2012-10-06 16:26:16 +02:00
|
|
|
|
2015-06-12 14:47:23 +02:00
|
|
|
#include "graphics/surface.h"
|
|
|
|
|
2015-06-16 15:32:57 +02:00
|
|
|
#include "audio/mixer.h"
|
|
|
|
#include "audio/audiostream.h"
|
|
|
|
|
2012-10-06 16:26:16 +02:00
|
|
|
#include "engines/util.h"
|
|
|
|
|
|
|
|
namespace Nancy {
|
|
|
|
|
2021-03-13 19:35:33 +02:00
|
|
|
NancyEngine *g_nancy;
|
|
|
|
|
2021-03-08 01:01:27 +02:00
|
|
|
NancyEngine::NancyEngine(OSystem *syst, const NancyGameDescription *gd) : Engine(syst), _gameDescription(gd), _system(syst) {
|
2021-03-13 19:35:33 +02:00
|
|
|
g_nancy = this;
|
|
|
|
|
2012-10-06 16:26:16 +02:00
|
|
|
DebugMan.addDebugChannel(kDebugEngine, "Engine", "Engine debug level");
|
2021-03-02 01:48:02 +02:00
|
|
|
DebugMan.addDebugChannel(kDebugActionRecord, "ActionRecord", "Action Record debug level");
|
|
|
|
DebugMan.addDebugChannel(kDebugScene, "Scene", "Scene debug level");
|
2012-10-06 16:26:16 +02:00
|
|
|
|
2021-03-10 21:23:40 +02:00
|
|
|
_console = new NancyConsole();
|
2021-03-14 12:33:56 +02:00
|
|
|
_randomSource = new Common::RandomSource("Nancy");
|
|
|
|
_randomSource->setSeed(_randomSource->getSeed());
|
2021-01-04 23:16:23 +02:00
|
|
|
|
2021-03-14 12:33:56 +02:00
|
|
|
_input = new InputManager();
|
|
|
|
_sound = new SoundManager();
|
|
|
|
_graphicsManager = new GraphicsManager();
|
|
|
|
_cursorManager = new CursorManager();
|
2021-01-07 22:41:11 +02:00
|
|
|
|
2021-03-14 12:33:56 +02:00
|
|
|
_launchConsole = false;
|
2012-10-06 16:26:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
NancyEngine::~NancyEngine() {
|
2021-01-04 23:16:23 +02:00
|
|
|
clearBootChunks();
|
2012-10-06 16:26:16 +02:00
|
|
|
DebugMan.clearAllDebugChannels();
|
|
|
|
delete _console;
|
2021-03-14 12:33:56 +02:00
|
|
|
delete _randomSource;
|
2021-03-10 21:23:40 +02:00
|
|
|
|
2021-03-14 12:33:56 +02:00
|
|
|
delete _graphicsManager;
|
|
|
|
delete _input;
|
|
|
|
delete _sound;
|
2012-10-06 16:26:16 +02:00
|
|
|
}
|
|
|
|
|
2021-03-13 17:16:02 +02:00
|
|
|
NancyEngine *NancyEngine::create(GameType type, OSystem *syst, const NancyGameDescription *gd) {
|
|
|
|
switch (type) {
|
|
|
|
case kGameTypeVampire:
|
|
|
|
return new NancyEngine(syst, gd);
|
|
|
|
case kGameTypeNancy1:
|
|
|
|
return new NancyEngine(syst, gd);
|
|
|
|
case kGameTypeNancy2:
|
|
|
|
return new NancyEngine(syst, gd);
|
|
|
|
case kGameTypeNancy3:
|
|
|
|
return new NancyEngine(syst, gd);
|
|
|
|
default:
|
|
|
|
error("Unknown GameType");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-06 16:26:16 +02:00
|
|
|
GUI::Debugger *NancyEngine::getDebugger() {
|
|
|
|
return _console;
|
|
|
|
}
|
|
|
|
|
2021-03-13 17:16:02 +02:00
|
|
|
Common::Error NancyEngine::loadGameStream(Common::SeekableReadStream *stream) {
|
|
|
|
Common::Serializer ser(stream, nullptr);
|
|
|
|
return synchronize(ser);
|
|
|
|
}
|
|
|
|
|
|
|
|
Common::Error NancyEngine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
|
|
|
|
Common::Serializer ser(nullptr, stream);
|
|
|
|
|
|
|
|
return synchronize(ser);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NancyEngine::canLoadGameStateCurrently() {
|
|
|
|
return canSaveGameStateCurrently();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NancyEngine::canSaveGameStateCurrently() {
|
|
|
|
// TODO also disable during secondary movie
|
2021-03-14 12:33:56 +02:00
|
|
|
return Action::PlayPrimaryVideoChan0::_activePrimaryVideo == nullptr;
|
2021-03-13 17:16:02 +02:00
|
|
|
}
|
|
|
|
|
2012-10-06 16:26:16 +02:00
|
|
|
bool NancyEngine::hasFeature(EngineFeature f) const {
|
2021-01-04 23:16:23 +02:00
|
|
|
return (f == kSupportsReturnToLauncher) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime);
|
2012-10-06 16:26:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *NancyEngine::getCopyrightString() const {
|
|
|
|
return "Copyright 1989-1997 David P Gray, All Rights Reserved.";
|
|
|
|
}
|
|
|
|
|
2021-03-13 17:16:02 +02:00
|
|
|
uint32 NancyEngine::getGameFlags() const {
|
|
|
|
return _gameDescription->desc.flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *NancyEngine::getGameId() const {
|
|
|
|
return _gameDescription->desc.gameId;
|
|
|
|
}
|
|
|
|
|
2012-10-06 16:26:16 +02:00
|
|
|
GameType NancyEngine::getGameType() const {
|
2021-03-13 17:16:02 +02:00
|
|
|
return _gameDescription->gameType;
|
2012-10-06 16:26:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Common::Platform NancyEngine::getPlatform() const {
|
2021-03-13 17:16:02 +02:00
|
|
|
return _gameDescription->desc.platform;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NancyEngine::setState(GameState state, GameState overridePrevious) {
|
|
|
|
// Handle special cases first
|
|
|
|
switch (state) {
|
|
|
|
case kBoot:
|
|
|
|
bootGameEngine();
|
|
|
|
setState(kLogo);
|
|
|
|
return;
|
|
|
|
case kMainMenu:
|
|
|
|
if (_gameFlow.currentState) {
|
|
|
|
if (_gameFlow.currentState->onStateExit()) {
|
|
|
|
_gameFlow.currentState = nullptr;
|
|
|
|
}
|
|
|
|
}
|
2021-03-19 18:37:20 +02:00
|
|
|
|
2021-03-13 17:16:02 +02:00
|
|
|
// TODO until the game's own menus are implemented we simply open the GMM
|
|
|
|
openMainMenuDialog();
|
|
|
|
|
|
|
|
if (shouldQuit()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_gameFlow.currentState) {
|
|
|
|
_gameFlow.currentState->onStateEnter();
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
case kCheat:
|
|
|
|
if (_cheatTypeIsEventFlag) {
|
|
|
|
EventFlagDialog *dialog = new EventFlagDialog();
|
|
|
|
runDialog(*dialog);
|
|
|
|
delete dialog;
|
|
|
|
} else {
|
|
|
|
CheatDialog *dialog = new CheatDialog();
|
|
|
|
runDialog(*dialog);
|
|
|
|
delete dialog;
|
|
|
|
}
|
2021-03-14 12:33:56 +02:00
|
|
|
_input->forceCleanInput();
|
2021-03-13 17:16:02 +02:00
|
|
|
return;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-03-14 12:33:56 +02:00
|
|
|
_graphicsManager->clearObjects();
|
2021-03-13 17:16:02 +02:00
|
|
|
|
|
|
|
_gameFlow.previousState = _gameFlow.currentState;
|
|
|
|
_gameFlow.currentState = getStateObject(state);
|
|
|
|
|
|
|
|
if (_gameFlow.previousState) {
|
|
|
|
_gameFlow.previousState->onStateExit();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_gameFlow.currentState) {
|
|
|
|
_gameFlow.currentState->onStateEnter();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (overridePrevious != kNone) {
|
|
|
|
_gameFlow.previousState = getStateObject(state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NancyEngine::setPreviousState() {
|
|
|
|
if (_gameFlow.currentState) {
|
|
|
|
_gameFlow.currentState->onStateExit();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_gameFlow.previousState) {
|
|
|
|
_gameFlow.previousState->onStateEnter();
|
|
|
|
}
|
|
|
|
|
|
|
|
SWAP<Nancy::State::State *>(_gameFlow.currentState, _gameFlow.previousState);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NancyEngine::setMouseEnabled(bool enabled) {
|
2021-03-14 12:33:56 +02:00
|
|
|
_cursorManager->showCursor(enabled); _input->setMouseInputEnabled(enabled);
|
2021-03-13 17:16:02 +02:00
|
|
|
}
|
|
|
|
|
2021-03-20 00:18:29 +02:00
|
|
|
void NancyEngine::callCheatMenu(bool eventFlags) {
|
2021-03-13 17:16:02 +02:00
|
|
|
setState(kCheat), _cheatTypeIsEventFlag = eventFlags;
|
2012-10-06 16:26:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Common::Error NancyEngine::run() {
|
2021-03-13 14:52:28 +02:00
|
|
|
// Boot the engine
|
|
|
|
setState(kBoot);
|
2021-03-19 18:37:20 +02:00
|
|
|
|
2021-03-13 14:52:28 +02:00
|
|
|
// Check if we need to load a save state from the launcher
|
|
|
|
if (ConfMan.hasKey("save_slot")) {
|
|
|
|
int saveSlot = ConfMan.getInt("save_slot");
|
|
|
|
if (saveSlot >= 0 && saveSlot <= getMetaEngine().getMaximumSaveSlot()) {
|
|
|
|
// Set to Scene but do not do the loading yet
|
|
|
|
setState(kScene);
|
2021-03-11 01:51:35 +02:00
|
|
|
}
|
|
|
|
}
|
2015-07-06 09:32:40 +02:00
|
|
|
|
2021-03-13 14:52:28 +02:00
|
|
|
// Main loop
|
2021-01-07 22:41:11 +02:00
|
|
|
while (!shouldQuit()) {
|
2021-03-14 12:33:56 +02:00
|
|
|
_cursorManager->setCursorType(CursorManager::kNormalArrow);
|
|
|
|
_input->processEvents();
|
2021-03-19 18:37:20 +02:00
|
|
|
|
2021-03-10 21:23:40 +02:00
|
|
|
if (_gameFlow.currentState) {
|
|
|
|
_gameFlow.currentState->process();
|
2015-07-06 09:32:40 +02:00
|
|
|
}
|
|
|
|
|
2021-03-14 12:33:56 +02:00
|
|
|
_graphicsManager->draw();
|
2021-02-19 02:17:41 +02:00
|
|
|
|
2021-03-14 12:33:56 +02:00
|
|
|
if (_launchConsole) {
|
2021-01-07 22:41:11 +02:00
|
|
|
_console->attach();
|
2021-03-14 12:33:56 +02:00
|
|
|
_launchConsole = false;
|
2021-01-07 22:41:11 +02:00
|
|
|
}
|
2021-01-04 23:16:23 +02:00
|
|
|
_console->onFrame();
|
|
|
|
|
2012-10-07 17:25:52 +02:00
|
|
|
_system->updateScreen();
|
|
|
|
_system->delayMillis(16);
|
|
|
|
}
|
|
|
|
|
2021-03-12 21:48:38 +02:00
|
|
|
NancySceneState.destroy();
|
|
|
|
|
2012-10-06 16:26:16 +02:00
|
|
|
return Common::kNoError;
|
|
|
|
}
|
|
|
|
|
2021-01-04 23:16:23 +02:00
|
|
|
void NancyEngine::bootGameEngine() {
|
2021-03-13 14:52:28 +02:00
|
|
|
// Load paths
|
|
|
|
const Common::FSNode gameDataDir(ConfMan.get("path"));
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "game");
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "datafiles");
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "hdsound");
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "cdsound");
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "hdvideo");
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "cdvideo");
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "iff");
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "art");
|
|
|
|
SearchMan.addSubDirectoryMatching(gameDataDir, "font");
|
2021-03-19 18:37:20 +02:00
|
|
|
|
2021-03-13 14:52:28 +02:00
|
|
|
// Load archive
|
|
|
|
Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember("data1.cab");
|
|
|
|
if (stream) {
|
|
|
|
Common::Archive *cab = Common::makeInstallShieldArchive(stream);
|
2021-03-19 18:37:20 +02:00
|
|
|
|
2021-03-13 14:52:28 +02:00
|
|
|
if (cab) {
|
|
|
|
SearchMan.add("data1.hdr", cab);
|
|
|
|
}
|
|
|
|
}
|
2021-03-19 18:37:20 +02:00
|
|
|
|
2021-03-14 12:33:56 +02:00
|
|
|
_resource = new ResourceManager();
|
|
|
|
_resource->initialize();
|
2021-03-13 14:52:28 +02:00
|
|
|
|
|
|
|
// Setup mixer
|
|
|
|
syncSoundSettings();
|
|
|
|
|
2021-01-04 23:16:23 +02:00
|
|
|
clearBootChunks();
|
2021-03-10 21:23:40 +02:00
|
|
|
IFF *boot = new IFF("boot");
|
2021-01-04 23:16:23 +02:00
|
|
|
if (!boot->load())
|
|
|
|
error("Failed to load boot script");
|
|
|
|
preloadCals(*boot);
|
|
|
|
|
|
|
|
addBootChunk("BSUM", boot->getChunkStream("BSUM"));
|
|
|
|
readBootSummary(*boot);
|
|
|
|
|
2021-03-13 14:52:28 +02:00
|
|
|
// Data chunks found in BOOT. These get used in many places in the engine,
|
|
|
|
// so we always keep them in memory
|
2021-01-04 23:16:23 +02:00
|
|
|
Common::String names[] = {
|
|
|
|
"INTR", "HINT", "LOGO", "SPUZ", "INV",
|
|
|
|
"FONT", "MENU", "HELP", "CRED", "LOAD",
|
|
|
|
"MAP", "CD", "TBOX", "CURS", "VIEW", "MSND",
|
|
|
|
"BUOK", "BUDE", "BULS", "GLOB", "SLID",
|
|
|
|
"SET", "CURT", "CANT", "TH1", "TH2",
|
2021-03-24 23:26:30 +02:00
|
|
|
"QUOT", "TMOD",
|
|
|
|
// Used in nancy2
|
2021-03-25 00:05:22 +02:00
|
|
|
"FR", "LG", "OB", "CLOK", "SPEC"
|
2021-03-24 23:26:30 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
Common::String persistentSounds[] = {
|
|
|
|
"BUOK", "BUDE", "BULS", "GLOB", "CURT",
|
|
|
|
"CANT"
|
|
|
|
};
|
|
|
|
|
|
|
|
SoundDescription desc;
|
2021-01-04 23:16:23 +02:00
|
|
|
|
|
|
|
for (auto const &n : names) {
|
|
|
|
addBootChunk(n, boot->getChunkStream(n));
|
|
|
|
}
|
|
|
|
|
2021-03-13 14:52:28 +02:00
|
|
|
// Persistent sounds that are used across the engine. These originally get loaded inside Logo
|
2021-03-24 23:26:30 +02:00
|
|
|
for (auto const &s : persistentSounds) {
|
|
|
|
Common::SeekableReadStream *str = g_nancy->getBootChunkStream(s);
|
|
|
|
if (str) {
|
|
|
|
desc.read(*str, SoundDescription::kNormal);
|
|
|
|
g_nancy->_sound->loadSound(desc);
|
|
|
|
}
|
|
|
|
}
|
2021-03-10 21:23:40 +02:00
|
|
|
|
2021-01-04 23:16:23 +02:00
|
|
|
delete boot;
|
2021-03-19 18:37:20 +02:00
|
|
|
|
2021-03-14 12:33:56 +02:00
|
|
|
_graphicsManager->init();
|
|
|
|
_cursorManager->init();
|
2021-01-04 23:16:23 +02:00
|
|
|
}
|
|
|
|
|
2021-03-20 19:52:39 +02:00
|
|
|
State::State *NancyEngine::getStateObject(GameState state) const {
|
2021-03-10 21:23:40 +02:00
|
|
|
switch (state) {
|
|
|
|
case kLogo:
|
|
|
|
return &State::Logo::instance();
|
|
|
|
case kCredits:
|
|
|
|
return &State::Credits::instance();
|
|
|
|
case kMap:
|
|
|
|
return &State::Map::instance();
|
|
|
|
case kHelp:
|
|
|
|
return &State::Help::instance();
|
|
|
|
case kScene:
|
|
|
|
return &State::Scene::instance();
|
|
|
|
default:
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 23:16:23 +02:00
|
|
|
bool NancyEngine::addBootChunk(const Common::String &name, Common::SeekableReadStream *stream) {
|
|
|
|
if (!stream)
|
|
|
|
return false;
|
|
|
|
_bootChunks[name] = stream;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-03-20 19:52:39 +02:00
|
|
|
Common::SeekableReadStream *NancyEngine::getBootChunkStream(const Common::String &name) const {
|
2021-01-04 23:16:23 +02:00
|
|
|
if (_bootChunks.contains(name)) {
|
|
|
|
return _bootChunks[name];
|
2021-03-20 03:01:58 +02:00
|
|
|
} else {
|
|
|
|
return nullptr;
|
2021-01-04 23:16:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void NancyEngine::clearBootChunks() {
|
|
|
|
for (auto const& i : _bootChunks) {
|
|
|
|
delete i._value;
|
|
|
|
}
|
|
|
|
_bootChunks.clear();
|
|
|
|
}
|
|
|
|
|
2012-10-22 13:12:42 +02:00
|
|
|
void NancyEngine::preloadCals(const IFF &boot) {
|
|
|
|
const byte *buf;
|
|
|
|
uint size;
|
|
|
|
buf = boot.getChunk(ID_PCAL, size);
|
|
|
|
|
|
|
|
if (buf) {
|
|
|
|
Common::MemoryReadStream stream(buf, size);
|
|
|
|
uint16 count = stream.readUint16LE();
|
|
|
|
debugC(1, kDebugEngine, "Preloading %d CALs", count);
|
|
|
|
int nameLen = size / count;
|
|
|
|
|
|
|
|
char *name = new char[nameLen];
|
|
|
|
|
|
|
|
for (uint i = 0; i < count; i++) {
|
|
|
|
stream.read(name, nameLen);
|
|
|
|
name[nameLen - 1] = 0;
|
|
|
|
debugC(1, kDebugEngine, "Preloading CAL '%s'", name);
|
2021-03-14 12:33:56 +02:00
|
|
|
if (!_resource->loadCifTree(name, "cal"))
|
2012-10-22 13:12:42 +02:00
|
|
|
error("Failed to preload CAL '%s'", name);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete[] name;
|
|
|
|
|
|
|
|
if (stream.err())
|
|
|
|
error("Error reading PCAL chunk");
|
|
|
|
} else
|
|
|
|
debugC(1, kDebugEngine, "No PCAL chunk found");
|
|
|
|
}
|
|
|
|
|
2021-03-11 01:21:48 +02:00
|
|
|
void NancyEngine::readChunkList(const IFF &boot, Common::Serializer &ser, const Common::String &prefix) {
|
|
|
|
byte numChunks;
|
|
|
|
ser.syncAsByte(numChunks);
|
|
|
|
for (byte i = 0; i < numChunks; ++ i) {
|
|
|
|
Common::String name = Common::String::format("%s%d", prefix.c_str(), i);
|
|
|
|
addBootChunk(name, boot.getChunkStream(name));
|
2015-06-16 11:29:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 01:21:48 +02:00
|
|
|
void NancyEngine::readBootSummary(const IFF &boot) {
|
2021-01-04 23:16:23 +02:00
|
|
|
Common::SeekableReadStream *bsum = getBootChunkStream("BSUM");
|
2021-03-11 01:21:48 +02:00
|
|
|
bsum->seek(0);
|
2021-03-10 21:23:40 +02:00
|
|
|
|
2021-03-11 01:21:48 +02:00
|
|
|
// Use a serializer to handle several games' BSUMs in the same function
|
|
|
|
Common::Serializer ser(bsum, nullptr);
|
|
|
|
ser.setVersion(_gameDescription->gameType);
|
2015-06-16 11:29:20 +02:00
|
|
|
|
2021-03-12 13:04:02 +02:00
|
|
|
ser.skip(0x71, kGameTypeVampire, kGameTypeVampire);
|
|
|
|
ser.skip(0xA3, kGameTypeNancy1, kGameTypeNancy2);
|
2021-03-14 12:33:56 +02:00
|
|
|
ser.syncAsUint16LE(_firstSceneID);
|
2021-03-12 13:04:02 +02:00
|
|
|
ser.skip(4, kGameTypeNancy1, kGameTypeNancy2);
|
2021-03-14 12:33:56 +02:00
|
|
|
ser.syncAsUint16LE(_startTimeHours, kGameTypeNancy1, kGameTypeNancy2);
|
2021-03-19 18:37:20 +02:00
|
|
|
|
2021-03-12 13:04:02 +02:00
|
|
|
ser.skip(0xB8, kGameTypeVampire, kGameTypeVampire);
|
2021-03-11 01:21:48 +02:00
|
|
|
ser.skip(0xA6, kGameTypeNancy1, kGameTypeNancy1);
|
|
|
|
ser.skip(0xA0, kGameTypeNancy2, kGameTypeNancy2);
|
2015-06-16 11:29:20 +02:00
|
|
|
|
2021-03-11 01:21:48 +02:00
|
|
|
// nancy3 has not been looked into, skip straight to images
|
|
|
|
ser.skip(0xA7, kGameTypeNancy3, kGameTypeNancy3);
|
2015-06-16 11:29:20 +02:00
|
|
|
|
2021-03-11 01:21:48 +02:00
|
|
|
readChunkList(boot, ser, "FR");
|
|
|
|
readChunkList(boot, ser, "LG");
|
2015-06-16 11:29:20 +02:00
|
|
|
|
2021-03-11 01:21:48 +02:00
|
|
|
if (ser.getVersion() < kGameTypeNancy3) {
|
|
|
|
readChunkList(boot, ser, "OB");
|
|
|
|
}
|
2015-06-16 11:29:20 +02:00
|
|
|
|
2021-03-11 01:21:48 +02:00
|
|
|
ser.skip(0x99, kGameTypeNancy1, kGameTypeNancy1);
|
|
|
|
int16 time = 0;
|
|
|
|
ser.syncAsSint16LE(time, kGameTypeNancy1, kGameTypeNancy1);
|
2021-03-14 12:33:56 +02:00
|
|
|
_playerTimeMinuteLength = time;
|
2021-03-11 01:21:48 +02:00
|
|
|
ser.skip(2, kGameTypeNancy1, kGameTypeNancy1);
|
2021-03-19 18:37:20 +02:00
|
|
|
ser.syncAsByte(_overrideMovementTimeDeltas, kGameTypeNancy1, kGameTypeNancy1);
|
2015-06-16 11:29:20 +02:00
|
|
|
|
2021-03-19 18:37:20 +02:00
|
|
|
if (_overrideMovementTimeDeltas) {
|
2021-03-11 01:21:48 +02:00
|
|
|
ser.syncAsSint16LE(time, kGameTypeNancy1, kGameTypeNancy1);
|
2021-03-14 12:33:56 +02:00
|
|
|
_slowMovementTimeDelta = time;
|
2021-03-11 01:21:48 +02:00
|
|
|
ser.syncAsSint16LE(time, kGameTypeNancy1, kGameTypeNancy1);
|
2021-03-14 12:33:56 +02:00
|
|
|
_fastMovementTimeDelta = time;
|
2021-03-19 18:37:20 +02:00
|
|
|
}
|
2015-06-16 11:29:20 +02:00
|
|
|
}
|
|
|
|
|
2021-03-13 17:16:02 +02:00
|
|
|
Common::Error NancyEngine::synchronize(Common::Serializer &ser) {
|
|
|
|
Common::SeekableReadStream *bsum = getBootChunkStream("BSUM");
|
|
|
|
bsum->seek(0);
|
|
|
|
|
|
|
|
// Sync boot summary header, which includes full game title
|
|
|
|
ser.syncVersion(kSavegameVersion);
|
|
|
|
char buf[90];
|
|
|
|
bsum->read(buf, 90);
|
|
|
|
ser.matchBytes(buf, 90);
|
|
|
|
|
|
|
|
// Sync scene and action records
|
|
|
|
NancySceneState.synchronize(ser);
|
|
|
|
NancySceneState._actionManager.synchronize(ser);
|
|
|
|
|
|
|
|
return Common::kNoError;
|
2015-06-16 11:29:20 +02:00
|
|
|
}
|
2012-10-06 16:26:16 +02:00
|
|
|
|
2021-02-19 02:17:41 +02:00
|
|
|
} // End of namespace Nancy
|