2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING . txt .
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below .
* See COPYING . txt for license details .
2006-03-20 17:12:09 +00:00
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ( " PARALLAX " ) . PARALLAX , IN DISTRIBUTING THE CODE TO
END - USERS , AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN , GRANTS A
ROYALTY - FREE , PERPETUAL LICENSE TO SUCH END - USERS FOR USE BY SUCH END - USERS
IN USING , DISPLAYING , AND CREATING DERIVATIVE WORKS THEREOF , SO LONG AS
SUCH USE , DISPLAY OR CREATION IS FOR NON - COMMERCIAL , ROYALTY OR REVENUE
FREE PURPOSES . IN NO EVENT SHALL THE END - USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE - BEARING PURPOSES . THE END - USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE .
COPYRIGHT 1993 - 1999 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
/*
*
* Code to handle multiple missions
*
*/
2012-11-11 22:12:51 +00:00
# include <algorithm>
2014-08-15 22:59:54 +00:00
# include <vector>
2006-03-20 17:12:09 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
# include <limits.h>
# include "pstypes.h"
# include "strutil.h"
# include "inferno.h"
# include "mission.h"
# include "gameseq.h"
# include "titles.h"
# include "songs.h"
2014-11-23 04:36:58 +00:00
# include "polyobj.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "config.h"
# include "newmenu.h"
# include "text.h"
# include "u_mem.h"
# include "ignorecase.h"
2012-11-11 00:14:30 +00:00
# include "physfsx.h"
# include "bm.h"
# if defined(DXX_BUILD_DESCENT_II)
# include "movie.h"
# endif
2006-03-20 17:12:09 +00:00
2014-08-16 04:15:16 +00:00
# include "compiler-make_unique.h"
2014-08-15 22:59:54 +00:00
# include "compiler-range_for.h"
# include "partial_range.h"
2014-08-24 03:36:35 +00:00
2012-11-11 22:12:51 +00:00
using std : : min ;
2013-01-12 10:53:43 +00:00
//values that describe where a mission is located
enum mle_loc
{
ML_CURDIR = 0 ,
ML_MISSIONDIR = 1
} ;
2006-03-20 17:12:09 +00:00
//mission list entry
2013-12-22 22:03:07 +00:00
struct mle
{
2014-08-16 03:59:14 +00:00
std : : string : : const_iterator filename ; // filename without extension
2006-03-20 17:12:09 +00:00
int builtin_hogsize ; // if it's the built-in mission, used for determining the version
char mission_name [ MISSION_NAME_LEN + 1 ] ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
ubyte descent_version ; // descent 1 or descent 2?
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
ubyte anarchy_only_flag ; // if true, mission is anarchy only
2014-08-16 03:59:14 +00:00
std : : string path ; // relative file path
2013-01-12 10:53:43 +00:00
enum mle_loc location ; // where the mission is
2013-12-22 22:03:07 +00:00
} ;
2006-03-20 17:12:09 +00:00
2014-08-15 22:59:54 +00:00
typedef std : : vector < mle > mission_list ;
2006-03-20 17:12:09 +00:00
2014-07-20 22:13:25 +00:00
Mission_ptr Current_mission ; // currently loaded mission
2006-03-20 17:12:09 +00:00
2013-01-12 10:53:43 +00:00
// Allocate the Level_names, Secret_level_names and Secret_level_table arrays
static int allocate_levels ( void )
{
2014-08-16 04:15:16 +00:00
Level_names = make_unique < d_fname [ ] > ( Last_level ) ;
2013-01-12 10:53:43 +00:00
if ( Last_secret_level )
{
N_secret_levels = - Last_secret_level ;
2014-08-16 04:15:16 +00:00
Secret_level_names = make_unique < d_fname [ ] > ( N_secret_levels ) ;
Secret_level_table = make_unique < ubyte [ ] > ( N_secret_levels ) ;
2013-01-12 10:53:43 +00:00
}
return 1 ;
}
2006-03-20 17:12:09 +00:00
//
// Special versions of mission routines for d1 builtins
//
2013-10-27 22:00:14 +00:00
static int load_mission_d1 ( void )
2006-03-20 17:12:09 +00:00
{
2011-06-01 07:59:55 +00:00
switch ( PHYSFSX_fsize ( " descent.hog " ) )
2007-10-29 21:40:49 +00:00
{
case D1_SHAREWARE_MISSION_HOGSIZE :
case D1_SHAREWARE_10_MISSION_HOGSIZE :
N_secret_levels = 0 ;
Last_level = 7 ;
Last_secret_level = 0 ;
2013-01-12 10:53:43 +00:00
if ( ! allocate_levels ( ) )
{
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ;
2013-01-12 10:53:43 +00:00
return 0 ;
}
2007-10-29 21:40:49 +00:00
//build level names
2014-09-26 02:42:10 +00:00
for ( int i = 0 ; i < Last_level ; i + + )
2014-07-26 22:45:01 +00:00
snprintf ( & Level_names [ i ] [ 0u ] , Level_names [ i ] . size ( ) , " level%02d.sdl " , i + 1 ) ;
2014-07-23 02:27:22 +00:00
Briefing_text_filename = BIMD1_BRIEFING_FILE ;
Ending_text_filename = BIMD1_ENDING_FILE_SHARE ;
2007-10-29 21:40:49 +00:00
break ;
case D1_MAC_SHARE_MISSION_HOGSIZE :
N_secret_levels = 0 ;
Last_level = 3 ;
Last_secret_level = 0 ;
2013-01-12 10:53:43 +00:00
if ( ! allocate_levels ( ) )
{
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ;
2013-01-12 10:53:43 +00:00
return 0 ;
}
2007-10-29 21:40:49 +00:00
//build level names
2014-09-26 02:42:10 +00:00
for ( int i = 0 ; i < Last_level ; i + + )
2014-07-26 22:45:01 +00:00
snprintf ( & Level_names [ i ] [ 0u ] , Level_names [ i ] . size ( ) , " level%02d.sdl " , i + 1 ) ;
2014-07-23 02:27:22 +00:00
Briefing_text_filename = BIMD1_BRIEFING_FILE ;
Ending_text_filename = BIMD1_ENDING_FILE_SHARE ;
2007-10-29 21:40:49 +00:00
break ;
case D1_OEM_MISSION_HOGSIZE :
case D1_OEM_10_MISSION_HOGSIZE :
N_secret_levels = 1 ;
Last_level = 15 ;
Last_secret_level = - 1 ;
2013-01-12 10:53:43 +00:00
if ( ! allocate_levels ( ) )
{
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ;
2013-01-12 10:53:43 +00:00
return 0 ;
}
2007-10-29 21:40:49 +00:00
//build level names
2014-09-26 02:42:10 +00:00
for ( int i = 0 ; i < Last_level - 1 ; i + + )
2014-07-26 22:45:01 +00:00
snprintf ( & Level_names [ i ] [ 0u ] , Level_names [ i ] . size ( ) , " level%02d.rdl " , i + 1 ) ;
snprintf ( & Level_names [ Last_level - 1 ] [ 0u ] , Level_names [ Last_level - 1 ] . size ( ) , " saturn%02d.rdl " , Last_level ) ;
2014-09-26 02:42:10 +00:00
for ( int i = 0 ; i < - Last_secret_level ; i + + )
2014-07-26 22:45:01 +00:00
snprintf ( & Secret_level_names [ i ] [ 0u ] , Secret_level_names [ i ] . size ( ) , " levels%1d.rdl " , i + 1 ) ;
2007-10-29 21:40:49 +00:00
Secret_level_table [ 0 ] = 10 ;
2014-07-23 02:27:22 +00:00
Briefing_text_filename = BIMD1_BRIEFING_FILE_OEM ;
Ending_text_filename = BIMD1_ENDING_FILE_OEM ;
2007-10-29 21:40:49 +00:00
break ;
default :
Int3 ( ) ; // fall through
case D1_MISSION_HOGSIZE :
case D1_10_MISSION_HOGSIZE :
case D1_MAC_MISSION_HOGSIZE :
N_secret_levels = 3 ;
2010-03-25 23:37:19 +00:00
Last_level = BIMD1_LAST_LEVEL ;
Last_secret_level = BIMD1_LAST_SECRET_LEVEL ;
2007-10-29 21:40:49 +00:00
2013-01-12 10:53:43 +00:00
if ( ! allocate_levels ( ) )
{
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ;
2013-01-12 10:53:43 +00:00
return 0 ;
}
2007-10-29 21:40:49 +00:00
//build level names
2014-09-26 02:42:10 +00:00
for ( int i = 0 ; i < Last_level ; i + + )
2014-07-26 22:45:01 +00:00
snprintf ( & Level_names [ i ] [ 0u ] , Level_names [ i ] . size ( ) , " level%02d.rdl " , i + 1 ) ;
2014-09-26 02:42:10 +00:00
for ( int i = 0 ; i < - Last_secret_level ; i + + )
2014-07-26 22:45:01 +00:00
snprintf ( & Secret_level_names [ i ] [ 0u ] , Secret_level_names [ i ] . size ( ) , " levels%1d.rdl " , i + 1 ) ;
2007-10-29 21:40:49 +00:00
Secret_level_table [ 0 ] = 10 ;
Secret_level_table [ 1 ] = 21 ;
Secret_level_table [ 2 ] = 24 ;
2014-07-23 02:27:22 +00:00
Briefing_text_filename = BIMD1_BRIEFING_FILE ;
Ending_text_filename = BIMD1_ENDING_FILE ;
2007-10-29 21:40:49 +00:00
break ;
2006-03-20 17:12:09 +00:00
}
return 1 ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
//
// Special versions of mission routines for shareware
//
2013-10-27 22:00:14 +00:00
static int load_mission_shareware ( void )
2006-03-20 17:12:09 +00:00
{
strcpy ( Current_mission - > mission_name , SHAREWARE_MISSION_NAME ) ;
Current_mission - > descent_version = 2 ;
Current_mission - > anarchy_only_flag = 0 ;
2013-01-12 10:53:43 +00:00
switch ( Current_mission - > builtin_hogsize )
{
case MAC_SHARE_MISSION_HOGSIZE :
N_secret_levels = 1 ;
2006-03-20 17:12:09 +00:00
2013-01-12 10:53:43 +00:00
Last_level = 4 ;
Last_secret_level = - 1 ;
2006-03-20 17:12:09 +00:00
2013-01-12 10:53:43 +00:00
if ( ! allocate_levels ( ) )
{
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ;
2013-01-12 10:53:43 +00:00
return 0 ;
}
// mac demo is using the regular hog and rl2 files
2014-07-23 02:27:22 +00:00
Level_names [ 0 ] = " d2leva-1.rl2 " ;
Level_names [ 1 ] = " d2leva-2.rl2 " ;
Level_names [ 2 ] = " d2leva-3.rl2 " ;
Level_names [ 3 ] = " d2leva-4.rl2 " ;
Secret_level_names [ 0 ] = " d2leva-s.rl2 " ;
2013-01-12 10:53:43 +00:00
break ;
default :
Int3 ( ) ; // fall through
case SHAREWARE_MISSION_HOGSIZE :
N_secret_levels = 0 ;
2006-03-20 17:12:09 +00:00
2013-01-12 10:53:43 +00:00
Last_level = 3 ;
Last_secret_level = 0 ;
2006-03-20 17:12:09 +00:00
2013-01-12 10:53:43 +00:00
if ( ! allocate_levels ( ) )
{
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ;
2013-01-12 10:53:43 +00:00
return 0 ;
}
2014-07-23 02:27:22 +00:00
Level_names [ 0 ] = " d2leva-1.sl2 " ;
Level_names [ 1 ] = " d2leva-2.sl2 " ;
Level_names [ 2 ] = " d2leva-3.sl2 " ;
2006-03-20 17:12:09 +00:00
}
return 1 ;
}
//
// Special versions of mission routines for Diamond/S3 version
//
2013-10-27 22:00:14 +00:00
static int load_mission_oem ( void )
2006-03-20 17:12:09 +00:00
{
strcpy ( Current_mission - > mission_name , OEM_MISSION_NAME ) ;
Current_mission - > descent_version = 2 ;
Current_mission - > anarchy_only_flag = 0 ;
N_secret_levels = 2 ;
Last_level = 8 ;
Last_secret_level = - 2 ;
2013-01-12 10:53:43 +00:00
if ( ! allocate_levels ( ) )
{
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ;
2013-01-12 10:53:43 +00:00
return 0 ;
}
2014-07-23 02:27:22 +00:00
Level_names [ 0 ] = " d2leva-1.rl2 " ;
Level_names [ 1 ] = " d2leva-2.rl2 " ;
Level_names [ 2 ] = " d2leva-3.rl2 " ;
Level_names [ 3 ] = " d2leva-4.rl2 " ;
Secret_level_names [ 0 ] = " d2leva-s.rl2 " ;
Level_names [ 4 ] = " d2levb-1.rl2 " ;
Level_names [ 5 ] = " d2levb-2.rl2 " ;
Level_names [ 6 ] = " d2levb-3.rl2 " ;
Level_names [ 7 ] = " d2levb-4.rl2 " ;
Secret_level_names [ 1 ] = " d2levb-s.rl2 " ;
2006-03-20 17:12:09 +00:00
Secret_level_table [ 0 ] = 1 ;
Secret_level_table [ 1 ] = 5 ;
return 1 ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//compare a string for a token. returns true if match
2013-10-27 22:00:14 +00:00
static int istok ( const char * buf , const char * tok )
2006-03-20 17:12:09 +00:00
{
2012-05-18 23:36:43 +00:00
return d_strnicmp ( buf , tok , strlen ( tok ) ) = = 0 ;
2006-03-20 17:12:09 +00:00
}
//adds a terminating 0 after a string at the first white space
2013-10-27 22:00:14 +00:00
static void add_term ( char * s )
2006-03-20 17:12:09 +00:00
{
while ( * s & & ! isspace ( * s ) ) s + + ;
* s = 0 ; //terminate!
}
//returns ptr to string after '=' & white space, or NULL if no '='
//adds 0 after parm at first white space
2013-10-27 22:00:14 +00:00
static char * get_value ( char * buf )
2006-03-20 17:12:09 +00:00
{
2014-07-20 20:56:39 +00:00
char * t = strchr ( buf , ' = ' ) ;
2006-03-20 17:12:09 +00:00
if ( t ) {
2014-07-20 20:56:39 +00:00
while ( isspace ( static_cast < unsigned > ( * + + t ) ) ) ;
2006-03-20 17:12:09 +00:00
if ( * t )
return t ;
}
return NULL ; //error!
}
//reads a line, returns ptr to value of passed parm. returns NULL if none
2014-09-07 19:48:10 +00:00
static char * get_parm_value ( PHYSFSX_gets_line_t < 80 > & buf , const char * parm , PHYSFS_file * f )
2006-03-20 17:12:09 +00:00
{
2013-11-23 00:13:36 +00:00
if ( ! PHYSFSX_fgets ( buf , f ) )
2006-03-20 17:12:09 +00:00
return NULL ;
if ( istok ( buf , parm ) )
return get_value ( buf ) ;
else
return NULL ;
}
2014-08-30 22:38:26 +00:00
static bool ml_sort_func ( const mle & e0 , const mle & e1 )
2006-03-20 17:12:09 +00:00
{
2014-08-30 22:38:26 +00:00
return d_stricmp ( e0 . mission_name , e1 . mission_name ) < 0 ;
2006-03-20 17:12:09 +00:00
}
//returns 1 if file read ok, else 0
2014-08-15 22:59:54 +00:00
static int read_mission_file ( mission_list & mission_list , const char * filename , enum mle_loc location )
2006-03-20 17:12:09 +00:00
{
char filename2 [ 100 ] ;
2014-08-15 22:59:54 +00:00
snprintf ( filename2 , sizeof ( filename2 ) , " %s%s " , location = = ML_MISSIONDIR ? MISSION_DIR : " " , filename ) ;
2011-06-01 07:59:55 +00:00
PHYSFS_file * mfile ;
mfile = PHYSFSX_openReadBuffered ( filename2 ) ;
2006-03-20 17:12:09 +00:00
if ( mfile ) {
char * p ;
char temp [ PATH_MAX ] , * ext ;
strcpy ( temp , filename ) ;
p = strrchr ( temp , ' / ' ) ; // get the filename at the end of the path
if ( ! p )
p = temp ;
else p + + ;
if ( ( ext = strchr ( p , ' . ' ) ) = = NULL )
return 0 ; //missing extension
2014-08-15 22:59:54 +00:00
mission_list . emplace_back ( ) ;
mle * mission = & mission_list . back ( ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
// look if it's .mn2 or .msn
mission - > descent_version = ( ext [ 3 ] = = ' 2 ' ) ? 2 : 1 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
* ext = 0 ; //kill extension
2014-08-16 03:59:14 +00:00
mission - > path = temp ;
2006-03-20 17:12:09 +00:00
mission - > anarchy_only_flag = 0 ;
2014-08-16 03:59:14 +00:00
mission - > filename = next ( begin ( mission - > path ) , p - temp ) ;
2006-03-20 17:12:09 +00:00
mission - > location = location ;
2014-09-07 19:48:10 +00:00
PHYSFSX_gets_line_t < 80 > buf ;
2014-08-26 03:19:29 +00:00
p = get_parm_value ( buf , " name " , mfile ) ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( ! p ) { //try enhanced mission
2011-06-01 07:59:55 +00:00
PHYSFSX_fseek ( mfile , 0 , SEEK_SET ) ;
2014-08-26 03:19:29 +00:00
p = get_parm_value ( buf , " xname " , mfile ) ;
2006-03-20 17:12:09 +00:00
}
if ( ! p ) { //try super-enhanced mission!
2011-06-01 07:59:55 +00:00
PHYSFSX_fseek ( mfile , 0 , SEEK_SET ) ;
2014-08-26 03:19:29 +00:00
p = get_parm_value ( buf , " zname " , mfile ) ;
2006-03-20 17:12:09 +00:00
}
2013-04-06 21:24:40 +00:00
if ( ! p ) { //try extensible-enhanced mission!
PHYSFSX_fseek ( mfile , 0 , SEEK_SET ) ;
2014-08-26 03:19:29 +00:00
p = get_parm_value ( buf , " !name " , mfile ) ;
2013-04-06 21:24:40 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2013-04-06 21:24:40 +00:00
2006-03-20 17:12:09 +00:00
if ( p ) {
char * t ;
if ( ( t = strchr ( p , ' ; ' ) ) ! = NULL )
* t = 0 ;
t = p + strlen ( p ) - 1 ;
while ( isspace ( * t ) )
* t - - = 0 ; // remove trailing whitespace
if ( strlen ( p ) > MISSION_NAME_LEN )
p [ MISSION_NAME_LEN ] = 0 ;
strncpy ( mission - > mission_name , p , MISSION_NAME_LEN + 1 ) ;
}
else {
2011-06-01 07:59:55 +00:00
PHYSFS_close ( mfile ) ;
2014-08-15 22:59:54 +00:00
mission_list . pop_back ( ) ;
2006-03-20 17:12:09 +00:00
return 0 ;
}
2014-09-07 19:48:10 +00:00
{
PHYSFSX_gets_line_t < 4096 > temp ;
2012-07-15 18:07:50 +00:00
if ( PHYSFSX_fgets ( temp , mfile ) )
{
if ( istok ( temp , " type " ) )
{
p = get_value ( temp ) ;
//get mission type
if ( p )
mission - > anarchy_only_flag = istok ( p , " anarchy " ) ;
}
}
2014-09-07 19:48:10 +00:00
}
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
PHYSFS_close ( mfile ) ;
2006-03-20 17:12:09 +00:00
return 1 ;
}
return 0 ;
}
2014-08-15 22:59:54 +00:00
static void add_d1_builtin_mission_to_list ( mission_list & mission_list )
2006-03-20 17:12:09 +00:00
{
int size ;
2011-06-01 07:59:55 +00:00
size = PHYSFSX_fsize ( " descent.hog " ) ;
2007-05-20 02:00:57 +00:00
if ( size = = - 1 )
return ;
2006-03-20 17:12:09 +00:00
2014-08-15 22:59:54 +00:00
mission_list . emplace_back ( ) ;
mle * mission = & mission_list . back ( ) ;
2006-03-20 17:12:09 +00:00
switch ( size ) {
case D1_SHAREWARE_MISSION_HOGSIZE :
case D1_SHAREWARE_10_MISSION_HOGSIZE :
case D1_MAC_SHARE_MISSION_HOGSIZE :
2014-08-16 03:59:14 +00:00
mission - > path = D1_MISSION_FILENAME ;
2006-03-20 17:12:09 +00:00
strcpy ( mission - > mission_name , D1_SHAREWARE_MISSION_NAME ) ;
mission - > anarchy_only_flag = 0 ;
break ;
case D1_OEM_MISSION_HOGSIZE :
case D1_OEM_10_MISSION_HOGSIZE :
2014-08-16 03:59:14 +00:00
mission - > path = D1_MISSION_FILENAME ;
2006-03-20 17:12:09 +00:00
strcpy ( mission - > mission_name , D1_OEM_MISSION_NAME ) ;
mission - > anarchy_only_flag = 0 ;
break ;
default :
Warning ( " Unknown D1 hogsize %d \n " , size ) ;
Int3 ( ) ;
// fall through
case D1_MISSION_HOGSIZE :
2008-05-19 12:45:33 +00:00
case D1_MISSION_HOGSIZE2 :
2006-03-20 17:12:09 +00:00
case D1_10_MISSION_HOGSIZE :
case D1_MAC_MISSION_HOGSIZE :
2014-08-16 03:59:14 +00:00
mission - > path = D1_MISSION_FILENAME ;
2006-03-20 17:12:09 +00:00
strcpy ( mission - > mission_name , D1_MISSION_NAME ) ;
mission - > anarchy_only_flag = 0 ;
break ;
}
mission - > anarchy_only_flag = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
mission - > builtin_hogsize = size ;
# elif defined(DXX_BUILD_DESCENT_II)
mission - > descent_version = 1 ;
2006-03-20 17:12:09 +00:00
mission - > builtin_hogsize = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2014-08-16 03:59:14 +00:00
mission - > filename = begin ( mission - > path ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-08-15 22:59:54 +00:00
template < std : : size_t N1 , std : : size_t N2 >
static void set_hardcoded_mission ( mission_list & mission_list , const char ( & path ) [ N1 ] , const char ( & mission_name ) [ N2 ] )
{
mission_list . emplace_back ( ) ;
mle * mission = & mission_list . back ( ) ;
2014-08-16 03:59:14 +00:00
mission - > path = path ;
mission - > filename = begin ( mission - > path ) ;
2014-08-15 22:59:54 +00:00
strcpy ( mission - > mission_name , mission_name ) ;
mission - > anarchy_only_flag = 0 ;
}
static void add_builtin_mission_to_list ( mission_list & mission_list , d_fname & name )
2006-03-20 17:12:09 +00:00
{
2011-06-01 07:59:55 +00:00
int size = PHYSFSX_fsize ( " descent2.hog " ) ;
2006-03-20 17:12:09 +00:00
if ( size = = - 1 )
2011-06-01 07:59:55 +00:00
size = PHYSFSX_fsize ( " d2demo.hog " ) ;
2006-03-20 17:12:09 +00:00
switch ( size ) {
case SHAREWARE_MISSION_HOGSIZE :
case MAC_SHARE_MISSION_HOGSIZE :
2014-08-15 22:59:54 +00:00
set_hardcoded_mission ( mission_list , SHAREWARE_MISSION_FILENAME , SHAREWARE_MISSION_NAME ) ;
2006-03-20 17:12:09 +00:00
break ;
case OEM_MISSION_HOGSIZE :
2014-08-15 22:59:54 +00:00
set_hardcoded_mission ( mission_list , OEM_MISSION_FILENAME , OEM_MISSION_NAME ) ;
2006-03-20 17:12:09 +00:00
break ;
default :
Warning ( " Unknown hogsize %d, trying %s \n " , size , FULL_MISSION_FILENAME " .mn2 " ) ;
Int3 ( ) ; //fall through
case FULL_MISSION_HOGSIZE :
case FULL_10_MISSION_HOGSIZE :
case MAC_FULL_MISSION_HOGSIZE :
2014-08-15 22:59:54 +00:00
if ( ! read_mission_file ( mission_list , FULL_MISSION_FILENAME " .mn2 " , ML_CURDIR ) )
2006-03-20 17:12:09 +00:00
Error ( " Could not find required mission file <%s> " , FULL_MISSION_FILENAME " .mn2 " ) ;
}
2014-08-15 22:59:54 +00:00
mle * mission = & mission_list . back ( ) ;
2014-08-16 03:59:14 +00:00
name . copy_if ( mission - > path . c_str ( ) , FILENAME_LEN ) ;
2006-03-20 17:12:09 +00:00
mission - > builtin_hogsize = size ;
mission - > descent_version = 2 ;
mission - > anarchy_only_flag = 0 ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2014-08-15 22:59:54 +00:00
static void add_missions_to_list ( mission_list & mission_list , char * path , char * rel_path , int anarchy_mode )
2006-03-20 17:12:09 +00:00
{
char * * find , * * i , * ext ;
find = PHYSFS_enumerateFiles ( path ) ;
for ( i = find ; * i ! = NULL ; i + + )
{
if ( strlen ( path ) + strlen ( * i ) + 1 > = PATH_MAX )
continue ; // path is too long
strcat ( rel_path , * i ) ;
if ( PHYSFS_isDirectory ( path ) )
{
strcat ( rel_path , " / " ) ;
add_missions_to_list ( mission_list , path , rel_path , anarchy_mode ) ;
* ( strrchr ( path , ' / ' ) ) = 0 ;
}
2012-05-18 23:36:43 +00:00
else if ( ( ext = strrchr ( * i , ' . ' ) ) & & ( ! d_strnicmp ( ext , " .msn " , 4 ) | | ! d_strnicmp ( ext , " .mn2 " , 4 ) ) )
2014-08-15 22:59:54 +00:00
if ( read_mission_file ( mission_list , rel_path , ML_MISSIONDIR ) )
2006-03-20 17:12:09 +00:00
{
2014-08-15 22:59:54 +00:00
if ( anarchy_mode | | ! mission_list . back ( ) . anarchy_only_flag )
2006-03-20 17:12:09 +00:00
{
2014-08-15 22:59:54 +00:00
mission_list . back ( ) . builtin_hogsize = 0 ;
2006-03-20 17:12:09 +00:00
}
else
2014-08-15 22:59:54 +00:00
mission_list . pop_back ( ) ;
2006-03-20 17:12:09 +00:00
}
2014-08-15 22:59:54 +00:00
if ( mission_list . size ( ) > = MAX_MISSIONS )
2006-03-20 17:12:09 +00:00
{
break ;
}
( strrchr ( path , ' / ' ) ) [ 1 ] = 0 ; // chop off the entry
}
PHYSFS_freeList ( find ) ;
}
/* move <mission_name> to <place> on mission list, increment <place> */
2014-08-15 22:59:54 +00:00
static void promote ( mission_list & mission_list , const char * mission_name , std : : size_t & top_place )
2006-03-20 17:12:09 +00:00
{
char name [ FILENAME_LEN ] , * t ;
strcpy ( name , mission_name ) ;
if ( ( t = strchr ( name , ' . ' ) ) ! = NULL )
* t = 0 ; //kill extension
2014-08-15 22:59:54 +00:00
range_for ( auto & i , partial_range ( mission_list , top_place , mission_list . size ( ) ) )
2014-08-16 03:59:14 +00:00
if ( ! d_stricmp ( & * i . filename , name ) ) {
2006-03-20 17:12:09 +00:00
//swap mission positions
2014-08-15 22:59:54 +00:00
std : : swap ( mission_list [ top_place + + ] , i ) ;
2006-03-20 17:12:09 +00:00
break ;
}
}
2014-08-16 04:22:01 +00:00
Mission : : ~ Mission ( )
2006-03-20 17:12:09 +00:00
{
// May become more complex with the editor
2014-08-16 03:59:14 +00:00
if ( ! path . empty ( ) & & builtin_hogsize = = 0 )
2007-05-27 05:48:16 +00:00
{
char hogpath [ PATH_MAX ] ;
2014-08-16 03:59:14 +00:00
snprintf ( hogpath , sizeof ( hogpath ) , MISSION_DIR " %s.hog " , path . c_str ( ) ) ;
2011-06-01 07:59:55 +00:00
PHYSFSX_contfile_close ( hogpath ) ;
2007-05-27 05:48:16 +00:00
}
2006-03-20 17:12:09 +00:00
}
//fills in the global list of missions. Returns the number of missions
//in the list. If anarchy_mode is set, then also add anarchy-only missions.
2014-08-15 22:59:54 +00:00
static mission_list build_mission_list ( int anarchy_mode )
2006-03-20 17:12:09 +00:00
{
char search_str [ PATH_MAX ] = MISSION_DIR ;
//now search for levels on disk
//@@Took out this code because after this routine was called once for
//@@a list of single-player missions, a subsequent call for a list of
//@@anarchy missions would not scan again, and thus would not find the
//@@anarchy-only missions. If we retain the minimum level of install,
//@@we may want to put the code back in, having it always scan for all
//@@missions, and have the code that uses it sort out the ones it wants.
//@@ if (num_missions != -1) {
//@@ if (Current_mission_num != 0)
//@@ load_mission(0); //set built-in mission as default
//@@ return num_missions;
//@@ }
2014-08-15 22:59:54 +00:00
mission_list mission_list ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-08-16 04:20:48 +00:00
d_fname builtin_mission_filename ;
2014-08-15 22:59:54 +00:00
add_builtin_mission_to_list ( mission_list , builtin_mission_filename ) ; //read built-in first
2013-03-03 01:03:33 +00:00
# endif
2014-08-15 22:59:54 +00:00
add_d1_builtin_mission_to_list ( mission_list ) ;
2006-03-20 17:12:09 +00:00
add_missions_to_list ( mission_list , search_str , search_str + strlen ( search_str ) , anarchy_mode ) ;
// move original missions (in story-chronological order)
// to top of mission list
2014-08-15 22:59:54 +00:00
std : : size_t top_place = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2014-08-15 22:59:54 +00:00
promote ( mission_list , " " , top_place ) ; // original descent 1 mission
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2014-08-15 22:59:54 +00:00
promote ( mission_list , " descent " , top_place ) ; // original descent 1 mission
promote ( mission_list , builtin_mission_filename , top_place ) ; // d2 or d2demo
promote ( mission_list , " d2x " , top_place ) ; // vertigo
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2014-08-15 22:59:54 +00:00
if ( mission_list . size ( ) > top_place )
std : : sort ( next ( begin ( mission_list ) , top_place ) , end ( mission_list ) , ml_sort_func ) ;
2006-03-20 17:12:09 +00:00
return mission_list ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
//values for built-in mission
2013-04-06 21:24:40 +00:00
int load_mission_ham ( )
{
read_hamfile ( ) ;
if ( Current_mission - > enhanced = = 3 & & Current_mission - > alternate_ham_file ) {
/*
* If an alternate HAM is specified , map a HOG of the same name
* ( if it exists ) so that users can reference a HAM within a
* HOG . This is required to let users reference the D2X . HAM
* file provided by Descent II : Vertigo .
*
* Try both plain NAME and missions / NAME , in that order .
*/
2014-07-23 01:52:10 +00:00
auto & altham = Current_mission - > alternate_ham_file ;
2013-04-06 21:24:40 +00:00
unsigned l = strlen ( * altham ) ;
char althog [ PATH_MAX ] ;
2014-07-23 02:27:22 +00:00
snprintf ( althog , sizeof ( althog ) , MISSION_DIR " %.*s.hog " , l - 4 , static_cast < const char * > ( * altham ) ) ;
2013-04-06 21:24:40 +00:00
char * p = althog + sizeof ( MISSION_DIR ) - 1 ;
int exists = PHYSFSX_exists ( p , 1 ) ;
if ( ! exists ) {
p = althog ;
exists = PHYSFSX_exists ( p , 1 ) ;
}
if ( exists )
PHYSFSX_contfile_init ( p , 0 ) ;
bm_read_extra_robots ( * Current_mission - > alternate_ham_file , 2 ) ;
if ( exists )
PHYSFSX_contfile_close ( p ) ;
return 1 ;
} else if ( Current_mission - > enhanced ) {
char t [ 50 ] ;
2014-08-16 03:59:14 +00:00
snprintf ( t , sizeof ( t ) , " %s.ham " , Current_mission_filename ) ;
2013-04-06 21:24:40 +00:00
bm_read_extra_robots ( t , Current_mission - > enhanced ) ;
return 1 ;
} else
return 0 ;
}
2013-03-03 01:03:33 +00:00
# endif
2013-04-06 21:24:40 +00:00
2014-07-23 02:27:22 +00:00
static void set_briefing_filename ( d_fname & f , const char * const v )
{
using std : : copy ;
using std : : next ;
auto & tex = " .tex " ;
2014-12-08 03:54:11 +00:00
auto a = [ ] ( char c ) {
return ! c | | c = = ' . ' ;
} ;
auto o = copy ( v , std : : find_if ( v , next ( v , f . size ( ) - sizeof ( tex ) ) , a ) , begin ( f ) ) ;
2014-07-23 02:27:22 +00:00
copy ( begin ( tex ) , end ( tex ) , o ) ;
auto & txb = " txb " ;
2014-07-26 22:45:01 +00:00
if ( ! PHYSFSX_exists ( static_cast < const char * > ( f ) , 1 ) & & ! ( copy ( begin ( txb ) , end ( txb ) , next ( o ) ) , PHYSFSX_exists ( static_cast < const char * > ( f ) , 1 ) ) ) // check if this file exists ...
2014-07-23 02:27:22 +00:00
f = { } ;
}
static void record_briefing ( d_fname & f , char ( & buf ) [ PATH_MAX ] )
{
char * const v = get_value ( buf ) ;
if ( v & & ( add_term ( v ) , * v ) )
set_briefing_filename ( f , v ) ;
else
f = { } ;
}
2006-03-20 17:12:09 +00:00
//loads the specfied mission from the mission list.
//build_mission_list() must have been called.
//Returns true if mission loaded ok, else false.
2014-08-16 03:59:14 +00:00
static int load_mission ( const mle * mission )
2006-03-20 17:12:09 +00:00
{
2011-06-01 07:59:55 +00:00
PHYSFS_file * mfile ;
2006-03-20 17:12:09 +00:00
char buf [ PATH_MAX ] , * v ;
2014-12-06 17:56:56 +00:00
# if defined(DXX_BUILD_DESCENT_II)
close_extra_robot_movie ( ) ;
# endif
2014-08-16 04:15:16 +00:00
Current_mission = make_unique < Mission > ( ) ;
2013-08-18 20:58:52 +00:00
Current_mission - > builtin_hogsize = mission - > builtin_hogsize ;
strcpy ( Current_mission - > mission_name , mission - > mission_name ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-18 20:58:52 +00:00
Current_mission - > descent_version = mission - > descent_version ;
2013-03-03 01:03:33 +00:00
# endif
2013-08-18 20:58:52 +00:00
Current_mission - > anarchy_only_flag = mission - > anarchy_only_flag ;
2014-08-16 03:59:14 +00:00
Current_mission - > path = mission - > path ;
Current_mission - > filename = next ( begin ( Current_mission - > path ) , distance ( begin ( mission - > path ) , mission - > filename ) ) ;
2008-03-08 22:37:09 +00:00
Current_mission - > n_secret_levels = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2007-04-04 07:40:13 +00:00
Current_mission - > enhanced = 0 ;
2013-04-06 21:24:40 +00:00
Current_mission - > alternate_ham_file = NULL ;
2013-03-03 01:03:33 +00:00
# endif
2007-04-04 07:40:13 +00:00
2010-03-04 17:19:47 +00:00
//init vars
Last_level = 0 ;
Last_secret_level = 0 ;
2014-07-23 02:27:22 +00:00
Briefing_text_filename = { } ;
Ending_text_filename = { } ;
2014-07-24 02:30:18 +00:00
Secret_level_table . reset ( ) ;
2014-07-24 02:39:21 +00:00
Level_names . reset ( ) ;
2014-07-24 02:35:57 +00:00
Secret_level_names . reset ( ) ;
2010-03-04 17:19:47 +00:00
2008-01-23 17:28:28 +00:00
// for Descent 1 missions, load descent.hog
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
if ( EMULATING_D1 )
# endif
{
2011-06-01 07:59:55 +00:00
if ( ! PHYSFSX_contfile_init ( " descent.hog " , 1 ) )
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
Error ( " descent.hog not available! \n " ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2008-01-23 17:28:28 +00:00
Warning ( " descent.hog not available, this mission may be missing some files required for briefings and exit sequence \n " ) ;
2013-03-03 01:03:33 +00:00
# endif
2012-05-18 23:36:43 +00:00
if ( ! d_stricmp ( Current_mission_filename , D1_MISSION_FILENAME ) )
2008-01-23 17:28:28 +00:00
return load_mission_d1 ( ) ;
}
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2008-01-23 17:28:28 +00:00
if ( PLAYING_BUILTIN_MISSION ) {
2006-03-20 17:12:09 +00:00
switch ( Current_mission - > builtin_hogsize ) {
case SHAREWARE_MISSION_HOGSIZE :
case MAC_SHARE_MISSION_HOGSIZE :
2014-07-23 02:27:22 +00:00
Briefing_text_filename = BIMD2_BRIEFING_FILE_SHARE ;
Ending_text_filename = BIMD2_ENDING_FILE_SHARE ;
2006-03-20 17:12:09 +00:00
return load_mission_shareware ( ) ;
case OEM_MISSION_HOGSIZE :
2014-07-23 02:27:22 +00:00
Briefing_text_filename = BIMD2_BRIEFING_FILE_OEM ;
Ending_text_filename = BIMD2_ENDING_FILE_OEM ;
2006-03-20 17:12:09 +00:00
return load_mission_oem ( ) ;
default :
Int3 ( ) ; // fall through
case FULL_MISSION_HOGSIZE :
case FULL_10_MISSION_HOGSIZE :
case MAC_FULL_MISSION_HOGSIZE :
2014-07-23 02:27:22 +00:00
Briefing_text_filename = BIMD2_BRIEFING_FILE ;
2006-03-20 17:12:09 +00:00
// continue on... (use d2.mn2 from hogfile)
break ;
}
2008-01-23 17:28:28 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//read mission from file
2014-08-16 03:59:14 +00:00
auto & msn_extension =
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-08-16 03:59:14 +00:00
( mission - > descent_version = = 2 ) ? " .mn2 " :
2013-03-03 01:03:33 +00:00
# endif
2014-08-16 03:59:14 +00:00
" .msn " ;
snprintf ( buf , sizeof ( buf ) , " %s%s%s " , mission - > location = = ML_MISSIONDIR ? MISSION_DIR : " " , mission - > path . c_str ( ) , msn_extension ) ;
2006-03-20 17:12:09 +00:00
PHYSFSEXT_locateCorrectCase ( buf ) ;
2011-06-01 07:59:55 +00:00
mfile = PHYSFSX_openReadBuffered ( buf ) ;
2006-03-20 17:12:09 +00:00
if ( mfile = = NULL ) {
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ;
2006-03-20 17:12:09 +00:00
return 0 ; //error!
}
2008-01-23 17:28:28 +00:00
//for non-builtin missions, load HOG
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2008-01-23 17:28:28 +00:00
if ( ! PLAYING_BUILTIN_MISSION )
2013-03-03 01:03:33 +00:00
# endif
2008-01-23 17:28:28 +00:00
{
strcpy ( buf + strlen ( buf ) - 4 , " .hog " ) ; //change extension
2006-03-20 17:12:09 +00:00
PHYSFSEXT_locateCorrectCase ( buf ) ;
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_exists ( buf , 1 ) )
PHYSFSX_contfile_init ( buf , 0 ) ;
2014-07-23 02:27:22 +00:00
set_briefing_filename ( Briefing_text_filename , Current_mission_filename ) ;
Ending_text_filename = Briefing_text_filename ;
2008-01-23 17:28:28 +00:00
}
2006-03-20 17:12:09 +00:00
2014-10-19 17:17:54 +00:00
for ( PHYSFSX_gets_line_t < PATH_MAX > buf ; PHYSFSX_fgets ( buf , mfile ) ; )
2014-09-07 19:48:10 +00:00
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2007-03-31 20:21:32 +00:00
if ( istok ( buf , " name " ) & & ! Current_mission - > enhanced ) {
2006-03-20 17:12:09 +00:00
Current_mission - > enhanced = 0 ;
continue ; //already have name, go to next line
}
2007-03-31 20:21:32 +00:00
if ( istok ( buf , " xname " ) & & ! Current_mission - > enhanced ) {
2006-03-20 17:12:09 +00:00
Current_mission - > enhanced = 1 ;
continue ; //already have name, go to next line
}
2007-03-31 20:21:32 +00:00
if ( istok ( buf , " zname " ) & & ! Current_mission - > enhanced ) {
2006-03-20 17:12:09 +00:00
Current_mission - > enhanced = 2 ;
continue ; //already have name, go to next line
}
2013-04-06 21:24:40 +00:00
if ( istok ( buf , " !name " ) & & ! Current_mission - > enhanced ) {
Current_mission - > enhanced = 3 ;
continue ; //already have name, go to next line
}
2013-03-03 01:03:33 +00:00
# endif
if ( istok ( buf , " type " ) )
2006-03-20 17:12:09 +00:00
continue ; //already have name, go to next line
else if ( istok ( buf , " briefing " ) ) {
2014-07-23 02:27:22 +00:00
record_briefing ( Briefing_text_filename , buf ) ;
2006-03-20 17:12:09 +00:00
}
else if ( istok ( buf , " ending " ) ) {
2014-07-23 02:27:22 +00:00
record_briefing ( Ending_text_filename , buf ) ;
2006-03-20 17:12:09 +00:00
}
else if ( istok ( buf , " num_levels " ) ) {
if ( ( v = get_value ( buf ) ) ! = NULL ) {
2014-09-26 02:42:10 +00:00
int n_levels ;
2006-03-20 17:12:09 +00:00
n_levels = atoi ( v ) ;
2013-01-12 10:53:43 +00:00
Assert ( n_levels < = MAX_LEVELS_PER_MISSION ) ;
n_levels = min ( n_levels , MAX_LEVELS_PER_MISSION ) ;
2014-08-16 04:15:16 +00:00
Level_names = make_unique < d_fname [ ] > ( n_levels ) ;
2014-09-26 02:42:10 +00:00
for ( int i = 0 ; i < n_levels ; i + + ) {
2013-11-23 00:13:36 +00:00
PHYSFSX_fgets ( buf , mfile ) ;
2006-03-20 17:12:09 +00:00
add_term ( buf ) ;
2014-09-07 19:48:10 +00:00
if ( Level_names [ i ] . copy_if ( buf . line ( ) ) ) {
2006-03-20 17:12:09 +00:00
Last_level + + ;
}
else
break ;
}
}
}
else if ( istok ( buf , " num_secrets " ) ) {
if ( ( v = get_value ( buf ) ) ! = NULL ) {
N_secret_levels = atoi ( v ) ;
Assert ( N_secret_levels < = MAX_SECRET_LEVELS_PER_MISSION ) ;
2013-01-12 10:53:43 +00:00
N_secret_levels = min ( N_secret_levels , MAX_SECRET_LEVELS_PER_MISSION ) ;
2006-03-20 17:12:09 +00:00
2014-08-16 04:15:16 +00:00
Secret_level_names = make_unique < d_fname [ ] > ( N_secret_levels ) ;
Secret_level_table = make_unique < ubyte [ ] > ( N_secret_levels ) ;
2014-09-26 02:42:10 +00:00
for ( int i = 0 ; i < N_secret_levels ; i + + ) {
2006-03-20 17:12:09 +00:00
char * t ;
2013-11-23 00:13:36 +00:00
PHYSFSX_fgets ( buf , mfile ) ;
2006-03-20 17:12:09 +00:00
if ( ( t = strchr ( buf , ' , ' ) ) ! = NULL ) * t + + = 0 ;
else
break ;
add_term ( buf ) ;
2014-09-07 19:48:10 +00:00
if ( Secret_level_names [ i ] . copy_if ( buf . line ( ) ) ) {
2006-03-20 17:12:09 +00:00
Secret_level_table [ i ] = atoi ( t ) ;
if ( Secret_level_table [ i ] < 1 | | Secret_level_table [ i ] > Last_level )
break ;
Last_secret_level - - ;
}
else
break ;
}
}
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-04-06 21:24:40 +00:00
else if ( Current_mission - > enhanced = = 3 & & buf [ 0 ] = = ' ! ' ) {
if ( istok ( buf + 1 , " ham " ) ) {
2014-08-16 04:15:16 +00:00
Current_mission - > alternate_ham_file = make_unique < d_fname > ( ) ;
2013-04-06 21:24:40 +00:00
if ( ( v = get_value ( buf ) ) ! = NULL ) {
unsigned l = strlen ( v ) ;
if ( l < = 4 )
2014-08-16 03:59:14 +00:00
con_printf ( CON_URGENT , " Mission %s has short HAM \" %s \" . " , Current_mission - > path . c_str ( ) , v ) ;
2013-04-06 21:24:40 +00:00
else if ( l > = sizeof ( * Current_mission - > alternate_ham_file ) )
2014-08-16 03:59:14 +00:00
con_printf ( CON_URGENT , " Mission %s has excessive HAM \" %s \" . " , Current_mission - > path . c_str ( ) , v ) ;
2013-04-06 21:24:40 +00:00
else {
2014-07-23 02:27:22 +00:00
Current_mission - > alternate_ham_file - > copy_if ( v , l + 1 ) ;
2014-08-16 03:59:14 +00:00
con_printf ( CON_VERBOSE , " Mission %s will use HAM %s. " , Current_mission - > path . c_str ( ) , static_cast < const char * > ( * Current_mission - > alternate_ham_file ) ) ;
2013-04-06 21:24:40 +00:00
}
}
else
2014-08-16 03:59:14 +00:00
con_printf ( CON_URGENT , " Mission %s has no HAM. " , Current_mission - > path . c_str ( ) ) ;
2013-04-06 21:24:40 +00:00
}
else {
2014-09-07 19:48:10 +00:00
con_printf ( CON_URGENT , " Mission %s uses unsupported critical directive \" %s \" . " , Current_mission - > path . c_str ( ) , buf . line ( ) ) ;
2013-04-06 21:24:40 +00:00
Last_level = 0 ;
break ;
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
2011-06-01 07:59:55 +00:00
PHYSFS_close ( mfile ) ;
2006-03-20 17:12:09 +00:00
if ( Last_level < = 0 ) {
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ; //no valid mission loaded
2006-03-20 17:12:09 +00:00
return 0 ;
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2011-04-20 17:42:02 +00:00
// re-read default HAM file, in case this mission brings it's own version of it
free_polygon_models ( ) ;
2013-04-06 21:24:40 +00:00
if ( load_mission_ham ( ) )
2007-03-31 20:21:32 +00:00
init_extra_robot_movie ( Current_mission_filename ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
return 1 ;
}
//loads the named mission if exists.
//Returns true if mission loaded ok, else false.
2013-06-08 22:24:17 +00:00
int load_mission_by_name ( const char * mission_name )
2006-03-20 17:12:09 +00:00
{
2014-08-15 22:59:54 +00:00
auto mission_list = build_mission_list ( 1 ) ;
2006-03-20 17:12:09 +00:00
bool found = 0 ;
2014-08-15 22:59:54 +00:00
range_for ( auto & i , mission_list )
2014-08-16 03:59:14 +00:00
if ( ! d_stricmp ( mission_name , & * i . filename ) )
2014-08-15 22:59:54 +00:00
{
found = load_mission ( & i ) ;
break ;
}
2006-03-20 17:12:09 +00:00
return found ;
}
2013-12-22 22:03:07 +00:00
struct mission_menu
2010-03-18 07:02:38 +00:00
{
2014-08-15 22:59:54 +00:00
mission_list ml ;
2010-03-18 07:02:38 +00:00
int ( * when_selected ) ( void ) ;
2013-12-22 22:03:07 +00:00
} ;
2010-03-18 07:02:38 +00:00
2014-10-04 21:47:13 +00:00
static int mission_menu_handler ( listbox * lb , const d_event & event , mission_menu * mm )
2010-03-18 07:02:38 +00:00
{
2013-09-02 23:21:13 +00:00
const char * * list = listbox_get_items ( lb ) ;
2010-03-18 07:02:38 +00:00
int citem = listbox_get_citem ( lb ) ;
2014-10-04 21:47:13 +00:00
switch ( event . type )
2010-03-18 07:02:38 +00:00
{
case EVENT_NEWMENU_SELECTED :
if ( citem > = 0 )
{
// Chose a mission
strcpy ( GameCfg . LastMission , list [ citem ] ) ;
2014-08-15 22:59:54 +00:00
if ( ! load_mission ( & mm - > ml [ citem ] ) )
2010-03-18 07:02:38 +00:00
{
nm_messagebox ( NULL , 1 , TXT_OK , TXT_MISSION_ERROR ) ;
2010-04-04 09:41:53 +00:00
return 1 ; // stay in listbox so user can select another one
2010-03-18 07:02:38 +00:00
}
}
return ! ( * mm - > when_selected ) ( ) ;
break ;
case EVENT_WINDOW_CLOSE :
d_free ( list ) ;
2014-08-15 22:59:54 +00:00
delete mm ;
2010-03-18 07:02:38 +00:00
break ;
default :
break ;
}
return 0 ;
}
2013-06-08 22:24:17 +00:00
int select_mission ( int anarchy_mode , const char * message , int ( * when_selected ) ( void ) )
2006-03-20 17:12:09 +00:00
{
2014-08-15 22:59:54 +00:00
auto mission_list = build_mission_list ( anarchy_mode ) ;
2006-03-20 17:12:09 +00:00
int new_mission_num ;
2014-08-15 22:59:54 +00:00
if ( mission_list . size ( ) < = 1 )
2010-03-18 07:02:38 +00:00
{
2014-08-15 22:59:54 +00:00
new_mission_num = ! mission_list . empty ( ) & & load_mission ( & mission_list . front ( ) ) ? 0 : - 1 ;
2010-03-18 07:02:38 +00:00
( * when_selected ) ( ) ;
return ( new_mission_num > = 0 ) ;
}
else
{
2014-09-20 23:47:27 +00:00
int default_mission ;
2013-09-02 23:21:13 +00:00
const char * * m ;
2010-03-18 07:02:38 +00:00
2014-08-15 22:59:54 +00:00
MALLOC ( m , const char * , mission_list . size ( ) ) ;
2010-03-18 07:02:38 +00:00
if ( ! m )
{
return 0 ;
}
2014-08-16 04:15:16 +00:00
auto mm = make_unique < mission_menu > ( ) ;
2010-03-18 07:02:38 +00:00
mm - > when_selected = when_selected ;
2006-03-20 17:12:09 +00:00
default_mission = 0 ;
2014-09-20 23:47:27 +00:00
for ( uint_fast32_t i = 0 ; i < mission_list . size ( ) ; i + + ) {
2006-03-20 17:12:09 +00:00
m [ i ] = mission_list [ i ] . mission_name ;
2012-05-18 23:36:43 +00:00
if ( ! d_stricmp ( m [ i ] , GameCfg . LastMission ) )
2006-03-20 17:12:09 +00:00
default_mission = i ;
}
2014-08-15 22:59:54 +00:00
mm - > ml = move ( mission_list ) ;
mission_menu * pmm = mm . release ( ) ;
newmenu_listbox1 ( message , pmm - > ml . size ( ) , m , 1 , default_mission , mission_menu_handler , pmm ) ;
2006-03-20 17:12:09 +00:00
}
2010-03-18 07:02:38 +00:00
return 1 ; // presume success
2006-03-20 17:12:09 +00:00
}
2012-04-17 09:37:15 +00:00
# ifdef EDITOR
void create_new_mission ( void )
{
2014-07-20 22:13:25 +00:00
Current_mission . reset ( new Mission { } ) ;
2014-08-16 03:59:14 +00:00
Current_mission - > path = " new_mission " ;
Current_mission - > filename = begin ( Current_mission - > path ) ;
2012-04-17 09:37:15 +00:00
2014-08-16 04:15:16 +00:00
Level_names = make_unique < d_fname [ ] > ( 1 ) ;
2013-01-12 10:53:43 +00:00
if ( ! Level_names )
{
2014-07-20 22:13:25 +00:00
Current_mission . reset ( ) ;
2013-01-12 10:53:43 +00:00
return ;
}
2014-07-23 02:27:22 +00:00
Level_names [ 0 ] = " GAMESAVE.LVL " ;
2012-04-17 09:37:15 +00:00
}
# endif