Started moving Save/Load code to saveload.cpp/.h
svn-id: r35033
This commit is contained in:
parent
0ba17539ac
commit
162634cc95
8 changed files with 1146 additions and 1067 deletions
|
@ -776,75 +776,4 @@ int loadResource(const char *resourceName, int16 idx) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Load animDataTable from save
|
|
||||||
* \param fHandle Savefile open for reading
|
|
||||||
* \param saveGameFormat The used savegame format
|
|
||||||
* \todo Add Operation Stealth savefile support
|
|
||||||
*
|
|
||||||
* Unlike the old code, this one actually rebuilds the table one frame
|
|
||||||
* at a time.
|
|
||||||
*/
|
|
||||||
void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) {
|
|
||||||
int16 currentAnim, foundFileIdx, frame;
|
|
||||||
char *animName, part[256], name[10];
|
|
||||||
uint16 width, height, bpp, var1;
|
|
||||||
|
|
||||||
strcpy(part, currentPartName);
|
|
||||||
|
|
||||||
// We only support these variations of the savegame format at the moment.
|
|
||||||
assert(saveGameFormat == ANIMSIZE_23 || saveGameFormat == ANIMSIZE_30_PTRS_INTACT);
|
|
||||||
|
|
||||||
const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30);
|
|
||||||
const int fileStartPos = fHandle.pos();
|
|
||||||
currentAnim = 0;
|
|
||||||
while (currentAnim < NUM_MAX_ANIMDATA) {
|
|
||||||
// Seek to the start of the current animation's entry
|
|
||||||
fHandle.seek(fileStartPos + currentAnim * entrySize);
|
|
||||||
// Read in the current animation entry
|
|
||||||
width = fHandle.readUint16BE();
|
|
||||||
var1 = fHandle.readUint16BE();
|
|
||||||
bpp = fHandle.readUint16BE();
|
|
||||||
height = fHandle.readUint16BE();
|
|
||||||
|
|
||||||
bool validPtr = false;
|
|
||||||
// Handle variables only present in animation entries of size 30
|
|
||||||
if (entrySize == 30) {
|
|
||||||
validPtr = (fHandle.readUint32BE() != 0); // Read data pointer
|
|
||||||
fHandle.readUint32BE(); // Discard mask pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
foundFileIdx = fHandle.readSint16BE();
|
|
||||||
frame = fHandle.readSint16BE();
|
|
||||||
fHandle.read(name, 10);
|
|
||||||
|
|
||||||
// Handle variables only present in animation entries of size 23
|
|
||||||
if (entrySize == 23) {
|
|
||||||
validPtr = (fHandle.readByte() != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't try to load invalid entries.
|
|
||||||
if (foundFileIdx < 0 || !validPtr) {
|
|
||||||
currentAnim++; // Jump over the invalid entry
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alright, the animation entry looks to be valid so let's start handling it...
|
|
||||||
if (strcmp(currentPartName, name)) {
|
|
||||||
closePart();
|
|
||||||
loadPart(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
animName = partBuffer[foundFileIdx].partName;
|
|
||||||
loadRelatedPalette(animName); // Is this for Future Wars only?
|
|
||||||
const int16 prevAnim = currentAnim;
|
|
||||||
currentAnim = loadResource(animName, currentAnim);
|
|
||||||
assert(currentAnim > prevAnim); // Make sure we advance forward
|
|
||||||
}
|
|
||||||
|
|
||||||
loadPart(part);
|
|
||||||
|
|
||||||
// Make sure we jump over all the animation entries
|
|
||||||
fHandle.seek(fileStartPos + NUM_MAX_ANIMDATA * entrySize);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // End of namespace Cine
|
} // End of namespace Cine
|
||||||
|
|
|
@ -30,59 +30,6 @@
|
||||||
|
|
||||||
namespace Cine {
|
namespace Cine {
|
||||||
|
|
||||||
/**
|
|
||||||
* Cine engine's save game formats.
|
|
||||||
* Enumeration entries (Excluding the one used as an error)
|
|
||||||
* are sorted according to age (i.e. top one is oldest, last one newest etc).
|
|
||||||
*
|
|
||||||
* ANIMSIZE_UNKNOWN:
|
|
||||||
* - Animation data entry size is unknown (Used as an error).
|
|
||||||
*
|
|
||||||
* ANIMSIZE_23:
|
|
||||||
* - Animation data entry size is 23 bytes.
|
|
||||||
* - Used at least by 0.11.0 and 0.11.1 releases of ScummVM.
|
|
||||||
* - Introduced in revision 21772, stopped using in revision 31444.
|
|
||||||
*
|
|
||||||
* ANIMSIZE_30_PTRS_BROKEN:
|
|
||||||
* - Animation data entry size is 30 bytes.
|
|
||||||
* - Data and mask pointers in the saved structs are always NULL.
|
|
||||||
* - Introduced in revision 31453, stopped using in revision 32073.
|
|
||||||
*
|
|
||||||
* ANIMSIZE_30_PTRS_INTACT:
|
|
||||||
* - Animation data entry size is 30 bytes.
|
|
||||||
* - Data and mask pointers in the saved structs are intact,
|
|
||||||
* so you can test them for equality or inequality with NULL
|
|
||||||
* but don't try using them for anything else, it won't work.
|
|
||||||
* - Introduced in revision 31444, got broken in revision 31453,
|
|
||||||
* got fixed in revision 32073 and used after that.
|
|
||||||
*
|
|
||||||
* TEMP_OS_FORMAT:
|
|
||||||
* - Temporary Operation Stealth savegame format.
|
|
||||||
* - NOT backward compatible and NOT to be supported in the future.
|
|
||||||
* This format should ONLY be used during development and abandoned
|
|
||||||
* later in favor of a better format!
|
|
||||||
*/
|
|
||||||
enum CineSaveGameFormat {
|
|
||||||
ANIMSIZE_UNKNOWN,
|
|
||||||
ANIMSIZE_23,
|
|
||||||
ANIMSIZE_30_PTRS_BROKEN,
|
|
||||||
ANIMSIZE_30_PTRS_INTACT,
|
|
||||||
TEMP_OS_FORMAT
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Identifier for the temporary Operation Stealth savegame format. */
|
|
||||||
static const uint32 TEMP_OS_FORMAT_ID = MKID_BE('TEMP');
|
|
||||||
|
|
||||||
/** The current version number of Operation Stealth's savegame format. */
|
|
||||||
static const uint32 CURRENT_OS_SAVE_VER = 0;
|
|
||||||
|
|
||||||
/** Chunk header used by the temporary Operation Stealth savegame format. */
|
|
||||||
struct ChunkHeader {
|
|
||||||
uint32 id; ///< Identifier (e.g. MKID_BE('TEMP'))
|
|
||||||
uint32 version; ///< Version number
|
|
||||||
uint32 size; ///< Size of the chunk after this header in bytes
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AnimHeaderStruct {
|
struct AnimHeaderStruct {
|
||||||
byte field_0;
|
byte field_0;
|
||||||
byte field_1;
|
byte field_1;
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
|
|
||||||
#include "common/scummsys.h"
|
#include "common/scummsys.h"
|
||||||
#include "common/savefile.h"
|
|
||||||
#include "common/list.h"
|
#include "common/list.h"
|
||||||
|
|
||||||
namespace Cine {
|
namespace Cine {
|
||||||
|
|
|
@ -14,6 +14,7 @@ MODULE_OBJS = \
|
||||||
part.o \
|
part.o \
|
||||||
prc.o \
|
prc.o \
|
||||||
rel.o \
|
rel.o \
|
||||||
|
saveload.o \
|
||||||
script_fw.o \
|
script_fw.o \
|
||||||
script_os.o \
|
script_os.o \
|
||||||
sound.o \
|
sound.o \
|
||||||
|
|
1048
engines/cine/saveload.cpp
Normal file
1048
engines/cine/saveload.cpp
Normal file
File diff suppressed because it is too large
Load diff
89
engines/cine/saveload.h
Normal file
89
engines/cine/saveload.h
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CINE_SAVELOAD_H
|
||||||
|
#define CINE_SAVELOAD_H
|
||||||
|
|
||||||
|
#include "common/endian.h"
|
||||||
|
|
||||||
|
namespace Cine {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cine engine's save game formats.
|
||||||
|
* Enumeration entries (Excluding the one used as an error)
|
||||||
|
* are sorted according to age (i.e. top one is oldest, last one newest etc).
|
||||||
|
*
|
||||||
|
* ANIMSIZE_UNKNOWN:
|
||||||
|
* - Animation data entry size is unknown (Used as an error).
|
||||||
|
*
|
||||||
|
* ANIMSIZE_23:
|
||||||
|
* - Animation data entry size is 23 bytes.
|
||||||
|
* - Used at least by 0.11.0 and 0.11.1 releases of ScummVM.
|
||||||
|
* - Introduced in revision 21772, stopped using in revision 31444.
|
||||||
|
*
|
||||||
|
* ANIMSIZE_30_PTRS_BROKEN:
|
||||||
|
* - Animation data entry size is 30 bytes.
|
||||||
|
* - Data and mask pointers in the saved structs are always NULL.
|
||||||
|
* - Introduced in revision 31453, stopped using in revision 32073.
|
||||||
|
*
|
||||||
|
* ANIMSIZE_30_PTRS_INTACT:
|
||||||
|
* - Animation data entry size is 30 bytes.
|
||||||
|
* - Data and mask pointers in the saved structs are intact,
|
||||||
|
* so you can test them for equality or inequality with NULL
|
||||||
|
* but don't try using them for anything else, it won't work.
|
||||||
|
* - Introduced in revision 31444, got broken in revision 31453,
|
||||||
|
* got fixed in revision 32073 and used after that.
|
||||||
|
*
|
||||||
|
* TEMP_OS_FORMAT:
|
||||||
|
* - Temporary Operation Stealth savegame format.
|
||||||
|
* - NOT backward compatible and NOT to be supported in the future.
|
||||||
|
* This format should ONLY be used during development and abandoned
|
||||||
|
* later in favor of a better format!
|
||||||
|
*/
|
||||||
|
enum CineSaveGameFormat {
|
||||||
|
ANIMSIZE_UNKNOWN,
|
||||||
|
ANIMSIZE_23,
|
||||||
|
ANIMSIZE_30_PTRS_BROKEN,
|
||||||
|
ANIMSIZE_30_PTRS_INTACT,
|
||||||
|
TEMP_OS_FORMAT
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Identifier for the temporary Operation Stealth savegame format. */
|
||||||
|
static const uint32 TEMP_OS_FORMAT_ID = MKID_BE('TEMP');
|
||||||
|
|
||||||
|
/** The current version number of Operation Stealth's savegame format. */
|
||||||
|
static const uint32 CURRENT_OS_SAVE_VER = 0;
|
||||||
|
|
||||||
|
/** Chunk header used by the temporary Operation Stealth savegame format. */
|
||||||
|
struct ChunkHeader {
|
||||||
|
uint32 id; ///< Identifier (e.g. MKID_BE('TEMP'))
|
||||||
|
uint32 version; ///< Version number
|
||||||
|
uint32 size; ///< Size of the chunk after this header in bytes
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // End of namespace Cine
|
||||||
|
|
||||||
|
#endif
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
#include "common/endian.h"
|
#include "common/endian.h"
|
||||||
#include "common/events.h"
|
#include "common/events.h"
|
||||||
#include "common/savefile.h"
|
|
||||||
|
|
||||||
#include "cine/cine.h"
|
#include "cine/cine.h"
|
||||||
#include "cine/main_loop.h"
|
#include "cine/main_loop.h"
|
||||||
|
@ -91,8 +90,6 @@ char currentCtName[15];
|
||||||
char currentPartName[15];
|
char currentPartName[15];
|
||||||
char currentDatName[30];
|
char currentDatName[30];
|
||||||
|
|
||||||
int16 saveVar2;
|
|
||||||
|
|
||||||
byte isInPause = 0;
|
byte isInPause = 0;
|
||||||
|
|
||||||
/*! \brief Values used by the xMoveKeyb variable */
|
/*! \brief Values used by the xMoveKeyb variable */
|
||||||
|
@ -116,7 +113,6 @@ uint16 yMoveKeyb = kKeybMoveCenterY;
|
||||||
SelectedObjStruct currentSelectedObject;
|
SelectedObjStruct currentSelectedObject;
|
||||||
|
|
||||||
CommandeType currentSaveName[10];
|
CommandeType currentSaveName[10];
|
||||||
int16 currentDisk;
|
|
||||||
|
|
||||||
static const int16 choiceResultTable[] = { 1, 1, 1, 2, 1, 1, 1 };
|
static const int16 choiceResultTable[] = { 1, 1, 1, 2, 1, 1, 1 };
|
||||||
static const int16 subObjectUseTable[] = { 3, 3, 3, 3, 3, 0, 0 };
|
static const int16 subObjectUseTable[] = { 3, 3, 3, 3, 3, 0, 0 };
|
||||||
|
@ -276,347 +272,6 @@ int16 getObjectUnderCursor(uint16 x, uint16 y) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool writeChunkHeader(Common::OutSaveFile &out, const ChunkHeader &header) {
|
|
||||||
out.writeUint32BE(header.id);
|
|
||||||
out.writeUint32BE(header.version);
|
|
||||||
out.writeUint32BE(header.size);
|
|
||||||
return !out.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadChunkHeader(Common::SeekableReadStream &in, ChunkHeader &header) {
|
|
||||||
header.id = in.readUint32BE();
|
|
||||||
header.version = in.readUint32BE();
|
|
||||||
header.size = in.readUint32BE();
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveObjectTable(Common::OutSaveFile &out) {
|
|
||||||
out.writeUint16BE(NUM_MAX_OBJECT); // Entry count
|
|
||||||
out.writeUint16BE(0x20); // Entry size
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_MAX_OBJECT; i++) {
|
|
||||||
out.writeUint16BE(objectTable[i].x);
|
|
||||||
out.writeUint16BE(objectTable[i].y);
|
|
||||||
out.writeUint16BE(objectTable[i].mask);
|
|
||||||
out.writeUint16BE(objectTable[i].frame);
|
|
||||||
out.writeUint16BE(objectTable[i].costume);
|
|
||||||
out.write(objectTable[i].name, 20);
|
|
||||||
out.writeUint16BE(objectTable[i].part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveZoneData(Common::OutSaveFile &out) {
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
out.writeUint16BE(zoneData[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveCommandVariables(Common::OutSaveFile &out) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
out.writeUint16BE(commandVar3[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \brief Save the 80 bytes long command buffer padded to that length with zeroes. */
|
|
||||||
void saveCommandBuffer(Common::OutSaveFile &out) {
|
|
||||||
// Let's make sure there's space for the trailing zero
|
|
||||||
// (That's why we subtract one from the maximum command buffer size here).
|
|
||||||
uint32 size = MIN<uint32>(commandBuffer.size(), kMaxCommandBufferSize - 1);
|
|
||||||
out.write(commandBuffer.c_str(), size);
|
|
||||||
// Write the rest as zeroes (Here we also write the string's trailing zero)
|
|
||||||
for (uint i = 0; i < kMaxCommandBufferSize - size; i++) {
|
|
||||||
out.writeByte(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveAnimDataTable(Common::OutSaveFile &out) {
|
|
||||||
out.writeUint16BE(NUM_MAX_ANIMDATA); // Entry count
|
|
||||||
out.writeUint16BE(0x1E); // Entry size
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_MAX_ANIMDATA; i++) {
|
|
||||||
animDataTable[i].save(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveScreenParams(Common::OutSaveFile &out) {
|
|
||||||
// Screen parameters, unhandled
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveGlobalScripts(Common::OutSaveFile &out) {
|
|
||||||
ScriptList::const_iterator it;
|
|
||||||
out.writeUint16BE(globalScripts.size());
|
|
||||||
for (it = globalScripts.begin(); it != globalScripts.end(); ++it) {
|
|
||||||
(*it)->save(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveObjectScripts(Common::OutSaveFile &out) {
|
|
||||||
ScriptList::const_iterator it;
|
|
||||||
out.writeUint16BE(objectScripts.size());
|
|
||||||
for (it = objectScripts.begin(); it != objectScripts.end(); ++it) {
|
|
||||||
(*it)->save(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveOverlayList(Common::OutSaveFile &out) {
|
|
||||||
Common::List<overlay>::const_iterator it;
|
|
||||||
|
|
||||||
out.writeUint16BE(overlayList.size());
|
|
||||||
|
|
||||||
for (it = overlayList.begin(); it != overlayList.end(); ++it) {
|
|
||||||
out.writeUint32BE(0); // next
|
|
||||||
out.writeUint32BE(0); // previous?
|
|
||||||
out.writeUint16BE(it->objIdx);
|
|
||||||
out.writeUint16BE(it->type);
|
|
||||||
out.writeSint16BE(it->x);
|
|
||||||
out.writeSint16BE(it->y);
|
|
||||||
out.writeSint16BE(it->width);
|
|
||||||
out.writeSint16BE(it->color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveBgIncrustList(Common::OutSaveFile &out) {
|
|
||||||
Common::List<BGIncrust>::const_iterator it;
|
|
||||||
out.writeUint16BE(bgIncrustList.size());
|
|
||||||
|
|
||||||
for (it = bgIncrustList.begin(); it != bgIncrustList.end(); ++it) {
|
|
||||||
out.writeUint32BE(0); // next
|
|
||||||
out.writeUint32BE(0); // previous?
|
|
||||||
out.writeUint16BE(it->objIdx);
|
|
||||||
out.writeUint16BE(it->param);
|
|
||||||
out.writeUint16BE(it->x);
|
|
||||||
out.writeUint16BE(it->y);
|
|
||||||
out.writeUint16BE(it->frame);
|
|
||||||
out.writeUint16BE(it->part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveZoneQuery(Common::OutSaveFile &out) {
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
out.writeUint16BE(zoneQuery[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveSeqList(Common::OutSaveFile &out) {
|
|
||||||
Common::List<SeqListElement>::const_iterator it;
|
|
||||||
out.writeUint16BE(seqList.size());
|
|
||||||
|
|
||||||
for (it = seqList.begin(); it != seqList.end(); ++it) {
|
|
||||||
out.writeSint16BE(it->var4);
|
|
||||||
out.writeUint16BE(it->objIdx);
|
|
||||||
out.writeSint16BE(it->var8);
|
|
||||||
out.writeSint16BE(it->frame);
|
|
||||||
out.writeSint16BE(it->varC);
|
|
||||||
out.writeSint16BE(it->varE);
|
|
||||||
out.writeSint16BE(it->var10);
|
|
||||||
out.writeSint16BE(it->var12);
|
|
||||||
out.writeSint16BE(it->var14);
|
|
||||||
out.writeSint16BE(it->var16);
|
|
||||||
out.writeSint16BE(it->var18);
|
|
||||||
out.writeSint16BE(it->var1A);
|
|
||||||
out.writeSint16BE(it->var1C);
|
|
||||||
out.writeSint16BE(it->var1E);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CineEngine::loadSaveDirectory(void) {
|
|
||||||
Common::InSaveFile *fHandle;
|
|
||||||
char tmp[80];
|
|
||||||
|
|
||||||
snprintf(tmp, 80, "%s.dir", _targetName.c_str());
|
|
||||||
fHandle = g_saveFileMan->openForLoading(tmp);
|
|
||||||
|
|
||||||
if (!fHandle) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
fHandle->read(currentSaveName, 10 * 20);
|
|
||||||
delete fHandle;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \brief Savegame format detector
|
|
||||||
* \param fHandle Savefile to check
|
|
||||||
* \return Savegame format on success, ANIMSIZE_UNKNOWN on failure
|
|
||||||
*
|
|
||||||
* This function seeks through the savefile and tries to determine the
|
|
||||||
* savegame format it uses. There's a miniscule chance that the detection
|
|
||||||
* algorithm could get confused and think that the file uses both the older
|
|
||||||
* and the newer format but that is such a remote possibility that I wouldn't
|
|
||||||
* worry about it at all.
|
|
||||||
*
|
|
||||||
* Also detects the temporary Operation Stealth savegame format now.
|
|
||||||
*/
|
|
||||||
enum CineSaveGameFormat detectSaveGameFormat(Common::SeekableReadStream &fHandle) {
|
|
||||||
const uint32 prevStreamPos = fHandle.pos();
|
|
||||||
|
|
||||||
// First check for the temporary Operation Stealth savegame format.
|
|
||||||
fHandle.seek(0);
|
|
||||||
ChunkHeader hdr;
|
|
||||||
loadChunkHeader(fHandle, hdr);
|
|
||||||
fHandle.seek(prevStreamPos);
|
|
||||||
if (hdr.id == TEMP_OS_FORMAT_ID) {
|
|
||||||
return TEMP_OS_FORMAT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ok, so the savegame isn't using the temporary Operation Stealth savegame format.
|
|
||||||
// Let's check for the plain Future Wars savegame format and its different versions then.
|
|
||||||
// The animDataTable begins at savefile position 0x2315.
|
|
||||||
// Each animDataTable entry takes 23 bytes in older saves (Revisions 21772-31443)
|
|
||||||
// and 30 bytes in the save format after that (Revision 31444 and onwards).
|
|
||||||
// There are 255 entries in the animDataTable in both of the savefile formats.
|
|
||||||
static const uint animDataTableStart = 0x2315;
|
|
||||||
static const uint animEntriesCount = 255;
|
|
||||||
static const uint oldAnimEntrySize = 23;
|
|
||||||
static const uint newAnimEntrySize = 30;
|
|
||||||
static const uint animEntrySizeChoices[] = {oldAnimEntrySize, newAnimEntrySize};
|
|
||||||
Common::Array<uint> animEntrySizeMatches;
|
|
||||||
|
|
||||||
// Try to walk through the savefile using different animDataTable entry sizes
|
|
||||||
// and make a list of all the successful entry sizes.
|
|
||||||
for (uint i = 0; i < ARRAYSIZE(animEntrySizeChoices); i++) {
|
|
||||||
// 206 = 2 * 50 * 2 + 2 * 3 (Size of global and object script entries)
|
|
||||||
// 20 = 4 * 2 + 2 * 6 (Size of overlay and background incrust entries)
|
|
||||||
static const uint sizeofScreenParams = 2 * 6;
|
|
||||||
static const uint globalScriptEntrySize = 206;
|
|
||||||
static const uint objectScriptEntrySize = 206;
|
|
||||||
static const uint overlayEntrySize = 20;
|
|
||||||
static const uint bgIncrustEntrySize = 20;
|
|
||||||
static const uint chainEntrySizes[] = {
|
|
||||||
globalScriptEntrySize,
|
|
||||||
objectScriptEntrySize,
|
|
||||||
overlayEntrySize,
|
|
||||||
bgIncrustEntrySize
|
|
||||||
};
|
|
||||||
|
|
||||||
uint animEntrySize = animEntrySizeChoices[i];
|
|
||||||
// Jump over the animDataTable entries and the screen parameters
|
|
||||||
int32 newPos = animDataTableStart + animEntrySize * animEntriesCount + sizeofScreenParams;
|
|
||||||
// Check that there's data left after the point we're going to jump to
|
|
||||||
if (newPos >= fHandle.size()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fHandle.seek(newPos);
|
|
||||||
|
|
||||||
// Jump over the remaining items in the savegame file
|
|
||||||
// (i.e. the global scripts, object scripts, overlays and background incrusts).
|
|
||||||
bool chainWalkSuccess = true;
|
|
||||||
for (uint chainIndex = 0; chainIndex < ARRAYSIZE(chainEntrySizes); chainIndex++) {
|
|
||||||
// Read entry count and jump over the entries
|
|
||||||
int entryCount = fHandle.readSint16BE();
|
|
||||||
newPos = fHandle.pos() + chainEntrySizes[chainIndex] * entryCount;
|
|
||||||
// Check that we didn't go past the end of file.
|
|
||||||
// Note that getting exactly to the end of file is acceptable.
|
|
||||||
if (newPos > fHandle.size()) {
|
|
||||||
chainWalkSuccess = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fHandle.seek(newPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we could walk the chain successfully and
|
|
||||||
// got exactly to the end of file then we've got a match.
|
|
||||||
if (chainWalkSuccess && fHandle.pos() == fHandle.size()) {
|
|
||||||
// We found a match, let's save it
|
|
||||||
animEntrySizeMatches.push_back(animEntrySize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that we got only one entry size match.
|
|
||||||
// If we didn't, then return an error.
|
|
||||||
enum CineSaveGameFormat result = ANIMSIZE_UNKNOWN;
|
|
||||||
if (animEntrySizeMatches.size() == 1) {
|
|
||||||
const uint animEntrySize = animEntrySizeMatches[0];
|
|
||||||
assert(animEntrySize == oldAnimEntrySize || animEntrySize == newAnimEntrySize);
|
|
||||||
if (animEntrySize == oldAnimEntrySize) {
|
|
||||||
result = ANIMSIZE_23;
|
|
||||||
} else { // animEntrySize == newAnimEntrySize
|
|
||||||
// Check data and mask pointers in all of the animDataTable entries
|
|
||||||
// to see whether we've got the version with the broken data and mask pointers or not.
|
|
||||||
// In the broken format all data and mask pointers were always zero.
|
|
||||||
static const uint relativeDataPos = 2 * 4;
|
|
||||||
bool pointersIntact = false;
|
|
||||||
for (uint i = 0; i < animEntriesCount; i++) {
|
|
||||||
fHandle.seek(animDataTableStart + i * animEntrySize + relativeDataPos);
|
|
||||||
uint32 data = fHandle.readUint32BE();
|
|
||||||
uint32 mask = fHandle.readUint32BE();
|
|
||||||
if ((data != 0) || (mask != 0)) {
|
|
||||||
pointersIntact = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = (pointersIntact ? ANIMSIZE_30_PTRS_INTACT : ANIMSIZE_30_PTRS_BROKEN);
|
|
||||||
}
|
|
||||||
} else if (animEntrySizeMatches.size() > 1) {
|
|
||||||
warning("Savegame format detector got confused by input data. Detecting savegame to be using an unknown format");
|
|
||||||
} else { // animEtrySizeMatches.size() == 0
|
|
||||||
debug(3, "Savegame format detector was unable to detect savegame's format");
|
|
||||||
}
|
|
||||||
|
|
||||||
fHandle.seek(prevStreamPos);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \brief Restore script list item from savefile
|
|
||||||
* \param fHandle Savefile handle open for reading
|
|
||||||
* \param isGlobal Restore object or global script?
|
|
||||||
*/
|
|
||||||
void loadScriptFromSave(Common::SeekableReadStream &fHandle, bool isGlobal) {
|
|
||||||
ScriptVars localVars, labels;
|
|
||||||
uint16 compare, pos;
|
|
||||||
int16 idx;
|
|
||||||
|
|
||||||
labels.load(fHandle);
|
|
||||||
localVars.load(fHandle);
|
|
||||||
|
|
||||||
compare = fHandle.readUint16BE();
|
|
||||||
pos = fHandle.readUint16BE();
|
|
||||||
idx = fHandle.readUint16BE();
|
|
||||||
|
|
||||||
// no way to reinitialize these
|
|
||||||
if (idx < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// original code loaded everything into globalScripts, this should be
|
|
||||||
// the correct behavior
|
|
||||||
if (isGlobal) {
|
|
||||||
ScriptPtr tmp(scriptInfo->create(*scriptTable[idx], idx, labels, localVars, compare, pos));
|
|
||||||
assert(tmp);
|
|
||||||
globalScripts.push_back(tmp);
|
|
||||||
} else {
|
|
||||||
ScriptPtr tmp(scriptInfo->create(*relTable[idx], idx, labels, localVars, compare, pos));
|
|
||||||
assert(tmp);
|
|
||||||
objectScripts.push_back(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! \brief Restore overlay sprites from savefile
|
|
||||||
* \param fHandle Savefile open for reading
|
|
||||||
*/
|
|
||||||
void loadOverlayFromSave(Common::SeekableReadStream &fHandle) {
|
|
||||||
overlay tmp;
|
|
||||||
|
|
||||||
fHandle.readUint32BE();
|
|
||||||
fHandle.readUint32BE();
|
|
||||||
|
|
||||||
tmp.objIdx = fHandle.readUint16BE();
|
|
||||||
tmp.type = fHandle.readUint16BE();
|
|
||||||
tmp.x = fHandle.readSint16BE();
|
|
||||||
tmp.y = fHandle.readSint16BE();
|
|
||||||
tmp.width = fHandle.readSint16BE();
|
|
||||||
tmp.color = fHandle.readSint16BE();
|
|
||||||
|
|
||||||
overlayList.push_back(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CineEngine::resetEngine() {
|
void CineEngine::resetEngine() {
|
||||||
g_sound->stopMusic();
|
g_sound->stopMusic();
|
||||||
freeAnimDataTable();
|
freeAnimDataTable();
|
||||||
|
@ -668,520 +323,6 @@ void CineEngine::resetEngine() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loadObjectTable(Common::SeekableReadStream &in) {
|
|
||||||
in.readUint16BE(); // Entry count
|
|
||||||
in.readUint16BE(); // Entry size
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_MAX_OBJECT; i++) {
|
|
||||||
objectTable[i].x = in.readSint16BE();
|
|
||||||
objectTable[i].y = in.readSint16BE();
|
|
||||||
objectTable[i].mask = in.readUint16BE();
|
|
||||||
objectTable[i].frame = in.readSint16BE();
|
|
||||||
objectTable[i].costume = in.readSint16BE();
|
|
||||||
in.read(objectTable[i].name, 20);
|
|
||||||
objectTable[i].part = in.readUint16BE();
|
|
||||||
}
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadZoneData(Common::SeekableReadStream &in) {
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
zoneData[i] = in.readUint16BE();
|
|
||||||
}
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadCommandVariables(Common::SeekableReadStream &in) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
commandVar3[i] = in.readUint16BE();
|
|
||||||
}
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadScreenParams(Common::SeekableReadStream &in) {
|
|
||||||
// TODO: handle screen params (really required ?)
|
|
||||||
in.readUint16BE();
|
|
||||||
in.readUint16BE();
|
|
||||||
in.readUint16BE();
|
|
||||||
in.readUint16BE();
|
|
||||||
in.readUint16BE();
|
|
||||||
in.readUint16BE();
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadGlobalScripts(Common::SeekableReadStream &in) {
|
|
||||||
int size = in.readSint16BE();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
loadScriptFromSave(in, true);
|
|
||||||
}
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadObjectScripts(Common::SeekableReadStream &in) {
|
|
||||||
int size = in.readSint16BE();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
loadScriptFromSave(in, false);
|
|
||||||
}
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadOverlayList(Common::SeekableReadStream &in) {
|
|
||||||
int size = in.readSint16BE();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
loadOverlayFromSave(in);
|
|
||||||
}
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadSeqList(Common::SeekableReadStream &in) {
|
|
||||||
uint size = in.readUint16BE();
|
|
||||||
SeqListElement tmp;
|
|
||||||
for (uint i = 0; i < size; i++) {
|
|
||||||
tmp.var4 = in.readSint16BE();
|
|
||||||
tmp.objIdx = in.readUint16BE();
|
|
||||||
tmp.var8 = in.readSint16BE();
|
|
||||||
tmp.frame = in.readSint16BE();
|
|
||||||
tmp.varC = in.readSint16BE();
|
|
||||||
tmp.varE = in.readSint16BE();
|
|
||||||
tmp.var10 = in.readSint16BE();
|
|
||||||
tmp.var12 = in.readSint16BE();
|
|
||||||
tmp.var14 = in.readSint16BE();
|
|
||||||
tmp.var16 = in.readSint16BE();
|
|
||||||
tmp.var18 = in.readSint16BE();
|
|
||||||
tmp.var1A = in.readSint16BE();
|
|
||||||
tmp.var1C = in.readSint16BE();
|
|
||||||
tmp.var1E = in.readSint16BE();
|
|
||||||
seqList.push_back(tmp);
|
|
||||||
}
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool loadZoneQuery(Common::SeekableReadStream &in) {
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
zoneQuery[i] = in.readUint16BE();
|
|
||||||
}
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CineEngine::loadTempSaveOS(Common::SeekableReadStream &in) {
|
|
||||||
char musicName[13];
|
|
||||||
char bgNames[8][13];
|
|
||||||
|
|
||||||
// First check the temporary Operation Stealth savegame format header.
|
|
||||||
ChunkHeader hdr;
|
|
||||||
loadChunkHeader(in, hdr);
|
|
||||||
if (hdr.id != TEMP_OS_FORMAT_ID) {
|
|
||||||
warning("loadTempSaveOS: File has incorrect identifier. Not loading savegame");
|
|
||||||
return false;
|
|
||||||
} else if (hdr.version > CURRENT_OS_SAVE_VER) {
|
|
||||||
warning("loadTempSaveOS: Detected newer format version. Not loading savegame");
|
|
||||||
return false;
|
|
||||||
} else if ((int)hdr.version < (int)CURRENT_OS_SAVE_VER) {
|
|
||||||
warning("loadTempSaveOS: Detected older format version. Trying to load nonetheless. Things may break");
|
|
||||||
} else { // hdr.id == TEMP_OS_FORMAT_ID && hdr.version == CURRENT_OS_SAVE_VER
|
|
||||||
debug(3, "loadTempSaveOS: Found correct header (Both the identifier and version number match).");
|
|
||||||
}
|
|
||||||
|
|
||||||
// There shouldn't be any data in the header's chunk currently so it's an error if there is.
|
|
||||||
if (hdr.size > 0) {
|
|
||||||
warning("loadTempSaveOS: Format header's chunk seems to contain data so format is incorrect. Not loading savegame");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ok, so we've got a correct header for a temporary Operation Stealth savegame.
|
|
||||||
// Let's start loading the plain savegame data then.
|
|
||||||
currentDisk = in.readUint16BE();
|
|
||||||
in.read(currentPartName, 13);
|
|
||||||
in.read(currentPrcName, 13);
|
|
||||||
in.read(currentRelName, 13);
|
|
||||||
in.read(currentMsgName, 13);
|
|
||||||
|
|
||||||
// Load the 8 background names.
|
|
||||||
for (uint i = 0; i < 8; i++) {
|
|
||||||
in.read(bgNames[i], 13);
|
|
||||||
}
|
|
||||||
|
|
||||||
in.read(currentCtName, 13);
|
|
||||||
|
|
||||||
// Moved the loading of current procedure, relation,
|
|
||||||
// backgrounds and Ct here because if they were at the
|
|
||||||
// end of this function then the global scripts loading
|
|
||||||
// made an array out of bounds access. In the original
|
|
||||||
// game's disassembly these aren't here but at the end.
|
|
||||||
// The difference is probably in how we handle loading
|
|
||||||
// the global scripts and some other things (i.e. the
|
|
||||||
// loading routines aren't exactly the same and subtle
|
|
||||||
// semantic differences result in having to do things
|
|
||||||
// in a different order).
|
|
||||||
{
|
|
||||||
// Not sure if this is needed with Operation Stealth...
|
|
||||||
checkDataDisk(currentDisk);
|
|
||||||
|
|
||||||
if (strlen(currentPrcName)) {
|
|
||||||
loadPrc(currentPrcName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(currentRelName)) {
|
|
||||||
loadRel(currentRelName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load first background (Uses loadBg)
|
|
||||||
if (strlen(bgNames[0])) {
|
|
||||||
loadBg(bgNames[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add backgrounds 1-7 (Uses addBackground)
|
|
||||||
for (int i = 1; i < 8; i++) {
|
|
||||||
if (strlen(bgNames[i])) {
|
|
||||||
addBackground(bgNames[i], i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(currentCtName)) {
|
|
||||||
loadCtOS(currentCtName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadObjectTable(in);
|
|
||||||
renderer->restorePalette(in);
|
|
||||||
globalVars.load(in, NUM_MAX_VAR);
|
|
||||||
loadZoneData(in);
|
|
||||||
loadCommandVariables(in);
|
|
||||||
char tempCommandBuffer[kMaxCommandBufferSize];
|
|
||||||
in.read(tempCommandBuffer, kMaxCommandBufferSize);
|
|
||||||
commandBuffer = tempCommandBuffer;
|
|
||||||
renderer->setCommand(commandBuffer);
|
|
||||||
loadZoneQuery(in);
|
|
||||||
|
|
||||||
// TODO: Use the loaded string (Current music name (String, 13 bytes)).
|
|
||||||
in.read(musicName, 13);
|
|
||||||
|
|
||||||
// TODO: Use the loaded value (Is music loaded? (Uint16BE, Boolean)).
|
|
||||||
in.readUint16BE();
|
|
||||||
|
|
||||||
// TODO: Use the loaded value (Is music playing? (Uint16BE, Boolean)).
|
|
||||||
in.readUint16BE();
|
|
||||||
|
|
||||||
renderer->_cmdY = in.readUint16BE();
|
|
||||||
in.readUint16BE(); // Some unknown variable that seems to always be zero
|
|
||||||
allowPlayerInput = in.readUint16BE();
|
|
||||||
playerCommand = in.readUint16BE();
|
|
||||||
commandVar1 = in.readUint16BE();
|
|
||||||
isDrawCommandEnabled = in.readUint16BE();
|
|
||||||
var5 = in.readUint16BE();
|
|
||||||
var4 = in.readUint16BE();
|
|
||||||
var3 = in.readUint16BE();
|
|
||||||
var2 = in.readUint16BE();
|
|
||||||
commandVar2 = in.readUint16BE();
|
|
||||||
renderer->_messageBg = in.readUint16BE();
|
|
||||||
|
|
||||||
// TODO: Use the loaded value (adBgVar1 (Uint16BE)).
|
|
||||||
in.readUint16BE();
|
|
||||||
|
|
||||||
currentAdditionalBgIdx = in.readSint16BE();
|
|
||||||
currentAdditionalBgIdx2 = in.readSint16BE();
|
|
||||||
|
|
||||||
// TODO: Check whether the scroll value really gets used correctly after this.
|
|
||||||
// Note that the backgrounds are loaded only later than this value is set.
|
|
||||||
renderer->setScroll(in.readUint16BE());
|
|
||||||
|
|
||||||
// TODO: Use the loaded value (adBgVar0 (Uint16BE). Maybe this means bgVar0?).
|
|
||||||
in.readUint16BE();
|
|
||||||
|
|
||||||
disableSystemMenu = in.readUint16BE();
|
|
||||||
|
|
||||||
// TODO: adBgVar1 = 1 here
|
|
||||||
|
|
||||||
// Load the animDataTable entries
|
|
||||||
in.readUint16BE(); // Entry count (255 in the PC version of Operation Stealth).
|
|
||||||
in.readUint16BE(); // Entry size (36 in the PC version of Operation Stealth).
|
|
||||||
loadResourcesFromSave(in, ANIMSIZE_30_PTRS_INTACT);
|
|
||||||
|
|
||||||
loadScreenParams(in);
|
|
||||||
loadGlobalScripts(in);
|
|
||||||
loadObjectScripts(in);
|
|
||||||
loadSeqList(in);
|
|
||||||
loadOverlayList(in);
|
|
||||||
loadBgIncrustFromSave(in);
|
|
||||||
|
|
||||||
// Left this here instead of moving it earlier in this function with
|
|
||||||
// the other current value loadings (e.g. loading of current procedure,
|
|
||||||
// current backgrounds etc). Mostly emulating the way we've handled
|
|
||||||
// Future Wars savegames and hoping that things work out.
|
|
||||||
if (strlen(currentMsgName)) {
|
|
||||||
loadMsg(currentMsgName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add current music loading and playing here
|
|
||||||
// TODO: Palette handling?
|
|
||||||
|
|
||||||
if (in.pos() == in.size()) {
|
|
||||||
debug(3, "loadTempSaveOS: Loaded the whole savefile.");
|
|
||||||
} else {
|
|
||||||
warning("loadTempSaveOS: Loaded the savefile but didn't exhaust it completely. Something was left over");
|
|
||||||
}
|
|
||||||
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CineEngine::loadPlainSaveFW(Common::SeekableReadStream &in, CineSaveGameFormat saveGameFormat) {
|
|
||||||
char bgName[13];
|
|
||||||
|
|
||||||
// At savefile position 0x0000:
|
|
||||||
currentDisk = in.readUint16BE();
|
|
||||||
|
|
||||||
// At 0x0002:
|
|
||||||
in.read(currentPartName, 13);
|
|
||||||
// At 0x000F:
|
|
||||||
in.read(currentDatName, 13);
|
|
||||||
|
|
||||||
// At 0x001C:
|
|
||||||
saveVar2 = in.readSint16BE();
|
|
||||||
|
|
||||||
// At 0x001E:
|
|
||||||
in.read(currentPrcName, 13);
|
|
||||||
// At 0x002B:
|
|
||||||
in.read(currentRelName, 13);
|
|
||||||
// At 0x0038:
|
|
||||||
in.read(currentMsgName, 13);
|
|
||||||
// At 0x0045:
|
|
||||||
in.read(bgName, 13);
|
|
||||||
// At 0x0052:
|
|
||||||
in.read(currentCtName, 13);
|
|
||||||
|
|
||||||
checkDataDisk(currentDisk);
|
|
||||||
|
|
||||||
if (strlen(currentPartName)) {
|
|
||||||
loadPart(currentPartName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(currentPrcName)) {
|
|
||||||
loadPrc(currentPrcName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(currentRelName)) {
|
|
||||||
loadRel(currentRelName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(bgName)) {
|
|
||||||
loadBg(bgName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(currentCtName)) {
|
|
||||||
loadCtFW(currentCtName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// At 0x005F:
|
|
||||||
loadObjectTable(in);
|
|
||||||
|
|
||||||
// At 0x2043 (i.e. 0x005F + 2 * 2 + 255 * 32):
|
|
||||||
renderer->restorePalette(in);
|
|
||||||
|
|
||||||
// At 0x2083 (i.e. 0x2043 + 16 * 2 * 2):
|
|
||||||
globalVars.load(in, NUM_MAX_VAR);
|
|
||||||
|
|
||||||
// At 0x2281 (i.e. 0x2083 + 255 * 2):
|
|
||||||
loadZoneData(in);
|
|
||||||
|
|
||||||
// At 0x22A1 (i.e. 0x2281 + 16 * 2):
|
|
||||||
loadCommandVariables(in);
|
|
||||||
|
|
||||||
// At 0x22A9 (i.e. 0x22A1 + 4 * 2):
|
|
||||||
char tempCommandBuffer[kMaxCommandBufferSize];
|
|
||||||
in.read(tempCommandBuffer, kMaxCommandBufferSize);
|
|
||||||
commandBuffer = tempCommandBuffer;
|
|
||||||
renderer->setCommand(commandBuffer);
|
|
||||||
|
|
||||||
// At 0x22F9 (i.e. 0x22A9 + 0x50):
|
|
||||||
renderer->_cmdY = in.readUint16BE();
|
|
||||||
|
|
||||||
// At 0x22FB:
|
|
||||||
bgVar0 = in.readUint16BE();
|
|
||||||
// At 0x22FD:
|
|
||||||
allowPlayerInput = in.readUint16BE();
|
|
||||||
// At 0x22FF:
|
|
||||||
playerCommand = in.readSint16BE();
|
|
||||||
// At 0x2301:
|
|
||||||
commandVar1 = in.readSint16BE();
|
|
||||||
// At 0x2303:
|
|
||||||
isDrawCommandEnabled = in.readUint16BE();
|
|
||||||
// At 0x2305:
|
|
||||||
var5 = in.readUint16BE();
|
|
||||||
// At 0x2307:
|
|
||||||
var4 = in.readUint16BE();
|
|
||||||
// At 0x2309:
|
|
||||||
var3 = in.readUint16BE();
|
|
||||||
// At 0x230B:
|
|
||||||
var2 = in.readUint16BE();
|
|
||||||
// At 0x230D:
|
|
||||||
commandVar2 = in.readSint16BE();
|
|
||||||
|
|
||||||
// At 0x230F:
|
|
||||||
renderer->_messageBg = in.readUint16BE();
|
|
||||||
|
|
||||||
// At 0x2311:
|
|
||||||
in.readUint16BE();
|
|
||||||
// At 0x2313:
|
|
||||||
in.readUint16BE();
|
|
||||||
|
|
||||||
// At 0x2315:
|
|
||||||
loadResourcesFromSave(in, saveGameFormat);
|
|
||||||
|
|
||||||
loadScreenParams(in);
|
|
||||||
loadGlobalScripts(in);
|
|
||||||
loadObjectScripts(in);
|
|
||||||
loadOverlayList(in);
|
|
||||||
loadBgIncrustFromSave(in);
|
|
||||||
|
|
||||||
if (strlen(currentMsgName)) {
|
|
||||||
loadMsg(currentMsgName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(currentDatName)) {
|
|
||||||
/* i = saveVar2;
|
|
||||||
saveVar2 = 0;
|
|
||||||
loadMusic();
|
|
||||||
if (i) {
|
|
||||||
playMusic();
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
return !in.ioFailed();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CineEngine::makeLoad(char *saveName) {
|
|
||||||
Common::SharedPtr<Common::InSaveFile> saveFile(g_saveFileMan->openForLoading(saveName));
|
|
||||||
|
|
||||||
if (!saveFile) {
|
|
||||||
drawString(otherMessages[0], 0);
|
|
||||||
waitPlayerInput();
|
|
||||||
// restoreScreen();
|
|
||||||
checkDataDisk(-1);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setMouseCursor(MOUSE_CURSOR_DISK);
|
|
||||||
|
|
||||||
uint32 saveSize = saveFile->size();
|
|
||||||
// TODO: Evaluate the maximum savegame size for the temporary Operation Stealth savegame format.
|
|
||||||
if (saveSize == 0) { // Savefile's compressed using zlib format can't tell their unpacked size, test for it
|
|
||||||
// Can't get information about the savefile's size so let's try
|
|
||||||
// reading as much as we can from the file up to a predefined upper limit.
|
|
||||||
//
|
|
||||||
// Some estimates for maximum savefile sizes (All with 255 animDataTable entries of 30 bytes each):
|
|
||||||
// With 256 global scripts, object scripts, overlays and background incrusts:
|
|
||||||
// 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 256 = ~129kB
|
|
||||||
// With 512 global scripts, object scripts, overlays and background incrusts:
|
|
||||||
// 0x2315 + (255 * 30) + (2 * 6) + (206 + 206 + 20 + 20) * 512 = ~242kB
|
|
||||||
//
|
|
||||||
// I think it extremely unlikely that there would be over 512 global scripts, object scripts,
|
|
||||||
// overlays and background incrusts so 256kB seems like quite a safe upper limit.
|
|
||||||
// NOTE: If the savegame format is changed then this value might have to be re-evaluated!
|
|
||||||
// Hopefully devices with more limited memory can also cope with this memory allocation.
|
|
||||||
saveSize = 256 * 1024;
|
|
||||||
}
|
|
||||||
Common::SharedPtr<Common::MemoryReadStream> in(saveFile->readStream(saveSize));
|
|
||||||
|
|
||||||
// Try to detect the used savegame format
|
|
||||||
enum CineSaveGameFormat saveGameFormat = detectSaveGameFormat(*in);
|
|
||||||
|
|
||||||
// Handle problematic savegame formats
|
|
||||||
bool load = true; // Should we try to load the savegame?
|
|
||||||
bool result = false;
|
|
||||||
if (saveGameFormat == ANIMSIZE_30_PTRS_BROKEN) {
|
|
||||||
// One might be able to load the ANIMSIZE_30_PTRS_BROKEN format but
|
|
||||||
// that's not implemented here because it was never used in a stable
|
|
||||||
// release of ScummVM but only during development (From revision 31453,
|
|
||||||
// which introduced the problem, until revision 32073, which fixed it).
|
|
||||||
// Therefore we bail out if we detect this particular savegame format.
|
|
||||||
warning("Detected a known broken savegame format, not loading savegame");
|
|
||||||
load = false; // Don't load the savegame
|
|
||||||
} else if (saveGameFormat == ANIMSIZE_UNKNOWN) {
|
|
||||||
// If we can't detect the savegame format
|
|
||||||
// then let's try the default format and hope for the best.
|
|
||||||
warning("Couldn't detect the used savegame format, trying default savegame format. Things may break");
|
|
||||||
saveGameFormat = ANIMSIZE_30_PTRS_INTACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (load) {
|
|
||||||
// Reset the engine's state
|
|
||||||
resetEngine();
|
|
||||||
|
|
||||||
if (saveGameFormat == TEMP_OS_FORMAT) {
|
|
||||||
// Load the temporary Operation Stealth savegame format
|
|
||||||
result = loadTempSaveOS(*in);
|
|
||||||
} else {
|
|
||||||
// Load the plain Future Wars savegame format
|
|
||||||
result = loadPlainSaveFW(*in, saveGameFormat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setMouseCursor(MOUSE_CURSOR_NORMAL);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CineEngine::makeSaveFW(Common::OutSaveFile &out) {
|
|
||||||
out.writeUint16BE(currentDisk);
|
|
||||||
out.write(currentPartName, 13);
|
|
||||||
out.write(currentDatName, 13);
|
|
||||||
out.writeUint16BE(saveVar2);
|
|
||||||
out.write(currentPrcName, 13);
|
|
||||||
out.write(currentRelName, 13);
|
|
||||||
out.write(currentMsgName, 13);
|
|
||||||
renderer->saveBgNames(out);
|
|
||||||
out.write(currentCtName, 13);
|
|
||||||
|
|
||||||
saveObjectTable(out);
|
|
||||||
renderer->savePalette(out);
|
|
||||||
globalVars.save(out, NUM_MAX_VAR);
|
|
||||||
saveZoneData(out);
|
|
||||||
saveCommandVariables(out);
|
|
||||||
saveCommandBuffer(out);
|
|
||||||
|
|
||||||
out.writeUint16BE(renderer->_cmdY);
|
|
||||||
out.writeUint16BE(bgVar0);
|
|
||||||
out.writeUint16BE(allowPlayerInput);
|
|
||||||
out.writeUint16BE(playerCommand);
|
|
||||||
out.writeUint16BE(commandVar1);
|
|
||||||
out.writeUint16BE(isDrawCommandEnabled);
|
|
||||||
out.writeUint16BE(var5);
|
|
||||||
out.writeUint16BE(var4);
|
|
||||||
out.writeUint16BE(var3);
|
|
||||||
out.writeUint16BE(var2);
|
|
||||||
out.writeUint16BE(commandVar2);
|
|
||||||
out.writeUint16BE(renderer->_messageBg);
|
|
||||||
|
|
||||||
saveAnimDataTable(out);
|
|
||||||
saveScreenParams(out);
|
|
||||||
|
|
||||||
saveGlobalScripts(out);
|
|
||||||
saveObjectScripts(out);
|
|
||||||
saveOverlayList(out);
|
|
||||||
saveBgIncrustList(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CineEngine::makeSave(char *saveFileName) {
|
|
||||||
Common::SharedPtr<Common::OutSaveFile> fHandle(g_saveFileMan->openForSaving(saveFileName));
|
|
||||||
|
|
||||||
setMouseCursor(MOUSE_CURSOR_DISK);
|
|
||||||
|
|
||||||
if (!fHandle) {
|
|
||||||
drawString(otherMessages[1], 0);
|
|
||||||
waitPlayerInput();
|
|
||||||
// restoreScreen();
|
|
||||||
checkDataDisk(-1);
|
|
||||||
} else {
|
|
||||||
if (g_cine->getGameType() == GType_FW) {
|
|
||||||
makeSaveFW(*fHandle);
|
|
||||||
} else {
|
|
||||||
makeSaveOS(*fHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setMouseCursor(MOUSE_CURSOR_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CineEngine::makeSystemMenu(void) {
|
void CineEngine::makeSystemMenu(void) {
|
||||||
int16 numEntry, systemCommand;
|
int16 numEntry, systemCommand;
|
||||||
int16 mouseX, mouseY, mouseButton;
|
int16 mouseX, mouseY, mouseButton;
|
||||||
|
@ -1319,89 +460,6 @@ void CineEngine::makeSystemMenu(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Save an Operation Stealth type savegame. WIP!
|
|
||||||
*
|
|
||||||
* NOTE: This is going to be very much a work in progress so the Operation Stealth's
|
|
||||||
* savegame formats that are going to be tried are extremely probably not going
|
|
||||||
* to be supported at all after Operation Stealth becomes officially supported.
|
|
||||||
* This means that the savegame format will hopefully change to something nicer
|
|
||||||
* when official support for Operation Stealth begins.
|
|
||||||
*/
|
|
||||||
void CineEngine::makeSaveOS(Common::OutSaveFile &out) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// Make a temporary Operation Stealth savegame format chunk header and save it.
|
|
||||||
ChunkHeader header;
|
|
||||||
header.id = TEMP_OS_FORMAT_ID;
|
|
||||||
header.version = CURRENT_OS_SAVE_VER;
|
|
||||||
header.size = 0; // No data is currently put inside the chunk, all the plain data comes right after it.
|
|
||||||
writeChunkHeader(out, header);
|
|
||||||
|
|
||||||
// Start outputting the plain savegame data right after the chunk header.
|
|
||||||
out.writeUint16BE(currentDisk);
|
|
||||||
out.write(currentPartName, 13);
|
|
||||||
out.write(currentPrcName, 13);
|
|
||||||
out.write(currentRelName, 13);
|
|
||||||
out.write(currentMsgName, 13);
|
|
||||||
renderer->saveBgNames(out);
|
|
||||||
out.write(currentCtName, 13);
|
|
||||||
|
|
||||||
saveObjectTable(out);
|
|
||||||
renderer->savePalette(out);
|
|
||||||
globalVars.save(out, NUM_MAX_VAR);
|
|
||||||
saveZoneData(out);
|
|
||||||
saveCommandVariables(out);
|
|
||||||
saveCommandBuffer(out);
|
|
||||||
saveZoneQuery(out);
|
|
||||||
|
|
||||||
// FIXME: Save a proper name here, saving an empty string currently.
|
|
||||||
// 0x2925: Current music name (String, 13 bytes).
|
|
||||||
for (i = 0; i < 13; i++) {
|
|
||||||
out.writeByte(0);
|
|
||||||
}
|
|
||||||
// FIXME: Save proper value for this variable, currently writing zero
|
|
||||||
// 0x2932: Is music loaded? (Uint16BE, Boolean).
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
// FIXME: Save proper value for this variable, currently writing zero
|
|
||||||
// 0x2934: Is music playing? (Uint16BE, Boolean).
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
|
|
||||||
out.writeUint16BE(renderer->_cmdY);
|
|
||||||
out.writeUint16BE(0); // Some unknown variable that seems to always be zero
|
|
||||||
out.writeUint16BE(allowPlayerInput);
|
|
||||||
out.writeUint16BE(playerCommand);
|
|
||||||
out.writeUint16BE(commandVar1);
|
|
||||||
out.writeUint16BE(isDrawCommandEnabled);
|
|
||||||
out.writeUint16BE(var5);
|
|
||||||
out.writeUint16BE(var4);
|
|
||||||
out.writeUint16BE(var3);
|
|
||||||
out.writeUint16BE(var2);
|
|
||||||
out.writeUint16BE(commandVar2);
|
|
||||||
out.writeUint16BE(renderer->_messageBg);
|
|
||||||
|
|
||||||
// FIXME: Save proper value for this variable, currently writing zero.
|
|
||||||
// An unknown variable at 0x295E: adBgVar1 (Uint16BE).
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
out.writeSint16BE(currentAdditionalBgIdx);
|
|
||||||
out.writeSint16BE(currentAdditionalBgIdx2);
|
|
||||||
// FIXME: Save proper value for this variable, currently writing zero.
|
|
||||||
// 0x2954: additionalBgVScroll (Uint16BE). This probably means renderer->_bgShift.
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
// FIXME: Save proper value for this variable, currently writing zero.
|
|
||||||
// An unknown variable at 0x2956: adBgVar0 (Uint16BE). Maybe this means bgVar0?
|
|
||||||
out.writeUint16BE(0);
|
|
||||||
out.writeUint16BE(disableSystemMenu);
|
|
||||||
|
|
||||||
saveAnimDataTable(out);
|
|
||||||
saveScreenParams(out);
|
|
||||||
saveGlobalScripts(out);
|
|
||||||
saveObjectScripts(out);
|
|
||||||
saveSeqList(out);
|
|
||||||
saveOverlayList(out);
|
|
||||||
saveBgIncrustList(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
void drawMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 offset, int16 color, byte* page) {
|
void drawMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 offset, int16 color, byte* page) {
|
||||||
gfxDrawLine(x + offset, y + offset, x + width - offset, y + offset, color, page); // top
|
gfxDrawLine(x + offset, y + offset, x + width - offset, y + offset, color, page); // top
|
||||||
gfxDrawLine(x + offset, currentY + 4 - offset, x + width - offset, currentY + 4 - offset, color, page); // bottom
|
gfxDrawLine(x + offset, currentY + 4 - offset, x + width - offset, currentY + 4 - offset, color, page); // bottom
|
||||||
|
|
|
@ -41,6 +41,9 @@ void initLanguage(Common::Language lang);
|
||||||
int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y, uint16 width, bool recheckValue = false);
|
int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y, uint16 width, bool recheckValue = false);
|
||||||
void makeCommandLine(void);
|
void makeCommandLine(void);
|
||||||
void makeActionMenu(void);
|
void makeActionMenu(void);
|
||||||
|
void drawString(const char *string, byte param);
|
||||||
|
void waitPlayerInput(void);
|
||||||
|
void setTextWindow(uint16 param1, uint16 param2, uint16 param3, uint16 param4);
|
||||||
|
|
||||||
extern bool disableSystemMenu;
|
extern bool disableSystemMenu;
|
||||||
extern bool inMenu;
|
extern bool inMenu;
|
||||||
|
@ -70,6 +73,11 @@ extern uint16 var2;
|
||||||
extern uint16 var3;
|
extern uint16 var3;
|
||||||
extern uint16 var4;
|
extern uint16 var4;
|
||||||
extern uint16 var5;
|
extern uint16 var5;
|
||||||
|
extern int16 commandVar1;
|
||||||
|
extern int16 commandVar2;
|
||||||
|
extern int16 commandVar3[4];
|
||||||
|
|
||||||
|
extern char currentDatName[30];
|
||||||
|
|
||||||
void setTextWindow(uint16 param1, uint16 param2, uint16 param3, uint16 param4);
|
void setTextWindow(uint16 param1, uint16 param2, uint16 param3, uint16 param4);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue