2007-01-15 12:09:25 -08:00
/*
This file is part of Warzone 2100.
Copyright ( C ) 1999 - 2004 Eidos Interactive
2013-01-16 12:34:57 -08:00
Copyright ( C ) 2005 - 2013 Warzone 2100 Project
2007-01-15 12:09:25 -08:00
Warzone 2100 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 .
Warzone 2100 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 Warzone 2100 ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
2007-06-28 10:47:08 -07:00
/*
* Levels . c
*
* Control the data loading for game levels
*
*/
# include <ctype.h>
2006-11-06 06:40:07 -08:00
# include <string.h>
2007-06-28 10:47:08 -07:00
2006-05-27 09:37:17 -07:00
# include "lib/framework/frame.h"
2006-09-23 11:38:12 -07:00
# include "lib/framework/frameresource.h"
2006-09-23 10:24:55 -07:00
# include "lib/framework/listmacs.h"
2012-06-18 08:24:06 -07:00
# include "lib/framework/file.h"
# include "lib/framework/crc.h"
# include "lib/framework/physfs_ext.h"
2009-06-15 20:36:14 -07:00
# include "lib/exceptionhandler/dumpinfo.h"
2007-06-28 10:47:08 -07:00
# include "init.h"
# include "objects.h"
# include "hci.h"
# include "levels.h"
# include "mission.h"
# include "levelint.h"
# include "game.h"
2010-12-31 13:37:14 -08:00
# include "lib/ivis_opengl/piestate.h"
2007-06-28 10:47:08 -07:00
# include "data.h"
2006-05-27 09:37:17 -07:00
# include "lib/script/script.h"
2007-06-28 10:47:08 -07:00
# include "scripttabs.h"
2008-04-19 06:14:10 -07:00
# include "research.h"
2008-05-24 05:20:23 -07:00
# include "lib/framework/lexer_input.h"
2009-06-13 18:00:18 -07:00
# include "effects.h"
2011-07-19 02:22:28 -07:00
# include "main.h"
2012-02-03 13:04:05 -08:00
# include "multiint.h"
2012-11-05 12:18:34 -08:00
# include "qtscript.h"
2008-05-24 05:20:23 -07:00
extern int lev_get_lineno ( void ) ;
extern char * lev_get_text ( void ) ;
extern int lev_lex ( void ) ;
extern void lev_set_extra ( YY_EXTRA_TYPE user_defined ) ;
extern int lev_lex_destroy ( void ) ;
2007-06-28 10:47:08 -07:00
// block ID number start for the current level data (as opposed to a dataset)
# define CURRENT_DATAID LEVEL_MAXFILES
2010-03-19 21:03:28 -07:00
static char currentLevelName [ 32 ] = { " main " } ;
2007-06-28 10:47:08 -07:00
// the current level descriptions
2008-05-11 03:50:15 -07:00
LEVEL_DATASET * psLevels = NULL ;
2007-06-28 10:47:08 -07:00
// the currently loaded data set
2008-05-11 03:50:15 -07:00
static LEVEL_DATASET * psBaseData = NULL ;
static LEVEL_DATASET * psCurrLevel = NULL ;
2007-06-28 10:47:08 -07:00
// dummy level data for single WRF loads
2012-12-21 06:01:30 -08:00
static LEVEL_DATASET sSingleWRF = { LDS_COMPLETE , 0 , 0 , 0 , mod_clean , { 0 } , 0 , 0 , 0 , NULL , { { 0 } } } ;
2007-06-28 10:47:08 -07:00
2008-05-24 05:20:23 -07:00
// return values from the lexer
char * pLevToken ;
2012-12-21 06:01:30 -08:00
LEVEL_TYPE levVal ;
2011-07-11 11:39:21 -07:00
static GAME_TYPE levelLoadType ;
2008-05-24 05:20:23 -07:00
// modes for the parser
2011-02-25 12:30:13 -08:00
enum LEVELPARSER_STATE
2008-05-24 05:20:23 -07:00
{
LP_START , // no input received
LP_LEVEL , // level token received
LP_LEVELDONE , // defined a level waiting for players/type/data
LP_PLAYERS , // players token received
LP_TYPE , // type token received
LP_DATASET , // dataset token received
LP_WAITDATA , // defining level data, waiting for data token
LP_DATA , // data token received
LP_GAME , // game token received
2011-02-25 12:30:13 -08:00
} ;
2008-05-24 05:20:23 -07:00
2007-06-28 10:47:08 -07:00
// initialise the level system
2011-03-12 17:32:15 -08:00
bool levInitialise ( void )
2007-06-28 10:47:08 -07:00
{
psLevels = NULL ;
psBaseData = NULL ;
psCurrLevel = NULL ;
2006-05-27 09:37:17 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
SDWORD getLevelLoadType ( void )
{
return levelLoadType ;
}
// shutdown the level system
void levShutDown ( void )
{
2008-05-02 12:51:23 -07:00
while ( psLevels ! = NULL )
2007-06-28 10:47:08 -07:00
{
2008-05-02 12:51:23 -07:00
LEVEL_DATASET * const toDelete = psLevels ;
psLevels = psLevels - > psNext ;
2013-01-05 15:18:05 -08:00
for ( int i = 0 ; i < ARRAY_SIZE ( toDelete - > apDataFiles ) ; + + i )
2007-06-28 10:47:08 -07:00
{
2008-05-02 12:51:23 -07:00
if ( toDelete - > apDataFiles [ i ] ! = NULL )
2007-06-28 10:47:08 -07:00
{
2008-05-02 12:51:23 -07:00
free ( toDelete - > apDataFiles [ i ] ) ;
2007-06-28 10:47:08 -07:00
}
}
2008-05-02 12:51:23 -07:00
free ( toDelete - > pName ) ;
2012-06-18 08:24:06 -07:00
free ( toDelete - > realFileName ) ;
2008-05-02 12:51:23 -07:00
free ( toDelete ) ;
2007-06-28 10:47:08 -07:00
}
2008-05-11 03:50:15 -07:00
psLevels = NULL ;
2007-06-28 10:47:08 -07:00
}
2008-05-24 05:20:23 -07:00
// error report function for the level parser
void lev_error ( const char * msg )
{
2008-06-21 10:32:03 -07:00
debug ( LOG_ERROR , " Level File parse error: `%s` at line `%d` text `%s` " , msg , lev_get_lineno ( ) , lev_get_text ( ) ) ;
2008-05-24 05:20:23 -07:00
}
2008-04-27 08:27:39 -07:00
/** Find a level dataset with the given name.
* @ param name the name of the dataset to search for .
* @ return a dataset with associated with the given @ c name , or NULL if none
* could be found .
*/
2012-06-18 08:24:06 -07:00
LEVEL_DATASET * levFindDataSet ( char const * name , Sha256 const * hash )
2007-06-28 10:47:08 -07:00
{
2012-06-18 08:24:06 -07:00
if ( hash ! = NULL & & hash - > isZero ( ) )
{
hash = NULL ; // Don't check hash if it's just 0000000000000000000000000000000000000000000000000000000000000000. Assuming real map files probably won't have that particular SHA-256 hash.
}
2007-06-28 10:47:08 -07:00
2012-06-18 08:24:06 -07:00
for ( LEVEL_DATASET * psNewLevel = psLevels ; psNewLevel ! = NULL ; psNewLevel = psNewLevel - > psNext )
2007-06-28 10:47:08 -07:00
{
2012-06-18 08:24:06 -07:00
if ( psNewLevel - > pName ! = NULL & & strcmp ( psNewLevel - > pName , name ) = = 0 )
2007-06-28 10:47:08 -07:00
{
2012-06-18 08:24:06 -07:00
if ( hash = = NULL | | levGetFileHash ( psNewLevel ) = = * hash )
{
return psNewLevel ;
}
2007-06-28 10:47:08 -07:00
}
}
2010-08-04 17:30:29 -07:00
return NULL ;
2007-06-28 10:47:08 -07:00
}
2012-06-18 08:24:06 -07:00
Sha256 levGetFileHash ( LEVEL_DATASET * level )
{
if ( level - > realFileName ! = NULL & & level - > realFileHash . isZero ( ) )
{
level - > realFileHash = findHashOfFile ( level - > realFileName ) ;
debug ( LOG_WZ , " Hash of file \" %s \" is %s. " , level - > realFileName , level - > realFileHash . toString ( ) . c_str ( ) ) ;
}
return level - > realFileHash ;
}
2012-06-20 02:26:54 -07:00
Sha256 levGetMapNameHash ( char const * mapName )
{
LEVEL_DATASET * level = levFindDataSet ( mapName , NULL ) ;
if ( level = = NULL )
{
debug ( LOG_WARNING , " Couldn't find map \" %s \" to hash. " , mapName ) ;
Sha256 zero ;
zero . setZero ( ) ;
return zero ;
}
return levGetFileHash ( level ) ;
}
2008-05-24 05:20:23 -07:00
// parse a level description data file
2011-01-12 12:15:25 -08:00
// the ignoreWrf hack is for compatibility with old maps that try to link in various
// data files that we have removed
2012-06-18 08:24:06 -07:00
bool levParse ( const char * buffer , size_t size , searchPathMode datadir , bool ignoreWrf , char const * realFileName )
2008-05-24 05:20:23 -07:00
{
lexerinput_t input ;
2008-06-21 10:32:03 -07:00
LEVELPARSER_STATE state ;
int token , currData = - 1 ;
2008-05-24 05:20:23 -07:00
LEVEL_DATASET * psDataSet = NULL ;
input . type = LEXINPUT_BUFFER ;
input . input . buffer . begin = buffer ;
input . input . buffer . end = & buffer [ size ] ;
lev_set_extra ( & input ) ;
state = LP_START ;
for ( token = lev_lex ( ) ; token ! = 0 ; token = lev_lex ( ) )
{
switch ( token )
{
case LTK_LEVEL :
case LTK_CAMPAIGN :
case LTK_CAMSTART :
case LTK_CAMCHANGE :
case LTK_EXPAND :
case LTK_BETWEEN :
case LTK_MKEEP :
case LTK_MCLEAR :
case LTK_EXPAND_LIMBO :
case LTK_MKEEP_LIMBO :
if ( state = = LP_START | | state = = LP_WAITDATA )
{
// start a new level data set
psDataSet = ( LEVEL_DATASET * ) malloc ( sizeof ( LEVEL_DATASET ) ) ;
if ( ! psDataSet )
{
2009-10-30 20:57:44 -07:00
debug ( LOG_FATAL , " Out of memory " ) ;
2008-05-24 05:20:23 -07:00
abort ( ) ;
return false ;
}
memset ( psDataSet , 0 , sizeof ( LEVEL_DATASET ) ) ;
psDataSet - > players = 1 ;
psDataSet - > game = - 1 ;
psDataSet - > dataDir = datadir ;
2012-06-18 08:24:06 -07:00
psDataSet - > realFileName = realFileName ! = NULL ? strdup ( realFileName ) : NULL ;
psDataSet - > realFileHash . setZero ( ) ; // The hash is only calculated on demand; for example, if the map name matches.
2008-11-09 14:58:04 -08:00
LIST_APPEND ( psLevels , psDataSet , LEVEL_DATASET ) ;
2008-05-24 05:20:23 -07:00
currData = 0 ;
// set the dataset type
switch ( token )
{
case LTK_LEVEL :
psDataSet - > type = LDS_COMPLETE ;
break ;
case LTK_CAMPAIGN :
psDataSet - > type = LDS_CAMPAIGN ;
break ;
case LTK_CAMSTART :
psDataSet - > type = LDS_CAMSTART ;
break ;
case LTK_BETWEEN :
psDataSet - > type = LDS_BETWEEN ;
break ;
case LTK_MKEEP :
psDataSet - > type = LDS_MKEEP ;
break ;
case LTK_CAMCHANGE :
psDataSet - > type = LDS_CAMCHANGE ;
break ;
case LTK_EXPAND :
psDataSet - > type = LDS_EXPAND ;
break ;
case LTK_MCLEAR :
psDataSet - > type = LDS_MCLEAR ;
break ;
case LTK_EXPAND_LIMBO :
psDataSet - > type = LDS_EXPAND_LIMBO ;
break ;
case LTK_MKEEP_LIMBO :
psDataSet - > type = LDS_MKEEP_LIMBO ;
break ;
default :
ASSERT ( false , " eh? " ) ;
break ;
}
}
else
{
lev_error ( " Syntax Error " ) ;
return false ;
}
state = LP_LEVEL ;
break ;
case LTK_PLAYERS :
if ( state = = LP_LEVELDONE & &
( psDataSet - > type = = LDS_COMPLETE | | psDataSet - > type > = LDS_MULTI_TYPE_START ) )
{
state = LP_PLAYERS ;
}
else
{
lev_error ( " Syntax Error " ) ;
return false ;
}
break ;
case LTK_TYPE :
if ( state = = LP_LEVELDONE & & psDataSet - > type = = LDS_COMPLETE )
{
state = LP_TYPE ;
}
else
{
lev_error ( " Syntax Error " ) ;
return false ;
}
break ;
case LTK_INTEGER :
if ( state = = LP_PLAYERS )
{
psDataSet - > players = ( SWORD ) levVal ;
}
else if ( state = = LP_TYPE )
{
if ( levVal < LDS_MULTI_TYPE_START )
{
lev_error ( " invalid type number " ) ;
return false ;
}
2012-12-21 06:01:30 -08:00
psDataSet - > type = levVal ;
2008-05-24 05:20:23 -07:00
}
else
{
lev_error ( " Syntax Error " ) ;
return false ;
}
state = LP_LEVELDONE ;
break ;
case LTK_DATASET :
if ( state = = LP_LEVELDONE & & psDataSet - > type ! = LDS_COMPLETE )
{
state = LP_DATASET ;
}
else
{
lev_error ( " Syntax Error " ) ;
return false ;
}
break ;
case LTK_DATA :
if ( state = = LP_WAITDATA )
{
state = LP_DATA ;
}
else if ( state = = LP_LEVELDONE )
{
if ( psDataSet - > type = = LDS_CAMSTART | |
psDataSet - > type = = LDS_MKEEP
| | psDataSet - > type = = LDS_CAMCHANGE | |
psDataSet - > type = = LDS_EXPAND | |
psDataSet - > type = = LDS_MCLEAR | |
psDataSet - > type = = LDS_EXPAND_LIMBO | |
psDataSet - > type = = LDS_MKEEP_LIMBO
)
{
lev_error ( " Missing dataset command " ) ;
return false ;
}
state = LP_DATA ;
}
else
{
lev_error ( " Syntax Error " ) ;
return false ;
}
break ;
case LTK_GAME :
if ( ( state = = LP_WAITDATA | | state = = LP_LEVELDONE ) & &
psDataSet - > game = = - 1 & & psDataSet - > type ! = LDS_CAMPAIGN )
{
state = LP_GAME ;
}
else
{
lev_error ( " Syntax Error " ) ;
return false ;
}
break ;
case LTK_IDENT :
if ( state = = LP_LEVEL )
{
if ( psDataSet - > type = = LDS_CAMCHANGE )
{
// This is a campaign change dataset, we need to find the full data set.
LEVEL_DATASET * const psFoundData = levFindDataSet ( pLevToken ) ;
if ( psFoundData = = NULL )
{
lev_error ( " Cannot find full data set for camchange " ) ;
return false ;
}
if ( psFoundData - > type ! = LDS_CAMSTART )
{
lev_error ( " Invalid data set name for cam change " ) ;
return false ;
}
psFoundData - > psChange = psDataSet ;
}
// store the level name
psDataSet - > pName = strdup ( pLevToken ) ;
if ( psDataSet - > pName = = NULL )
{
2009-10-30 20:57:44 -07:00
debug ( LOG_FATAL , " Out of memory! " ) ;
2008-05-24 05:20:23 -07:00
abort ( ) ;
return false ;
}
state = LP_LEVELDONE ;
}
else if ( state = = LP_DATASET )
{
// find the dataset
psDataSet - > psBaseData = levFindDataSet ( pLevToken ) ;
if ( psDataSet - > psBaseData = = NULL )
{
lev_error ( " Unknown dataset " ) ;
return false ;
}
state = LP_WAITDATA ;
}
else
{
lev_error ( " Syntax Error " ) ;
return false ;
}
break ;
case LTK_STRING :
if ( state = = LP_DATA | | state = = LP_GAME )
{
if ( currData > = LEVEL_MAXFILES )
{
lev_error ( " Too many data files " ) ;
return false ;
}
// note the game index if necessary
if ( state = = LP_GAME )
{
psDataSet - > game = ( SWORD ) currData ;
}
2011-01-12 12:15:25 -08:00
else if ( ignoreWrf )
{
state = LP_WAITDATA ;
break ; // ignore this wrf line
}
2008-05-24 05:20:23 -07:00
// store the data name
psDataSet - > apDataFiles [ currData ] = strdup ( pLevToken ) ;
resToLower ( pLevToken ) ;
currData + = 1 ;
state = LP_WAITDATA ;
}
else
{
lev_error ( " Syntax Error " ) ;
return false ;
}
break ;
default :
lev_error ( " Unexpected token " ) ;
break ;
}
}
lev_lex_destroy ( ) ;
2008-06-21 10:32:03 -07:00
// Accept empty files when parsing (indicated by currData < 0)
if ( currData > = 0
& & ( state ! = LP_WAITDATA
| | currData = = 0 ) )
2008-05-24 05:20:23 -07:00
{
lev_error ( " Unexpected end of file " ) ;
return false ;
}
return true ;
}
2007-06-28 10:47:08 -07:00
// free the data for the current mission
2011-03-12 17:32:15 -08:00
bool levReleaseMissionData ( void )
2007-06-28 10:47:08 -07:00
{
// release old data if any was loaded
if ( psCurrLevel ! = NULL )
{
if ( ! stageThreeShutDown ( ) )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
// free up the old data
2013-01-05 15:18:05 -08:00
for ( int i = LEVEL_MAXFILES - 1 ; i > = 0 ; i - - )
2007-06-28 10:47:08 -07:00
{
if ( i = = psCurrLevel - > game )
{
if ( psCurrLevel - > psBaseData = = NULL )
{
if ( ! stageTwoShutDown ( ) )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
}
else // if (psCurrLevel->apDataFiles[i])
{
resReleaseBlockData ( i + CURRENT_DATAID ) ;
}
}
}
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
// free the currently loaded dataset
2011-03-12 17:32:15 -08:00
bool levReleaseAll ( void )
2007-06-28 10:47:08 -07:00
{
2009-06-13 18:00:18 -07:00
// clear out old effect data first
initEffectsSystem ( ) ;
2013-01-05 15:18:05 -08:00
2007-06-28 10:47:08 -07:00
// release old data if any was loaded
if ( psCurrLevel ! = NULL )
{
if ( ! levReleaseMissionData ( ) )
{
2008-05-11 03:50:15 -07:00
debug ( LOG_ERROR , " Failed to unload mission data " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
// release the game data
if ( psCurrLevel - > psBaseData ! = NULL )
{
if ( ! stageTwoShutDown ( ) )
{
2008-05-11 03:50:15 -07:00
debug ( LOG_ERROR , " Failed stage two shutdown " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
if ( psCurrLevel - > psBaseData )
{
2013-01-05 15:18:05 -08:00
for ( int i = LEVEL_MAXFILES - 1 ; i > = 0 ; i - - )
2007-06-28 10:47:08 -07:00
{
if ( psCurrLevel - > psBaseData - > apDataFiles [ i ] )
{
resReleaseBlockData ( i ) ;
}
}
}
if ( ! stageOneShutDown ( ) )
{
2008-05-11 03:50:15 -07:00
debug ( LOG_ERROR , " Failed stage one shutdown " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
psCurrLevel = NULL ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
// load up a single wrf file
2011-03-12 17:32:15 -08:00
static bool levLoadSingleWRF ( const char * name )
2007-06-28 10:47:08 -07:00
{
// free the old data
2008-05-11 03:50:15 -07:00
if ( ! levReleaseAll ( ) )
{
return false ;
}
2007-06-28 10:47:08 -07:00
// create the dummy level data
2008-04-20 08:08:14 -07:00
if ( sSingleWRF . pName )
{
free ( sSingleWRF . pName ) ;
}
2007-06-28 10:47:08 -07:00
memset ( & sSingleWRF , 0 , sizeof ( LEVEL_DATASET ) ) ;
2008-04-20 08:08:14 -07:00
sSingleWRF . pName = strdup ( name ) ;
2007-06-28 10:47:08 -07:00
// load up the WRF
if ( ! stageOneInitialise ( ) )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2007-04-03 03:33:26 -07:00
2007-06-28 10:47:08 -07:00
// load the data
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Loading %s ... " , name ) ;
2008-04-20 08:08:14 -07:00
if ( ! resLoad ( name , 0 ) )
2007-06-28 10:47:08 -07:00
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
if ( ! stageThreeInitialise ( ) )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
psCurrLevel = & sSingleWRF ;
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}
2006-08-08 11:48:06 -07:00
char * getLevelName ( void )
2007-06-28 10:47:08 -07:00
{
return ( currentLevelName ) ;
}
// load up the data for a level
2012-06-18 08:24:06 -07:00
bool levLoadData ( char const * name , Sha256 const * hash , char * pSaveName , GAME_TYPE saveType )
2007-06-28 10:47:08 -07:00
{
LEVEL_DATASET * psNewLevel , * psBaseData , * psChangeLevel ;
2011-03-12 17:32:15 -08:00
bool bCamChangeSaveGame ;
2007-06-28 10:47:08 -07:00
2012-06-18 08:24:06 -07:00
debug ( LOG_WZ , " Loading level %s hash %s (%s, type %d) " , name , hash = = NULL ? " builtin " : hash - > toString ( ) . c_str ( ) , pSaveName , ( int ) saveType ) ;
2008-05-11 03:46:38 -07:00
if ( saveType = = GTYPE_SAVE_START | | saveType = = GTYPE_SAVE_MIDMISSION )
{
if ( ! levReleaseAll ( ) )
{
debug ( LOG_ERROR , " Failed to unload old data " ) ;
return false ;
}
}
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
levelLoadType = saveType ;
// find the level dataset
2012-06-18 08:24:06 -07:00
psNewLevel = levFindDataSet ( name , hash ) ;
2008-04-27 08:27:39 -07:00
if ( psNewLevel = = NULL )
2007-06-28 10:47:08 -07:00
{
2012-06-25 19:31:25 -07:00
debug ( LOG_INFO , " Dataset %s not found - trying to load as WRF " , name ) ;
2008-04-20 08:08:14 -07:00
return levLoadSingleWRF ( name ) ;
2007-06-28 10:47:08 -07:00
}
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " ** Data set found is %s type %d " , psNewLevel - > pName , ( int ) psNewLevel - > type ) ;
2007-06-28 10:47:08 -07:00
/* Keep a copy of the present level name */
2008-05-25 06:46:49 -07:00
sstrcpy ( currentLevelName , name ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
bCamChangeSaveGame = false ;
2007-05-12 07:13:40 -07:00
if ( pSaveName & & saveType = = GTYPE_SAVE_START )
{
if ( psNewLevel - > psChange ! = NULL )
{
2008-03-24 09:51:17 -07:00
bCamChangeSaveGame = true ;
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " ** CAMCHANGE FOUND " ) ;
2007-05-12 07:13:40 -07:00
}
}
2007-06-28 10:47:08 -07:00
// select the change dataset if there is one
2007-05-12 07:13:40 -07:00
psChangeLevel = NULL ;
2007-02-10 08:39:39 -08:00
if ( ( ( psNewLevel - > psChange ! = NULL ) & & ( psCurrLevel ! = NULL ) ) | | bCamChangeSaveGame )
2007-06-28 10:47:08 -07:00
{
2007-05-12 07:13:40 -07:00
//store the level name
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Found CAMCHANGE dataset " ) ;
2007-05-12 07:13:40 -07:00
psChangeLevel = psNewLevel ;
2007-06-28 10:47:08 -07:00
psNewLevel = psNewLevel - > psChange ;
}
// ensure the correct dataset is loaded
if ( psNewLevel - > type = = LDS_CAMPAIGN )
{
2008-05-11 02:21:47 -07:00
debug ( LOG_ERROR , " Cannot load a campaign dataset (%s) " , psNewLevel - > pName ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
else
{
if ( psCurrLevel ! = NULL )
{
if ( ( psCurrLevel - > psBaseData ! = psNewLevel - > psBaseData ) | |
( psCurrLevel - > type < LDS_NONE & & psNewLevel - > type > = LDS_NONE ) | |
( psCurrLevel - > type > = LDS_NONE & & psNewLevel - > type < LDS_NONE ) )
{
// there is a dataset loaded but it isn't the correct one
2008-05-11 03:50:15 -07:00
debug ( LOG_WZ , " Incorrect base dataset loaded (%p != %p, %d - %d) " ,
psCurrLevel - > psBaseData , psNewLevel - > psBaseData , ( int ) psCurrLevel - > type , ( int ) psNewLevel - > type ) ;
if ( ! levReleaseAll ( ) ) // this sets psCurrLevel to NULL
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed to release old data " ) ;
2008-05-11 03:50:15 -07:00
return false ;
}
2007-06-28 10:47:08 -07:00
}
2007-07-31 05:47:08 -07:00
else
{
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Correct base dataset already loaded. " ) ;
2007-07-31 05:47:08 -07:00
}
2007-06-28 10:47:08 -07:00
}
// setup the correct dataset to load if necessary
if ( psCurrLevel = = NULL )
{
if ( psNewLevel - > psBaseData ! = NULL )
{
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Setting base dataset to load: %s " , psNewLevel - > psBaseData - > pName ) ;
2007-06-28 10:47:08 -07:00
}
psBaseData = psNewLevel - > psBaseData ;
}
else
{
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " No base dataset to load " ) ;
2007-06-28 10:47:08 -07:00
psBaseData = NULL ;
}
}
2012-12-08 05:07:15 -08:00
if ( ! rebuildSearchPath ( psNewLevel - > dataDir , true , psNewLevel - > realFileName ) )
2010-04-06 06:54:56 -07:00
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed to rebuild search path " ) ;
2010-04-06 06:54:56 -07:00
return false ;
}
2005-12-22 06:33:32 -08:00
2007-06-28 10:47:08 -07:00
// reset the old mission data if necessary
if ( psCurrLevel ! = NULL )
{
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Reseting old mission data " ) ;
2007-06-28 10:47:08 -07:00
if ( ! levReleaseMissionData ( ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed to unload old mission data " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
// need to free the current map and droids etc for a save game
2013-01-05 15:18:05 -08:00
if ( psBaseData = = NULL & & pSaveName ! = NULL )
2007-06-28 10:47:08 -07:00
{
if ( ! saveGameReset ( ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed to saveGameReset()! " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
// initialise if necessary
2013-01-05 15:18:05 -08:00
if ( psNewLevel - > type = = LDS_COMPLETE | | psBaseData ! = NULL )
2007-06-28 10:47:08 -07:00
{
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Calling stageOneInitialise! " ) ;
2007-06-28 10:47:08 -07:00
if ( ! stageOneInitialise ( ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed stageOneInitialise! " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
// load up a base dataset if necessary
if ( psBaseData ! = NULL )
{
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Loading base dataset %s " , psBaseData - > pName ) ;
2013-01-05 15:18:05 -08:00
for ( int i = 0 ; i < LEVEL_MAXFILES ; i + + )
2007-06-28 10:47:08 -07:00
{
if ( psBaseData - > apDataFiles [ i ] )
{
// load the data
2008-09-07 13:00:54 -07:00
debug ( LOG_WZ , " Loading [directory: %s] %s ... " , PHYSFS_getRealDir ( psBaseData - > apDataFiles [ i ] ) , psBaseData - > apDataFiles [ i ] ) ;
2007-12-10 15:15:46 -08:00
if ( ! resLoad ( psBaseData - > apDataFiles [ i ] , i ) )
2007-06-28 10:47:08 -07:00
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed resLoad(%s)! " , psBaseData - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
}
}
if ( psNewLevel - > type = = LDS_CAMCHANGE )
{
if ( ! campaignReset ( ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed campaignReset()! " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
if ( psNewLevel - > game = = - 1 ) //no .gam file to load - BETWEEN missions (for Editor games only)
{
2013-01-05 15:18:05 -08:00
ASSERT ( psNewLevel - > type = = LDS_BETWEEN , " Only BETWEEN missions do not need a .gam file " ) ;
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " No .gam file for level: BETWEEN mission " ) ;
2007-06-28 10:47:08 -07:00
if ( pSaveName ! = NULL )
{
if ( psBaseData ! = NULL )
{
if ( ! stageTwoInitialise ( ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed stageTwoInitialise()! " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
2007-05-12 07:13:40 -07:00
//set the mission type before the saveGame data is loaded
2007-06-28 10:47:08 -07:00
if ( saveType = = GTYPE_SAVE_MIDMISSION )
{
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Init mission stuff " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMissionSave ( psNewLevel - > type ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMissionSave(%d)! " , psNewLevel - > type ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2008-05-11 02:21:47 -07:00
debug ( LOG_NEVER , " dataSetSaveFlag " ) ;
2007-06-28 10:47:08 -07:00
dataSetSaveFlag ( ) ;
}
2008-05-11 02:21:47 -07:00
debug ( LOG_NEVER , " Loading savegame: %s " , pSaveName ) ;
2008-03-24 09:51:17 -07:00
if ( ! loadGame ( pSaveName , false , true , true ) )
2007-06-28 10:47:08 -07:00
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed loadGame(%s)! " , pSaveName ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
2013-01-05 15:18:05 -08:00
if ( pSaveName = = NULL | | saveType = = GTYPE_SAVE_START )
2007-06-28 10:47:08 -07:00
{
2008-05-11 02:21:47 -07:00
debug ( LOG_NEVER , " Start mission - no .gam " ) ;
2010-12-05 08:25:43 -08:00
if ( ! startMission ( ( LEVEL_TYPE ) psNewLevel - > type , NULL ) )
2007-06-28 10:47:08 -07:00
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d)! " , psNewLevel - > type ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
}
2007-05-12 07:13:40 -07:00
//we need to load up the save game data here for a camchange
if ( bCamChangeSaveGame )
{
2007-06-28 10:47:08 -07:00
if ( pSaveName ! = NULL )
{
if ( psBaseData ! = NULL )
{
if ( ! stageTwoInitialise ( ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed stageTwoInitialise() [camchange]! " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
2008-05-11 02:21:47 -07:00
debug ( LOG_NEVER , " loading savegame: %s " , pSaveName ) ;
2008-03-24 09:51:17 -07:00
if ( ! loadGame ( pSaveName , false , true , true ) )
2007-06-28 10:47:08 -07:00
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed loadGame(%s)! " , pSaveName ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2007-05-12 07:13:40 -07:00
if ( ! campaignReset ( ) )
{
2008-03-24 09:51:17 -07:00
return false ;
2007-05-12 07:13:40 -07:00
}
}
}
2007-06-28 10:47:08 -07:00
// load the new data
2008-05-11 02:21:47 -07:00
debug ( LOG_NEVER , " Loading mission dataset: %s " , psNewLevel - > pName ) ;
2013-01-05 15:18:05 -08:00
for ( int i = 0 ; i < LEVEL_MAXFILES ; i + + )
2007-06-28 10:47:08 -07:00
{
if ( psNewLevel - > game = = i )
{
// do some more initialising if necessary
2008-04-27 16:25:36 -07:00
if ( psNewLevel - > type = = LDS_COMPLETE | | psNewLevel - > type > = LDS_MULTI_TYPE_START | | ( psBaseData ! = NULL & & ! bCamChangeSaveGame ) )
2007-06-28 10:47:08 -07:00
{
if ( ! stageTwoInitialise ( ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed stageTwoInitialise() [newdata]! " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
// load a savegame if there is one - but not if already done so
2007-02-10 08:39:39 -08:00
if ( pSaveName ! = NULL & & ! bCamChangeSaveGame )
2007-06-28 10:47:08 -07:00
{
2007-05-12 07:13:40 -07:00
//set the mission type before the saveGame data is loaded
2007-06-28 10:47:08 -07:00
if ( saveType = = GTYPE_SAVE_MIDMISSION )
{
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Init mission stuff " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMissionSave ( psNewLevel - > type ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMissionSave(%d)! " , psNewLevel - > type ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2008-05-11 02:21:47 -07:00
debug ( LOG_NEVER , " dataSetSaveFlag " ) ;
2007-06-28 10:47:08 -07:00
dataSetSaveFlag ( ) ;
}
2008-05-11 02:21:47 -07:00
debug ( LOG_NEVER , " Loading save game %s " , pSaveName ) ;
2008-03-24 09:51:17 -07:00
if ( ! loadGame ( pSaveName , false , true , true ) )
2007-06-28 10:47:08 -07:00
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed loadGame(%s)! " , pSaveName ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
2013-01-05 15:18:05 -08:00
if ( pSaveName = = NULL | | saveType = = GTYPE_SAVE_START )
2007-06-28 10:47:08 -07:00
{
// load the game
debug ( LOG_WZ , " Loading scenario file %s " , psNewLevel - > apDataFiles [ i ] ) ;
switch ( psNewLevel - > type )
{
case LDS_COMPLETE :
case LDS_CAMSTART :
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " LDS_COMPLETE / LDS_CAMSTART " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMission ( LDS_CAMSTART , psNewLevel - > apDataFiles [ i ] ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d, %s)! " , LDS_CAMSTART , psNewLevel - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
break ;
case LDS_BETWEEN :
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " LDS_BETWEEN " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMission ( LDS_BETWEEN , psNewLevel - > apDataFiles [ i ] ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d, %s)! " , LDS_BETWEEN , psNewLevel - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
break ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
case LDS_MKEEP :
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " LDS_MKEEP " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMission ( LDS_MKEEP , psNewLevel - > apDataFiles [ i ] ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d, %s)! " , LDS_MKEEP , psNewLevel - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
break ;
case LDS_CAMCHANGE :
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " LDS_CAMCHANGE " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMission ( LDS_CAMCHANGE , psNewLevel - > apDataFiles [ i ] ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d, %s)! " , LDS_CAMCHANGE , psNewLevel - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
break ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
case LDS_EXPAND :
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " LDS_EXPAND " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMission ( LDS_EXPAND , psNewLevel - > apDataFiles [ i ] ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d, %s)! " , LDS_EXPAND , psNewLevel - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
break ;
case LDS_EXPAND_LIMBO :
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " LDS_LIMBO " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMission ( LDS_EXPAND_LIMBO , psNewLevel - > apDataFiles [ i ] ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d, %s)! " , LDS_EXPAND_LIMBO , psNewLevel - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
break ;
2006-05-27 09:37:17 -07:00
2007-06-28 10:47:08 -07:00
case LDS_MCLEAR :
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " LDS_MCLEAR " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMission ( LDS_MCLEAR , psNewLevel - > apDataFiles [ i ] ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d, %s)! " , LDS_MCLEAR , psNewLevel - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
break ;
case LDS_MKEEP_LIMBO :
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " LDS_MKEEP_LIMBO " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMission ( LDS_MKEEP_LIMBO , psNewLevel - > apDataFiles [ i ] ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d, %s)! " , LDS_MKEEP_LIMBO , psNewLevel - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
break ;
default :
2012-06-25 19:31:25 -07:00
ASSERT ( psNewLevel - > type > = LDS_MULTI_TYPE_START , " Unexpected mission type " ) ;
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " default (MULTIPLAYER) " ) ;
2007-06-28 10:47:08 -07:00
if ( ! startMission ( LDS_CAMSTART , psNewLevel - > apDataFiles [ i ] ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed startMission(%d, %s) (default)! " , LDS_CAMSTART , psNewLevel - > apDataFiles [ i ] ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
break ;
}
}
}
else if ( psNewLevel - > apDataFiles [ i ] )
{
// load the data
2008-05-11 02:21:47 -07:00
debug ( LOG_WZ , " Loading %s " , psNewLevel - > apDataFiles [ i ] ) ;
2007-12-10 15:15:46 -08:00
if ( ! resLoad ( psNewLevel - > apDataFiles [ i ] , i + CURRENT_DATAID ) )
2007-06-28 10:47:08 -07:00
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed resLoad(%s, %d) (default)! " , psNewLevel - > apDataFiles [ i ] , i + CURRENT_DATAID ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
}
2007-05-12 07:13:40 -07:00
if ( pSaveName ! = NULL )
2007-06-28 10:47:08 -07:00
{
//load MidMission Extras
if ( ! loadMissionExtras ( pSaveName , psNewLevel - > type ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed loadMissionExtras(%s, %d)! " , pSaveName , psNewLevel - > type ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2007-05-12 07:13:40 -07:00
}
2007-06-28 10:47:08 -07:00
2012-02-03 13:04:05 -08:00
if ( bMultiPlayer )
{
loadMultiScripts ( ) ;
}
2007-05-12 07:13:40 -07:00
if ( pSaveName ! = NULL & & saveType = = GTYPE_SAVE_MIDMISSION )
{
2007-06-28 10:47:08 -07:00
//load script stuff
// load the event system state here for a save game
2012-02-03 13:04:05 -08:00
debug ( LOG_SAVE , " Loading script system state " ) ;
2007-06-28 10:47:08 -07:00
if ( ! loadScriptState ( pSaveName ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed loadScriptState(%s)! " , pSaveName ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
}
if ( ! stageThreeInitialise ( ) )
{
2012-06-25 19:31:25 -07:00
debug ( LOG_ERROR , " Failed stageThreeInitialise()! " ) ;
2008-03-24 09:51:17 -07:00
return false ;
2007-06-28 10:47:08 -07:00
}
2011-02-12 14:15:48 -08:00
dataClearSaveFlag ( ) ;
2007-05-12 07:13:40 -07:00
//this enables us to to start cam2/cam3 without going via a save game and get the extra droids
//in from the script-controlled Transporters
if ( ! pSaveName & & psNewLevel - > type = = LDS_CAMSTART )
{
eventFireCallbackTrigger ( ( TRIGGER_TYPE ) CALL_NO_REINFORCEMENTS_LEFT ) ;
}
2007-06-28 10:47:08 -07:00
2007-05-12 07:13:40 -07:00
//restore the level name for comparisons on next mission load up
if ( psChangeLevel = = NULL )
{
psCurrLevel = psNewLevel ;
}
else
{
psCurrLevel = psChangeLevel ;
}
2007-06-28 10:47:08 -07:00
2013-01-05 15:18:05 -08:00
// Copy this info to be used by the crash handler for the dump file
char buf [ 256 ] ;
ssprintf ( buf , " Current Level/map is %s " , psCurrLevel - > pName ) ;
addDumpInfo ( buf ) ;
2009-06-15 20:36:14 -07:00
2012-11-05 12:18:34 -08:00
triggerEvent ( TRIGGER_GAME_LOADED ) ;
2007-06-28 10:47:08 -07:00
2008-03-24 09:51:17 -07:00
return true ;
2007-06-28 10:47:08 -07:00
}