mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-14 00:54:05 +02:00
fix save game
This commit is contained in:
@@ -330,7 +330,7 @@ struct Camera : ICamera {
|
|||||||
|
|
||||||
if (indexA == level->cameraFramesCount - 1) {
|
if (indexA == level->cameraFramesCount - 1) {
|
||||||
if (level->isCutsceneLevel())
|
if (level->isCutsceneLevel())
|
||||||
game->loadNextLevel(true);
|
game->loadNextLevel();
|
||||||
else {
|
else {
|
||||||
Character *lara = (Character*)owner;
|
Character *lara = (Character*)owner;
|
||||||
if (lara->health > 0.0f)
|
if (lara->health > 0.0f)
|
||||||
|
@@ -49,9 +49,9 @@ struct ICamera {
|
|||||||
|
|
||||||
struct IGame {
|
struct IGame {
|
||||||
virtual ~IGame() {}
|
virtual ~IGame() {}
|
||||||
virtual void loadLevel(TR::LevelID id, bool showSaveGame) {}
|
virtual void loadLevel(TR::LevelID id) {}
|
||||||
virtual void loadNextLevel(bool showSaveGame) {}
|
virtual void loadNextLevel() {}
|
||||||
virtual void saveGame(bool checkpoint) {}
|
virtual void saveGame(bool checkpoint, bool updateStats) {}
|
||||||
virtual void loadGame(int slot) {}
|
virtual void loadGame(int slot) {}
|
||||||
virtual void applySettings(const Core::Settings &settings) {}
|
virtual void applySettings(const Core::Settings &settings) {}
|
||||||
|
|
||||||
@@ -1079,7 +1079,7 @@ struct Controller {
|
|||||||
switch (fx) {
|
switch (fx) {
|
||||||
case TR::Effect::ROTATE_180 : angle.y = angle.y + PI; break;
|
case TR::Effect::ROTATE_180 : angle.y = angle.y + PI; break;
|
||||||
case TR::Effect::FLOOR_SHAKE : game->setEffect(this, TR::Effect::Type(fx)); break;
|
case TR::Effect::FLOOR_SHAKE : game->setEffect(this, TR::Effect::Type(fx)); break;
|
||||||
case TR::Effect::FINISH_LEVEL : game->loadNextLevel(true); break;
|
case TR::Effect::FINISH_LEVEL : game->loadNextLevel(); break;
|
||||||
case TR::Effect::FLIP_MAP : game->flipMap(); break;
|
case TR::Effect::FLIP_MAP : game->flipMap(); break;
|
||||||
default : cmdEffect(fx); break;
|
default : cmdEffect(fx); break;
|
||||||
}
|
}
|
||||||
|
@@ -188,7 +188,7 @@ namespace Game {
|
|||||||
|
|
||||||
if (Input::down[ik5] && !level->inventory->isActive()) {
|
if (Input::down[ik5] && !level->inventory->isActive()) {
|
||||||
if (level->players[0]->canSaveGame())
|
if (level->players[0]->canSaveGame())
|
||||||
level->saveGame(true);
|
level->saveGame(true, false);
|
||||||
Input::down[ik5] = false;
|
Input::down[ik5] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -754,6 +754,20 @@ namespace TR {
|
|||||||
return VER_UNKNOWN;
|
return VER_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LevelID getNextSaveLevel(LevelID id) {
|
||||||
|
Version version = getGameVersionByLevel(id);
|
||||||
|
LevelID end = getEndId(version);
|
||||||
|
|
||||||
|
while (id != end) {
|
||||||
|
id = LevelID(id + 1);
|
||||||
|
if (!isCutsceneLevel(id))
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LVL_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
void getGameLevelFile(char *dst, Version version, LevelID id) {
|
void getGameLevelFile(char *dst, Version version, LevelID id) {
|
||||||
if (useEasyStart) {
|
if (useEasyStart) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
|
@@ -1096,7 +1096,7 @@ struct Inventory {
|
|||||||
Controller *controller = (Controller*)e.controller;
|
Controller *controller = (Controller*)e.controller;
|
||||||
controller->deactivate(true);
|
controller->deactivate(true);
|
||||||
}
|
}
|
||||||
game->saveGame(index > -1);
|
game->saveGame(index > -1, false);
|
||||||
}
|
}
|
||||||
toggle(playerIndex, targetPage);
|
toggle(playerIndex, targetPage);
|
||||||
}
|
}
|
||||||
@@ -1220,7 +1220,7 @@ struct Inventory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!isActive() && nextLevel != TR::LVL_MAX)
|
if (!isActive() && nextLevel != TR::LVL_MAX)
|
||||||
game->loadLevel(nextLevel, false);
|
game->loadLevel(nextLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void chooseItem() {
|
void chooseItem() {
|
||||||
|
@@ -1788,7 +1788,7 @@ struct Lara : Character {
|
|||||||
if (level->state.tracks[track].once) {
|
if (level->state.tracks[track].once) {
|
||||||
timer += Core::deltaTime;
|
timer += Core::deltaTime;
|
||||||
if (timer > 3.0f)
|
if (timer > 3.0f)
|
||||||
game->loadNextLevel(false);
|
game->loadNextLevel();
|
||||||
} else {
|
} else {
|
||||||
if (state != STATE_WATER_OUT)
|
if (state != STATE_WATER_OUT)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2063,7 +2063,7 @@ struct Lara : Character {
|
|||||||
cameraTarget = (Controller*)level->entities[cmd.args].controller;
|
cameraTarget = (Controller*)level->entities[cmd.args].controller;
|
||||||
break;
|
break;
|
||||||
case TR::Action::END :
|
case TR::Action::END :
|
||||||
game->loadNextLevel(true);
|
game->loadNextLevel();
|
||||||
break;
|
break;
|
||||||
case TR::Action::SOUNDTRACK : {
|
case TR::Action::SOUNDTRACK : {
|
||||||
int track = doTutorial(cmd.args);
|
int track = doTutorial(cmd.args);
|
||||||
|
99
src/level.h
99
src/level.h
@@ -69,26 +69,35 @@ struct Level : IGame {
|
|||||||
float animTexTimer;
|
float animTexTimer;
|
||||||
|
|
||||||
// IGame implementation ========
|
// IGame implementation ========
|
||||||
virtual void loadLevel(TR::LevelID id, bool showSaveGame) {
|
virtual void loadLevel(TR::LevelID id) {
|
||||||
if (nextLevel != TR::LVL_MAX) return;
|
if (nextLevel != TR::LVL_MAX) return;
|
||||||
|
|
||||||
sndWater = sndTrack = NULL;
|
sndWater = sndTrack = NULL;
|
||||||
Sound::stopAll();
|
Sound::stopAll();
|
||||||
|
|
||||||
nextLevel = id;
|
if (loadSlot == -1 && !TR::isCutsceneLevel(level.id)) {
|
||||||
|
// update statistics info for current level
|
||||||
|
saveGame(false, true);
|
||||||
|
// save next level
|
||||||
|
level.id = TR::getNextSaveLevel(level.id); // get next not cutscene level
|
||||||
|
if (level.id != TR::LVL_MAX) {
|
||||||
|
memset(&level.levelStats, 0, sizeof(level.levelStats));
|
||||||
|
saveGame(false, false);
|
||||||
|
loadSlot = getSaveSlot(level.id, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (showSaveGame && !TR::isCutsceneLevel(nextLevel))
|
nextLevel = id;
|
||||||
invShow(camera->cameraIndex, Inventory::PAGE_SAVEGAME, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void loadNextLevel(bool showSaveGame) {
|
virtual void loadNextLevel() {
|
||||||
#ifdef _OS_WEB
|
#ifdef _OS_WEB
|
||||||
if (level.id == TR::LVL_TR1_2 && level.version != TR::VER_TR1_PC) {
|
if (level.id == TR::LVL_TR1_2 && level.version != TR::VER_TR1_PC) {
|
||||||
loadLevel(TR::LVL_TR1_TITLE, showSaveGame);
|
loadLevel(TR::LVL_TR1_TITLE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
loadLevel((level.isEnd() || level.isHome()) ? level.getTitleId() : TR::LevelID(level.id + 1), showSaveGame);
|
loadLevel((level.isEnd() || level.isHome()) ? level.getTitleId() : TR::LevelID(level.id + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void invShow(int playerIndex, int page, int itemIndex = -1) {
|
virtual void invShow(int playerIndex, int page, int itemIndex = -1) {
|
||||||
@@ -103,14 +112,17 @@ struct Level : IGame {
|
|||||||
|
|
||||||
// allocate oversized data for save slot
|
// allocate oversized data for save slot
|
||||||
slot.data = new uint8[sizeof(SaveProgress) + sizeof(SaveItem) * inventory->itemsCount + // for every save
|
slot.data = new uint8[sizeof(SaveProgress) + sizeof(SaveItem) * inventory->itemsCount + // for every save
|
||||||
sizeof(SaveProgress) + sizeof(SaveState) + sizeof(SaveEntity) * level.entitiesCount]; // only for checkpoints
|
sizeof(SaveState) + sizeof(SaveEntity) * level.entitiesCount]; // only for checkpoints
|
||||||
|
|
||||||
uint8 *ptr = slot.data;
|
uint8 *ptr = slot.data;
|
||||||
|
|
||||||
// game progress stats
|
// level progress stats
|
||||||
SaveProgress *gameStats = (SaveProgress*)ptr;
|
SaveProgress *levelStats = (SaveProgress*)ptr;
|
||||||
ptr += sizeof(*gameStats);
|
ptr += sizeof(*levelStats);
|
||||||
*gameStats = level.gameStats;
|
if (dummy)
|
||||||
|
memset(levelStats, 0, sizeof(*levelStats));
|
||||||
|
else
|
||||||
|
*levelStats = level.levelStats;
|
||||||
|
|
||||||
// inventory items
|
// inventory items
|
||||||
int32 *itemsCount = (int32*)ptr;
|
int32 *itemsCount = (int32*)ptr;
|
||||||
@@ -129,7 +141,7 @@ struct Level : IGame {
|
|||||||
for (int i = 0; i < inventory->itemsCount; i++) {
|
for (int i = 0; i < inventory->itemsCount; i++) {
|
||||||
Inventory::Item *invItem = inventory->items[i];
|
Inventory::Item *invItem = inventory->items[i];
|
||||||
|
|
||||||
if (!TR::Entity::isPickup(TR::Entity::convFromInv(invItem->type))) continue;
|
if (!checkpoint && !TR::Entity::isCrossLevelItem(TR::Entity::convFromInv(invItem->type))) continue;
|
||||||
|
|
||||||
SaveItem *item = (SaveItem*)ptr;
|
SaveItem *item = (SaveItem*)ptr;
|
||||||
ptr += sizeof(*item);
|
ptr += sizeof(*item);
|
||||||
@@ -142,11 +154,6 @@ struct Level : IGame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (checkpoint) {
|
if (checkpoint) {
|
||||||
// level progress stats
|
|
||||||
SaveProgress *levelStats = (SaveProgress*)ptr;
|
|
||||||
ptr += sizeof(*levelStats);
|
|
||||||
*levelStats = level.levelStats;
|
|
||||||
|
|
||||||
// level state
|
// level state
|
||||||
SaveState *state = (SaveState*)ptr;
|
SaveState *state = (SaveState*)ptr;
|
||||||
ptr += sizeof(*state);
|
ptr += sizeof(*state);
|
||||||
@@ -182,9 +189,9 @@ struct Level : IGame {
|
|||||||
uint8 *data = slot.data;
|
uint8 *data = slot.data;
|
||||||
uint8 *ptr = data;
|
uint8 *ptr = data;
|
||||||
|
|
||||||
// game progress stats
|
// level progress stats
|
||||||
level.gameStats = *(SaveProgress*)ptr;
|
level.levelStats = *(SaveProgress*)ptr;
|
||||||
ptr += sizeof(level.gameStats);
|
ptr += sizeof(level.levelStats);
|
||||||
|
|
||||||
// inventory items
|
// inventory items
|
||||||
int32 itemsCount = *(int32*)ptr;
|
int32 itemsCount = *(int32*)ptr;
|
||||||
@@ -199,10 +206,6 @@ struct Level : IGame {
|
|||||||
if (slot.level & LVL_FLAG_CHECKPOINT) {
|
if (slot.level & LVL_FLAG_CHECKPOINT) {
|
||||||
clearEntities();
|
clearEntities();
|
||||||
|
|
||||||
// level progress stats
|
|
||||||
level.levelStats = *(SaveProgress*)ptr;
|
|
||||||
ptr += sizeof(level.levelStats);
|
|
||||||
|
|
||||||
// level state
|
// level state
|
||||||
level.state = *(SaveState*)ptr;
|
level.state = *(SaveState*)ptr;
|
||||||
ptr += sizeof(level.state);
|
ptr += sizeof(level.state);
|
||||||
@@ -235,10 +238,15 @@ struct Level : IGame {
|
|||||||
ptr += (sizeof(SaveEntity) - sizeof(SaveEntity::Extra)) + entity->extraSize;
|
ptr += (sizeof(SaveEntity) - sizeof(SaveEntity::Extra)) + entity->extraSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (level.state.flags.flipped) {
|
||||||
|
flipMap();
|
||||||
|
}
|
||||||
|
|
||||||
uint8 track = level.state.flags.track;
|
uint8 track = level.state.flags.track;
|
||||||
level.state.flags.track = 0;
|
level.state.flags.track = 0;
|
||||||
playTrack(track);
|
playTrack(track);
|
||||||
}
|
} else
|
||||||
|
memset(&level.levelStats, 0, sizeof(level.levelStats));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveGameWriteAsync(Stream *stream, void *userData) {
|
static void saveGameWriteAsync(Stream *stream, void *userData) {
|
||||||
@@ -253,7 +261,7 @@ struct Level : IGame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void saveGame(bool checkpoint) {
|
virtual void saveGame(bool checkpoint, bool updateStats) {
|
||||||
ASSERT(saveResult != SAVE_RESULT_WAIT);
|
ASSERT(saveResult != SAVE_RESULT_WAIT);
|
||||||
|
|
||||||
if (saveResult == SAVE_RESULT_WAIT)
|
if (saveResult == SAVE_RESULT_WAIT)
|
||||||
@@ -265,18 +273,22 @@ struct Level : IGame {
|
|||||||
LOG("Save Game...\n");
|
LOG("Save Game...\n");
|
||||||
|
|
||||||
TR::LevelID id = level.id;
|
TR::LevelID id = level.id;
|
||||||
if (!checkpoint) {
|
|
||||||
ASSERT(nextLevel != TR::LVL_MAX);
|
SaveSlot slot;
|
||||||
id = nextLevel;
|
if (updateStats) {
|
||||||
|
int index = getSaveSlot(id, false);
|
||||||
|
if (index == -1) {
|
||||||
|
slot = createSaveSlot(id, false, true);
|
||||||
|
saveSlots.push(slot);
|
||||||
|
} else
|
||||||
|
slot = saveSlots[index];
|
||||||
|
SaveProgress *levelStats = (SaveProgress*)slot.data;
|
||||||
|
*levelStats = level.levelStats;
|
||||||
|
} else {
|
||||||
|
removeSaveSlot(id, checkpoint); // remove checkpoints and level saves
|
||||||
|
saveSlots.push(createSaveSlot(id, checkpoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeSaveSlot(id, checkpoint);
|
|
||||||
|
|
||||||
TR::LevelID startID = TR::getStartId(level.version);
|
|
||||||
if (!checkpoint && getSaveSlot(startID, false) == -1)
|
|
||||||
saveSlots.push(createSaveSlot(startID, false, true)); // add first level save game
|
|
||||||
|
|
||||||
saveSlots.push(createSaveSlot(id, checkpoint));
|
|
||||||
saveSlots.sort();
|
saveSlots.sort();
|
||||||
|
|
||||||
int size;
|
int size;
|
||||||
@@ -843,7 +855,8 @@ struct Level : IGame {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
saveResult = SAVE_RESULT_SUCCESS;
|
saveResult = SAVE_RESULT_SUCCESS;
|
||||||
parseLoadSlot();
|
if (loadSlot != -1 && (saveSlots[loadSlot].level & ~LVL_FLAG_CHECKPOINT) == level.id)
|
||||||
|
parseLoadSlot();
|
||||||
|
|
||||||
Core::resetTime();
|
Core::resetTime();
|
||||||
}
|
}
|
||||||
@@ -1685,7 +1698,7 @@ struct Level : IGame {
|
|||||||
if (level.isCutsceneLevel() && waitTrack) {
|
if (level.isCutsceneLevel() && waitTrack) {
|
||||||
if (!sndTrack && TR::LEVEL_INFO[level.id].track != TR::NO_TRACK) {
|
if (!sndTrack && TR::LEVEL_INFO[level.id].track != TR::NO_TRACK) {
|
||||||
if (camera->timer > 0.0f) // for the case that audio stops before animation ends
|
if (camera->timer > 0.0f) // for the case that audio stops before animation ends
|
||||||
loadNextLevel(true);
|
loadNextLevel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1706,7 +1719,7 @@ struct Level : IGame {
|
|||||||
int playerIndex = (Input::lastState[0] == cInventory) ? 0 : 1;
|
int playerIndex = (Input::lastState[0] == cInventory) ? 0 : 1;
|
||||||
|
|
||||||
if (level.isCutsceneLevel()) { // skip cutscene level
|
if (level.isCutsceneLevel()) { // skip cutscene level
|
||||||
loadNextLevel(true);
|
loadNextLevel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1723,12 +1736,12 @@ struct Level : IGame {
|
|||||||
if (inventory->titleTimer > 1.0f)
|
if (inventory->titleTimer > 1.0f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (loadSlot > -1 && nextLevel == TR::LVL_MAX) {
|
if (loadSlot > -1 && nextLevel == TR::LVL_MAX && !level.isCutsceneLevel()) {
|
||||||
if (inventory->isActive())
|
if (inventory->isActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TR::LevelID id = TR::LevelID(saveSlots[loadSlot].level & ~LVL_FLAG_CHECKPOINT);
|
TR::LevelID id = TR::LevelID(saveSlots[loadSlot].level & ~LVL_FLAG_CHECKPOINT);
|
||||||
loadLevel(id, false);
|
loadLevel(id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -163,7 +163,7 @@ void removeSaveSlot(TR::LevelID levelID, bool checkpoint) {
|
|||||||
if (TR::getGameVersionByLevel(id) != version)
|
if (TR::getGameVersionByLevel(id) != version)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ((checkpoint && isCheckpointSlot) || (!checkpoint && levelID == id)) {
|
if (isCheckpointSlot || (!checkpoint && levelID == id)) {
|
||||||
delete[] slot.data;
|
delete[] slot.data;
|
||||||
saveSlots.remove(i);
|
saveSlots.remove(i);
|
||||||
i--;
|
i--;
|
||||||
|
Reference in New Issue
Block a user