scummvm/engines/tinsel/savescn.cpp
2008-07-25 09:18:39 +00:00

337 lines
8.1 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 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$
*
* Save and restore scene and game.
*/
#include "tinsel/actors.h"
#include "tinsel/background.h"
#include "tinsel/config.h"
#include "tinsel/dw.h"
#include "tinsel/faders.h" // FadeOutFast()
#include "tinsel/graphics.h" // ClearScreen()
#include "tinsel/handle.h"
#include "tinsel/inventory.h"
#include "tinsel/music.h"
#include "tinsel/pid.h"
#include "tinsel/polygons.h"
#include "tinsel/rince.h"
#include "tinsel/savescn.h"
#include "tinsel/sched.h"
#include "tinsel/scroll.h"
#include "tinsel/sound.h"
#include "tinsel/tinlib.h"
#include "tinsel/token.h"
namespace Tinsel {
//----------------- EXTERN FUNCTIONS --------------------
// in BG.C
extern void startupBackground(SCNHANDLE bfilm);
extern SCNHANDLE GetBgroundHandle(void);
extern void SetDoFadeIn(bool tf);
// In DOS_DW.C
void RestoreMasterProcess(INT_CONTEXT *pic);
// in EVENTS.C (declared here and not in events.h because of strange goings-on)
void RestoreProcess(INT_CONTEXT *pic);
// in PLAY.C
extern void playThisReel(SCNHANDLE film, short reelnum, short z, int x, int y);
// in SCENE.C
extern SCNHANDLE GetSceneHandle(void);
extern void NewScene(SCNHANDLE scene, int entry);
//----------------- LOCAL DEFINES --------------------
enum {
RS_COUNT = 5, // Restore scene count
MAX_NEST = 4
};
//----------------- LOCAL GLOBAL DATA --------------------
static bool ASceneIsSaved = false;
static int savedSceneCount = 0;
//static SAVED_DATA s_ssData[MAX_NEST];
static SAVED_DATA *s_ssData = 0;
static SAVED_DATA sgData;
static SAVED_DATA *s_rsd = 0;
static int s_restoreSceneCount = 0;
static bool bNoFade = false;
//----------------- FORWARD REFERENCES --------------------
void InitialiseSs(void) {
if (s_ssData == NULL) {
s_ssData = (SAVED_DATA *)calloc(MAX_NEST, sizeof(SAVED_DATA));
if (s_ssData == NULL) {
error("Cannot allocate memory for scene changes");
}
} else
savedSceneCount = 0;
}
void FreeSs(void) {
if (s_ssData) {
free(s_ssData);
s_ssData = NULL;
}
}
/**
* Save current scene.
* @param sd Pointer to the scene data
*/
void SaveScene(SAVED_DATA *sd) {
sd->SavedSceneHandle = GetSceneHandle();
sd->SavedBgroundHandle = GetBgroundHandle();
SaveMovers(sd->SavedMoverInfo);
sd->NumSavedActors = SaveActors(sd->SavedActorInfo);
PlayfieldGetPos(FIELD_WORLD, &sd->SavedLoffset, &sd->SavedToffset);
SaveInterpretContexts(sd->SavedICInfo);
SaveDeadPolys(sd->SavedDeadPolys);
sd->SavedControl = TestToken(TOKEN_CONTROL);
CurrentMidiFacts(&sd->SavedMidi, &sd->SavedLoop);
sd->SavedNoBlocking = bNoBlocking;
GetNoScrollData(&sd->SavedNoScrollData);
ASceneIsSaved = true;
}
/**
* Initiate restoration of the saved scene.
* @param sd Pointer to the scene data
* @param bFadeOut Flag to perform a fade out
*/
void RestoreScene(SAVED_DATA *sd, bool bFadeOut) {
s_rsd = sd;
if (bFadeOut)
s_restoreSceneCount = RS_COUNT + COUNTOUT_COUNT; // Set restore scene count
else
s_restoreSceneCount = RS_COUNT; // Set restore scene count
}
/**
* Checks that all non-moving actors are playing the same reel as when
* the scene was saved.
* Also 'stand' all the moving actors at their saved positions.
*/
void sortActors(SAVED_DATA *rsd) {
for (int i = 0; i < rsd->NumSavedActors; i++) {
ActorsLife(rsd->SavedActorInfo[i].actorID, rsd->SavedActorInfo[i].bAlive);
// Should be playing the same reel.
if (rsd->SavedActorInfo[i].presFilm != 0) {
if (!actorAlive(rsd->SavedActorInfo[i].actorID))
continue;
playThisReel(rsd->SavedActorInfo[i].presFilm, rsd->SavedActorInfo[i].presRnum, rsd->SavedActorInfo[i].z,
rsd->SavedActorInfo[i].presX, rsd->SavedActorInfo[i].presY);
}
}
RestoreAuxScales(rsd->SavedMoverInfo);
for (int i = 0; i < MAX_MOVERS; i++) {
if (rsd->SavedMoverInfo[i].MActorState == NORM_MACTOR)
stand(rsd->SavedMoverInfo[i].actorID, rsd->SavedMoverInfo[i].objx,
rsd->SavedMoverInfo[i].objy, rsd->SavedMoverInfo[i].lastfilm);
}
}
//---------------------------------------------------------------------------
void ResumeInterprets(SAVED_DATA *rsd) {
// Master script only affected on restore game, not restore scene
if (rsd == &sgData) {
g_scheduler->killMatchingProcess(PID_MASTER_SCR, -1);
FreeMasterInterpretContext();
}
for (int i = 0; i < MAX_INTERPRET; i++) {
switch (rsd->SavedICInfo[i].GSort) {
case GS_NONE:
break;
case GS_INVENTORY:
if (rsd->SavedICInfo[i].event != POINTED) {
RestoreProcess(&rsd->SavedICInfo[i]);
}
break;
case GS_MASTER:
// Master script only affected on restore game, not restore scene
if (rsd == &sgData)
RestoreMasterProcess(&rsd->SavedICInfo[i]);
break;
case GS_ACTOR:
RestoreActorProcess(rsd->SavedICInfo[i].actorid, &rsd->SavedICInfo[i]);
break;
case GS_POLYGON:
case GS_SCENE:
RestoreProcess(&rsd->SavedICInfo[i]);
break;
}
}
}
/**
* Do restore scene
* @param n Id
*/
static int DoRestoreScene(SAVED_DATA *rsd, int n) {
switch (n) {
case RS_COUNT + COUNTOUT_COUNT:
// Trigger pre-load and fade and start countdown
FadeOutFast(NULL);
break;
case RS_COUNT:
_vm->_sound->stopAllSamples();
ClearScreen();
RestoreDeadPolys(rsd->SavedDeadPolys);
NewScene(rsd->SavedSceneHandle, NO_ENTRY_NUM);
SetDoFadeIn(!bNoFade);
bNoFade = false;
startupBackground(rsd->SavedBgroundHandle);
KillScroll();
PlayfieldSetPos(FIELD_WORLD, rsd->SavedLoffset, rsd->SavedToffset);
bNoBlocking = rsd->SavedNoBlocking;
RestoreNoScrollData(&rsd->SavedNoScrollData);
/*
break;
case RS_COUNT - 1:
*/
sortActors(rsd);
break;
case 2:
break;
case 1:
RestoreMidiFacts(rsd->SavedMidi, rsd->SavedLoop);
if (rsd->SavedControl)
control(CONTROL_ON); // TOKEN_CONTROL was free
ResumeInterprets(rsd);
}
return n - 1;
}
/**
* Restore game
* @param num num
*/
void RestoreGame(int num) {
KillInventory();
RequestRestoreGame(num, &sgData, &savedSceneCount, s_ssData);
// Actual restoring is performed by ProcessSRQueue
}
/**
* Save game
* @param name Name of savegame
* @param desc Description of savegame
*/
void SaveGame(char *name, char *desc) {
// Get current scene data
SaveScene(&sgData);
RequestSaveGame(name, desc, &sgData, &savedSceneCount, s_ssData);
// Actual saving is performed by ProcessSRQueue
}
//---------------------------------------------------------------------------------
bool IsRestoringScene() {
if (s_restoreSceneCount) {
s_restoreSceneCount = DoRestoreScene(s_rsd, s_restoreSceneCount);
}
return s_restoreSceneCount ? true : false;
}
/**
* Please Restore Scene
*/
void PleaseRestoreScene(bool bFade) {
// only called by restore_scene PCODE
if (s_restoreSceneCount == 0) {
assert(savedSceneCount >= 1); // No saved scene to restore
if (ASceneIsSaved)
RestoreScene(&s_ssData[--savedSceneCount], bFade);
if (!bFade)
bNoFade = true;
}
}
/**
* Please Save Scene
*/
void PleaseSaveScene(CORO_PARAM) {
// only called by save_scene PCODE
CORO_BEGIN_CONTEXT;
CORO_END_CONTEXT(_ctx);
CORO_BEGIN_CODE(_ctx);
assert(savedSceneCount < MAX_NEST); // nesting limit reached
// Don't save the same thing multiple times!
// FIXME/TODO: Maybe this can be changed to an assert?
if (savedSceneCount && s_ssData[savedSceneCount-1].SavedSceneHandle == GetSceneHandle())
CORO_KILL_SELF();
SaveScene(&s_ssData[savedSceneCount++]);
CORO_END_CODE;
}
} // end of namespace Tinsel