2006-03-20 16:43:15 +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
2009-08-22 07:21:19 +00:00
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE .
2006-03-20 16:43:15 +00:00
COPYRIGHT 1993 - 1998 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
2008-04-06 20:23:28 +00:00
2006-03-20 16:43:15 +00:00
/*
2008-04-06 20:23:28 +00:00
*
2006-03-20 16:43:15 +00:00
* Functions to save / restore game state .
2008-04-06 20:23:28 +00:00
*
2006-03-20 16:43:15 +00:00
*/
# include <stdio.h>
# include <stdlib.h>
# include <math.h>
# include <string.h>
2009-08-22 07:21:19 +00:00
# include "pstypes.h"
2006-03-20 16:43:15 +00:00
# include "inferno.h"
# include "segment.h"
# include "textures.h"
# include "wall.h"
# include "object.h"
# include "gamemine.h"
# include "error.h"
2009-08-22 07:21:19 +00:00
# include "gamefont.h"
2006-03-20 16:43:15 +00:00
# include "gameseg.h"
# include "switch.h"
# include "game.h"
# include "newmenu.h"
2006-09-04 22:22:54 +00:00
# include "cfile.h"
2006-03-20 16:43:15 +00:00
# include "fuelcen.h"
# include "hash.h"
# include "key.h"
# include "piggy.h"
# include "player.h"
# include "cntrlcen.h"
# include "morph.h"
# include "weapon.h"
# include "render.h"
# include "gameseq.h"
# include "gauges.h"
# include "newdemo.h"
# include "automap.h"
# include "piggy.h"
# include "paging.h"
# include "titles.h"
# include "text.h"
# include "mission.h"
# include "pcx.h"
# include "u_mem.h"
# include "args.h"
2009-08-22 07:21:19 +00:00
# include "ai.h"
# include "state.h"
2009-03-20 12:10:38 +00:00
# include "multi.h"
2009-08-22 07:21:19 +00:00
# include "gr.h"
2009-09-11 05:15:53 +00:00
# ifdef OGL
# include "ogl_init.h"
2006-03-20 16:43:15 +00:00
# endif
2008-01-23 17:25:09 +00:00
# include "physfsx.h"
2006-03-20 16:43:15 +00:00
# define STATE_VERSION 7
# define STATE_COMPATIBLE_VERSION 6
// 0 - Put DGSS (Descent Game State Save) id at tof.
// 1 - Added Difficulty level save
// 2 - Added Cheats_enabled flag
// 3 - Added between levels save.
// 4 - Added mission support
// 5 - Mike changed ai and object structure.
// 6 - Added buggin' cheat save
// 7 - Added other cheat saves and game_id.
# define NUM_SAVES 10
# define THUMBNAIL_W 100
# define THUMBNAIL_H 50
# define DESC_LENGTH 20
extern int Do_appearance_effect ;
extern int Laser_rapid_fire , Ugly_robot_cheat , Ugly_robot_texture ;
extern int Physics_cheat_flag ;
2009-08-22 07:21:19 +00:00
extern int Lunacy ;
2006-03-20 16:43:15 +00:00
extern void do_lunacy_on ( void ) ;
extern void do_lunacy_off ( void ) ;
int state_save_all_sub ( char * filename , char * desc , int between_levels ) ;
2007-10-31 00:49:24 +00:00
int state_restore_all_sub ( char * filename ) ;
2006-03-20 16:43:15 +00:00
int sc_last_item = 0 ;
char dgss_id [ 4 ] = " DGSS " ;
uint state_game_id ;
2006-08-13 16:23:43 +00:00
2010-12-22 00:17:49 +00:00
// Following functions convert object to object_rw and back to be written to/read from Savegames. Mostly object differs to object_rw in terms of timer values (fix/fix64). as we reset GameTime64 for writing so it can fit into fix it's not necessary to increment savegame version. But if we once store something else into object which might be useful after restoring, it might be handy to increment Savegame version and actually store these new infos.
// turn object to object_rw to be saved to Savegame.
void state_object_to_object_rw ( object * obj , object_rw * obj_rw )
{
obj_rw - > signature = obj - > signature ;
obj_rw - > type = obj - > type ;
obj_rw - > id = obj - > id ;
obj_rw - > next = obj - > next ;
obj_rw - > prev = obj - > prev ;
obj_rw - > control_type = obj - > control_type ;
obj_rw - > movement_type = obj - > movement_type ;
obj_rw - > render_type = obj - > render_type ;
obj_rw - > flags = obj - > flags ;
obj_rw - > segnum = obj - > segnum ;
obj_rw - > attached_obj = obj - > attached_obj ;
obj_rw - > pos . x = obj - > pos . x ;
obj_rw - > pos . y = obj - > pos . y ;
obj_rw - > pos . z = obj - > pos . z ;
obj_rw - > orient . rvec . x = obj - > orient . rvec . x ;
obj_rw - > orient . rvec . y = obj - > orient . rvec . y ;
obj_rw - > orient . rvec . z = obj - > orient . rvec . z ;
obj_rw - > orient . fvec . x = obj - > orient . fvec . x ;
obj_rw - > orient . fvec . y = obj - > orient . fvec . y ;
obj_rw - > orient . fvec . z = obj - > orient . fvec . z ;
obj_rw - > orient . uvec . x = obj - > orient . uvec . x ;
obj_rw - > orient . uvec . y = obj - > orient . uvec . y ;
obj_rw - > orient . uvec . z = obj - > orient . uvec . z ;
obj_rw - > size = obj - > size ;
obj_rw - > shields = obj - > shields ;
obj_rw - > last_pos . x = obj - > last_pos . x ;
obj_rw - > last_pos . y = obj - > last_pos . y ;
obj_rw - > last_pos . z = obj - > last_pos . z ;
obj_rw - > contains_type = obj - > contains_type ;
obj_rw - > contains_id = obj - > contains_id ;
obj_rw - > contains_count = obj - > contains_count ;
obj_rw - > matcen_creator = obj - > matcen_creator ;
obj_rw - > lifeleft = obj - > lifeleft ;
switch ( obj_rw - > movement_type )
{
case MT_PHYSICS :
obj_rw - > mtype . phys_info . velocity . x = obj - > mtype . phys_info . velocity . x ;
obj_rw - > mtype . phys_info . velocity . y = obj - > mtype . phys_info . velocity . y ;
obj_rw - > mtype . phys_info . velocity . z = obj - > mtype . phys_info . velocity . z ;
obj_rw - > mtype . phys_info . thrust . x = obj - > mtype . phys_info . thrust . x ;
obj_rw - > mtype . phys_info . thrust . y = obj - > mtype . phys_info . thrust . y ;
obj_rw - > mtype . phys_info . thrust . z = obj - > mtype . phys_info . thrust . z ;
obj_rw - > mtype . phys_info . mass = obj - > mtype . phys_info . mass ;
obj_rw - > mtype . phys_info . drag = obj - > mtype . phys_info . drag ;
obj_rw - > mtype . phys_info . brakes = obj - > mtype . phys_info . brakes ;
obj_rw - > mtype . phys_info . rotvel . x = obj - > mtype . phys_info . rotvel . x ;
obj_rw - > mtype . phys_info . rotvel . y = obj - > mtype . phys_info . rotvel . y ;
obj_rw - > mtype . phys_info . rotvel . z = obj - > mtype . phys_info . rotvel . z ;
obj_rw - > mtype . phys_info . rotthrust . x = obj - > mtype . phys_info . rotthrust . x ;
obj_rw - > mtype . phys_info . rotthrust . y = obj - > mtype . phys_info . rotthrust . y ;
obj_rw - > mtype . phys_info . rotthrust . z = obj - > mtype . phys_info . rotthrust . z ;
obj_rw - > mtype . phys_info . turnroll = obj - > mtype . phys_info . turnroll ;
obj_rw - > mtype . phys_info . flags = obj - > mtype . phys_info . flags ;
break ;
case MT_SPINNING :
obj_rw - > mtype . spin_rate . x = obj - > mtype . spin_rate . x ;
obj_rw - > mtype . spin_rate . y = obj - > mtype . spin_rate . y ;
obj_rw - > mtype . spin_rate . z = obj - > mtype . spin_rate . z ;
break ;
}
switch ( obj_rw - > control_type )
{
case CT_WEAPON :
obj_rw - > ctype . laser_info . parent_type = obj - > ctype . laser_info . parent_type ;
obj_rw - > ctype . laser_info . parent_num = obj - > ctype . laser_info . parent_num ;
obj_rw - > ctype . laser_info . parent_signature = obj - > ctype . laser_info . parent_signature ;
if ( obj - > ctype . laser_info . creation_time - GameTime64 < F1_0 * ( - 18000 ) )
obj_rw - > ctype . laser_info . creation_time = F1_0 * ( - 18000 ) ;
else
obj_rw - > ctype . laser_info . creation_time = obj - > ctype . laser_info . creation_time - GameTime64 ;
obj_rw - > ctype . laser_info . last_hitobj = obj - > ctype . laser_info . last_hitobj ;
obj_rw - > ctype . laser_info . track_goal = obj - > ctype . laser_info . track_goal ;
obj_rw - > ctype . laser_info . multiplier = obj - > ctype . laser_info . multiplier ;
break ;
case CT_EXPLOSION :
obj_rw - > ctype . expl_info . spawn_time = obj - > ctype . expl_info . spawn_time ;
obj_rw - > ctype . expl_info . delete_time = obj - > ctype . expl_info . delete_time ;
obj_rw - > ctype . expl_info . delete_objnum = obj - > ctype . expl_info . delete_objnum ;
obj_rw - > ctype . expl_info . attach_parent = obj - > ctype . expl_info . attach_parent ;
obj_rw - > ctype . expl_info . prev_attach = obj - > ctype . expl_info . prev_attach ;
obj_rw - > ctype . expl_info . next_attach = obj - > ctype . expl_info . next_attach ;
break ;
case CT_AI :
{
int i ;
obj_rw - > ctype . ai_info . behavior = obj - > ctype . ai_info . behavior ;
for ( i = 0 ; i < MAX_AI_FLAGS ; i + + )
obj_rw - > ctype . ai_info . flags [ i ] = obj - > ctype . ai_info . flags [ i ] ;
obj_rw - > ctype . ai_info . hide_segment = obj - > ctype . ai_info . hide_segment ;
obj_rw - > ctype . ai_info . hide_index = obj - > ctype . ai_info . hide_index ;
obj_rw - > ctype . ai_info . path_length = obj - > ctype . ai_info . path_length ;
obj_rw - > ctype . ai_info . cur_path_index = obj - > ctype . ai_info . cur_path_index ;
obj_rw - > ctype . ai_info . follow_path_start_seg = obj - > ctype . ai_info . follow_path_start_seg ;
obj_rw - > ctype . ai_info . follow_path_end_seg = obj - > ctype . ai_info . follow_path_end_seg ;
obj_rw - > ctype . ai_info . danger_laser_signature = obj - > ctype . ai_info . danger_laser_signature ;
obj_rw - > ctype . ai_info . danger_laser_num = obj - > ctype . ai_info . danger_laser_num ;
break ;
}
case CT_LIGHT :
obj_rw - > ctype . light_info . intensity = obj - > ctype . light_info . intensity ;
break ;
case CT_POWERUP :
obj_rw - > ctype . powerup_info . count = obj - > ctype . powerup_info . count ;
break ;
}
switch ( obj_rw - > render_type )
{
case RT_MORPH :
case RT_POLYOBJ :
case RT_NONE : // HACK below
{
int i ;
if ( obj - > render_type = = RT_NONE & & obj - > type ! = OBJ_GHOST ) // HACK: when a player is dead or not connected yet, clients still expect to get polyobj data - even if render_type == RT_NONE at this time. Here it's not important, but it might be for Multiplayer Savegames.
break ;
obj_rw - > rtype . pobj_info . model_num = obj - > rtype . pobj_info . model_num ;
for ( i = 0 ; i < MAX_SUBMODELS ; i + + )
{
obj_rw - > rtype . pobj_info . anim_angles [ i ] . p = obj - > rtype . pobj_info . anim_angles [ i ] . p ;
obj_rw - > rtype . pobj_info . anim_angles [ i ] . b = obj - > rtype . pobj_info . anim_angles [ i ] . b ;
obj_rw - > rtype . pobj_info . anim_angles [ i ] . h = obj - > rtype . pobj_info . anim_angles [ i ] . h ;
}
obj_rw - > rtype . pobj_info . subobj_flags = obj - > rtype . pobj_info . subobj_flags ;
obj_rw - > rtype . pobj_info . tmap_override = obj - > rtype . pobj_info . tmap_override ;
obj_rw - > rtype . pobj_info . alt_textures = obj - > rtype . pobj_info . alt_textures ;
break ;
}
case RT_WEAPON_VCLIP :
case RT_HOSTAGE :
case RT_POWERUP :
case RT_FIREBALL :
obj_rw - > rtype . vclip_info . vclip_num = obj - > rtype . vclip_info . vclip_num ;
obj_rw - > rtype . vclip_info . frametime = obj - > rtype . vclip_info . frametime ;
obj_rw - > rtype . vclip_info . framenum = obj - > rtype . vclip_info . framenum ;
break ;
case RT_LASER :
break ;
}
}
// turn object_rw to object after reading from Savegame
void state_object_rw_to_object ( object_rw * obj_rw , object * obj )
{
obj - > signature = obj_rw - > signature ;
obj - > type = obj_rw - > type ;
obj - > id = obj_rw - > id ;
obj - > next = obj_rw - > next ;
obj - > prev = obj_rw - > prev ;
obj - > control_type = obj_rw - > control_type ;
obj - > movement_type = obj_rw - > movement_type ;
obj - > render_type = obj_rw - > render_type ;
obj - > flags = obj_rw - > flags ;
obj - > segnum = obj_rw - > segnum ;
obj - > attached_obj = obj_rw - > attached_obj ;
obj - > pos . x = obj_rw - > pos . x ;
obj - > pos . y = obj_rw - > pos . y ;
obj - > pos . z = obj_rw - > pos . z ;
obj - > orient . rvec . x = obj_rw - > orient . rvec . x ;
obj - > orient . rvec . y = obj_rw - > orient . rvec . y ;
obj - > orient . rvec . z = obj_rw - > orient . rvec . z ;
obj - > orient . fvec . x = obj_rw - > orient . fvec . x ;
obj - > orient . fvec . y = obj_rw - > orient . fvec . y ;
obj - > orient . fvec . z = obj_rw - > orient . fvec . z ;
obj - > orient . uvec . x = obj_rw - > orient . uvec . x ;
obj - > orient . uvec . y = obj_rw - > orient . uvec . y ;
obj - > orient . uvec . z = obj_rw - > orient . uvec . z ;
obj - > size = obj_rw - > size ;
obj - > shields = obj_rw - > shields ;
obj - > last_pos . x = obj_rw - > last_pos . x ;
obj - > last_pos . y = obj_rw - > last_pos . y ;
obj - > last_pos . z = obj_rw - > last_pos . z ;
obj - > contains_type = obj_rw - > contains_type ;
obj - > contains_id = obj_rw - > contains_id ;
obj - > contains_count = obj_rw - > contains_count ;
obj - > matcen_creator = obj_rw - > matcen_creator ;
obj - > lifeleft = obj_rw - > lifeleft ;
switch ( obj - > movement_type )
{
case MT_PHYSICS :
obj - > mtype . phys_info . velocity . x = obj_rw - > mtype . phys_info . velocity . x ;
obj - > mtype . phys_info . velocity . y = obj_rw - > mtype . phys_info . velocity . y ;
obj - > mtype . phys_info . velocity . z = obj_rw - > mtype . phys_info . velocity . z ;
obj - > mtype . phys_info . thrust . x = obj_rw - > mtype . phys_info . thrust . x ;
obj - > mtype . phys_info . thrust . y = obj_rw - > mtype . phys_info . thrust . y ;
obj - > mtype . phys_info . thrust . z = obj_rw - > mtype . phys_info . thrust . z ;
obj - > mtype . phys_info . mass = obj_rw - > mtype . phys_info . mass ;
obj - > mtype . phys_info . drag = obj_rw - > mtype . phys_info . drag ;
obj - > mtype . phys_info . brakes = obj_rw - > mtype . phys_info . brakes ;
obj - > mtype . phys_info . rotvel . x = obj_rw - > mtype . phys_info . rotvel . x ;
obj - > mtype . phys_info . rotvel . y = obj_rw - > mtype . phys_info . rotvel . y ;
obj - > mtype . phys_info . rotvel . z = obj_rw - > mtype . phys_info . rotvel . z ;
obj - > mtype . phys_info . rotthrust . x = obj_rw - > mtype . phys_info . rotthrust . x ;
obj - > mtype . phys_info . rotthrust . y = obj_rw - > mtype . phys_info . rotthrust . y ;
obj - > mtype . phys_info . rotthrust . z = obj_rw - > mtype . phys_info . rotthrust . z ;
obj - > mtype . phys_info . turnroll = obj_rw - > mtype . phys_info . turnroll ;
obj - > mtype . phys_info . flags = obj_rw - > mtype . phys_info . flags ;
break ;
case MT_SPINNING :
obj - > mtype . spin_rate . x = obj_rw - > mtype . spin_rate . x ;
obj - > mtype . spin_rate . y = obj_rw - > mtype . spin_rate . y ;
obj - > mtype . spin_rate . z = obj_rw - > mtype . spin_rate . z ;
break ;
}
switch ( obj - > control_type )
{
case CT_WEAPON :
obj - > ctype . laser_info . parent_type = obj_rw - > ctype . laser_info . parent_type ;
obj - > ctype . laser_info . parent_num = obj_rw - > ctype . laser_info . parent_num ;
obj - > ctype . laser_info . parent_signature = obj_rw - > ctype . laser_info . parent_signature ;
obj - > ctype . laser_info . creation_time = obj_rw - > ctype . laser_info . creation_time ;
obj - > ctype . laser_info . last_hitobj = obj_rw - > ctype . laser_info . last_hitobj ;
2010-12-22 09:41:15 +00:00
obj - > ctype . laser_info . hitobj_list [ obj - > ctype . laser_info . last_hitobj ] = 1 ; // restore most recent hitobj to hitobj_list
2010-12-22 00:17:49 +00:00
obj - > ctype . laser_info . track_goal = obj_rw - > ctype . laser_info . track_goal ;
obj - > ctype . laser_info . multiplier = obj_rw - > ctype . laser_info . multiplier ;
break ;
case CT_EXPLOSION :
obj - > ctype . expl_info . spawn_time = obj_rw - > ctype . expl_info . spawn_time ;
obj - > ctype . expl_info . delete_time = obj_rw - > ctype . expl_info . delete_time ;
obj - > ctype . expl_info . delete_objnum = obj_rw - > ctype . expl_info . delete_objnum ;
obj - > ctype . expl_info . attach_parent = obj_rw - > ctype . expl_info . attach_parent ;
obj - > ctype . expl_info . prev_attach = obj_rw - > ctype . expl_info . prev_attach ;
obj - > ctype . expl_info . next_attach = obj_rw - > ctype . expl_info . next_attach ;
break ;
case CT_AI :
{
int i ;
obj - > ctype . ai_info . behavior = obj_rw - > ctype . ai_info . behavior ;
for ( i = 0 ; i < MAX_AI_FLAGS ; i + + )
obj - > ctype . ai_info . flags [ i ] = obj_rw - > ctype . ai_info . flags [ i ] ;
obj - > ctype . ai_info . hide_segment = obj_rw - > ctype . ai_info . hide_segment ;
obj - > ctype . ai_info . hide_index = obj_rw - > ctype . ai_info . hide_index ;
obj - > ctype . ai_info . path_length = obj_rw - > ctype . ai_info . path_length ;
obj - > ctype . ai_info . cur_path_index = obj_rw - > ctype . ai_info . cur_path_index ;
obj - > ctype . ai_info . follow_path_start_seg = obj_rw - > ctype . ai_info . follow_path_start_seg ;
obj - > ctype . ai_info . follow_path_end_seg = obj_rw - > ctype . ai_info . follow_path_end_seg ;
obj - > ctype . ai_info . danger_laser_signature = obj_rw - > ctype . ai_info . danger_laser_signature ;
obj - > ctype . ai_info . danger_laser_num = obj_rw - > ctype . ai_info . danger_laser_num ;
break ;
}
case CT_LIGHT :
obj - > ctype . light_info . intensity = obj_rw - > ctype . light_info . intensity ;
break ;
case CT_POWERUP :
obj - > ctype . powerup_info . count = obj_rw - > ctype . powerup_info . count ;
break ;
}
switch ( obj - > render_type )
{
case RT_MORPH :
case RT_POLYOBJ :
case RT_NONE : // HACK below
{
int i ;
if ( obj - > render_type = = RT_NONE & & obj - > type ! = OBJ_GHOST ) // HACK: when a player is dead or not connected yet, clients still expect to get polyobj data - even if render_type == RT_NONE at this time. Here it's not important, but it might be for Multiplayer Savegames.
break ;
obj - > rtype . pobj_info . model_num = obj_rw - > rtype . pobj_info . model_num ;
for ( i = 0 ; i < MAX_SUBMODELS ; i + + )
{
obj - > rtype . pobj_info . anim_angles [ i ] . p = obj_rw - > rtype . pobj_info . anim_angles [ i ] . p ;
obj - > rtype . pobj_info . anim_angles [ i ] . b = obj_rw - > rtype . pobj_info . anim_angles [ i ] . b ;
obj - > rtype . pobj_info . anim_angles [ i ] . h = obj_rw - > rtype . pobj_info . anim_angles [ i ] . h ;
}
obj - > rtype . pobj_info . subobj_flags = obj_rw - > rtype . pobj_info . subobj_flags ;
obj - > rtype . pobj_info . tmap_override = obj_rw - > rtype . pobj_info . tmap_override ;
obj - > rtype . pobj_info . alt_textures = obj_rw - > rtype . pobj_info . alt_textures ;
break ;
}
case RT_WEAPON_VCLIP :
case RT_HOSTAGE :
case RT_POWERUP :
case RT_FIREBALL :
obj - > rtype . vclip_info . vclip_num = obj_rw - > rtype . vclip_info . vclip_num ;
obj - > rtype . vclip_info . frametime = obj_rw - > rtype . vclip_info . frametime ;
obj - > rtype . vclip_info . framenum = obj_rw - > rtype . vclip_info . framenum ;
break ;
case RT_LASER :
break ;
}
}
// Following functions convert player to player_rw and back to be written to/read from Savegames. player only differ to player_rw in terms of timer values (fix/fix64). as we reset GameTime64 for writing so it can fit into fix it's not necessary to increment savegame version. But if we once store something else into object which might be useful after restoring, it might be handy to increment Savegame version and actually store these new infos.
// turn player to player_rw to be saved to Savegame.
void state_player_to_player_rw ( player * pl , player_rw * pl_rw )
{
int i = 0 ;
memcpy ( pl_rw - > callsign , pl - > callsign , CALLSIGN_LEN + 1 ) ;
memcpy ( pl_rw - > net_address , pl - > net_address , 6 ) ;
pl_rw - > connected = pl - > connected ;
pl_rw - > objnum = pl - > objnum ;
pl_rw - > n_packets_got = pl - > n_packets_got ;
pl_rw - > n_packets_sent = pl - > n_packets_sent ;
pl_rw - > flags = pl - > flags ;
pl_rw - > energy = pl - > energy ;
pl_rw - > shields = pl - > shields ;
pl_rw - > lives = pl - > lives ;
pl_rw - > level = pl - > level ;
pl_rw - > laser_level = pl - > laser_level ;
pl_rw - > starting_level = pl - > starting_level ;
pl_rw - > killer_objnum = pl - > killer_objnum ;
pl_rw - > primary_weapon_flags = pl - > primary_weapon_flags ;
pl_rw - > secondary_weapon_flags = pl - > secondary_weapon_flags ;
for ( i = 0 ; i < MAX_PRIMARY_WEAPONS ; i + + )
pl_rw - > primary_ammo [ i ] = pl - > primary_ammo [ i ] ;
for ( i = 0 ; i < MAX_SECONDARY_WEAPONS ; i + + )
pl_rw - > secondary_ammo [ i ] = pl - > secondary_ammo [ i ] ;
pl_rw - > last_score = pl - > last_score ;
pl_rw - > score = pl - > score ;
pl_rw - > time_level = pl - > time_level ;
pl_rw - > time_total = pl - > time_total ;
if ( pl - > cloak_time - GameTime64 < F1_0 * ( - 18000 ) )
pl_rw - > cloak_time = F1_0 * ( - 18000 ) ;
else
pl_rw - > cloak_time = pl - > cloak_time - GameTime64 ;
if ( pl - > invulnerable_time - GameTime64 < F1_0 * ( - 18000 ) )
pl_rw - > invulnerable_time = F1_0 * ( - 18000 ) ;
else
pl_rw - > invulnerable_time = pl - > invulnerable_time - GameTime64 ;
pl_rw - > net_killed_total = pl - > net_killed_total ;
pl_rw - > net_kills_total = pl - > net_kills_total ;
pl_rw - > num_kills_level = pl - > num_kills_level ;
pl_rw - > num_kills_total = pl - > num_kills_total ;
pl_rw - > num_robots_level = pl - > num_robots_level ;
pl_rw - > num_robots_total = pl - > num_robots_total ;
pl_rw - > hostages_rescued_total = pl - > hostages_rescued_total ;
pl_rw - > hostages_total = pl - > hostages_total ;
pl_rw - > hostages_on_board = pl - > hostages_on_board ;
pl_rw - > hostages_level = pl - > hostages_level ;
pl_rw - > homing_object_dist = pl - > homing_object_dist ;
pl_rw - > hours_level = pl - > hours_level ;
pl_rw - > hours_total = pl - > hours_total ;
}
// turn player_rw to player after reading from Savegame
void state_player_rw_to_player ( player_rw * pl_rw , player * pl )
{
int i = 0 ;
memcpy ( pl - > callsign , pl_rw - > callsign , CALLSIGN_LEN + 1 ) ;
memcpy ( pl - > net_address , pl_rw - > net_address , 6 ) ;
pl - > connected = pl_rw - > connected ;
pl - > objnum = pl_rw - > objnum ;
pl - > n_packets_got = pl_rw - > n_packets_got ;
pl - > n_packets_sent = pl_rw - > n_packets_sent ;
pl - > flags = pl_rw - > flags ;
pl - > energy = pl_rw - > energy ;
pl - > shields = pl_rw - > shields ;
pl - > lives = pl_rw - > lives ;
pl - > level = pl_rw - > level ;
pl - > laser_level = pl_rw - > laser_level ;
pl - > starting_level = pl_rw - > starting_level ;
pl - > killer_objnum = pl_rw - > killer_objnum ;
pl - > primary_weapon_flags = pl_rw - > primary_weapon_flags ;
pl - > secondary_weapon_flags = pl_rw - > secondary_weapon_flags ;
for ( i = 0 ; i < MAX_PRIMARY_WEAPONS ; i + + )
pl - > primary_ammo [ i ] = pl_rw - > primary_ammo [ i ] ;
for ( i = 0 ; i < MAX_SECONDARY_WEAPONS ; i + + )
pl - > secondary_ammo [ i ] = pl_rw - > secondary_ammo [ i ] ;
pl - > last_score = pl_rw - > last_score ;
pl - > score = pl_rw - > score ;
pl - > time_level = pl_rw - > time_level ;
pl - > time_total = pl_rw - > time_total ;
pl - > cloak_time = pl_rw - > cloak_time ;
pl - > invulnerable_time = pl_rw - > invulnerable_time ;
pl - > net_killed_total = pl_rw - > net_killed_total ;
pl - > net_kills_total = pl_rw - > net_kills_total ;
pl - > num_kills_level = pl_rw - > num_kills_level ;
pl - > num_kills_total = pl_rw - > num_kills_total ;
pl - > num_robots_level = pl_rw - > num_robots_level ;
pl - > num_robots_total = pl_rw - > num_robots_total ;
pl - > hostages_rescued_total = pl_rw - > hostages_rescued_total ;
pl - > hostages_total = pl_rw - > hostages_total ;
pl - > hostages_on_board = pl_rw - > hostages_on_board ;
pl - > hostages_level = pl_rw - > hostages_level ;
pl - > homing_object_dist = pl_rw - > homing_object_dist ;
pl - > hours_level = pl_rw - > hours_level ;
pl - > hours_total = pl_rw - > hours_total ;
}
2009-08-22 07:21:19 +00:00
//-------------------------------------------------------------------
2010-01-07 14:49:07 +00:00
int state_callback ( newmenu * menu , d_event * event , grs_bitmap * sc_bmp [ ] )
2006-03-20 16:43:15 +00:00
{
2010-01-07 14:49:07 +00:00
newmenu_item * items = newmenu_get_items ( menu ) ;
int citem = newmenu_get_citem ( menu ) ;
2006-03-20 16:43:15 +00:00
2010-01-30 03:24:19 +00:00
if ( ( citem > 0 ) & & ( event - > type = = EVENT_NEWMENU_DRAW ) )
2008-02-24 14:41:27 +00:00
{
if ( sc_bmp [ citem - 1 ] ) {
grs_canvas * save_canv = grd_curcanv ;
grs_canvas * temp_canv = gr_create_canvas ( THUMBNAIL_W * 2 , ( THUMBNAIL_H * 24 / 10 ) ) ;
grs_point vertbuf [ 3 ] = { { 0 , 0 } , { 0 , 0 } , { i2f ( THUMBNAIL_W * 2 ) , i2f ( THUMBNAIL_H * 24 / 10 ) } } ;
gr_set_current_canvas ( temp_canv ) ;
2011-01-19 20:51:59 +00:00
scale_bitmap ( sc_bmp [ citem - 1 ] , vertbuf , 0 ) ;
2008-02-24 14:41:27 +00:00
gr_set_current_canvas ( save_canv ) ;
2006-08-13 15:52:49 +00:00
# ifndef OGL
2008-02-24 14:41:27 +00:00
gr_bitmap ( ( grd_curcanv - > cv_bitmap . bm_w - THUMBNAIL_W * 2 ) / 2 , items [ 0 ] . y - 3 , & temp_canv - > cv_bitmap ) ;
2006-08-13 15:52:49 +00:00
# else
2010-09-19 11:53:39 +00:00
ogl_ubitmapm_cs ( ( grd_curcanv - > cv_bitmap . bm_w / 2 ) - FSPACX ( THUMBNAIL_W / 2 ) , items [ 0 ] . y - FSPACY ( 3 ) , FSPACX ( THUMBNAIL_W ) , FSPACY ( THUMBNAIL_H ) , & temp_canv - > cv_bitmap , - 1 , F1_0 ) ;
2006-08-13 15:52:49 +00:00
# endif
2008-02-24 14:41:27 +00:00
gr_free_canvas ( temp_canv ) ;
2006-03-20 16:43:15 +00:00
}
2010-01-07 14:49:07 +00:00
return 1 ;
2008-02-24 14:41:27 +00:00
}
2010-01-07 14:49:07 +00:00
return 0 ;
2006-03-20 16:43:15 +00:00
}
2006-10-06 00:12:16 +00:00
#if 0
2006-03-20 16:43:15 +00:00
void rpad_string ( char * string , int max_chars )
{
int i , end_found ;
end_found = 0 ;
for ( i = 0 ; i < max_chars ; i + + ) {
if ( * string = = 0 )
end_found = 1 ;
if ( end_found )
* string = ' ' ;
string + + ;
}
* string = 0 ; // NULL terminate
}
2006-10-06 00:12:16 +00:00
# endif
2006-03-20 16:43:15 +00:00
2010-07-19 17:07:12 +00:00
static int state_default_item = 0 ;
//Since state_default_item should ALWAYS point to a valid savegame slot, we use this to check if we once already actually SAVED a game. If yes, state_quick_item will be equal state_default_item, otherwise it should be -1 on every new mission and tell us we need to select a slot for quicksave.
int state_quick_item = - 1 ;
2010-02-25 03:08:10 +00:00
2006-03-20 16:43:15 +00:00
/* Present a menu for selection of a savegame filename.
* For saving , dsc should be a pre - allocated buffer into which the new
* savegame description will be stored .
* For restoring , dsc should be NULL , in which case empty slots will not be
* selectable and savagames descriptions will not be editable .
*/
2010-02-25 03:08:10 +00:00
int state_get_savegame_filename ( char * fname , char * dsc , char * caption , int blind_save )
2006-03-20 16:43:15 +00:00
{
2008-01-23 17:25:09 +00:00
PHYSFS_file * fp ;
2006-03-20 16:43:15 +00:00
int i , choice , version , nsaves ;
newmenu_item m [ NUM_SAVES + 1 ] ;
2008-04-24 14:27:54 +00:00
char filename [ NUM_SAVES ] [ FILENAME_LEN + 9 ] ;
2006-03-20 16:43:15 +00:00
char desc [ NUM_SAVES ] [ DESC_LENGTH + 16 ] ;
2010-01-07 14:49:07 +00:00
grs_bitmap * sc_bmp [ NUM_SAVES ] ;
2006-03-20 16:43:15 +00:00
char id [ 5 ] ;
int valid ;
nsaves = 0 ;
2006-09-04 22:22:54 +00:00
m [ 0 ] . type = NM_TYPE_TEXT ; m [ 0 ] . text = " \n \n \n \n " ;
2006-03-20 16:43:15 +00:00
for ( i = 0 ; i < NUM_SAVES ; i + + ) {
sc_bmp [ i ] = NULL ;
2007-10-31 00:49:24 +00:00
sprintf ( filename [ i ] , GameArg . SysUsePlayersDir ? " Players/%s.sg%x " : " %s.sg%x " , Players [ Player_num ] . callsign , i ) ;
2006-03-20 16:43:15 +00:00
valid = 0 ;
2008-01-23 17:25:09 +00:00
fp = PHYSFSX_openReadBuffered ( filename [ i ] ) ;
2006-03-20 16:43:15 +00:00
if ( fp ) {
//Read id
2008-01-23 17:25:09 +00:00
PHYSFS_read ( fp , id , sizeof ( char ) * 4 , 1 ) ;
2006-03-20 16:43:15 +00:00
if ( ! memcmp ( id , dgss_id , 4 ) ) {
//Read version
2008-01-23 17:25:09 +00:00
PHYSFS_read ( fp , & version , sizeof ( int ) , 1 ) ;
2009-10-05 02:51:37 +00:00
if ( ( version > = STATE_COMPATIBLE_VERSION ) | | ( SWAPINT ( version ) > = STATE_COMPATIBLE_VERSION ) ) {
2006-03-20 16:43:15 +00:00
// Read description
2008-01-23 17:25:09 +00:00
PHYSFS_read ( fp , desc [ i ] , sizeof ( char ) * DESC_LENGTH , 1 ) ;
2006-03-20 16:43:15 +00:00
//rpad_string( desc[i], DESC_LENGTH-1 );
if ( dsc = = NULL ) m [ i + 1 ] . type = NM_TYPE_MENU ;
// Read thumbnail
sc_bmp [ i ] = gr_create_bitmap ( THUMBNAIL_W , THUMBNAIL_H ) ;
2008-01-23 17:25:09 +00:00
PHYSFS_read ( fp , sc_bmp [ i ] - > bm_data , THUMBNAIL_W * THUMBNAIL_H , 1 ) ;
2006-03-20 16:43:15 +00:00
nsaves + + ;
valid = 1 ;
2006-09-04 22:22:54 +00:00
}
2006-03-20 16:43:15 +00:00
}
2008-01-23 17:25:09 +00:00
PHYSFS_close ( fp ) ;
2006-03-20 16:43:15 +00:00
}
if ( ! valid ) {
strcpy ( desc [ i ] , TXT_EMPTY ) ;
//rpad_string( desc[i], DESC_LENGTH-1 );
if ( dsc = = NULL ) m [ i + 1 ] . type = NM_TYPE_TEXT ;
}
if ( dsc ! = NULL ) {
m [ i + 1 ] . type = NM_TYPE_INPUT_MENU ;
}
m [ i + 1 ] . text_len = DESC_LENGTH - 1 ;
m [ i + 1 ] . text = desc [ i ] ;
}
if ( dsc = = NULL & & nsaves < 1 ) {
nm_messagebox ( NULL , 1 , " Ok " , " No saved games were found! " ) ;
return 0 ;
}
sc_last_item = - 1 ;
2010-02-25 03:08:10 +00:00
2010-07-19 17:07:12 +00:00
if ( blind_save & & state_quick_item < 0 )
2010-02-25 03:08:10 +00:00
blind_save = 0 ; // haven't picked a slot yet
if ( blind_save )
choice = state_default_item + 1 ;
else
2010-04-03 07:24:50 +00:00
choice = newmenu_do2 ( NULL , caption , NUM_SAVES + 1 , m , ( int ( * ) ( newmenu * , d_event * , void * ) ) state_callback , sc_bmp , state_default_item + 1 , NULL ) ;
2006-03-20 16:43:15 +00:00
for ( i = 0 ; i < NUM_SAVES ; i + + ) {
if ( sc_bmp [ i ] )
gr_free_bitmap ( sc_bmp [ i ] ) ;
}
if ( choice > 0 ) {
2009-08-22 07:21:19 +00:00
strcpy ( fname , filename [ choice - 1 ] ) ;
2006-03-20 16:43:15 +00:00
if ( dsc ! = NULL ) strcpy ( dsc , desc [ choice - 1 ] ) ;
2010-07-19 17:07:12 +00:00
state_quick_item = state_default_item = choice - 1 ;
2006-03-20 16:43:15 +00:00
return choice ;
}
return 0 ;
}
2010-02-25 03:08:10 +00:00
int state_get_save_file ( char * fname , char * dsc , int blind_save )
2006-03-20 16:43:15 +00:00
{
2010-02-25 03:08:10 +00:00
return state_get_savegame_filename ( fname , dsc , " Save Game " , blind_save ) ;
2006-03-20 16:43:15 +00:00
}
2007-10-31 00:49:24 +00:00
int state_get_restore_file ( char * fname )
2006-03-20 16:43:15 +00:00
{
2010-02-25 03:08:10 +00:00
return state_get_savegame_filename ( fname , NULL , " Select Game to Restore " , 0 ) ;
2006-03-20 16:43:15 +00:00
}
2010-12-22 00:17:49 +00:00
int state_save_old_game ( int slotnum , char * sg_name , player_rw * sg_player ,
2006-03-20 16:43:15 +00:00
int sg_difficulty_level , int sg_primary_weapon ,
int sg_secondary_weapon , int sg_next_level_num )
{
2007-06-11 09:06:14 +00:00
int i ;
2006-03-20 16:43:15 +00:00
int temp_int ;
ubyte temp_byte ;
char desc [ DESC_LENGTH + 1 ] ;
char filename [ 128 ] ;
grs_canvas * cnv ;
2008-01-23 17:25:09 +00:00
PHYSFS_file * fp ;
2007-03-22 11:32:22 +00:00
ubyte * pal ;
# ifdef OGL
2007-06-11 09:06:14 +00:00
int j ;
2007-03-22 11:32:22 +00:00
GLint gl_draw_buffer ;
# endif
2006-03-20 16:43:15 +00:00
2007-09-28 15:14:09 +00:00
sprintf ( filename , ( GameArg . SysUsePlayersDir ? " Players/%s.sg%d " : " %s.sg%d " ) , sg_player - > callsign , slotnum ) ;
2008-01-23 17:25:09 +00:00
fp = PHYSFSX_openWriteBuffered ( filename ) ;
2006-03-20 16:43:15 +00:00
if ( ! fp ) return 0 ;
//Save id
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , dgss_id , sizeof ( char ) * 4 , 1 ) ;
2006-03-20 16:43:15 +00:00
//Save version
temp_int = STATE_VERSION ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_int , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
//Save description
strncpy ( desc , sg_name , DESC_LENGTH ) ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , desc , sizeof ( char ) * DESC_LENGTH , 1 ) ;
2006-03-20 16:43:15 +00:00
// Save the current screen shot...
cnv = gr_create_canvas ( THUMBNAIL_W , THUMBNAIL_H ) ;
2007-03-22 11:32:22 +00:00
if ( cnv )
{
# ifdef OGL
ubyte * buf ;
int k ;
# endif
grs_canvas * cnv_save ;
cnv_save = grd_curcanv ;
2006-03-20 16:43:15 +00:00
gr_set_current_canvas ( cnv ) ;
2007-03-22 11:32:22 +00:00
render_frame ( 0 ) ;
# ifdef OGL
2011-01-06 11:43:55 +00:00
buf = d_malloc ( THUMBNAIL_W * THUMBNAIL_H * 4 ) ;
# ifndef OGLES
glGetIntegerv ( GL_DRAW_BUFFER , & gl_draw_buffer ) ;
glReadBuffer ( gl_draw_buffer ) ;
# endif
glReadPixels ( 0 , SHEIGHT - THUMBNAIL_H , THUMBNAIL_W , THUMBNAIL_H , GL_RGBA , GL_UNSIGNED_BYTE , buf ) ;
2007-03-22 11:32:22 +00:00
k = THUMBNAIL_H ;
for ( i = 0 ; i < THUMBNAIL_W * THUMBNAIL_H ; i + + ) {
if ( ! ( j = i % THUMBNAIL_W ) )
k - - ;
cnv - > cv_bitmap . bm_data [ THUMBNAIL_W * k + j ] =
2011-01-06 11:43:55 +00:00
gr_find_closest_color ( buf [ 4 * i ] / 4 , buf [ 4 * i + 1 ] / 4 , buf [ 4 * i + 2 ] / 4 ) ;
2006-03-20 16:43:15 +00:00
}
2008-01-23 17:25:09 +00:00
d_free ( buf ) ;
2007-03-22 11:32:22 +00:00
# endif
pal = gr_palette ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , cnv - > cv_bitmap . bm_data , THUMBNAIL_W * THUMBNAIL_H , 1 ) ;
2007-03-22 11:32:22 +00:00
gr_set_current_canvas ( cnv_save ) ;
2006-03-20 16:43:15 +00:00
gr_free_canvas ( cnv ) ;
2007-03-22 11:32:22 +00:00
}
else
{
2006-03-20 16:43:15 +00:00
ubyte color = 0 ;
for ( i = 0 ; i < THUMBNAIL_W * THUMBNAIL_H ; i + + )
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & color , sizeof ( ubyte ) , 1 ) ;
2006-03-20 16:43:15 +00:00
}
// Save the Between levels flag...
temp_int = 1 ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_int , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
// Save the mission info...
2006-10-06 00:12:16 +00:00
# ifndef SHAREWARE
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , Current_mission_filename , 9 * sizeof ( char ) , 1 ) ;
2006-10-06 00:12:16 +00:00
# else
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , " \0 \0 \0 \0 \0 \0 \0 \0 " , 9 * sizeof ( char ) , 1 ) ;
2006-10-06 00:12:16 +00:00
# endif
2006-03-20 16:43:15 +00:00
//Save level info
temp_int = sg_player - > level ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_int , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
temp_int = sg_next_level_num ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_int , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
//Save GameTime
temp_int = 0 ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_int , sizeof ( fix ) , 1 ) ;
2006-03-20 16:43:15 +00:00
//Save player info
2010-12-22 00:17:49 +00:00
PHYSFS_write ( fp , & sg_player , sizeof ( player_rw ) , 1 ) ;
2006-03-20 16:43:15 +00:00
// Save the current weapon info
temp_byte = sg_primary_weapon ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_byte , sizeof ( sbyte ) , 1 ) ;
2006-03-20 16:43:15 +00:00
temp_byte = sg_secondary_weapon ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_byte , sizeof ( sbyte ) , 1 ) ;
2006-03-20 16:43:15 +00:00
// Save the difficulty level
temp_int = sg_difficulty_level ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_int , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
// Save the Cheats_enabled
temp_int = 0 ;
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_int , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
temp_int = 0 ; // turbo mode
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & temp_int , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
2008-01-23 17:25:09 +00:00
PHYSFS_write ( fp , & state_game_id , sizeof ( uint ) , 1 ) ;
PHYSFS_write ( fp , & Laser_rapid_fire , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Ugly_robot_cheat , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Ugly_robot_texture , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Physics_cheat_flag , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Lunacy , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
2008-01-23 17:25:09 +00:00
PHYSFS_close ( fp ) ;
2006-03-20 16:43:15 +00:00
return 1 ;
}
2009-08-22 07:21:19 +00:00
// -----------------------------------------------------------------------------------
2010-02-25 03:08:10 +00:00
int state_save_all ( int between_levels , int blind_save )
2006-03-20 16:43:15 +00:00
{
2009-08-22 07:21:19 +00:00
int rval ;
char filename [ 128 ] , desc [ DESC_LENGTH + 1 ] ;
2006-03-20 16:43:15 +00:00
2009-08-22 07:21:19 +00:00
# ifdef NETWORK
2006-03-20 16:43:15 +00:00
if ( Game_mode & GM_MULTI ) {
return 0 ;
}
2006-10-06 00:12:16 +00:00
# endif
2006-03-20 16:43:15 +00:00
stop_time ( ) ;
2010-02-25 03:08:10 +00:00
if ( ! state_get_save_file ( filename , desc , blind_save ) )
{
2006-03-20 16:43:15 +00:00
start_time ( ) ;
return 0 ;
}
2008-01-23 17:25:09 +00:00
rval = state_save_all_sub ( filename , desc , between_levels ) ;
if ( rval )
2010-07-13 06:35:25 +00:00
HUD_init_message ( HM_DEFAULT , " Game saved " ) ;
2008-01-23 17:25:09 +00:00
return rval ;
2006-03-20 16:43:15 +00:00
}
int state_save_all_sub ( char * filename , char * desc , int between_levels )
{
int i , j ;
2009-08-22 07:21:19 +00:00
PHYSFS_file * fp ;
2006-03-20 16:43:15 +00:00
grs_canvas * cnv ;
2007-03-22 11:32:22 +00:00
ubyte * pal ;
# ifdef OGL
GLint gl_draw_buffer ;
# endif
2010-12-22 00:17:49 +00:00
fix tmptime32 = 0 ;
2006-03-20 16:43:15 +00:00
2009-08-22 07:21:19 +00:00
# ifndef NDEBUG
if ( GameArg . SysUsePlayersDir & & strncmp ( filename , " Players/ " , 8 ) )
Int3 ( ) ;
# endif
2008-01-23 17:25:09 +00:00
fp = PHYSFSX_openWriteBuffered ( filename ) ;
2006-03-20 16:43:15 +00:00
if ( ! fp ) {
2009-08-22 07:21:19 +00:00
nm_messagebox ( NULL , 1 , TXT_OK , " Error writing savegame. \n Possibly out of disk \n space. " ) ;
2006-03-20 16:43:15 +00:00
start_time ( ) ;
return 0 ;
}
//Save id
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , dgss_id , sizeof ( char ) * 4 , 1 ) ;
2006-03-20 16:43:15 +00:00
//Save version
i = STATE_VERSION ;
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & i , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
//Save description
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , desc , sizeof ( char ) * DESC_LENGTH , 1 ) ;
2006-03-20 16:43:15 +00:00
// Save the current screen shot...
2009-08-22 07:21:19 +00:00
2006-03-20 16:43:15 +00:00
cnv = gr_create_canvas ( THUMBNAIL_W , THUMBNAIL_H ) ;
2007-03-22 11:32:22 +00:00
if ( cnv )
{
2006-03-20 16:43:15 +00:00
# ifdef OGL
2007-03-22 11:32:22 +00:00
ubyte * buf ;
int k ;
2006-03-20 16:43:15 +00:00
# endif
2007-03-22 11:32:22 +00:00
grs_canvas * cnv_save ;
cnv_save = grd_curcanv ;
gr_set_current_canvas ( cnv ) ;
render_frame ( 0 ) ;
2009-08-22 07:21:19 +00:00
# if defined(OGL)
2011-01-06 11:43:55 +00:00
buf = d_malloc ( THUMBNAIL_W * THUMBNAIL_H * 4 ) ;
# ifndef OGLES
glGetIntegerv ( GL_DRAW_BUFFER , & gl_draw_buffer ) ;
glReadBuffer ( gl_draw_buffer ) ;
# endif
glReadPixels ( 0 , SHEIGHT - THUMBNAIL_H , THUMBNAIL_W , THUMBNAIL_H , GL_RGBA , GL_UNSIGNED_BYTE , buf ) ;
2007-03-22 11:32:22 +00:00
k = THUMBNAIL_H ;
for ( i = 0 ; i < THUMBNAIL_W * THUMBNAIL_H ; i + + ) {
if ( ! ( j = i % THUMBNAIL_W ) )
k - - ;
cnv - > cv_bitmap . bm_data [ THUMBNAIL_W * k + j ] =
2011-01-06 11:43:55 +00:00
gr_find_closest_color ( buf [ 4 * i ] / 4 , buf [ 4 * i + 1 ] / 4 , buf [ 4 * i + 2 ] / 4 ) ;
2006-03-20 16:43:15 +00:00
}
2008-01-23 17:25:09 +00:00
d_free ( buf ) ;
2007-03-22 11:32:22 +00:00
# endif
2009-08-22 07:21:19 +00:00
2007-03-22 11:32:22 +00:00
pal = gr_palette ;
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , cnv - > cv_bitmap . bm_data , THUMBNAIL_W * THUMBNAIL_H , 1 ) ;
2007-03-22 11:32:22 +00:00
gr_set_current_canvas ( cnv_save ) ;
2006-03-20 16:43:15 +00:00
gr_free_canvas ( cnv ) ;
2007-03-22 11:32:22 +00:00
}
else
{
2006-03-20 16:43:15 +00:00
ubyte color = 0 ;
for ( i = 0 ; i < THUMBNAIL_W * THUMBNAIL_H ; i + + )
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & color , sizeof ( ubyte ) , 1 ) ;
}
2006-03-20 16:43:15 +00:00
// Save the Between levels flag...
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & between_levels , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
// Save the mission info...
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , Current_mission_filename , 9 * sizeof ( char ) , 1 ) ;
2006-03-20 16:43:15 +00:00
//Save level info
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & Current_level_num , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Next_level_num , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
//Save GameTime
2010-12-22 00:17:49 +00:00
// NOTE: GameTime now is GameTime64 with fix64 since GameTime could only last 9 hrs. To even help old Savegames, we do not increment Savegame version but rather RESET GameTime64 to 0 on every save! ALL variables based on GameTime64 now will get the current GameTime64 value substracted and saved to fix size as well.
tmptime32 = 0 ;
PHYSFS_write ( fp , & tmptime32 , sizeof ( fix ) , 1 ) ;
2006-03-20 16:43:15 +00:00
//Save player info
2010-12-22 00:17:49 +00:00
//PHYSFS_write(fp, &Players[Player_num], sizeof(player), 1);
{
player_rw * pl_rw ;
MALLOC ( pl_rw , player_rw , 1 ) ;
state_player_to_player_rw ( & Players [ Player_num ] , pl_rw ) ;
PHYSFS_write ( fp , pl_rw , sizeof ( player_rw ) , 1 ) ;
d_free ( pl_rw ) ;
}
2006-03-20 16:43:15 +00:00
// Save the current weapon info
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & Primary_weapon , sizeof ( sbyte ) , 1 ) ;
PHYSFS_write ( fp , & Secondary_weapon , sizeof ( sbyte ) , 1 ) ;
2006-03-20 16:43:15 +00:00
// Save the difficulty level
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & Difficulty_level , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
2009-08-22 07:21:19 +00:00
// Save cheats enabled
PHYSFS_write ( fp , & Cheats_enabled , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Game_turbo_mode , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
if ( ! between_levels ) {
//Finish all morph objects
for ( i = 0 ; i < = Highest_object_index ; i + + ) {
if ( ( Objects [ i ] . type ! = OBJ_NONE ) & & ( Objects [ i ] . render_type = = RT_MORPH ) ) {
morph_data * md ;
md = find_morph_data ( & Objects [ i ] ) ;
if ( md ) {
md - > obj - > control_type = md - > morph_save_control_type ;
md - > obj - > movement_type = md - > morph_save_movement_type ;
md - > obj - > render_type = RT_POLYOBJ ;
md - > obj - > mtype . phys_info = md - > morph_save_phys_info ;
md - > obj = NULL ;
} else { //maybe loaded half-morphed from disk
Objects [ i ] . flags | = OF_SHOULD_BE_DEAD ;
Objects [ i ] . render_type = RT_POLYOBJ ;
Objects [ i ] . control_type = CT_NONE ;
Objects [ i ] . movement_type = MT_NONE ;
}
}
}
//Save object info
i = Highest_object_index + 1 ;
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & i , sizeof ( int ) , 1 ) ;
2010-12-22 00:17:49 +00:00
//PHYSFS_write(fp, Objects, sizeof(object), i);
for ( i = 0 ; i < = Highest_object_index ; i + + )
{
object_rw * obj_rw ;
MALLOC ( obj_rw , object_rw , 1 ) ;
state_object_to_object_rw ( & Objects [ i ] , obj_rw ) ;
PHYSFS_write ( fp , obj_rw , sizeof ( object_rw ) , 1 ) ;
d_free ( obj_rw ) ;
}
2006-03-20 16:43:15 +00:00
//Save wall info
i = Num_walls ;
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & i , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , Walls , sizeof ( wall ) , i ) ;
2006-03-20 16:43:15 +00:00
//Save door info
i = Num_open_doors ;
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & i , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , ActiveDoors , sizeof ( active_door ) , i ) ;
2006-03-20 16:43:15 +00:00
//Save trigger info
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & Num_triggers , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , Triggers , sizeof ( trigger ) , Num_triggers ) ;
2006-03-20 16:43:15 +00:00
//Save tmap info
2009-08-22 07:21:19 +00:00
for ( i = 0 ; i < = Highest_segment_index ; i + + )
{
for ( j = 0 ; j < 6 ; j + + )
{
PHYSFS_write ( fp , & Segments [ i ] . sides [ j ] . wall_num , sizeof ( short ) , 1 ) ;
PHYSFS_write ( fp , & Segments [ i ] . sides [ j ] . tmap_num , sizeof ( short ) , 1 ) ;
PHYSFS_write ( fp , & Segments [ i ] . sides [ j ] . tmap_num2 , sizeof ( short ) , 1 ) ;
2006-03-20 16:43:15 +00:00
}
}
// Save the fuelcen info
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & Control_center_destroyed , sizeof ( int ) , 1 ) ;
2010-03-20 13:21:53 +00:00
PHYSFS_write ( fp , & Countdown_seconds_left , sizeof ( int ) , 1 ) ;
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & Num_robot_centers , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , RobotCenters , sizeof ( matcen_info ) , Num_robot_centers ) ;
PHYSFS_write ( fp , & ControlCenterTriggers , sizeof ( control_center_triggers ) , 1 ) ;
PHYSFS_write ( fp , & Num_fuelcenters , sizeof ( int ) , 1 ) ;
2011-01-22 16:56:23 +00:00
for ( i = 0 ; i < Num_fuelcenters ; i + + )
{
// NOTE: Usually Descent1 handles countdown by Timer value of the Reactor Station. Since we now use Descent2 code to handle countdown (which we do in case there IS NO Reactor Station which causes potential trouble in Multiplayer), let's find the Reactor here and store the timer in it.
if ( Station [ i ] . Type = = SEGMENT_IS_CONTROLCEN )
Station [ i ] . Timer = Countdown_timer ;
PHYSFS_write ( fp , & Station [ i ] , sizeof ( FuelCenter ) , 1 ) ;
}
// PHYSFS_write(fp, Station, sizeof(FuelCenter), Num_fuelcenters);
2006-03-20 16:43:15 +00:00
// Save the control cen info
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & Control_center_been_hit , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Control_center_player_been_seen , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Control_center_next_fire_time , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Control_center_present , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Dead_controlcen_object_num , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
// Save the AI state
ai_save_state ( fp ) ;
// Save the automap visited info
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , Automap_visited , sizeof ( ubyte ) , MAX_SEGMENTS ) ;
2006-03-20 16:43:15 +00:00
}
2009-08-22 07:21:19 +00:00
PHYSFS_write ( fp , & state_game_id , sizeof ( uint ) , 1 ) ;
PHYSFS_write ( fp , & Laser_rapid_fire , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Ugly_robot_cheat , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Ugly_robot_texture , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Physics_cheat_flag , sizeof ( int ) , 1 ) ;
PHYSFS_write ( fp , & Lunacy , sizeof ( int ) , 1 ) ;
2006-03-20 16:43:15 +00:00
2008-01-23 17:25:09 +00:00
PHYSFS_close ( fp ) ;
2006-03-20 16:43:15 +00:00
start_time ( ) ;
return 1 ;
}
2009-08-22 07:21:19 +00:00
// -----------------------------------------------------------------------------------
2006-03-20 16:43:15 +00:00
int state_restore_all ( int in_game )
{
char filename [ 128 ] ;
2009-08-22 07:21:19 +00:00
# ifdef NETWORK
2006-03-20 16:43:15 +00:00
if ( Game_mode & GM_MULTI ) {
return 0 ;
}
2007-07-22 19:24:26 +00:00
# endif
2006-03-20 16:43:15 +00:00
if ( Newdemo_state = = ND_STATE_RECORDING )
newdemo_stop_recording ( ) ;
if ( Newdemo_state ! = ND_STATE_NORMAL )
return 0 ;
stop_time ( ) ;
2007-10-31 00:49:24 +00:00
if ( ! state_get_restore_file ( filename ) ) {
2006-03-20 16:43:15 +00:00
start_time ( ) ;
return 0 ;
}
if ( in_game ) {
int choice ;
choice = nm_messagebox ( NULL , 2 , " Yes " , " No " , " Restore Game? " ) ;
if ( choice ! = 0 ) {
start_time ( ) ;
return 0 ;
}
}
start_time ( ) ;
2007-10-31 00:49:24 +00:00
return state_restore_all_sub ( filename ) ;
2006-03-20 16:43:15 +00:00
}
2007-10-31 00:49:24 +00:00
int state_restore_all_sub ( char * filename )
2006-03-20 16:43:15 +00:00
{
int ObjectStartLocation ;
int BogusSaturnShit = 0 ;
int version , i , j , segnum ;
object * obj ;
2008-01-23 17:25:09 +00:00
PHYSFS_file * fp ;
2009-10-05 02:51:37 +00:00
int swap = 0 ; // if file is not endian native, have to swap all shorts and ints
2006-03-20 16:43:15 +00:00
int current_level , next_level ;
int between_levels ;
char mission [ 16 ] ;
char desc [ DESC_LENGTH + 1 ] ;
char id [ 5 ] ;
char org_callsign [ CALLSIGN_LEN + 16 ] ;
2010-12-22 00:17:49 +00:00
fix tmptime32 = 0 ;
2006-03-20 16:43:15 +00:00
2009-08-22 07:21:19 +00:00
# ifndef NDEBUG
if ( GameArg . SysUsePlayersDir & & strncmp ( filename , " Players/ " , 8 ) )
Int3 ( ) ;
# endif
2008-01-23 17:25:09 +00:00
fp = PHYSFSX_openReadBuffered ( filename ) ;
2006-03-20 16:43:15 +00:00
if ( ! fp ) return 0 ;
//Read id
2009-08-22 07:21:19 +00:00
PHYSFS_read ( fp , id , sizeof ( char ) * 4 , 1 ) ;
2006-03-20 16:43:15 +00:00
if ( memcmp ( id , dgss_id , 4 ) ) {
2008-01-23 17:25:09 +00:00
PHYSFS_close ( fp ) ;
2006-03-20 16:43:15 +00:00
return 0 ;
}
//Read version
2009-10-05 02:51:37 +00:00
//Check for swapped file here, as dgss_id is written as a string (i.e. endian independent)
2009-08-22 07:21:19 +00:00
PHYSFS_read ( fp , & version , sizeof ( int ) , 1 ) ;
2009-10-05 02:51:37 +00:00
if ( version & 0xffff0000 )
{
swap = 1 ;
version = SWAPINT ( version ) ;
}
2006-03-20 16:43:15 +00:00
if ( version < STATE_COMPATIBLE_VERSION ) {
2008-01-23 17:25:09 +00:00
PHYSFS_close ( fp ) ;
2006-03-20 16:43:15 +00:00
return 0 ;
}
// Read description
2009-08-22 07:21:19 +00:00
PHYSFS_read ( fp , desc , sizeof ( char ) * DESC_LENGTH , 1 ) ;
2006-03-20 16:43:15 +00:00
// Skip the current screen shot...
2008-01-23 17:25:09 +00:00
PHYSFS_seek ( fp , PHYSFS_tell ( fp ) + THUMBNAIL_W * THUMBNAIL_H ) ;
2006-03-20 16:43:15 +00:00
// Read the Between levels flag...
2009-10-05 02:51:37 +00:00
between_levels = PHYSFSX_readSXE32 ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
// Read the mission info...
2009-08-22 07:21:19 +00:00
PHYSFS_read ( fp , mission , sizeof ( char ) * 9 , 1 ) ;
2006-03-20 16:43:15 +00:00
if ( ! load_mission_by_name ( mission ) ) {
nm_messagebox ( NULL , 1 , " Ok " , " Error! \n Unable to load mission \n '%s' \n " , mission ) ;
2008-01-23 17:25:09 +00:00
PHYSFS_close ( fp ) ;
2006-03-20 16:43:15 +00:00
return 0 ;
}
//Read level info
2009-10-05 02:51:37 +00:00
current_level = PHYSFSX_readSXE32 ( fp , swap ) ;
next_level = PHYSFSX_readSXE32 ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
//Restore GameTime
2010-12-22 00:17:49 +00:00
tmptime32 = PHYSFSX_readSXE32 ( fp , swap ) ;
GameTime64 = ( fix64 ) tmptime32 ;
2006-03-20 16:43:15 +00:00
// Start new game....
2007-10-31 00:49:24 +00:00
Game_mode = GM_NORMAL ;
2006-03-20 16:43:15 +00:00
# ifdef NETWORK
2007-10-31 00:49:24 +00:00
change_playernum_to ( 0 ) ;
2006-03-20 16:43:15 +00:00
# endif
2007-10-31 00:49:24 +00:00
strcpy ( org_callsign , Players [ 0 ] . callsign ) ;
N_players = 1 ;
InitPlayerObject ( ) ; //make sure player's object set up
init_player_stats_game ( ) ; //clear all stats
2010-07-30 17:59:21 +00:00
if ( Game_wind )
window_set_visible ( Game_wind , 0 ) ;
2006-03-20 16:43:15 +00:00
//Read player info
if ( between_levels ) {
int saved_offset ;
2010-12-22 00:17:49 +00:00
player_rw * pl_rw ;
MALLOC ( pl_rw , player_rw , 1 ) ;
PHYSFS_read ( fp , pl_rw , sizeof ( player_rw ) , 1 ) ;
player_rw_swap ( pl_rw , swap ) ;
state_player_rw_to_player ( pl_rw , & Players [ Player_num ] ) ;
d_free ( pl_rw ) ;
2008-01-23 17:25:09 +00:00
saved_offset = PHYSFS_tell ( fp ) ;
PHYSFS_close ( fp ) ;
2010-03-01 07:27:51 +00:00
do_briefing_screens ( Briefing_text_filename , next_level ) ;
2008-01-23 17:25:09 +00:00
fp = PHYSFSX_openReadBuffered ( filename ) ;
PHYSFS_seek ( fp , saved_offset ) ;
2006-03-20 16:43:15 +00:00
StartNewLevelSub ( next_level , 1 ) ; //use page_in_textures here to fix OGL texture precashing crash -MPM
} else {
2010-12-22 00:17:49 +00:00
player_rw * pl_rw ;
2006-03-20 16:43:15 +00:00
StartNewLevelSub ( current_level , 1 ) ; //use page_in_textures here to fix OGL texture precashing crash -MPM
2010-12-22 00:17:49 +00:00
MALLOC ( pl_rw , player_rw , 1 ) ;
PHYSFS_read ( fp , pl_rw , sizeof ( player_rw ) , 1 ) ;
player_rw_swap ( pl_rw , swap ) ;
state_player_rw_to_player ( pl_rw , & Players [ Player_num ] ) ;
d_free ( pl_rw ) ;
2006-03-20 16:43:15 +00:00
}
strcpy ( Players [ Player_num ] . callsign , org_callsign ) ;
// Set the right level
if ( between_levels )
Players [ Player_num ] . level = next_level ;
// Restore the weapon states
2008-01-23 17:25:09 +00:00
PHYSFS_read ( fp , & Primary_weapon , sizeof ( sbyte ) , 1 ) ;
PHYSFS_read ( fp , & Secondary_weapon , sizeof ( sbyte ) , 1 ) ;
2006-03-20 16:43:15 +00:00
select_weapon ( Primary_weapon , 0 , 0 , 0 ) ;
select_weapon ( Secondary_weapon , 1 , 0 , 0 ) ;
// Restore the difficulty level
2009-10-05 02:51:37 +00:00
Difficulty_level = PHYSFSX_readSXE32 ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
// Restore the cheats enabled flag
2009-08-22 07:21:19 +00:00
2009-10-05 02:51:37 +00:00
Cheats_enabled = PHYSFSX_readSXE32 ( fp , swap ) ;
Game_turbo_mode = PHYSFSX_readSXE32 ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
if ( ! between_levels ) {
Do_appearance_effect = 0 ; // Don't do this for middle o' game stuff.
2009-08-22 07:21:19 +00:00
ObjectStartLocation = PHYSFS_tell ( fp ) ;
2006-03-20 16:43:15 +00:00
RetryObjectLoading :
//Clear out all the objects from the lvl file
for ( segnum = 0 ; segnum < = Highest_segment_index ; segnum + + )
Segments [ segnum ] . objects = - 1 ;
reset_objects ( 1 ) ;
//Read objects, and pop 'em into their respective segments.
2009-10-05 02:51:37 +00:00
i = PHYSFSX_readSXE32 ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
Highest_object_index = i - 1 ;
2009-10-05 02:51:37 +00:00
if ( ! BogusSaturnShit )
2010-12-22 00:17:49 +00:00
//object_read_n_swap(Objects, i, swap, fp);
for ( i = 0 ; i < = Highest_object_index ; i + + )
{
object_rw * obj_rw ;
MALLOC ( obj_rw , object_rw , 1 ) ;
PHYSFS_read ( fp , obj_rw , sizeof ( object_rw ) , 1 ) ;
object_rw_swap ( obj_rw , swap ) ;
state_object_rw_to_object ( obj_rw , & Objects [ i ] ) ;
d_free ( obj_rw ) ;
}
2006-03-20 16:43:15 +00:00
else {
2010-12-22 00:17:49 +00:00
for ( i = 0 ; i < = Highest_object_index ; i + + )
{
object_rw * obj_rw ;
MALLOC ( obj_rw , object_rw , 1 ) ;
2006-03-20 16:43:15 +00:00
// Insert 3 bytes after the read in obj->rtype.pobj_info.alt_textures field.
2010-12-22 00:17:49 +00:00
PHYSFS_read ( fp , obj_rw , sizeof ( object_rw ) - 3 , 1 ) ;
object_rw_swap ( obj_rw , swap ) ;
state_object_rw_to_object ( obj_rw , & Objects [ i ] ) ;
d_free ( obj_rw ) ;
2006-03-20 16:43:15 +00:00
Objects [ i ] . rtype . pobj_info . alt_textures = - 1 ;
}
}
for ( i = 0 ; i < = Highest_object_index ; i + + ) {
obj = & Objects [ i ] ;
obj - > rtype . pobj_info . alt_textures = - 1 ;
segnum = obj - > segnum ;
obj - > next = obj - > prev = obj - > segnum = - 1 ;
if ( obj - > type ! = OBJ_NONE ) {
// Check for a bogus Saturn version!!!!
if ( ! BogusSaturnShit ) {
if ( ( segnum < 0 ) | | ( segnum > Highest_segment_index ) ) {
BogusSaturnShit = 1 ;
2008-01-23 17:25:09 +00:00
PHYSFS_seek ( fp , ObjectStartLocation ) ;
2006-03-20 16:43:15 +00:00
goto RetryObjectLoading ;
}
}
obj_link ( i , segnum ) ;
}
}
special_reset_objects ( ) ;
//Restore wall info
2009-10-05 02:51:37 +00:00
Num_walls = PHYSFSX_readSXE32 ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
// Check for a bogus Saturn version!!!!
if ( ! BogusSaturnShit ) {
if ( ( Num_walls < 0 ) | | ( Num_walls > MAX_WALLS ) ) {
BogusSaturnShit = 1 ;
2008-01-23 17:25:09 +00:00
PHYSFS_seek ( fp , ObjectStartLocation ) ;
2006-03-20 16:43:15 +00:00
goto RetryObjectLoading ;
}
}
2009-10-05 02:51:37 +00:00
wall_read_n_swap ( Walls , Num_walls , swap , fp ) ;
2006-03-20 16:43:15 +00:00
// Check for a bogus Saturn version!!!!
if ( ! BogusSaturnShit ) {
for ( i = 0 ; i < Num_walls ; i + + ) {
if ( ( Walls [ i ] . segnum < 0 ) | | ( Walls [ i ] . segnum > Highest_segment_index ) | | ( Walls [ i ] . sidenum < - 1 ) | | ( Walls [ i ] . sidenum > 5 ) ) {
BogusSaturnShit = 1 ;
2008-01-23 17:25:09 +00:00
PHYSFS_seek ( fp , ObjectStartLocation ) ;
2006-03-20 16:43:15 +00:00
goto RetryObjectLoading ;
}
}
}
2009-08-22 07:21:19 +00:00
2006-03-20 16:43:15 +00:00
//Restore door info
2009-10-05 02:51:37 +00:00
Num_open_doors = PHYSFSX_readSXE32 ( fp , swap ) ;
active_door_read_n_swap ( ActiveDoors , Num_open_doors , swap , fp ) ;
2006-03-20 16:43:15 +00:00
//Restore trigger info
2009-10-05 02:51:37 +00:00
Num_triggers = PHYSFSX_readSXE32 ( fp , swap ) ;
trigger_read_n_swap ( Triggers , Num_triggers , swap , fp ) ;
2006-03-20 16:43:15 +00:00
//Restore tmap info
for ( i = 0 ; i < = Highest_segment_index ; i + + ) {
for ( j = 0 ; j < 6 ; j + + ) {
2009-10-05 02:51:37 +00:00
Segments [ i ] . sides [ j ] . wall_num = PHYSFSX_readSXE16 ( fp , swap ) ;
Segments [ i ] . sides [ j ] . tmap_num = PHYSFSX_readSXE16 ( fp , swap ) ;
Segments [ i ] . sides [ j ] . tmap_num2 = PHYSFSX_readSXE16 ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
}
}
//Restore the fuelcen info
2009-10-05 02:51:37 +00:00
Control_center_destroyed = PHYSFSX_readSXE32 ( fp , swap ) ;
2010-03-20 13:21:53 +00:00
Countdown_seconds_left = PHYSFSX_readSXE32 ( fp , swap ) ;
2009-10-05 02:51:37 +00:00
Num_robot_centers = PHYSFSX_readSXE32 ( fp , swap ) ;
matcen_info_read_n_swap ( RobotCenters , Num_robot_centers , swap , fp ) ;
control_center_triggers_read_n_swap ( & ControlCenterTriggers , 1 , swap , fp ) ;
Num_fuelcenters = PHYSFSX_readSXE32 ( fp , swap ) ;
fuelcen_read_n_swap ( Station , Num_fuelcenters , swap , fp ) ;
2011-01-22 16:56:23 +00:00
Countdown_timer = 0 ;
for ( i = 0 ; i < Num_fuelcenters ; i + + )
{
// NOTE: Usually Descent1 handles countdown by Timer value of the Reactor Station. Since we now use Descent2 code to handle countdown (which we do in case there IS NO Reactor Station which causes potential trouble in Multiplayer), let's find the Reactor here and read the timer from it.
if ( Station [ i ] . Type = = SEGMENT_IS_CONTROLCEN )
Countdown_timer = Station [ i ] . Timer ;
}
2006-03-20 16:43:15 +00:00
// Restore the control cen info
2009-10-05 02:51:37 +00:00
Control_center_been_hit = PHYSFSX_readSXE32 ( fp , swap ) ;
Control_center_player_been_seen = PHYSFSX_readSXE32 ( fp , swap ) ;
Control_center_next_fire_time = PHYSFSX_readSXE32 ( fp , swap ) ;
Control_center_present = PHYSFSX_readSXE32 ( fp , swap ) ;
Dead_controlcen_object_num = PHYSFSX_readSXE32 ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
// Restore the AI state
2009-10-05 02:51:37 +00:00
ai_restore_state ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
// Restore the automap visited info
2008-01-23 17:25:09 +00:00
PHYSFS_read ( fp , Automap_visited , sizeof ( ubyte ) , MAX_SEGMENTS ) ;
2006-03-20 16:43:15 +00:00
// Restore hacked up weapon system stuff.
Auto_fire_fusion_cannon_time = 0 ;
2010-12-22 00:17:49 +00:00
Next_laser_fire_time = GameTime64 ;
Next_missile_fire_time = GameTime64 ;
Last_laser_fired_time = GameTime64 ;
2006-03-20 16:43:15 +00:00
}
state_game_id = 0 ;
if ( version > = 7 ) {
int tmp_Lunacy ;
2009-10-05 02:51:37 +00:00
state_game_id = PHYSFSX_readSXE32 ( fp , swap ) ;
Laser_rapid_fire = PHYSFSX_readSXE32 ( fp , swap ) ;
Ugly_robot_cheat = PHYSFSX_readSXE32 ( fp , swap ) ;
Ugly_robot_texture = PHYSFSX_readSXE32 ( fp , swap ) ;
Physics_cheat_flag = PHYSFSX_readSXE32 ( fp , swap ) ;
tmp_Lunacy = PHYSFSX_readSXE32 ( fp , swap ) ;
2006-03-20 16:43:15 +00:00
if ( tmp_Lunacy )
do_lunacy_on ( ) ;
}
2008-01-23 17:25:09 +00:00
PHYSFS_close ( fp ) ;
2006-03-20 16:43:15 +00:00
2010-07-30 17:59:21 +00:00
if ( Game_wind )
if ( ! window_is_visible ( Game_wind ) )
window_set_visible ( Game_wind , 1 ) ;
reset_time ( ) ;
2006-03-20 16:43:15 +00:00
return 1 ;
}