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 .
*/
/*
*
* Save game information
*
*/
2015-03-22 04:16:49 +00:00
# include <stdexcept>
2006-03-20 17:12:09 +00:00
# include <stdio.h>
# include <string.h>
# include "pstypes.h"
# include "strutil.h"
2008-04-06 20:23:28 +00:00
# include "console.h"
2006-03-20 17:12:09 +00:00
# include "gr.h"
# include "palette.h"
# include "newmenu.h"
# include "inferno.h"
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2006-03-20 17:12:09 +00:00
# include "editor/editor.h"
2013-03-16 03:10:55 +00:00
# include "editor/esegment.h"
2012-11-11 00:14:30 +00:00
# include "editor/eswitch.h"
2006-03-20 17:12:09 +00:00
# endif
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "object.h"
# include "game.h"
2013-12-26 04:18:28 +00:00
# include "gameseg.h"
2006-03-20 17:12:09 +00:00
# include "wall.h"
# include "gamemine.h"
# include "robot.h"
# include "bm.h"
2015-02-28 19:36:01 +00:00
# include "fireball.h"
2006-03-20 17:12:09 +00:00
# include "switch.h"
# include "fuelcen.h"
# include "cntrlcen.h"
# include "powerup.h"
# include "weapon.h"
2015-07-25 23:10:45 +00:00
# include "player.h"
2006-03-20 17:12:09 +00:00
# include "newdemo.h"
# include "gameseq.h"
# include "polyobj.h"
# include "text.h"
# include "gamefont.h"
# include "gamesave.h"
# include "gamepal.h"
2012-11-11 00:14:30 +00:00
# include "physics.h"
2006-03-20 17:12:09 +00:00
# include "laser.h"
# include "multi.h"
# include "makesig.h"
2013-03-03 01:03:33 +00:00
# include "textures.h"
2017-04-22 21:23:56 +00:00
# include "d_enumerate.h"
2019-05-04 18:27:36 +00:00
# include "d_range.h"
2021-02-05 12:54:08 +00:00
# include "vclip.h"
2014-01-20 04:34:20 +00:00
# include "compiler-range_for.h"
2020-08-10 03:45:14 +00:00
# include "d_levelstate.h"
2021-09-04 12:17:14 +00:00
# include "d_underlying_value.h"
2020-07-05 23:34:33 +00:00
# include "d_zip.h"
2014-01-20 04:34:20 +00:00
# include "partial_range.h"
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2013-09-02 23:21:13 +00:00
const char Shareware_level_names [ NUM_SHAREWARE_LEVELS ] [ 12 ] = {
2013-03-03 01:03:33 +00:00
" level01.rdl " ,
" level02.rdl " ,
" level03.rdl " ,
" level04.rdl " ,
" level05.rdl " ,
" level06.rdl " ,
" level07.rdl "
} ;
2013-09-02 23:21:13 +00:00
const char Registered_level_names [ NUM_REGISTERED_LEVELS ] [ 12 ] = {
2013-03-03 01:03:33 +00:00
" level08.rdl " ,
" level09.rdl " ,
" level10.rdl " ,
" level11.rdl " ,
" level12.rdl " ,
" level13.rdl " ,
" level14.rdl " ,
" level15.rdl " ,
" level16.rdl " ,
" level17.rdl " ,
" level18.rdl " ,
" level19.rdl " ,
" level20.rdl " ,
" level21.rdl " ,
" level22.rdl " ,
" level23.rdl " ,
" level24.rdl " ,
" level25.rdl " ,
" level26.rdl " ,
" level27.rdl " ,
" levels1.rdl " ,
" levels2.rdl " ,
" levels3.rdl "
} ;
# endif
# endif
2006-03-20 17:12:09 +00:00
char Gamesave_current_filename [ PATH_MAX ] ;
int Gamesave_current_version ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
# define GAME_VERSION 25
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
# define GAME_VERSION 32
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
# define GAME_COMPATIBLE_VERSION 22
//version 28->29 add delta light support
//version 27->28 controlcen id now is reactor number, not model number
//version 28->29 ??
//version 29->30 changed trigger structure
//version 30->31 changed trigger structure some more
//version 31->32 change segment structure, make it 512 bytes w/o editor, add Segment2s array.
# define MENU_CURSOR_X_MIN MENU_X
# define MENU_CURSOR_X_MAX MENU_X+6
int Gamesave_num_org_robots = 0 ;
//--unused-- grs_bitmap * Gamesave_saved_bitmap = NULL;
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2006-03-20 17:12:09 +00:00
// Return true if this level has a name of the form "level??"
// Note that a pathspec can appear at the beginning of the filename.
2013-06-08 22:24:17 +00:00
static int is_real_level ( const char * filename )
2006-03-20 17:12:09 +00:00
{
int len = strlen ( filename ) ;
if ( len < 6 )
return 0 ;
2015-01-12 00:26:03 +00:00
return ! d_strnicmp ( & filename [ len - 11 ] , " level " ) ;
2006-03-20 17:12:09 +00:00
}
# endif
//--unused-- vms_angvec zero_angles={0,0,0};
int Gamesave_num_players = 0 ;
2020-08-24 01:31:28 +00:00
namespace dsx {
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2020-08-24 01:31:28 +00:00
namespace {
using savegame_pof_names_type = std : : array < char [ FILENAME_LEN ] , 167 > ;
2013-03-03 01:03:33 +00:00
2018-10-21 00:24:07 +00:00
static int convert_vclip ( const d_vclip_array & Vclip , int vc )
{
2013-03-03 01:03:33 +00:00
if ( vc < 0 )
return vc ;
2018-10-21 00:24:07 +00:00
if ( vc < Vclip . size ( ) & & ( Vclip [ vc ] . num_frames ! = ~ 0u ) )
2013-03-03 01:03:33 +00:00
return vc ;
return 0 ;
}
static int convert_wclip ( int wc ) {
return ( wc < Num_wall_anims ) ? wc : wc % Num_wall_anims ;
}
2020-08-24 01:31:28 +00:00
}
2013-03-03 01:03:33 +00:00
int convert_tmap ( int tmap )
{
2014-06-28 15:29:25 +00:00
if ( tmap = = - 1 )
return tmap ;
2013-03-03 01:03:33 +00:00
return ( tmap > = NumTextures ) ? tmap % NumTextures : tmap ;
}
2020-08-24 01:31:28 +00:00
2020-12-26 21:17:29 +00:00
namespace {
2020-08-24 01:31:28 +00:00
static unsigned convert_polymod ( const unsigned N_polygon_models , const unsigned polymod )
{
2013-03-03 01:03:33 +00:00
return ( polymod > = N_polygon_models ) ? polymod % N_polygon_models : polymod ;
}
2020-12-26 21:17:29 +00:00
}
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2020-08-24 01:31:28 +00:00
namespace {
using savegame_pof_names_type = std : : array < char [ FILENAME_LEN ] , MAX_POLYGON_MODELS > ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2020-12-26 21:17:29 +00:00
namespace {
2020-08-24 01:31:28 +00:00
static void verify_object ( const d_vclip_array & Vclip , object & obj , const savegame_pof_names_type & Save_pof_names )
2014-10-02 03:02:34 +00:00
{
2018-12-30 00:43:59 +00:00
auto & Robot_info = LevelSharedRobotInfoState . Robot_info ;
2018-06-24 05:06:15 +00:00
obj . lifeleft = IMMORTAL_TIME ; //all loaded object are immortal, for now
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:59 +00:00
auto & Polygon_models = LevelSharedPolygonModelState . Polygon_models ;
2018-06-24 05:06:15 +00:00
if ( obj . type = = OBJ_ROBOT )
{
2006-03-20 17:12:09 +00:00
Gamesave_num_org_robots + + ;
// Make sure valid id...
2018-12-30 00:43:59 +00:00
const auto N_robot_types = LevelSharedRobotInfoState . N_robot_types ;
2013-10-07 23:52:33 +00:00
if ( get_robot_id ( obj ) > = N_robot_types )
set_robot_id ( obj , get_robot_id ( obj ) % N_robot_types ) ;
2006-03-20 17:12:09 +00:00
// Make sure model number & size are correct...
2018-06-24 05:06:15 +00:00
if ( obj . render_type = = RT_POLYOBJ )
{
auto & ri = Robot_info [ get_robot_id ( obj ) ] ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2018-06-24 05:06:15 +00:00
assert ( ri . model_num ! = - 1 ) ;
2006-03-20 17:12:09 +00:00
//if you fail this assert, it means that a robot in this level
//hasn't been loaded, possibly because he's marked as
2018-06-24 05:06:15 +00:00
//non-shareware. To see what robot number, print obj.id.
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
assert ( ri . always_0xabcd = = 0xabcd ) ;
2006-03-20 17:12:09 +00:00
//if you fail this assert, it means that the robot_ai for
//a robot in this level hasn't been loaded, possibly because
//it's marked as non-shareware. To see what robot number,
2018-06-24 05:06:15 +00:00
//print obj.id.
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
obj . rtype . pobj_info . model_num = ri . model_num ;
obj . size = Polygon_models [ obj . rtype . pobj_info . model_num ] . rad ;
2006-03-20 17:12:09 +00:00
//@@Took out this ugly hack 1/12/96, because Mike has added code
//@@that should fix it in a better way.
//@@//this is a super-ugly hack. Since the baby stripe robots have
//@@//their firing point on their bounding sphere, the firing points
//@@//can poke through a wall if the robots are very close to it. So
//@@//we make their radii bigger so the guns can't get too close to
//@@//the walls
2018-06-24 05:06:15 +00:00
//@@if (Robot_info[obj.id].flags & RIF_BIG_RADIUS)
//@@ obj.size = (obj.size*3)/2;
2006-03-20 17:12:09 +00:00
2020-08-10 03:45:13 +00:00
//@@if (obj.control_source==CT_AI && Robot_info[obj.id].attack_type)
2018-06-24 05:06:15 +00:00
//@@ obj.size = obj.size*3/4;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2015-11-27 03:56:13 +00:00
if ( get_robot_id ( obj ) = = 65 ) //special "reactor" robots
2020-08-10 03:45:13 +00:00
obj . movement_source = object : : movement_type : : None ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2020-08-10 03:45:13 +00:00
if ( obj . movement_source = = object : : movement_type : : physics )
2018-06-24 05:06:15 +00:00
{
auto & ri = Robot_info [ get_robot_id ( obj ) ] ;
obj . mtype . phys_info . mass = ri . mass ;
obj . mtype . phys_info . drag = ri . drag ;
2006-03-20 17:12:09 +00:00
}
}
else { //Robots taken care of above
2018-06-24 05:06:15 +00:00
if ( obj . render_type = = RT_POLYOBJ )
{
2020-08-24 01:31:28 +00:00
const auto name = Save_pof_names [ obj . rtype . pobj_info . model_num ] ;
2021-06-28 03:37:50 +00:00
for ( auto & & [ i , candidate_name ] : enumerate ( partial_range ( LevelSharedPolygonModelState . Pof_names , LevelSharedPolygonModelState . N_polygon_models ) ) )
2020-08-24 01:31:28 +00:00
if ( ! d_stricmp ( candidate_name , name ) ) { //found it!
2018-06-24 05:06:15 +00:00
obj . rtype . pobj_info . model_num = i ;
2006-03-20 17:12:09 +00:00
break ;
}
}
}
2018-06-24 05:06:15 +00:00
if ( obj . type = = OBJ_POWERUP )
{
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( obj ) > = N_powerup_types ) {
2018-10-08 03:58:48 +00:00
set_powerup_id ( Powerup_info , Vclip , obj , POW_SHIELD_BOOST ) ;
2018-06-24 05:06:15 +00:00
Assert ( obj . render_type ! = RT_POLYOBJ ) ;
2006-03-20 17:12:09 +00:00
}
2020-08-10 03:45:13 +00:00
obj . control_source = object : : control_type : : powerup ;
2018-06-24 05:06:15 +00:00
obj . size = Powerup_info [ get_powerup_id ( obj ) ] . size ;
obj . ctype . powerup_info . creation_time = 0 ;
2006-03-20 17:12:09 +00:00
}
2018-06-24 05:06:15 +00:00
if ( obj . type = = OBJ_WEAPON )
{
2013-10-07 23:52:33 +00:00
if ( get_weapon_id ( obj ) > = N_weapon_types ) {
2015-12-03 03:26:49 +00:00
set_weapon_id ( obj , weapon_id_type : : LASER_ID_L1 ) ;
2018-06-24 05:06:15 +00:00
Assert ( obj . render_type ! = RT_POLYOBJ ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2015-11-27 03:56:13 +00:00
const auto weapon_id = get_weapon_id ( obj ) ;
2015-12-03 03:26:49 +00:00
if ( weapon_id = = weapon_id_type : : PMINE_ID )
2015-11-27 03:56:13 +00:00
{ //make sure pmines have correct values
2018-06-24 05:06:15 +00:00
obj . mtype . phys_info . mass = Weapon_info [ weapon_id ] . mass ;
obj . mtype . phys_info . drag = Weapon_info [ weapon_id ] . drag ;
obj . mtype . phys_info . flags | = PF_FREE_SPINNING ;
2006-03-20 17:12:09 +00:00
// Make sure model number & size are correct...
2018-06-24 05:06:15 +00:00
Assert ( obj . render_type = = RT_POLYOBJ ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
obj . rtype . pobj_info . model_num = Weapon_info [ weapon_id ] . model_num ;
obj . size = Polygon_models [ obj . rtype . pobj_info . model_num ] . rad ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
2018-06-24 05:06:15 +00:00
if ( obj . type = = OBJ_CNTRLCEN )
{
obj . render_type = RT_POLYOBJ ;
2020-08-10 03:45:13 +00:00
obj . control_source = object : : control_type : : cntrlcen ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
// Make model number is correct...
for ( int i = 0 ; i < Num_total_object_types ; i + + )
if ( ObjType [ i ] = = OL_CONTROL_CENTER ) {
2018-06-24 05:06:15 +00:00
obj . rtype . pobj_info . model_num = ObjId [ i ] ;
obj . shields = ObjStrength [ i ] ;
2013-03-03 01:03:33 +00:00
break ;
}
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version < = 1 ) { // descent 1 reactor
2015-11-27 03:56:13 +00:00
set_reactor_id ( obj , 0 ) ; // used to be only one kind of reactor
2018-06-24 05:06:15 +00:00
obj . rtype . pobj_info . model_num = Reactors [ 0 ] . model_num ; // descent 1 reactor
2006-03-20 17:12:09 +00:00
}
// Make sure model number is correct...
2018-06-24 05:06:15 +00:00
//obj.rtype.pobj_info.model_num = Reactors[obj.id].model_num;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
2018-06-24 05:06:15 +00:00
if ( obj . type = = OBJ_PLAYER )
{
2006-03-20 17:12:09 +00:00
//int i;
//Assert(obj == Player);
2018-06-24 05:06:15 +00:00
if ( & obj = = ConsoleObject )
2006-03-20 17:12:09 +00:00
init_player_object ( ) ;
else
2018-06-24 05:06:15 +00:00
if ( obj . render_type = = RT_POLYOBJ ) //recover from Matt's pof file matchup bug
obj . rtype . pobj_info . model_num = Player_ship - > model_num ;
2006-03-20 17:12:09 +00:00
//Make sure orient matrix is orthogonal
2018-06-24 05:06:15 +00:00
check_and_fix_matrix ( obj . orient ) ;
2006-03-20 17:12:09 +00:00
2013-10-07 23:52:33 +00:00
set_player_id ( obj , Gamesave_num_players + + ) ;
2006-03-20 17:12:09 +00:00
}
2018-06-24 05:06:15 +00:00
if ( obj . type = = OBJ_HOSTAGE )
{
obj . render_type = RT_HOSTAGE ;
2020-08-10 03:45:13 +00:00
obj . control_source = object : : control_type : : powerup ;
2006-03-20 17:12:09 +00:00
}
}
2018-06-24 05:06:15 +00:00
2016-01-09 16:38:14 +00:00
//static gs_skip(int len,PHYSFS_File *file)
2006-03-20 17:12:09 +00:00
//{
//
2011-06-01 07:59:55 +00:00
// PHYSFSX_fseek(file,len,SEEK_CUR);
2006-03-20 17:12:09 +00:00
//}
//reads one object of the given version from the given file
2017-06-10 03:31:02 +00:00
static void read_object ( const vmobjptr_t obj , PHYSFS_File * f , int version )
2006-03-20 17:12:09 +00:00
{
2015-12-10 03:25:37 +00:00
const auto poison_obj = reinterpret_cast < uint8_t * > ( & * obj ) ;
DXX_POISON_MEMORY ( poison_obj , sizeof ( * obj ) , 0xfd ) ;
2019-07-07 22:00:02 +00:00
obj - > signature = object_signature_t { 0 } ;
2016-11-20 23:12:00 +00:00
set_object_type ( * obj , PHYSFSX_readByte ( f ) ) ;
2011-06-01 07:59:55 +00:00
obj - > id = PHYSFSX_readByte ( f ) ;
2006-03-20 17:12:09 +00:00
2019-07-07 22:00:02 +00:00
if ( obj - > type = = OBJ_ROBOT )
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2019-07-07 22:00:02 +00:00
const auto id = get_robot_id ( obj ) ;
if ( id > 23 )
set_robot_id ( obj , id % 24 ) ;
2013-03-03 01:03:33 +00:00
# endif
2019-07-07 22:00:02 +00:00
obj - > matcen_creator = 0 ;
}
2020-08-06 03:47:56 +00:00
{
uint8_t ctype = PHYSFSX_readByte ( f ) ;
switch ( typename object : : control_type { ctype } )
{
case object : : control_type : : None :
case object : : control_type : : ai :
case object : : control_type : : explosion :
case object : : control_type : : flying :
case object : : control_type : : slew :
case object : : control_type : : flythrough :
case object : : control_type : : weapon :
case object : : control_type : : repaircen :
case object : : control_type : : morph :
case object : : control_type : : debris :
case object : : control_type : : powerup :
case object : : control_type : : light :
case object : : control_type : : remote :
case object : : control_type : : cntrlcen :
break ;
default :
ctype = static_cast < uint8_t > ( object : : control_type : : None ) ;
break ;
}
2020-08-10 03:45:13 +00:00
obj - > control_source = typename object : : control_type { ctype } ;
2020-08-06 03:47:56 +00:00
}
2020-08-10 03:45:13 +00:00
{
uint8_t mtype = PHYSFSX_readByte ( f ) ;
switch ( typename object : : movement_type { mtype } )
{
case object : : movement_type : : None :
case object : : movement_type : : physics :
case object : : movement_type : : spinning :
break ;
default :
mtype = static_cast < uint8_t > ( object : : movement_type : : None ) ;
break ;
}
2020-08-10 03:45:13 +00:00
obj - > movement_source = typename object : : movement_type { mtype } ;
2020-08-10 03:45:13 +00:00
}
2020-05-02 21:18:43 +00:00
const uint8_t render_type = PHYSFSX_readByte ( f ) ;
if ( valid_render_type ( render_type ) )
obj - > render_type = render_type_t { render_type } ;
else
{
LevelError ( " Level contains bogus render type %#x for object %p; using none instead " , render_type , & * obj ) ;
obj - > render_type = RT_NONE ;
}
2011-06-01 07:59:55 +00:00
obj - > flags = PHYSFSX_readByte ( f ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
obj - > segnum = PHYSFSX_readShort ( f ) ;
2013-12-26 22:21:16 +00:00
obj - > attached_obj = object_none ;
2006-03-20 17:12:09 +00:00
2014-10-26 22:08:58 +00:00
PHYSFSX_readVector ( f , obj - > pos ) ;
2011-06-01 07:59:55 +00:00
PHYSFSX_readMatrix ( & obj - > orient , f ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
obj - > size = PHYSFSX_readFix ( f ) ;
obj - > shields = PHYSFSX_readFix ( f ) ;
2006-03-20 17:12:09 +00:00
2019-12-22 05:34:08 +00:00
{
vms_vector last_pos ;
PHYSFSX_readVector ( f , last_pos ) ;
}
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
obj - > contains_type = PHYSFSX_readByte ( f ) ;
obj - > contains_id = PHYSFSX_readByte ( f ) ;
obj - > contains_count = PHYSFSX_readByte ( f ) ;
2006-03-20 17:12:09 +00:00
2020-08-10 03:45:13 +00:00
switch ( obj - > movement_source ) {
2006-03-20 17:12:09 +00:00
2020-08-10 03:45:13 +00:00
case object : : movement_type : : physics :
2006-03-20 17:12:09 +00:00
2014-10-26 22:08:58 +00:00
PHYSFSX_readVector ( f , obj - > mtype . phys_info . velocity ) ;
PHYSFSX_readVector ( f , obj - > mtype . phys_info . thrust ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
obj - > mtype . phys_info . mass = PHYSFSX_readFix ( f ) ;
obj - > mtype . phys_info . drag = PHYSFSX_readFix ( f ) ;
2013-12-26 02:47:34 +00:00
PHYSFSX_readFix ( f ) ; /* brakes */
2006-03-20 17:12:09 +00:00
2014-10-26 22:08:58 +00:00
PHYSFSX_readVector ( f , obj - > mtype . phys_info . rotvel ) ;
PHYSFSX_readVector ( f , obj - > mtype . phys_info . rotthrust ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
obj - > mtype . phys_info . turnroll = PHYSFSX_readFixAng ( f ) ;
obj - > mtype . phys_info . flags = PHYSFSX_readShort ( f ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-10 03:45:13 +00:00
case object : : movement_type : : spinning :
2006-03-20 17:12:09 +00:00
2014-10-26 22:08:58 +00:00
PHYSFSX_readVector ( f , obj - > mtype . spin_rate ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-10 03:45:13 +00:00
case object : : movement_type : : None :
2006-03-20 17:12:09 +00:00
break ;
default :
Int3 ( ) ;
}
2020-08-10 03:45:13 +00:00
switch ( obj - > control_source ) {
2006-03-20 17:12:09 +00:00
2020-08-06 03:47:56 +00:00
case object : : control_type : : ai : {
2015-04-26 20:15:51 +00:00
obj - > ctype . ai_info . behavior = static_cast < ai_behavior > ( PHYSFSX_readByte ( f ) ) ;
2006-03-20 17:12:09 +00:00
2022-01-08 17:48:09 +00:00
std : : array < int8_t , 11 > ai_info_flags { } ;
2022-01-08 17:48:09 +00:00
PHYSFS_read ( f , & ai_info_flags [ 0 ] , 1 , 11 ) ;
obj - > ctype . ai_info . CURRENT_GUN = ai_info_flags [ 0 ] ;
2022-01-08 17:48:09 +00:00
obj - > ctype . ai_info . CURRENT_STATE = build_ai_state_from_untrusted ( ai_info_flags [ 1 ] ) . value ( ) ;
2022-01-08 17:48:09 +00:00
obj - > ctype . ai_info . GOAL_STATE = build_ai_state_from_untrusted ( ai_info_flags [ 2 ] ) . value ( ) ;
2022-01-08 17:48:09 +00:00
obj - > ctype . ai_info . PATH_DIR = ai_info_flags [ 3 ] ;
2022-01-08 17:48:09 +00:00
# if defined(DXX_BUILD_DESCENT_I)
obj - > ctype . ai_info . SUBMODE = ai_info_flags [ 4 ] ;
# elif defined(DXX_BUILD_DESCENT_II)
obj - > ctype . ai_info . SUB_FLAGS = ai_info_flags [ 4 ] ;
# endif
2022-01-08 17:48:09 +00:00
obj - > ctype . ai_info . GOALSIDE = build_sidenum_from_untrusted ( ai_info_flags [ 5 ] ) . value ( ) ;
2022-01-08 17:48:09 +00:00
obj - > ctype . ai_info . CLOAKED = ai_info_flags [ 6 ] ;
2022-01-08 17:48:09 +00:00
obj - > ctype . ai_info . SKIP_AI_COUNT = ai_info_flags [ 7 ] ;
2022-01-08 17:48:09 +00:00
obj - > ctype . ai_info . REMOTE_OWNER = ai_info_flags [ 8 ] ;
2022-01-08 17:48:09 +00:00
obj - > ctype . ai_info . REMOTE_SLOT_NUM = ai_info_flags [ 9 ] ;
2011-06-01 07:59:55 +00:00
obj - > ctype . ai_info . hide_segment = PHYSFSX_readShort ( f ) ;
obj - > ctype . ai_info . hide_index = PHYSFSX_readShort ( f ) ;
obj - > ctype . ai_info . path_length = PHYSFSX_readShort ( f ) ;
obj - > ctype . ai_info . cur_path_index = PHYSFSX_readShort ( f ) ;
2006-03-20 17:12:09 +00:00
if ( version < = 25 ) {
2011-06-01 07:59:55 +00:00
PHYSFSX_readShort ( f ) ; // obj->ctype.ai_info.follow_path_start_seg =
2015-05-09 17:39:00 +00:00
PHYSFSX_readShort ( f ) ; // obj->ctype.ai_info.follow_path_end_seg =
2006-03-20 17:12:09 +00:00
}
break ;
}
2020-08-06 03:47:56 +00:00
case object : : control_type : : explosion :
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
obj - > ctype . expl_info . spawn_time = PHYSFSX_readFix ( f ) ;
obj - > ctype . expl_info . delete_time = PHYSFSX_readFix ( f ) ;
obj - > ctype . expl_info . delete_objnum = PHYSFSX_readShort ( f ) ;
2013-12-26 22:21:16 +00:00
obj - > ctype . expl_info . next_attach = obj - > ctype . expl_info . prev_attach = obj - > ctype . expl_info . attach_parent = object_none ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : weapon :
2006-03-20 17:12:09 +00:00
//do I really need to read these? Are they even saved to disk?
2011-06-01 07:59:55 +00:00
obj - > ctype . laser_info . parent_type = PHYSFSX_readShort ( f ) ;
obj - > ctype . laser_info . parent_num = PHYSFSX_readShort ( f ) ;
2015-03-22 18:49:21 +00:00
obj - > ctype . laser_info . parent_signature = object_signature_t { static_cast < uint16_t > ( PHYSFSX_readInt ( f ) ) } ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-24 22:09:58 +00:00
obj - > ctype . laser_info . last_afterburner_time = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2018-03-31 21:53:01 +00:00
obj - > ctype . laser_info . clear_hitobj ( ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : light :
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
obj - > ctype . light_info . intensity = PHYSFSX_readFix ( f ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : powerup :
2006-03-20 17:12:09 +00:00
if ( version > = 25 )
2011-06-01 07:59:55 +00:00
obj - > ctype . powerup_info . count = PHYSFSX_readInt ( f ) ;
2006-03-20 17:12:09 +00:00
else
obj - > ctype . powerup_info . count = 1 ;
2015-11-26 02:56:56 +00:00
if ( obj - > type = = OBJ_POWERUP )
{
2019-07-07 22:00:02 +00:00
/* Objects loaded from a level file were not ejected by
* the player .
*/
obj - > ctype . powerup_info . flags = 0 ;
2020-08-06 03:47:56 +00:00
/* Hostages have control type object::control_type::powerup, but object
2015-11-26 02:56:56 +00:00
* type OBJ_HOSTAGE . Hostages are never weapons , so
* prevent checking their IDs .
*/
2013-10-07 23:52:33 +00:00
if ( get_powerup_id ( obj ) = = POW_VULCAN_WEAPON )
2006-03-20 17:12:09 +00:00
obj - > ctype . powerup_info . count = VULCAN_WEAPON_AMMO_AMOUNT ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2015-11-26 02:56:56 +00:00
else if ( get_powerup_id ( obj ) = = POW_GAUSS_WEAPON )
2006-03-20 17:12:09 +00:00
obj - > ctype . powerup_info . count = VULCAN_WEAPON_AMMO_AMOUNT ;
2015-11-26 02:56:56 +00:00
else if ( get_powerup_id ( obj ) = = POW_OMEGA_WEAPON )
2006-03-20 17:12:09 +00:00
obj - > ctype . powerup_info . count = MAX_OMEGA_CHARGE ;
2013-03-03 01:03:33 +00:00
# endif
2015-11-26 02:56:56 +00:00
}
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : None :
case object : : control_type : : flying :
case object : : control_type : : debris :
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : slew : //the player is generally saved as slew
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : cntrlcen :
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : morph :
case object : : control_type : : flythrough :
case object : : control_type : : repaircen :
2006-03-20 17:12:09 +00:00
default :
Int3 ( ) ;
}
switch ( obj - > render_type ) {
case RT_NONE :
break ;
case RT_MORPH :
case RT_POLYOBJ : {
2014-09-26 02:42:09 +00:00
int tmo ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2020-08-24 01:31:28 +00:00
obj - > rtype . pobj_info . model_num = convert_polymod ( LevelSharedPolygonModelState . N_polygon_models , PHYSFSX_readInt ( f ) ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2011-06-01 07:59:55 +00:00
obj - > rtype . pobj_info . model_num = PHYSFSX_readInt ( f ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2015-01-22 03:34:20 +00:00
range_for ( auto & i , obj - > rtype . pobj_info . anim_angles )
PHYSFSX_readAngleVec ( & i , f ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
obj - > rtype . pobj_info . subobj_flags = PHYSFSX_readInt ( f ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
tmo = PHYSFSX_readInt ( f ) ;
2006-03-20 17:12:09 +00:00
2016-09-11 18:49:16 +00:00
# if !DXX_USE_EDITOR
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
obj - > rtype . pobj_info . tmap_override = convert_tmap ( tmo ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
obj - > rtype . pobj_info . tmap_override = tmo ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
# else
if ( tmo = = - 1 )
obj - > rtype . pobj_info . tmap_override = - 1 ;
else {
int xlated_tmo = tmap_xlate_table [ tmo ] ;
if ( xlated_tmo < 0 ) {
Int3 ( ) ;
xlated_tmo = 0 ;
}
obj - > rtype . pobj_info . tmap_override = xlated_tmo ;
}
# endif
obj - > rtype . pobj_info . alt_textures = 0 ;
break ;
}
case RT_WEAPON_VCLIP :
case RT_HOSTAGE :
case RT_POWERUP :
case RT_FIREBALL :
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2018-10-21 00:24:07 +00:00
obj - > rtype . vclip_info . vclip_num = convert_vclip ( Vclip , PHYSFSX_readInt ( f ) ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2011-06-01 07:59:55 +00:00
obj - > rtype . vclip_info . vclip_num = PHYSFSX_readInt ( f ) ;
2013-03-03 01:03:33 +00:00
# endif
2011-06-01 07:59:55 +00:00
obj - > rtype . vclip_info . frametime = PHYSFSX_readFix ( f ) ;
obj - > rtype . vclip_info . framenum = PHYSFSX_readByte ( f ) ;
2006-03-20 17:12:09 +00:00
break ;
case RT_LASER :
break ;
default :
Int3 ( ) ;
}
}
2016-08-25 04:05:32 +00:00
}
2020-12-26 21:17:29 +00:00
}
2006-03-20 17:12:09 +00:00
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2020-12-26 21:17:29 +00:00
namespace {
2016-01-09 16:38:14 +00:00
static int PHYSFSX_writeMatrix ( PHYSFS_File * file , const vms_matrix & m )
2014-10-26 22:56:50 +00:00
{
if ( PHYSFSX_writeVector ( file , m . rvec ) < 1 | |
PHYSFSX_writeVector ( file , m . uvec ) < 1 | |
PHYSFSX_writeVector ( file , m . fvec ) < 1 )
return 0 ;
return 1 ;
}
2006-03-20 17:12:09 +00:00
2016-01-09 16:38:14 +00:00
static int PHYSFSX_writeAngleVec ( PHYSFS_File * file , const vms_angvec & v )
2014-10-26 22:56:50 +00:00
{
if ( PHYSFSX_writeFixAng ( file , v . p ) < 1 | |
PHYSFSX_writeFixAng ( file , v . b ) < 1 | |
PHYSFSX_writeFixAng ( file , v . h ) < 1 )
return 0 ;
return 1 ;
}
2020-12-26 21:17:29 +00:00
}
2014-10-26 22:56:50 +00:00
2006-03-20 17:12:09 +00:00
//writes one object to the given file
2016-08-25 04:05:32 +00:00
namespace dsx {
2020-12-26 21:17:29 +00:00
namespace {
2018-06-24 05:06:15 +00:00
static void write_object ( const object & obj , short version , PHYSFS_File * f )
2006-03-20 17:12:09 +00:00
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
( void ) version ;
# endif
2018-06-24 05:06:15 +00:00
PHYSFSX_writeU8 ( f , obj . type ) ;
PHYSFSX_writeU8 ( f , obj . id ) ;
2006-03-20 17:12:09 +00:00
2020-08-10 03:45:13 +00:00
PHYSFSX_writeU8 ( f , static_cast < uint8_t > ( obj . control_source ) ) ;
2020-08-10 03:45:13 +00:00
PHYSFSX_writeU8 ( f , static_cast < uint8_t > ( obj . movement_source ) ) ;
2018-06-24 05:06:15 +00:00
PHYSFSX_writeU8 ( f , obj . render_type ) ;
PHYSFSX_writeU8 ( f , obj . flags ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE16 ( f , obj . segnum ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeVector ( f , obj . pos ) ;
PHYSFSX_writeMatrix ( f , obj . orient ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeFix ( f , obj . size ) ;
PHYSFSX_writeFix ( f , obj . shields ) ;
2006-03-20 17:12:09 +00:00
2019-12-22 05:34:08 +00:00
PHYSFSX_writeVector ( f , obj . pos ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeU8 ( f , obj . contains_type ) ;
PHYSFSX_writeU8 ( f , obj . contains_id ) ;
PHYSFSX_writeU8 ( f , obj . contains_count ) ;
2006-03-20 17:12:09 +00:00
2020-08-10 03:45:13 +00:00
switch ( obj . movement_source ) {
2006-03-20 17:12:09 +00:00
2020-08-10 03:45:13 +00:00
case object : : movement_type : : physics :
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeVector ( f , obj . mtype . phys_info . velocity ) ;
PHYSFSX_writeVector ( f , obj . mtype . phys_info . thrust ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeFix ( f , obj . mtype . phys_info . mass ) ;
PHYSFSX_writeFix ( f , obj . mtype . phys_info . drag ) ;
2013-12-26 02:47:34 +00:00
PHYSFSX_writeFix ( f , 0 ) ; /* brakes */
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeVector ( f , obj . mtype . phys_info . rotvel ) ;
PHYSFSX_writeVector ( f , obj . mtype . phys_info . rotthrust ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeFixAng ( f , obj . mtype . phys_info . turnroll ) ;
PHYSFS_writeSLE16 ( f , obj . mtype . phys_info . flags ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-10 03:45:13 +00:00
case object : : movement_type : : spinning :
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeVector ( f , obj . mtype . spin_rate ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-10 03:45:13 +00:00
case object : : movement_type : : None :
2006-03-20 17:12:09 +00:00
break ;
default :
Int3 ( ) ;
}
2020-08-10 03:45:13 +00:00
switch ( obj . control_source ) {
2006-03-20 17:12:09 +00:00
2020-08-06 03:47:56 +00:00
case object : : control_type : : ai : {
2018-06-24 05:06:15 +00:00
PHYSFSX_writeU8 ( f , static_cast < uint8_t > ( obj . ctype . ai_info . behavior ) ) ;
2006-03-20 17:12:09 +00:00
2022-01-08 17:48:09 +00:00
std : : array < int8_t , 11 > ai_info_flags { } ;
2022-01-08 17:48:09 +00:00
ai_info_flags [ 0 ] = obj . ctype . ai_info . CURRENT_GUN ;
2022-01-08 17:48:09 +00:00
ai_info_flags [ 1 ] = obj . ctype . ai_info . CURRENT_STATE ;
2022-01-08 17:48:09 +00:00
ai_info_flags [ 2 ] = obj . ctype . ai_info . GOAL_STATE ;
2022-01-08 17:48:09 +00:00
ai_info_flags [ 3 ] = obj . ctype . ai_info . PATH_DIR ;
2022-01-08 17:48:09 +00:00
# if defined(DXX_BUILD_DESCENT_I)
ai_info_flags [ 4 ] = obj . ctype . ai_info . SUBMODE ;
# elif defined(DXX_BUILD_DESCENT_II)
ai_info_flags [ 4 ] = obj . ctype . ai_info . SUB_FLAGS ;
# endif
2022-06-05 17:44:52 +00:00
ai_info_flags [ 5 ] = underlying_value ( obj . ctype . ai_info . GOALSIDE ) ;
2022-01-08 17:48:09 +00:00
ai_info_flags [ 6 ] = obj . ctype . ai_info . CLOAKED ;
2022-01-08 17:48:09 +00:00
ai_info_flags [ 7 ] = obj . ctype . ai_info . SKIP_AI_COUNT ;
2022-01-08 17:48:09 +00:00
ai_info_flags [ 8 ] = obj . ctype . ai_info . REMOTE_OWNER ;
2022-01-08 17:48:09 +00:00
ai_info_flags [ 9 ] = obj . ctype . ai_info . REMOTE_SLOT_NUM ;
2022-01-08 17:48:09 +00:00
PHYSFS_write ( f , & ai_info_flags [ 0 ] , 1 , 11 ) ;
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE16 ( f , obj . ctype . ai_info . hide_segment ) ;
PHYSFS_writeSLE16 ( f , obj . ctype . ai_info . hide_index ) ;
PHYSFS_writeSLE16 ( f , obj . ctype . ai_info . path_length ) ;
PHYSFS_writeSLE16 ( f , obj . ctype . ai_info . cur_path_index ) ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2015-05-09 17:39:01 +00:00
PHYSFS_writeSLE16 ( f , segment_none ) ;
2015-05-09 17:39:00 +00:00
PHYSFS_writeSLE16 ( f , segment_none ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( version < = 25 )
{
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE16 ( f , - 1 ) ; //obj.ctype.ai_info.follow_path_start_seg
PHYSFS_writeSLE16 ( f , - 1 ) ; //obj.ctype.ai_info.follow_path_end_seg
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
break ;
}
2020-08-06 03:47:56 +00:00
case object : : control_type : : explosion :
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeFix ( f , obj . ctype . expl_info . spawn_time ) ;
PHYSFSX_writeFix ( f , obj . ctype . expl_info . delete_time ) ;
PHYSFS_writeSLE16 ( f , obj . ctype . expl_info . delete_objnum ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : weapon :
2006-03-20 17:12:09 +00:00
//do I really need to write these objects?
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE16 ( f , obj . ctype . laser_info . parent_type ) ;
PHYSFS_writeSLE16 ( f , obj . ctype . laser_info . parent_num ) ;
2020-08-10 03:45:13 +00:00
PHYSFS_writeSLE32 ( f , static_cast < uint16_t > ( obj . ctype . laser_info . parent_signature ) ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : light :
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFSX_writeFix ( f , obj . ctype . light_info . intensity ) ;
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : powerup :
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE32 ( f , obj . ctype . powerup_info . count ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( version > = 25 )
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE32 ( f , obj . ctype . powerup_info . count ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : None :
case object : : control_type : : flying :
case object : : control_type : : debris :
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : slew : //the player is generally saved as slew
2006-03-20 17:12:09 +00:00
break ;
2020-08-06 03:47:56 +00:00
case object : : control_type : : cntrlcen :
2006-03-20 17:12:09 +00:00
break ; //control center object.
2020-08-06 03:47:56 +00:00
case object : : control_type : : morph :
case object : : control_type : : repaircen :
case object : : control_type : : flythrough :
2006-03-20 17:12:09 +00:00
default :
Int3 ( ) ;
}
2018-06-24 05:06:15 +00:00
switch ( obj . render_type ) {
2006-03-20 17:12:09 +00:00
case RT_NONE :
break ;
case RT_MORPH :
case RT_POLYOBJ : {
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE32 ( f , obj . rtype . pobj_info . model_num ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
range_for ( auto & i , obj . rtype . pobj_info . anim_angles )
2014-10-26 22:56:50 +00:00
PHYSFSX_writeAngleVec ( f , i ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE32 ( f , obj . rtype . pobj_info . subobj_flags ) ;
2006-03-20 17:12:09 +00:00
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE32 ( f , obj . rtype . pobj_info . tmap_override ) ;
2006-03-20 17:12:09 +00:00
break ;
}
case RT_WEAPON_VCLIP :
case RT_HOSTAGE :
case RT_POWERUP :
case RT_FIREBALL :
2018-06-24 05:06:15 +00:00
PHYSFS_writeSLE32 ( f , obj . rtype . vclip_info . vclip_num ) ;
PHYSFSX_writeFix ( f , obj . rtype . vclip_info . frametime ) ;
PHYSFSX_writeU8 ( f , obj . rtype . vclip_info . framenum ) ;
2006-03-20 17:12:09 +00:00
break ;
case RT_LASER :
break ;
default :
Int3 ( ) ;
}
2020-12-26 21:17:29 +00:00
}
2016-08-25 04:05:32 +00:00
}
2006-03-20 17:12:09 +00:00
}
# endif
// --------------------------------------------------------------------
// Load game
// Loads all the relevant data for a level.
// If level != -1, it loads the filename with extension changed to .min
// Otherwise it loads the appropriate level mine.
// returns 0=everything ok, 1=old version, -1=error
2016-08-25 04:05:32 +00:00
namespace dsx {
2020-12-26 21:17:29 +00:00
namespace {
2017-04-22 21:23:56 +00:00
2022-01-15 20:39:10 +00:00
static void validate_segment_wall ( const vcsegptridx_t seg , shared_side & side , const sidenum_t sidenum )
2017-04-22 21:23:56 +00:00
{
auto & rwn0 = side . wall_num ;
const auto wn0 = rwn0 ;
2018-12-30 00:43:58 +00:00
auto & Walls = LevelUniqueWallSubsystemState . Walls ;
auto & vcwallptr = Walls . vcptr ;
2017-04-22 21:23:56 +00:00
auto & w0 = * vcwallptr ( wn0 ) ;
switch ( w0 . type )
{
case WALL_DOOR :
{
2020-08-24 01:31:28 +00:00
const auto connected_seg = seg - > shared_segment : : children [ sidenum ] ;
2017-04-22 21:23:56 +00:00
if ( connected_seg = = segment_none )
{
rwn0 = wall_none ;
2022-06-05 17:44:52 +00:00
LevelError ( " segment %u side %u wall %u has no child segment; removing orphan wall. " , seg . get_unchecked_index ( ) , underlying_value ( sidenum ) , static_cast < unsigned > ( wn0 ) ) ;
2017-04-22 21:23:56 +00:00
return ;
}
2019-12-22 05:34:08 +00:00
const shared_segment & vcseg = * vcsegptr ( connected_seg ) ;
2022-01-15 20:39:10 +00:00
const auto connected_side = find_connect_side ( seg , vcseg ) ;
2022-02-19 14:52:17 +00:00
if ( connected_side = = side_none )
{
rwn0 = wall_none ;
2022-06-05 17:44:52 +00:00
LevelError ( " segment %u side %u wall %u has child segment %u side %u, but child segment does not link back; removing orphan wall. " , seg . get_unchecked_index ( ) , underlying_value ( sidenum ) , underlying_value ( wn0 ) , connected_seg , underlying_value ( connected_side ) ) ;
2022-02-19 14:52:17 +00:00
return ;
}
2019-12-22 05:34:08 +00:00
const auto wn1 = vcseg . sides [ connected_side ] . wall_num ;
2017-04-22 21:23:56 +00:00
if ( wn1 = = wall_none )
{
rwn0 = wall_none ;
2022-06-05 17:44:52 +00:00
LevelError ( " segment %u side %u wall %u has child segment %u side %u, but no wall; removing orphan wall. " , seg . get_unchecked_index ( ) , underlying_value ( sidenum ) , static_cast < unsigned > ( wn0 ) , connected_seg , underlying_value ( connected_side ) ) ;
2017-04-22 21:23:56 +00:00
return ;
}
}
break ;
default :
break ;
}
}
2018-12-30 00:43:57 +00:00
static int load_game_data (
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:58 +00:00
d_level_shared_destructible_light_state & LevelSharedDestructibleLightState ,
2018-12-30 00:43:57 +00:00
# endif
fvmobjptridx & vmobjptridx , fvmsegptridx & vmsegptridx , PHYSFS_File * LoadFile )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptr = Objects . vmptr ;
2020-04-04 19:30:22 +00:00
auto & WallAnims = GameSharedState . WallAnims ;
2019-02-02 18:36:39 +00:00
auto & RobotCenters = LevelSharedRobotcenterState . RobotCenters ;
2017-07-26 03:15:59 +00:00
const auto & vcsegptridx = vmsegptridx ;
2006-03-20 17:12:09 +00:00
short game_top_fileinfo_version ;
int object_offset ;
2015-01-22 03:34:20 +00:00
unsigned gs_num_objects ;
2006-03-20 17:12:09 +00:00
int trig_size ;
//===================== READ FILE INFO ========================
// Check signature
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_readShort ( LoadFile ) ! = 0x6705 )
2006-03-20 17:12:09 +00:00
return - 1 ;
// Read and check version number
2011-06-01 07:59:55 +00:00
game_top_fileinfo_version = PHYSFSX_readShort ( LoadFile ) ;
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version < GAME_COMPATIBLE_VERSION )
return - 1 ;
// We skip some parts of the former game_top_fileinfo
2011-06-01 07:59:55 +00:00
PHYSFSX_fseek ( LoadFile , 31 , SEEK_CUR ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
object_offset = PHYSFSX_readInt ( LoadFile ) ;
gs_num_objects = PHYSFSX_readInt ( LoadFile ) ;
PHYSFSX_fseek ( LoadFile , 8 , SEEK_CUR ) ;
2006-03-20 17:12:09 +00:00
2018-08-12 21:08:07 +00:00
init_exploding_walls ( ) ;
2018-12-30 00:43:58 +00:00
auto & Walls = LevelUniqueWallSubsystemState . Walls ;
2016-02-06 22:12:54 +00:00
Walls . set_count ( PHYSFSX_readInt ( LoadFile ) ) ;
2011-06-01 07:59:55 +00:00
PHYSFSX_fseek ( LoadFile , 20 , SEEK_CUR ) ;
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:58 +00:00
auto & Triggers = LevelUniqueWallSubsystemState . Triggers ;
2016-02-06 22:12:53 +00:00
Triggers . set_count ( PHYSFSX_readInt ( LoadFile ) ) ;
2011-06-01 07:59:55 +00:00
PHYSFSX_fseek ( LoadFile , 24 , SEEK_CUR ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
trig_size = PHYSFSX_readInt ( LoadFile ) ;
2022-01-09 15:25:42 +00:00
if ( trig_size ! = sizeof ( v1_control_center_triggers ) )
throw std : : runtime_error ( " wrong size for v1_control_center_triggers " ) ;
2011-06-01 07:59:55 +00:00
PHYSFSX_fseek ( LoadFile , 4 , SEEK_CUR ) ;
2006-03-20 17:12:09 +00:00
2019-03-12 04:01:07 +00:00
const unsigned Num_robot_centers = PHYSFSX_readInt ( LoadFile ) ;
LevelSharedRobotcenterState . Num_robot_centers = Num_robot_centers ;
2011-06-01 07:59:55 +00:00
PHYSFSX_fseek ( LoadFile , 4 , SEEK_CUR ) ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
# elif defined(DXX_BUILD_DESCENT_II)
2014-11-23 04:36:59 +00:00
unsigned num_delta_lights ;
2018-06-06 04:53:45 +00:00
unsigned Num_static_lights ;
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version > = 29 ) {
2011-06-01 07:59:55 +00:00
PHYSFSX_fseek ( LoadFile , 4 , SEEK_CUR ) ;
Num_static_lights = PHYSFSX_readInt ( LoadFile ) ;
PHYSFSX_fseek ( LoadFile , 8 , SEEK_CUR ) ;
num_delta_lights = PHYSFSX_readInt ( LoadFile ) ;
PHYSFSX_fseek ( LoadFile , 4 , SEEK_CUR ) ;
2006-03-20 17:12:09 +00:00
} else {
Num_static_lights = 0 ;
num_delta_lights = 0 ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version > = 31 ) //load mine filename
// read newline-terminated string, not sure what version this changed.
2013-11-23 00:13:36 +00:00
PHYSFSX_fgets ( Current_level_name , LoadFile ) ;
2006-03-20 17:12:09 +00:00
else if ( game_top_fileinfo_version > = 14 ) { //load mine filename
// read null-terminated string
2011-06-01 07:59:55 +00:00
//must do read one char at a time, since no PHYSFSX_fgets()
2015-01-15 04:30:04 +00:00
for ( auto p = Current_level_name . next ( ) . begin ( ) ; ( * p = PHYSFSX_fgetc ( LoadFile ) ) ; )
{
if ( + + p = = Current_level_name . line ( ) . end ( ) )
2013-11-25 00:20:18 +00:00
{
p [ - 1 ] = 0 ;
while ( PHYSFSX_fgetc ( LoadFile ) )
;
break ;
}
}
2006-03-20 17:12:09 +00:00
}
else
2014-12-22 04:35:47 +00:00
Current_level_name . next ( ) [ 0 ] = 0 ;
2006-03-20 17:12:09 +00:00
2020-08-24 01:31:28 +00:00
savegame_pof_names_type Save_pof_names ;
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version > = 19 ) { //load pof names
2017-07-15 21:50:22 +00:00
const unsigned N_save_pof_names = PHYSFSX_readShort ( LoadFile ) ;
if ( N_save_pof_names < MAX_POLYGON_MODELS )
2011-06-01 07:59:55 +00:00
PHYSFS_read ( LoadFile , Save_pof_names , N_save_pof_names , FILENAME_LEN ) ;
2017-07-15 21:50:22 +00:00
else
LevelError ( " Level contains bogus N_save_pof_names %#x; ignoring " , N_save_pof_names ) ;
2006-03-20 17:12:09 +00:00
}
//===================== READ PLAYER INFO ==========================
2010-01-28 15:26:27 +00:00
2006-03-20 17:12:09 +00:00
//===================== READ OBJECT INFO ==========================
Gamesave_num_org_robots = 0 ;
Gamesave_num_players = 0 ;
if ( object_offset > - 1 ) {
2011-06-01 07:59:55 +00:00
if ( PHYSFSX_fseek ( LoadFile , object_offset , SEEK_SET ) )
2006-03-20 17:12:09 +00:00
Error ( " Error seeking to object_offset in gamesave.c " ) ;
2015-01-22 03:34:20 +00:00
range_for ( auto & i , partial_range ( Objects , gs_num_objects ) )
{
2017-06-10 03:31:02 +00:00
const auto & & o = vmobjptr ( & i ) ;
2015-07-12 01:04:20 +00:00
read_object ( o , LoadFile , game_top_fileinfo_version ) ;
2020-08-24 01:31:28 +00:00
verify_object ( Vclip , o , Save_pof_names ) ;
2006-03-20 17:12:09 +00:00
}
}
//===================== READ WALL INFO ============================
2018-12-30 00:43:58 +00:00
auto & vmwallptr = Walls . vmptr ;
2017-06-10 03:31:02 +00:00
range_for ( const auto & & vw , vmwallptr )
2014-04-27 23:12:34 +00:00
{
2016-05-21 17:24:51 +00:00
auto & nw = * vw ;
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version > = 20 )
2014-04-27 03:09:11 +00:00
wall_read ( LoadFile , nw ) ; // v20 walls and up.
2006-03-20 17:12:09 +00:00
else if ( game_top_fileinfo_version > = 17 ) {
v19_wall w ;
2014-04-27 03:09:11 +00:00
v19_wall_read ( LoadFile , w ) ;
2014-04-27 23:12:34 +00:00
nw . segnum = w . segnum ;
2022-01-09 15:25:42 +00:00
nw . sidenum = build_sidenum_from_untrusted ( w . sidenum ) . value ( ) ;
2014-04-27 23:12:34 +00:00
nw . linked_wall = w . linked_wall ;
nw . type = w . type ;
2021-11-01 03:37:19 +00:00
auto wf = static_cast < wall_flags > ( w . flags ) ;
wf & = ~ wall_flag : : exploding ;
nw . flags = wf ;
2014-04-27 23:12:34 +00:00
nw . hps = w . hps ;
2021-09-04 12:17:14 +00:00
nw . trigger = static_cast < trgnum_t > ( w . trigger ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2014-04-27 23:12:34 +00:00
nw . clip_num = convert_wclip ( w . clip_num ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2014-04-27 23:12:34 +00:00
nw . clip_num = w . clip_num ;
2013-03-03 01:03:33 +00:00
# endif
2020-12-19 16:13:26 +00:00
nw . keys = static_cast < wall_key > ( w . keys ) ;
2021-11-01 03:37:19 +00:00
nw . state = wall_state : : closed ;
2006-03-20 17:12:09 +00:00
} else {
v16_wall w ;
2014-04-27 03:09:11 +00:00
v16_wall_read ( LoadFile , w ) ;
2014-04-27 23:12:34 +00:00
nw . segnum = segment_none ;
2022-01-09 15:25:42 +00:00
nw . sidenum = { } ;
2020-12-26 21:17:29 +00:00
nw . linked_wall = wall_none ;
2014-04-27 23:12:34 +00:00
nw . type = w . type ;
2021-11-01 03:37:19 +00:00
auto wf = static_cast < wall_flags > ( w . flags ) ;
wf & = ~ wall_flag : : exploding ;
nw . flags = wf ;
2014-04-27 23:12:34 +00:00
nw . hps = w . hps ;
2021-09-04 12:17:14 +00:00
nw . trigger = static_cast < trgnum_t > ( w . trigger ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2014-04-27 23:12:34 +00:00
nw . clip_num = convert_wclip ( w . clip_num ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2014-04-27 23:12:34 +00:00
nw . clip_num = w . clip_num ;
2013-03-03 01:03:33 +00:00
# endif
2020-12-19 16:13:26 +00:00
nw . keys = static_cast < wall_key > ( w . keys ) ;
2006-03-20 17:12:09 +00:00
}
}
//==================== READ TRIGGER INFO ==========================
2018-12-30 00:43:58 +00:00
auto & vmtrgptr = Triggers . vmptr ;
2017-06-10 03:31:02 +00:00
range_for ( const auto vt , vmtrgptr )
2006-03-20 17:12:09 +00:00
{
2016-10-02 00:34:39 +00:00
auto & i = * vt ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
if ( game_top_fileinfo_version < = 25 )
2014-12-08 04:19:26 +00:00
v25_trigger_read ( LoadFile , & i ) ;
2013-03-03 01:03:33 +00:00
else {
2014-12-08 04:19:26 +00:00
v26_trigger_read ( LoadFile , i ) ;
2013-03-03 01:03:33 +00:00
}
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version < 31 )
{
if ( game_top_fileinfo_version < 30 ) {
2014-12-08 04:19:26 +00:00
v29_trigger_read_as_v31 ( LoadFile , i ) ;
2006-03-20 17:12:09 +00:00
}
else
2014-12-08 04:19:26 +00:00
v30_trigger_read_as_v31 ( LoadFile , i ) ;
2006-03-20 17:12:09 +00:00
}
else
2022-01-09 15:25:42 +00:00
trigger_read ( LoadFile , i ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
//================ READ CONTROL CENTER TRIGGER INFO ===============
2022-01-09 15:25:42 +00:00
control_center_triggers_read ( ControlCenterTriggers , LoadFile ) ;
2006-03-20 17:12:09 +00:00
//================ READ MATERIALOGRIFIZATIONATORS INFO ===============
2021-06-28 03:37:50 +00:00
for ( auto & & [ i , r ] : enumerate ( partial_range ( RobotCenters , Num_robot_centers ) ) )
2019-03-12 04:01:07 +00:00
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
2019-03-12 04:01:07 +00:00
matcen_info_read ( LoadFile , r , game_top_fileinfo_version ) ;
2013-03-03 01:03:33 +00:00
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version < 27 ) {
2019-03-12 04:01:07 +00:00
d1_matcen_info_read ( LoadFile , r ) ;
2006-03-20 17:12:09 +00:00
}
else
2019-03-12 04:01:07 +00:00
matcen_info_read ( LoadFile , r ) ;
2013-03-03 01:03:33 +00:00
# endif
2014-01-20 04:34:20 +00:00
// Set links in RobotCenters to Station array
2019-12-22 05:34:08 +00:00
range_for ( const shared_segment & seg , partial_const_range ( Segments , Highest_segment_index + 1 ) )
2021-11-01 03:37:19 +00:00
if ( seg . special = = segment_special : : robotmaker )
2014-01-20 04:34:20 +00:00
if ( seg . matcen_num = = i )
2019-03-12 04:01:07 +00:00
r . fuelcen_num = seg . station_idx ;
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
//================ READ DL_INDICES INFO ===============
2018-12-30 00:43:58 +00:00
{
auto & Dl_indices = LevelSharedDestructibleLightState . Dl_indices ;
2018-06-06 04:53:45 +00:00
Dl_indices . set_count ( Num_static_lights ) ;
2014-11-23 04:36:58 +00:00
if ( game_top_fileinfo_version < 29 )
{
if ( Num_static_lights )
throw std : : logic_error ( " Static lights in old file " ) ;
}
else
{
2015-12-22 04:18:52 +00:00
const auto & & lr = partial_range ( Dl_indices , Num_static_lights ) ;
range_for ( auto & i , lr )
2014-11-23 04:36:58 +00:00
dl_index_read ( & i , LoadFile ) ;
2017-01-15 00:03:14 +00:00
std : : sort ( lr . begin ( ) , lr . end ( ) ) ;
2006-03-20 17:12:09 +00:00
}
2018-12-30 00:43:58 +00:00
}
2006-03-20 17:12:09 +00:00
// Indicate that no light has been subtracted from any vertices.
clear_light_subtracted ( ) ;
//================ READ DELTA LIGHT INFO ===============
if ( game_top_fileinfo_version < 29 ) {
2008-04-06 20:23:28 +00:00
;
2006-03-20 17:12:09 +00:00
} else
2014-11-23 04:36:59 +00:00
{
2018-12-30 00:43:58 +00:00
auto & Delta_lights = LevelSharedDestructibleLightState . Delta_lights ;
2014-11-23 04:36:59 +00:00
range_for ( auto & i , partial_range ( Delta_lights , num_delta_lights ) )
delta_light_read ( & i , LoadFile ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//========================= UPDATE VARIABLES ======================
2018-12-30 00:43:57 +00:00
reset_objects ( LevelUniqueObjectState , gs_num_objects ) ;
2006-03-20 17:12:09 +00:00
2015-01-22 03:34:20 +00:00
range_for ( auto & i , Objects )
{
if ( i . type ! = OBJ_NONE ) {
auto objsegnum = i . segnum ;
2006-03-20 17:12:09 +00:00
if ( objsegnum > Highest_segment_index ) //bogus object
2012-07-07 23:46:05 +00:00
{
2015-01-22 03:34:20 +00:00
Warning ( " Object %p is in non-existent segment %i, highest=%i " , & i , objsegnum , Highest_segment_index ) ;
i . type = OBJ_NONE ;
2012-07-07 23:46:05 +00:00
}
2006-03-20 17:12:09 +00:00
else {
2018-03-12 03:43:46 +00:00
obj_link_unchecked ( Objects . vmptr , vmobjptridx ( & i ) , vmsegptridx ( objsegnum ) ) ;
2006-03-20 17:12:09 +00:00
}
}
}
clear_transient_objects ( 1 ) ; //1 means clear proximity bombs
// Make sure non-transparent doors are set correctly.
2017-06-10 03:31:02 +00:00
range_for ( auto & & i , vmsegptridx )
2022-01-09 15:25:42 +00:00
for ( auto & & [ side_idx , sside , uside ] : enumerate ( zip ( i - > shared_segment : : sides , i - > unique_segment : : sides ) ) )
2015-01-22 03:34:20 +00:00
{
2020-07-05 23:34:33 +00:00
if ( sside . wall_num = = wall_none )
2016-02-12 04:02:28 +00:00
continue ;
2020-07-05 23:34:33 +00:00
auto & w = * vmwallptr ( sside . wall_num ) ;
2016-02-12 04:02:28 +00:00
if ( w . clip_num ! = - 1 )
{
2020-04-04 19:30:22 +00:00
auto & wa = WallAnims [ w . clip_num ] ;
if ( wa . flags & WCF_TMAP1 )
2016-02-12 04:02:28 +00:00
{
2020-09-11 03:08:02 +00:00
uside . tmap_num = build_texture1_value ( wa . frames [ 0 ] ) ;
2020-08-24 01:31:28 +00:00
uside . tmap_num2 = texture2_value ( ) ;
2006-03-20 17:12:09 +00:00
}
}
2020-07-05 23:34:33 +00:00
validate_segment_wall ( i , sside , side_idx ) ;
2006-03-20 17:12:09 +00:00
}
2018-12-30 00:43:58 +00:00
auto & ActiveDoors = LevelUniqueWallSubsystemState . ActiveDoors ;
2016-12-10 17:51:08 +00:00
ActiveDoors . set_count ( 0 ) ;
2006-03-20 17:12:09 +00:00
//go through all walls, killing references to invalid triggers
2017-06-10 03:31:02 +00:00
range_for ( const auto & & p , vmwallptr )
2016-02-12 04:02:28 +00:00
{
auto & w = * p ;
2021-09-04 12:17:14 +00:00
if ( underlying_value ( w . trigger ) > = Triggers . get_count ( ) )
{
2016-10-15 00:53:18 +00:00
w . trigger = trigger_none ; //kill trigger
2006-03-20 17:12:09 +00:00
}
2016-02-12 04:02:28 +00:00
}
2006-03-20 17:12:09 +00:00
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2006-03-20 17:12:09 +00:00
//go through all triggers, killing unused ones
2016-02-12 04:02:28 +00:00
{
2017-06-10 03:31:02 +00:00
const auto & & wr = make_range ( vmwallptr ) ;
2021-09-04 12:17:14 +00:00
for ( auto iter = Triggers . vmptridx . begin ( ) ; iter ! = Triggers . vmptridx . end ( ) ; )
{
const auto i = ( * iter ) . get_unchecked_index ( ) ;
2015-01-22 03:34:20 +00:00
auto a = [ i ] ( const wall & w ) { return w . trigger = = i ; } ;
2006-03-20 17:12:09 +00:00
// Find which wall this trigger is connected to.
2016-02-12 04:02:28 +00:00
auto w = std : : find_if ( wr . begin ( ) , wr . end ( ) , a ) ;
if ( w = = wr . end ( ) )
2015-01-22 03:34:20 +00:00
{
2021-09-04 12:17:14 +00:00
remove_trigger_num ( Triggers , Walls . vmptr , i ) ;
2006-03-20 17:12:09 +00:00
}
else
2021-09-04 12:17:14 +00:00
+ + iter ;
2006-03-20 17:12:09 +00:00
}
2016-02-12 04:02:28 +00:00
}
2015-01-22 03:34:20 +00:00
# endif
2006-03-20 17:12:09 +00:00
// MK, 10/17/95: Make walls point back at the triggers that control them.
// Go through all triggers, stuffing controlling_trigger field in Walls.
2010-12-24 04:34:30 +00:00
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2017-06-10 03:31:02 +00:00
range_for ( const auto & & w , vmwallptr )
2021-09-04 12:17:14 +00:00
w - > controlling_trigger = trigger_none ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:58 +00:00
auto & vctrgptridx = Triggers . vcptridx ;
2016-10-06 02:08:07 +00:00
range_for ( const auto & & t , vctrgptridx )
2016-02-06 22:12:54 +00:00
{
2016-10-06 02:08:07 +00:00
auto & tr = * t ;
2016-02-06 22:12:54 +00:00
for ( unsigned l = 0 ; l < tr . num_links ; + + l )
{
2010-12-24 04:34:30 +00:00
//check to see that if a trigger requires a wall that it has one,
//and if it requires a matcen that it has one
2016-02-06 22:12:54 +00:00
const auto seg_num = tr . seg [ l ] ;
if ( trigger_is_matcen ( tr ) )
2014-12-14 21:02:40 +00:00
{
2021-11-01 03:37:19 +00:00
if ( Segments [ seg_num ] . special ! = segment_special : : robotmaker )
2021-09-04 12:17:14 +00:00
con_printf ( CON_URGENT , " matcen %u triggers non-matcen segment %hu " , underlying_value ( t . get_unchecked_index ( ) ) , seg_num ) ;
2014-12-14 21:02:40 +00:00
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2020-07-05 23:34:32 +00:00
else if ( tr . type ! = trigger_action : : light_off & & tr . type ! = trigger_action : : light_on )
2016-02-06 22:12:54 +00:00
{ //light triggers don't require walls
const auto side_num = tr . side [ l ] ;
2018-12-13 02:31:38 +00:00
auto wall_num = vmsegptr ( seg_num ) - > shared_segment : : sides [ side_num ] . wall_num ;
2017-06-10 03:31:02 +00:00
if ( const auto & & uwall = vmwallptr . check_untrusted ( wall_num ) )
2017-01-28 18:12:20 +00:00
( * uwall ) - > controlling_trigger = t ;
else
{
2022-06-05 17:44:52 +00:00
LevelError ( " trigger %u link %u type %u references segment %hu, side %u which is an invalid wall; ignoring. " , underlying_value ( t . get_unchecked_index ( ) ) , l , static_cast < unsigned > ( tr . type ) , seg_num , underlying_value ( side_num ) ) ;
2016-10-08 23:24:22 +00:00
}
2010-12-24 04:34:30 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
}
}
}
//fix old wall structs
if ( game_top_fileinfo_version < 17 ) {
2016-02-12 04:02:28 +00:00
range_for ( const auto & & segp , vcsegptridx )
2015-06-13 22:42:17 +00:00
{
2022-01-09 15:25:42 +00:00
for ( const auto & & [ sidenum , side ] : enumerate ( segp - > shared_segment : : sides ) )
2016-02-06 22:12:54 +00:00
{
2022-01-09 15:25:42 +00:00
const auto wallnum = side . wall_num ;
2016-02-06 22:12:54 +00:00
if ( wallnum ! = wall_none )
2015-06-13 22:42:17 +00:00
{
2017-06-10 03:31:02 +00:00
auto & w = * vmwallptr ( wallnum ) ;
2016-02-12 04:02:28 +00:00
w . segnum = segp ;
2022-01-09 15:25:42 +00:00
w . sidenum = static_cast < sidenum_t > ( sidenum ) ;
2006-03-20 17:12:09 +00:00
}
2016-02-06 22:12:54 +00:00
}
2015-06-13 22:42:17 +00:00
}
2006-03-20 17:12:09 +00:00
}
fix_object_segs ( ) ;
if ( game_top_fileinfo_version < GAME_VERSION
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
& & ! ( game_top_fileinfo_version = = 25 & & GAME_VERSION = = 26 )
# endif
)
2006-03-20 17:12:09 +00:00
return 1 ; //means old version
else
return 0 ;
}
2016-08-25 04:05:32 +00:00
}
2020-12-26 21:17:29 +00:00
}
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
# define LEVEL_FILE_VERSION 1
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
# define LEVEL_FILE_VERSION 8
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//1 -> 2 add palette name
//2 -> 3 add control center explosion time
//3 -> 4 add reactor strength
//4 -> 5 killed hostage text stuff
//5 -> 6 added Secret_return_segment and Secret_return_orient
//6 -> 7 added flickering lights
//7 -> 8 made version 8 to be not compatible with D2 1.0 & 1.1
# ifndef RELEASE
2012-07-22 23:17:54 +00:00
const char * Level_being_loaded = NULL ;
2006-03-20 17:12:09 +00:00
# endif
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
int no_old_level_file_error = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//loads a level (.LVL) file from disk
//returns 0 if success, else error code
2016-08-25 04:05:32 +00:00
namespace dsx {
2018-12-30 00:43:57 +00:00
int load_level (
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:58 +00:00
d_level_shared_destructible_light_state & LevelSharedDestructibleLightState ,
2018-12-30 00:43:57 +00:00
# endif
const char * filename_passed )
2006-03-20 17:12:09 +00:00
{
2020-05-17 23:35:25 +00:00
auto & LevelSharedVertexState = LevelSharedSegmentState . get_vertex_state ( ) ;
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
2020-05-17 23:35:25 +00:00
auto & Vertices = LevelSharedVertexState . get_vertices ( ) ;
2019-03-03 00:31:08 +00:00
auto & vmobjptridx = Objects . vmptridx ;
2006-03-20 17:12:09 +00:00
char filename [ PATH_MAX ] ;
int sig , minedata_offset , gamedata_offset ;
int mine_err , game_err ;
# ifndef RELEASE
Level_being_loaded = filename_passed ;
# endif
strcpy ( filename , filename_passed ) ;
2021-07-25 23:00:56 +00:00
auto LoadFile = PHYSFSX_openReadBuffered ( filename ) . first ;
2015-10-11 22:21:00 +00:00
if ( ! LoadFile )
{
2016-08-19 03:41:41 +00:00
snprintf ( filename , sizeof ( filename ) , " %.*s%s " , DXX_ptrdiff_cast_int ( std : : distance ( Current_mission - > path . cbegin ( ) , Current_mission - > filename ) ) , Current_mission - > path . c_str ( ) , filename_passed ) ;
2021-07-25 23:00:56 +00:00
auto & & [ fp , physfserr ] = PHYSFSX_openReadBuffered ( filename ) ;
if ( ! fp )
{
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2021-09-12 16:20:52 +00:00
con_printf ( CON_VERBOSE , " Failed to open file <%s>: %s " , filename , PHYSFS_getErrorByCode ( physfserr ) ) ;
2006-03-20 17:12:09 +00:00
return 1 ;
# else
2021-07-25 23:00:56 +00:00
Error ( " Failed to open file <%s>: %s " , filename , PHYSFS_getErrorByCode ( physfserr ) ) ;
2006-03-20 17:12:09 +00:00
# endif
2021-07-25 23:00:56 +00:00
}
LoadFile = std : : move ( fp ) ;
2006-03-20 17:12:09 +00:00
}
2011-06-01 07:59:55 +00:00
sig = PHYSFSX_readInt ( LoadFile ) ;
Gamesave_current_version = PHYSFSX_readInt ( LoadFile ) ;
minedata_offset = PHYSFSX_readInt ( LoadFile ) ;
gamedata_offset = PHYSFSX_readInt ( LoadFile ) ;
2006-03-20 17:12:09 +00:00
Assert ( sig = = MAKE_SIG ( ' P ' , ' L ' , ' V ' , ' L ' ) ) ;
2011-09-26 23:31:19 +00:00
( void ) sig ;
2006-03-20 17:12:09 +00:00
2013-03-03 01:03:33 +00:00
if ( Gamesave_current_version < 5 )
PHYSFSX_readInt ( LoadFile ) ; //was hostagetext_offset
2015-02-28 19:36:01 +00:00
init_exploding_walls ( ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version > = 8 ) { //read dummy data
2011-06-01 07:59:55 +00:00
PHYSFSX_readInt ( LoadFile ) ;
PHYSFSX_readShort ( LoadFile ) ;
PHYSFSX_readByte ( LoadFile ) ;
2006-03-20 17:12:09 +00:00
}
if ( Gamesave_current_version > 1 )
2013-11-23 00:13:36 +00:00
PHYSFSX_fgets ( Current_level_palette , LoadFile ) ;
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version < = 1 | | Current_level_palette [ 0 ] = = 0 ) // descent 1 level
2014-12-20 04:36:10 +00:00
strcpy ( Current_level_palette . next ( ) . data ( ) , DEFAULT_LEVEL_PALETTE ) ;
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version > = 3 )
2019-08-15 01:34:22 +00:00
LevelSharedControlCenterState . Base_control_center_explosion_time = PHYSFSX_readInt ( LoadFile ) ;
2006-03-20 17:12:09 +00:00
else
2019-08-15 01:34:22 +00:00
LevelSharedControlCenterState . Base_control_center_explosion_time = DEFAULT_CONTROL_CENTER_EXPLOSION_TIME ;
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version > = 4 )
2019-08-15 01:34:22 +00:00
LevelSharedControlCenterState . Reactor_strength = PHYSFSX_readInt ( LoadFile ) ;
2006-03-20 17:12:09 +00:00
else
2019-08-15 01:34:22 +00:00
LevelSharedControlCenterState . Reactor_strength = - 1 ; //use old defaults
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version > = 7 ) {
2018-03-31 21:53:01 +00:00
Flickering_light_state . Num_flickering_lights = PHYSFSX_readInt ( LoadFile ) ;
range_for ( auto & i , partial_range ( Flickering_light_state . Flickering_lights , Flickering_light_state . Num_flickering_lights ) )
2018-03-27 03:49:34 +00:00
flickering_light_read ( i , LoadFile ) ;
2006-03-20 17:12:09 +00:00
}
else
2018-03-31 21:53:01 +00:00
Flickering_light_state . Num_flickering_lights = 0 ;
2006-03-20 17:12:09 +00:00
2019-08-06 02:59:41 +00:00
{
auto & Secret_return_orient = LevelSharedSegmentState . Secret_return_orient ;
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version < 6 ) {
2019-08-06 02:59:41 +00:00
LevelSharedSegmentState . Secret_return_segment = segment_first ;
2006-03-20 17:12:09 +00:00
Secret_return_orient . rvec . x = F1_0 ;
Secret_return_orient . rvec . y = 0 ;
Secret_return_orient . rvec . z = 0 ;
Secret_return_orient . fvec . x = 0 ;
Secret_return_orient . fvec . y = F1_0 ;
Secret_return_orient . fvec . z = 0 ;
Secret_return_orient . uvec . x = 0 ;
Secret_return_orient . uvec . y = 0 ;
Secret_return_orient . uvec . z = F1_0 ;
} else {
2019-08-06 02:59:41 +00:00
LevelSharedSegmentState . Secret_return_segment = PHYSFSX_readInt ( LoadFile ) ;
2011-06-01 07:59:55 +00:00
Secret_return_orient . rvec . x = PHYSFSX_readInt ( LoadFile ) ;
Secret_return_orient . rvec . y = PHYSFSX_readInt ( LoadFile ) ;
Secret_return_orient . rvec . z = PHYSFSX_readInt ( LoadFile ) ;
Secret_return_orient . fvec . x = PHYSFSX_readInt ( LoadFile ) ;
Secret_return_orient . fvec . y = PHYSFSX_readInt ( LoadFile ) ;
Secret_return_orient . fvec . z = PHYSFSX_readInt ( LoadFile ) ;
Secret_return_orient . uvec . x = PHYSFSX_readInt ( LoadFile ) ;
Secret_return_orient . uvec . y = PHYSFSX_readInt ( LoadFile ) ;
Secret_return_orient . uvec . z = PHYSFSX_readInt ( LoadFile ) ;
2006-03-20 17:12:09 +00:00
}
2019-08-06 02:59:41 +00:00
}
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
PHYSFSX_fseek ( LoadFile , minedata_offset , SEEK_SET ) ;
2006-03-20 17:12:09 +00:00
//NOTE LINK TO ABOVE!!
2019-08-06 02:59:40 +00:00
mine_err = load_mine_data_compiled ( LoadFile , filename ) ;
2006-03-20 17:12:09 +00:00
2010-07-17 11:19:29 +00:00
/* !!!HACK!!!
* Descent 1 - Level 19 : OBERON MINE has some ugly overlapping rooms ( segment 484 ) .
* HACK to make this issue less visible by moving one vertex a little .
*/
2018-12-30 00:43:57 +00:00
auto & vmvertptr = Vertices . vmptr ;
2021-11-01 03:37:19 +00:00
if ( Current_mission & & ! d_stricmp ( " Descent: First Strike " , Current_mission - > mission_name ) & & ! d_stricmp ( " level19.rdl " , filename ) & & PHYSFS_fileLength ( LoadFile ) = = 136706 )
2020-12-26 21:17:29 +00:00
vmvertptr ( vertnum_t { 1905u } ) - > z = - 385 * F1_0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2011-03-27 21:58:53 +00:00
/* !!!HACK!!!
* Descent 2 - Level 12 : MAGNACORE STATION has a segment ( 104 ) with illegal dimensions .
* HACK to fix this by moving the Vertex and fixing the associated Normals .
* NOTE : This only fixes the normals of segment 104 , not the other ones connected to this Vertex but this is unsignificant .
*/
2021-11-01 03:37:19 +00:00
if ( Current_mission & & ! d_stricmp ( " Descent 2: Counterstrike! " , Current_mission - > mission_name ) & & ! d_stricmp ( " d2levc-4.rl2 " , filename ) )
2011-03-27 21:58:53 +00:00
{
2019-12-22 05:34:08 +00:00
shared_segment & s104 = * vmsegptr ( vmsegidx_t ( 104 ) ) ;
2022-01-09 15:25:42 +00:00
auto & s104v0 = * vmvertptr ( s104 . verts [ segment_relative_vertnum : : _0 ] ) ;
2022-01-15 20:39:10 +00:00
auto & s104s1 = s104 . sides [ sidenum_t : : WTOP ] ;
2016-10-15 00:53:17 +00:00
auto & s104s1n0 = s104s1 . normals [ 0 ] ;
auto & s104s1n1 = s104s1 . normals [ 1 ] ;
2022-01-15 20:39:10 +00:00
auto & s104s2 = s104 . sides [ sidenum_t : : WRIGHT ] ;
2016-10-15 00:53:17 +00:00
auto & s104s2n0 = s104s2 . normals [ 0 ] ;
auto & s104s2n1 = s104s2 . normals [ 1 ] ;
if (
( s104v0 . x = = - 53990800 & & s104v0 . y = = - 59927741 & & s104v0 . z = = 23034584 ) & &
( s104s1n0 . x = = 56775 & & s104s1n0 . y = = - 27796 & & s104s1n0 . z = = - 17288 & & s104s1n1 . x = = 50157 & & s104s1n1 . y = = - 34561 & & s104s1n1 . z = = - 24180 ) & &
( s104s2n0 . x = = 60867 & & s104s2n0 . y = = - 19485 & & s104s2n0 . z = = - 14507 & & s104s2n1 . x = = 55485 & & s104s2n1 . y = = - 29668 & & s104s2n1 . z = = - 18332 )
)
{
s104v0 . x = - 53859726 ;
s104v0 . y = - 59927743 ;
s104v0 . z = 23034586 ;
s104s1n0 . x = 56123 ;
s104s1n0 . y = - 27725 ;
s104s1n0 . z = - 19401 ;
s104s1n1 . x = 49910 ;
s104s1n1 . y = - 33946 ;
s104s1n1 . z = - 25525 ;
s104s2n0 . x = 60903 ;
s104s2n0 . y = - 18371 ;
s104s2n0 . z = - 15753 ;
s104s2n1 . x = 57004 ;
s104s2n1 . y = - 26385 ;
s104s2n1 . z = - 18688 ;
2011-03-27 21:58:53 +00:00
// I feel so dirty now ...
2016-10-15 00:53:17 +00:00
}
2011-03-27 21:58:53 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2010-07-17 11:19:29 +00:00
2006-03-20 17:12:09 +00:00
if ( mine_err = = - 1 ) { //error!!
return 2 ;
}
2011-06-01 07:59:55 +00:00
PHYSFSX_fseek ( LoadFile , gamedata_offset , SEEK_SET ) ;
2018-12-30 00:43:57 +00:00
game_err = load_game_data (
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:58 +00:00
LevelSharedDestructibleLightState ,
2018-12-30 00:43:57 +00:00
# endif
vmobjptridx , vmsegptridx , LoadFile ) ;
2006-03-20 17:12:09 +00:00
if ( game_err = = - 1 ) { //error!!
return 3 ;
}
//======================== CLOSE FILE =============================
2015-01-17 18:31:42 +00:00
LoadFile . reset ( ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
set_ambient_sound_flags ( ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
//If an old version, ask the use if he wants to save as new version
2013-12-04 22:19:04 +00:00
if ( ( ( LEVEL_FILE_VERSION > 1 ) & & Gamesave_current_version < LEVEL_FILE_VERSION ) | | mine_err = = 1 | | game_err = = 1 ) {
2013-03-03 01:03:33 +00:00
gr_palette_load ( gr_palette ) ;
2020-12-19 16:13:26 +00:00
if ( nm_messagebox_str ( menu_title { nullptr } , nm_messagebox_tie ( " Don't Save " , " Save " ) , menu_subtitle { " You just loaded a old version level. Would \n "
" you like to save it as a current version level? " } ) = = 1 )
2013-03-03 01:03:33 +00:00
save_level ( filename ) ;
}
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
//If a Descent 1 level and the Descent 1 pig isn't present, pretend it's a Descent 2 level.
2012-03-19 06:09:26 +00:00
if ( EditorWindow & & ( Gamesave_current_version < = 3 ) & & ! d1_pig_present )
2006-03-20 17:12:09 +00:00
{
if ( ! no_old_level_file_error )
Warning ( " A Descent 1 level was loaded, \n "
" and there is no Descent 1 texture \n "
" set available. Saving it will \n "
" convert it to a Descent 2 level. " ) ;
Gamesave_current_version = LEVEL_FILE_VERSION ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
# endif
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2012-03-19 06:09:26 +00:00
if ( EditorWindow )
2014-12-20 04:36:10 +00:00
editor_status_fmt ( " Loaded NEW mine %s, \" %s \" " , filename , static_cast < const char * > ( Current_level_name ) ) ;
2006-03-20 17:12:09 +00:00
# endif
2017-07-26 03:15:59 +00:00
# ifdef NDEBUG
if ( ! PLAYING_BUILTIN_MISSION )
# endif
2006-03-20 17:12:09 +00:00
if ( check_segment_connections ( ) )
2017-07-26 03:15:59 +00:00
{
# ifndef NDEBUG
2020-12-19 16:13:26 +00:00
nm_messagebox_str ( menu_title { TXT_ERROR } , nm_messagebox_tie ( TXT_OK ) ,
menu_subtitle { " Connectivity errors detected in \n "
2006-03-20 17:12:09 +00:00
" mine. See monochrome screen for \n "
2020-12-19 16:13:26 +00:00
" details, and contact Matt or Mike. " } ) ;
2006-03-20 17:12:09 +00:00
# endif
2017-07-26 03:15:59 +00:00
}
2006-03-20 17:12:09 +00:00
2015-05-17 20:37:59 +00:00
# if defined(DXX_BUILD_DESCENT_II)
compute_slide_segs ( ) ;
# endif
2006-03-20 17:12:09 +00:00
return 0 ;
}
2016-08-25 04:05:32 +00:00
}
2006-03-20 17:12:09 +00:00
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2006-03-20 17:12:09 +00:00
int get_level_name ( )
{
2020-12-27 22:03:09 +00:00
using items_type = std : : array < newmenu_item , 2 > ;
struct request_menu : items_type , passive_newmenu
{
2021-09-12 16:20:52 +00:00
request_menu ( grs_canvas & canvas ) :
2020-12-27 22:03:09 +00:00
items_type { {
2021-06-28 03:37:49 +00:00
newmenu_item : : nm_item_text { " Please enter a name for this mine: " } ,
2021-06-28 03:37:49 +00:00
newmenu_item : : nm_item_input ( Current_level_name . next ( ) ) ,
2020-12-27 22:03:09 +00:00
} } ,
2021-09-12 16:20:52 +00:00
passive_newmenu ( menu_title { nullptr } , menu_subtitle { " Enter mine name " } , menu_filename { nullptr } , tiny_mode_flag : : normal , tab_processing_flag : : ignore , adjusted_citem : : create ( * static_cast < items_type * > ( this ) , 1 ) , canvas , draw_box_flag : : none )
2020-12-27 22:03:09 +00:00
{
}
} ;
2021-09-12 16:20:52 +00:00
return run_blocking_newmenu < request_menu > ( * grd_curcanv ) ;
2006-03-20 17:12:09 +00:00
}
# endif
2016-09-11 18:49:16 +00:00
# if DXX_USE_EDITOR
2006-03-20 17:12:09 +00:00
2012-04-14 05:46:20 +00:00
// --------------------------------------------------------------------------------------
// Create a new mine, set global variables.
2016-08-25 04:05:32 +00:00
namespace dsx {
2012-04-14 05:46:20 +00:00
int create_new_mine ( void )
{
2020-05-17 23:35:25 +00:00
auto & LevelSharedVertexState = LevelSharedSegmentState . get_vertex_state ( ) ;
auto & Vertices = LevelSharedVertexState . get_vertices ( ) ;
2012-04-14 05:46:20 +00:00
vms_matrix m1 = IDENTITY_MATRIX ;
// initialize_mine_arrays();
// gamestate_not_restored = 1;
// Clear refueling center code
fuelcen_reset ( ) ;
init_all_vertices ( ) ;
2016-11-15 03:13:23 +00:00
Current_level_num = 1 ; // make level 1 (for now)
2014-12-20 04:36:07 +00:00
Current_level_name . next ( ) [ 0 ] = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
Gamesave_current_version = LEVEL_FILE_VERSION ;
# elif defined(DXX_BUILD_DESCENT_II)
2012-04-14 05:46:20 +00:00
Gamesave_current_version = GAME_VERSION ;
2014-12-20 04:36:10 +00:00
strcpy ( Current_level_palette . next ( ) . data ( ) , DEFAULT_LEVEL_PALETTE ) ;
2013-03-03 01:03:33 +00:00
# endif
2012-04-14 10:29:02 +00:00
2012-04-14 05:46:20 +00:00
Cur_object_index = - 1 ;
2018-12-30 00:43:57 +00:00
reset_objects ( LevelUniqueObjectState , 1 ) ; //just one object, the player
2012-04-14 05:46:20 +00:00
num_groups = 0 ;
current_group = - 1 ;
2018-12-30 00:43:57 +00:00
LevelSharedVertexState . Num_vertices = 0 ; // Number of vertices in global array.
2017-08-11 23:43:54 +00:00
Vertices . set_count ( 1 ) ;
2018-09-19 02:13:29 +00:00
LevelSharedSegmentState . Num_segments = 0 ; // Number of segments in global array, will get increased in med_create_segment
2016-01-09 16:38:12 +00:00
Segments . set_count ( 1 ) ;
2017-06-10 03:31:02 +00:00
Cursegp = imsegptridx ( segment_first ) ; // Say current segment is the only segment.
2022-02-19 14:52:17 +00:00
Curside = sidenum_t : : WBACK ; // The active side is the back side
2015-07-12 01:04:18 +00:00
Markedsegp = segment_none ; // Say there is no marked segment.
2022-02-19 14:52:17 +00:00
Markedside = sidenum_t : : WBACK ; // Shouldn't matter since Markedsegp == 0, but just in case...
2014-09-26 02:42:09 +00:00
for ( int s = 0 ; s < MAX_GROUPS + 1 ; s + + ) {
2013-12-11 23:59:36 +00:00
GroupList [ s ] . clear ( ) ;
2012-04-14 05:46:20 +00:00
Groupsegp [ s ] = NULL ;
}
2022-01-09 15:25:42 +00:00
Groupside = { } ;
2012-04-14 05:46:20 +00:00
2019-03-12 04:01:07 +00:00
LevelSharedRobotcenterState . Num_robot_centers = 0 ;
2022-04-17 22:27:19 +00:00
wall_init ( LevelUniqueWallSubsystemState ) ;
2022-04-17 22:27:19 +00:00
auto & Triggers = LevelUniqueWallSubsystemState . Triggers ;
Triggers . set_count ( 0 ) ;
2012-04-14 05:46:20 +00:00
// Create New_segment, which is the segment we will be adding at each instance.
2015-01-12 00:26:02 +00:00
med_create_new_segment ( { DEFAULT_X_SIZE , DEFAULT_Y_SIZE , DEFAULT_Z_SIZE } ) ; // New_segment = Segments[0];
2012-04-14 05:46:20 +00:00
// med_create_segment(Segments,0,0,0,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE,vm_mat_make(&m1,F1_0,0,0,0,F1_0,0,0,0,F1_0));
2017-06-10 03:31:02 +00:00
med_create_segment ( vmsegptridx ( segment_first ) , 0 , 0 , 0 , DEFAULT_X_SIZE , DEFAULT_Y_SIZE , DEFAULT_Z_SIZE , m1 ) ;
2012-04-14 05:46:20 +00:00
2013-12-11 23:59:36 +00:00
Found_segs . clear ( ) ;
2013-12-11 23:59:36 +00:00
Selected_segs . clear ( ) ;
2013-12-11 23:59:36 +00:00
Warning_segs . clear ( ) ;
2012-04-14 05:46:20 +00:00
//--repair-- create_local_segment_data();
ControlCenterTriggers . num_links = 0 ;
2012-04-17 09:37:15 +00:00
create_new_mission ( ) ;
2012-04-14 05:46:20 +00:00
//editor_status("New mine created.");
return 0 ; // say no error
}
2016-08-25 04:05:32 +00:00
}
2012-04-14 05:46:20 +00:00
2006-03-20 17:12:09 +00:00
int Errors_in_mine ;
2018-12-30 00:43:57 +00:00
namespace dsx {
2020-12-26 21:17:29 +00:00
namespace {
2006-03-20 17:12:09 +00:00
// -----------------------------------------------------------------------------
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:57 +00:00
static unsigned compute_num_delta_light_records ( fvcdlindexptr & vcdlindexptr )
2006-03-20 17:12:09 +00:00
{
2018-12-30 00:43:57 +00:00
unsigned total = 0 ;
range_for ( const auto & & i , vcdlindexptr )
2018-06-06 04:53:45 +00:00
total + = i - > count ;
2006-03-20 17:12:09 +00:00
return total ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
// -----------------------------------------------------------------------------
// Save game
2018-12-30 00:43:57 +00:00
static int save_game_data (
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:58 +00:00
const d_level_shared_destructible_light_state & LevelSharedDestructibleLightState ,
2018-12-30 00:43:57 +00:00
# endif
PHYSFS_File * SaveFile )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vcobjptr = Objects . vcptr ;
2019-02-02 18:36:39 +00:00
auto & RobotCenters = LevelSharedRobotcenterState . RobotCenters ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
short game_top_fileinfo_version = Gamesave_current_version > = 5 ? 31 : GAME_VERSION ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
short game_top_fileinfo_version = Gamesave_current_version > = 5 ? 31 : 25 ;
2007-06-11 15:54:09 +00:00
int dl_indices_offset = 0 , delta_light_offset = 0 ;
2013-03-03 01:03:33 +00:00
# endif
2013-08-27 02:20:05 +00:00
int player_offset = 0 , object_offset = 0 , walls_offset = 0 , doors_offset = 0 , triggers_offset = 0 , control_offset = 0 , matcen_offset = 0 ; //, links_offset;
int offset_offset = 0 , end_offset = 0 ;
2006-03-20 17:12:09 +00:00
//===================== SAVE FILE INFO ========================
PHYSFS_writeSLE16 ( SaveFile , 0x6705 ) ; // signature
PHYSFS_writeSLE16 ( SaveFile , game_top_fileinfo_version ) ;
2013-10-03 02:43:25 +00:00
PHYSFS_writeSLE32 ( SaveFile , 0 ) ;
2014-12-20 04:36:07 +00:00
PHYSFS_write ( SaveFile , Current_level_name . line ( ) , 15 , 1 ) ;
2006-03-20 17:12:09 +00:00
PHYSFS_writeSLE32 ( SaveFile , Current_level_num ) ;
offset_offset = PHYSFS_tell ( SaveFile ) ; // write the offsets later
PHYSFS_writeSLE32 ( SaveFile , - 1 ) ;
2013-12-22 21:10:47 +00:00
PHYSFS_writeSLE32 ( SaveFile , 0 ) ;
2006-03-20 17:12:09 +00:00
# define WRITE_HEADER_ENTRY(t, n) do { PHYSFS_writeSLE32(SaveFile, -1); PHYSFS_writeSLE32(SaveFile, n); PHYSFS_writeSLE32(SaveFile, sizeof(t)); } while(0)
2022-02-06 16:12:31 +00:00
WRITE_HEADER_ENTRY ( object , Objects . get_count ( ) ) ;
2018-12-30 00:43:58 +00:00
auto & Walls = LevelUniqueWallSubsystemState . Walls ;
2018-12-13 02:31:39 +00:00
WRITE_HEADER_ENTRY ( wall , Walls . get_count ( ) ) ;
2018-12-30 00:43:58 +00:00
auto & ActiveDoors = LevelUniqueWallSubsystemState . ActiveDoors ;
2016-12-10 17:51:08 +00:00
WRITE_HEADER_ENTRY ( active_door , ActiveDoors . get_count ( ) ) ;
2018-12-30 00:43:58 +00:00
auto & Triggers = LevelUniqueWallSubsystemState . Triggers ;
2018-12-13 02:31:39 +00:00
WRITE_HEADER_ENTRY ( trigger , Triggers . get_count ( ) ) ;
2006-03-20 17:12:09 +00:00
WRITE_HEADER_ENTRY ( 0 , 0 ) ; // links (removed by Parallax)
WRITE_HEADER_ENTRY ( control_center_triggers , 1 ) ;
2019-03-12 04:01:07 +00:00
const auto Num_robot_centers = LevelSharedRobotcenterState . Num_robot_centers ;
2006-03-20 17:12:09 +00:00
WRITE_HEADER_ENTRY ( matcen_info , Num_robot_centers ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2014-11-23 04:36:59 +00:00
unsigned num_delta_lights = 0 ;
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version > = 29 )
{
2018-12-30 00:43:58 +00:00
auto & Dl_indices = LevelSharedDestructibleLightState . Dl_indices ;
2018-06-06 04:53:45 +00:00
const unsigned Num_static_lights = Dl_indices . get_count ( ) ;
2006-03-20 17:12:09 +00:00
WRITE_HEADER_ENTRY ( dl_index , Num_static_lights ) ;
2018-12-30 00:43:57 +00:00
WRITE_HEADER_ENTRY ( delta_light , num_delta_lights = compute_num_delta_light_records ( Dl_indices . vcptr ) ) ;
2006-03-20 17:12:09 +00:00
}
// Write the mine name
if ( game_top_fileinfo_version > = 31 )
2013-03-03 01:03:33 +00:00
# endif
2014-12-20 04:36:10 +00:00
PHYSFSX_printf ( SaveFile , " %s \n " , static_cast < const char * > ( Current_level_name ) ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
else if ( game_top_fileinfo_version > = 14 )
PHYSFSX_writeString ( SaveFile , Current_level_name ) ;
if ( game_top_fileinfo_version > = 19 )
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
{
2020-08-24 01:31:28 +00:00
const auto N_polygon_models = LevelSharedPolygonModelState . N_polygon_models ;
2006-03-20 17:12:09 +00:00
PHYSFS_writeSLE16 ( SaveFile , N_polygon_models ) ;
2020-08-24 01:31:28 +00:00
range_for ( auto & i , partial_const_range ( LevelSharedPolygonModelState . Pof_names , N_polygon_models ) )
2015-08-12 03:11:46 +00:00
PHYSFS_write ( SaveFile , & i , sizeof ( i ) , 1 ) ;
2006-03-20 17:12:09 +00:00
}
//==================== SAVE PLAYER INFO ===========================
player_offset = PHYSFS_tell ( SaveFile ) ;
//==================== SAVE OBJECT INFO ===========================
object_offset = PHYSFS_tell ( SaveFile ) ;
2016-02-12 04:02:28 +00:00
range_for ( const auto & & objp , vcobjptr )
2006-03-20 17:12:09 +00:00
{
2015-06-13 22:42:17 +00:00
write_object ( objp , game_top_fileinfo_version , SaveFile ) ;
2006-03-20 17:12:09 +00:00
}
//==================== SAVE WALL INFO =============================
walls_offset = PHYSFS_tell ( SaveFile ) ;
2018-12-30 00:43:58 +00:00
auto & vcwallptr = Walls . vcptr ;
2016-02-12 04:02:28 +00:00
range_for ( const auto & & w , vcwallptr )
wall_write ( SaveFile , * w , game_top_fileinfo_version ) ;
2006-03-20 17:12:09 +00:00
//==================== SAVE TRIGGER INFO =============================
triggers_offset = PHYSFS_tell ( SaveFile ) ;
2018-12-30 00:43:58 +00:00
auto & vctrgptr = Triggers . vcptr ;
2016-10-02 00:34:39 +00:00
range_for ( const auto vt , vctrgptr )
{
auto & t = * vt ;
2014-02-09 18:41:42 +00:00
if ( game_top_fileinfo_version < = 29 )
v29_trigger_write ( SaveFile , t ) ;
else if ( game_top_fileinfo_version < = 30 )
v30_trigger_write ( SaveFile , t ) ;
else if ( game_top_fileinfo_version > = 31 )
v31_trigger_write ( SaveFile , t ) ;
2016-10-02 00:34:39 +00:00
}
2006-03-20 17:12:09 +00:00
//================ SAVE CONTROL CENTER TRIGGER INFO ===============
control_offset = PHYSFS_tell ( SaveFile ) ;
2022-01-09 15:25:42 +00:00
control_center_triggers_write ( ControlCenterTriggers , SaveFile ) ;
2006-03-20 17:12:09 +00:00
//================ SAVE MATERIALIZATION CENTER TRIGGER INFO ===============
matcen_offset = PHYSFS_tell ( SaveFile ) ;
2016-02-12 04:02:28 +00:00
range_for ( auto & r , partial_const_range ( RobotCenters , Num_robot_centers ) )
2014-01-18 18:02:02 +00:00
matcen_info_write ( SaveFile , r , game_top_fileinfo_version ) ;
2006-03-20 17:12:09 +00:00
//================ SAVE DELTA LIGHT INFO ===============
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version > = 29 )
{
dl_indices_offset = PHYSFS_tell ( SaveFile ) ;
2018-12-30 00:43:58 +00:00
auto & Dl_indices = LevelSharedDestructibleLightState . Dl_indices ;
2018-06-06 04:53:45 +00:00
range_for ( const auto & & i , Dl_indices . vcptr )
dl_index_write ( i , SaveFile ) ;
2006-03-20 17:12:09 +00:00
delta_light_offset = PHYSFS_tell ( SaveFile ) ;
2018-12-30 00:43:58 +00:00
auto & Delta_lights = LevelSharedDestructibleLightState . Delta_lights ;
2016-02-12 04:02:28 +00:00
range_for ( auto & i , partial_const_range ( Delta_lights , num_delta_lights ) )
2014-11-23 04:36:59 +00:00
delta_light_write ( & i , SaveFile ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//============= SAVE OFFSETS ===============
end_offset = PHYSFS_tell ( SaveFile ) ;
// Update the offset fields
# define WRITE_OFFSET(o, n) do { PHYSFS_seek(SaveFile, offset_offset); PHYSFS_writeSLE32(SaveFile, o ## _offset); offset_offset += sizeof(int)*n; } while (0)
WRITE_OFFSET ( player , 2 ) ;
WRITE_OFFSET ( object , 3 ) ;
WRITE_OFFSET ( walls , 3 ) ;
WRITE_OFFSET ( doors , 3 ) ;
WRITE_OFFSET ( triggers , 6 ) ;
WRITE_OFFSET ( control , 3 ) ;
WRITE_OFFSET ( matcen , 3 ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( game_top_fileinfo_version > = 29 )
{
WRITE_OFFSET ( dl_indices , 3 ) ;
WRITE_OFFSET ( delta_light , 0 ) ;
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
// Go back to end of data
PHYSFS_seek ( SaveFile , end_offset ) ;
return 0 ;
}
// -----------------------------------------------------------------------------
// Save game
2018-12-30 00:43:57 +00:00
static int save_level_sub (
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:58 +00:00
const d_level_shared_destructible_light_state & LevelSharedDestructibleLightState ,
2018-12-30 00:43:57 +00:00
# endif
fvmobjptridx & vmobjptridx , const char * const filename )
2006-03-20 17:12:09 +00:00
{
2020-05-17 23:35:25 +00:00
auto & LevelSharedVertexState = LevelSharedSegmentState . get_vertex_state ( ) ;
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
2020-05-17 23:35:25 +00:00
auto & Vertices = LevelSharedVertexState . get_vertices ( ) ;
2019-03-03 00:31:08 +00:00
auto & vmobjptr = Objects . vmptr ;
2006-03-20 17:12:09 +00:00
char temp_filename [ PATH_MAX ] ;
int minedata_offset = 0 , gamedata_offset = 0 ;
// if ( !compiled_version )
{
write_game_text_file ( filename ) ;
if ( Errors_in_mine ) {
if ( is_real_level ( filename ) ) {
gr_palette_load ( gr_palette ) ;
2020-12-19 16:13:26 +00:00
if ( nm_messagebox ( menu_title { nullptr } , 2 , " Cancel Save " , " Save " , " Warning: %i errors in this mine! \n " , Errors_in_mine ) ! = 1 ) {
2006-03-20 17:12:09 +00:00
return 1 ;
}
2008-04-06 20:23:28 +00:00
}
2006-03-20 17:12:09 +00:00
}
// change_filename_extension(temp_filename,filename,".LVL");
}
// else
{
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-08-27 02:20:05 +00:00
if ( Gamesave_current_version > 3 )
2013-03-17 22:18:42 +00:00
change_filename_extension ( temp_filename , filename , " . " D2X_LEVEL_FILE_EXTENSION ) ;
2013-08-27 02:20:05 +00:00
else
2013-03-03 01:03:33 +00:00
# endif
2013-08-27 02:20:05 +00:00
change_filename_extension ( temp_filename , filename , " . " D1X_LEVEL_FILE_EXTENSION ) ;
2006-03-20 17:12:09 +00:00
}
2021-07-25 23:00:56 +00:00
auto & & [ SaveFile , physfserr ] = PHYSFSX_openWriteBuffered ( temp_filename ) ;
2006-03-20 17:12:09 +00:00
if ( ! SaveFile )
{
gr_palette_load ( gr_palette ) ;
2021-07-25 23:00:56 +00:00
nm_messagebox ( menu_title { nullptr } , 1 , TXT_OK , " ERROR: Cannot write to '%s'. \n %s " , temp_filename , PHYSFS_getErrorByCode ( physfserr ) ) ;
2006-03-20 17:12:09 +00:00
return 1 ;
}
if ( Current_level_name [ 0 ] = = 0 )
2014-12-22 04:35:47 +00:00
strcpy ( Current_level_name . next ( ) . data ( ) , " Untitled " ) ;
2006-03-20 17:12:09 +00:00
clear_transient_objects ( 1 ) ; //1 means clear proximity bombs
compress_objects ( ) ; //after this, Highest_object_index == num objects
//make sure player is in a segment
2014-12-23 04:20:27 +00:00
{
2017-08-13 20:38:32 +00:00
const auto & & plr = vmobjptridx ( vcplayerptr ( 0u ) - > objnum ) ;
2018-10-08 03:58:48 +00:00
if ( update_object_seg ( vmobjptr , LevelSharedSegmentState , LevelUniqueSegmentState , plr ) = = 0 )
{
2014-12-23 04:20:27 +00:00
if ( plr - > segnum > Highest_segment_index )
plr - > segnum = segment_first ;
2018-12-30 00:43:57 +00:00
auto & vcvertptr = Vertices . vcptr ;
2018-03-12 03:43:47 +00:00
compute_segment_center ( vcvertptr , plr - > pos , vcsegptr ( plr - > segnum ) ) ;
2014-12-23 04:20:27 +00:00
}
2006-03-20 17:12:09 +00:00
}
fix_object_segs ( ) ;
//Write the header
PHYSFS_writeSLE32 ( SaveFile , MAKE_SIG ( ' P ' , ' L ' , ' V ' , ' L ' ) ) ;
PHYSFS_writeSLE32 ( SaveFile , Gamesave_current_version ) ;
//save placeholders
PHYSFS_writeSLE32 ( SaveFile , minedata_offset ) ;
PHYSFS_writeSLE32 ( SaveFile , gamedata_offset ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
int hostagetext_offset = 0 ;
PHYSFS_writeSLE32 ( SaveFile , hostagetext_offset ) ;
# endif
2006-03-20 17:12:09 +00:00
//Now write the damn data
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version > = 8 )
{
//write the version 8 data (to make file unreadable by 1.0 & 1.1)
2010-12-22 09:48:00 +00:00
PHYSFS_writeSLE32 ( SaveFile , GameTime64 ) ;
2012-05-14 17:06:28 +00:00
PHYSFS_writeSLE16 ( SaveFile , d_tick_count ) ;
2006-03-20 17:12:09 +00:00
PHYSFSX_writeU8 ( SaveFile , FrameTime ) ;
}
if ( Gamesave_current_version < 5 )
PHYSFS_writeSLE32 ( SaveFile , - 1 ) ; //was hostagetext_offset
// Write the palette file name
if ( Gamesave_current_version > 1 )
2014-12-20 04:36:10 +00:00
PHYSFSX_printf ( SaveFile , " %s \n " , static_cast < const char * > ( Current_level_palette ) ) ;
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version > = 3 )
2019-08-15 01:34:22 +00:00
PHYSFS_writeSLE32 ( SaveFile , LevelSharedControlCenterState . Base_control_center_explosion_time ) ;
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version > = 4 )
2019-08-15 01:34:22 +00:00
PHYSFS_writeSLE32 ( SaveFile , LevelSharedControlCenterState . Reactor_strength ) ;
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version > = 7 )
{
2018-03-31 21:53:01 +00:00
const auto Num_flickering_lights = Flickering_light_state . Num_flickering_lights ;
2006-03-20 17:12:09 +00:00
PHYSFS_writeSLE32 ( SaveFile , Num_flickering_lights ) ;
2018-03-31 21:53:01 +00:00
range_for ( auto & i , partial_const_range ( Flickering_light_state . Flickering_lights , Num_flickering_lights ) )
2018-03-27 03:49:34 +00:00
flickering_light_write ( i , SaveFile ) ;
2006-03-20 17:12:09 +00:00
}
if ( Gamesave_current_version > = 6 )
{
2019-08-06 02:59:41 +00:00
PHYSFS_writeSLE32 ( SaveFile , LevelSharedSegmentState . Secret_return_segment ) ;
2019-08-06 02:59:41 +00:00
auto & Secret_return_orient = LevelSharedSegmentState . Secret_return_orient ;
2014-10-26 22:08:58 +00:00
PHYSFSX_writeVector ( SaveFile , Secret_return_orient . rvec ) ;
PHYSFSX_writeVector ( SaveFile , Secret_return_orient . fvec ) ;
PHYSFSX_writeVector ( SaveFile , Secret_return_orient . uvec ) ;
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
minedata_offset = PHYSFS_tell ( SaveFile ) ;
save_mine_data_compiled ( SaveFile ) ;
gamedata_offset = PHYSFS_tell ( SaveFile ) ;
2018-12-30 00:43:57 +00:00
save_game_data (
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:58 +00:00
LevelSharedDestructibleLightState ,
2018-12-30 00:43:57 +00:00
# endif
SaveFile ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
hostagetext_offset = PHYSFS_tell ( SaveFile ) ;
# endif
2006-03-20 17:12:09 +00:00
PHYSFS_seek ( SaveFile , sizeof ( int ) + sizeof ( Gamesave_current_version ) ) ;
PHYSFS_writeSLE32 ( SaveFile , minedata_offset ) ;
PHYSFS_writeSLE32 ( SaveFile , gamedata_offset ) ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
PHYSFS_writeSLE32 ( SaveFile , hostagetext_offset ) ;
# elif defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
if ( Gamesave_current_version < 5 )
PHYSFS_writeSLE32 ( SaveFile , PHYSFS_fileLength ( SaveFile ) ) ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
//==================== CLOSE THE FILE =============================
// if ( !compiled_version )
{
2012-03-19 06:09:26 +00:00
if ( EditorWindow )
2014-12-20 04:36:10 +00:00
editor_status_fmt ( " Saved mine %s, \" %s \" " , filename , static_cast < const char * > ( Current_level_name ) ) ;
2006-03-20 17:12:09 +00:00
}
return 0 ;
}
2020-12-26 21:17:29 +00:00
}
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:57 +00:00
int save_level (
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:58 +00:00
const d_level_shared_destructible_light_state & LevelSharedDestructibleLightState ,
2018-12-30 00:43:57 +00:00
# endif
const char * filename )
2006-03-20 17:12:09 +00:00
{
2019-03-03 00:31:08 +00:00
auto & Objects = LevelUniqueObjectState . Objects ;
auto & vmobjptridx = Objects . vmptridx ;
2006-03-20 17:12:09 +00:00
int r1 ;
// Save compiled version...
2018-12-30 00:43:57 +00:00
r1 = save_level_sub (
# if defined(DXX_BUILD_DESCENT_II)
2018-12-30 00:43:58 +00:00
LevelSharedDestructibleLightState ,
2018-12-30 00:43:57 +00:00
# endif
vmobjptridx , filename ) ;
2006-03-20 17:12:09 +00:00
return r1 ;
}
2018-12-30 00:43:57 +00:00
}
2006-03-20 17:12:09 +00:00
# endif //EDITOR