]> icculus.org git repositories - btb/d2x.git/blob - main/state.c
This commit was generated by cvs2svn to compensate for changes in r2,
[btb/d2x.git] / main / state.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14
15 #ifdef RCS
16 char state_rcsid[] = "$Id: state.c,v 1.1.1.1 2001-01-19 03:30:00 bradleyb Exp $";
17 #endif
18
19 #include <conf.h>
20
21 #ifdef WINDOWS
22 #include "desw.h"
23 #endif
24
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #ifdef MACINTOSH
33 #include <Files.h>
34 #endif
35
36 #include "pstypes.h"
37 #include "pa_enabl.h"                   //$$POLY_ACC
38 #include "mono.h"
39 #include "inferno.h"
40 #include "segment.h"
41 #include "textures.h"
42 #include "wall.h"
43 #include "object.h"
44 #include "digi.h"
45 #include "gamemine.h"
46 #include "error.h"
47 #include "gameseg.h"
48 #include "menu.h"
49 #include "switch.h"
50 #include "game.h"
51 #include "screens.h"
52 #include "newmenu.h"
53 #include "cfile.h"              
54 #include "fuelcen.h"
55 #include "hash.h"
56 #include "key.h"
57 #include "piggy.h"
58 #include "player.h"
59 #include "cntrlcen.h"
60 #include "morph.h"
61 #include "weapon.h"
62 #include "render.h"
63 #include "gameseq.h"
64 #include "gauges.h"
65 #include "newdemo.h"
66 #include "automap.h"
67 #include "piggy.h"
68 #include "paging.h"
69 #include "titles.h"
70 #include "text.h"
71 #include "mission.h"
72 #include "pcx.h"
73 #include "u_mem.h"
74 #include "network.h"
75 #include "args.h"
76 #include "ai.h"
77 #include "fireball.h"
78 #include "controls.h"
79 #include "laser.h"
80 #include "multibot.h"
81
82 #if defined(POLY_ACC)
83 #include "poly_acc.h"
84 #endif
85
86 #define STATE_VERSION 22
87 #define STATE_COMPATIBLE_VERSION 20
88 // 0 - Put DGSS (Descent Game State Save) id at tof.
89 // 1 - Added Difficulty level save
90 // 2 - Added Cheats_enabled flag
91 // 3 - Added between levels save.
92 // 4 - Added mission support
93 // 5 - Mike changed ai and object structure.
94 // 6 - Added buggin' cheat save
95 // 7 - Added other cheat saves and game_id.
96 // 8 - Added AI stuff for escort and thief.
97 // 9 - Save palette with screen shot
98 // 12- Saved last_was_super array
99 // 13- Saved palette flash stuff
100 // 14- Save cloaking wall stuff
101 // 15- Save additional ai info
102 // 16- Save Light_subtracted
103 // 17- New marker save
104 // 18- Took out saving of old cheat status
105 // 19- Saved cheats_enabled flag
106 // 20- First_secret_visit
107 // 22- Omega_charge
108
109 #define NUM_SAVES 9
110 #define THUMBNAIL_W 100
111 #define THUMBNAIL_H 50
112 #define DESC_LENGTH 20
113
114 extern void multi_initiate_save_game();
115 extern void multi_initiate_restore_game();
116 extern void apply_all_changed_light(void);
117
118 extern int Do_appearance_effect;
119 extern fix Fusion_next_sound_time;
120
121 extern int Laser_rapid_fire;
122 extern int Physics_cheat_flag;
123 extern int      Lunacy;
124 extern void do_lunacy_on(void);
125 extern void do_lunacy_off(void);
126 extern int First_secret_visit;
127
128 int sc_last_item= 0;
129 grs_bitmap *sc_bmp[NUM_SAVES+1];
130
131 char dgss_id[4] = "DGSS";
132
133 int state_default_item = 0;
134
135 uint state_game_id;
136
137 extern int robot_controlled[MAX_ROBOTS_CONTROLLED];
138 extern int robot_agitation[MAX_ROBOTS_CONTROLLED];
139 extern fix robot_controlled_time[MAX_ROBOTS_CONTROLLED];
140 extern fix robot_last_send_time[MAX_ROBOTS_CONTROLLED];
141 extern fix robot_last_message_time[MAX_ROBOTS_CONTROLLED];
142 extern int robot_send_pending[MAX_ROBOTS_CONTROLLED];
143 extern int robot_fired[MAX_ROBOTS_CONTROLLED];
144 extern byte robot_fire_buf[MAX_ROBOTS_CONTROLLED][18+3];
145
146
147 #if defined(WINDOWS) || defined(MACINTOSH)
148 extern ubyte Hack_DblClick_MenuMode;
149 #endif
150
151
152 //-------------------------------------------------------------------
153 void state_callback(int nitems,newmenu_item * items, int * last_key, int citem)
154 {
155         nitems = nitems;
156         last_key = last_key;
157         
158 //      if ( sc_last_item != citem )    {
159 //              sc_last_item = citem;
160                 if ( citem > 0 )        {
161                         if ( sc_bmp[citem-1] )  {
162                                 if (MenuHires) {
163                                 WINDOS(
164                                         dd_grs_canvas *save_canv = dd_grd_curcanv,
165                                         grs_canvas *save_canv = grd_curcanv
166                                 );
167                                         grs_canvas *temp_canv = gr_create_canvas(THUMBNAIL_W*2,(THUMBNAIL_H*24/10));
168                                         grs_point vertbuf[3] = {{0,0}, {0,0}, {i2f(THUMBNAIL_W*2),i2f(THUMBNAIL_H*24/10)} };
169                                         gr_set_current_canvas(temp_canv);
170                                         scale_bitmap(sc_bmp[citem-1], vertbuf, 0 );
171                                 WINDOS(
172                                         dd_gr_set_current_canvas(save_canv),
173                                         gr_set_current_canvas( save_canv )
174                                 );
175                                 WIN(DDGRLOCK(dd_grd_curcanv));
176                                         gr_bitmap( (grd_curcanv->cv_bitmap.bm_w-THUMBNAIL_W*2)/2,items[0].y-10, &temp_canv->cv_bitmap);
177                                 WIN(DDGRUNLOCK(dd_grd_curcanv));
178                                         gr_free_canvas(temp_canv);
179                                 }
180                                 else    {
181                                 #ifdef WINDOWS
182                                         Int3();
183                                 #else
184                                         gr_bitmap( (grd_curcanv->cv_bitmap.bm_w-THUMBNAIL_W)/2,items[0].y-5, sc_bmp[citem-1] );
185                                 #endif
186                                 }
187                         }
188                 }
189 //      }       
190 }
191
192 void rpad_string( char * string, int max_chars )
193 {
194         int i, end_found;
195
196         end_found = 0;
197         for( i=0; i<max_chars; i++ )    {
198                 if ( *string == 0 )
199                         end_found = 1;
200                 if ( end_found )
201                         *string = ' ';
202                 string++;
203         }
204         *string = 0;            // NULL terminate
205 }
206
207 int state_get_save_file(char * fname, char * dsc, int multi )
208 {
209         FILE * fp;
210         int i, choice, version;
211         newmenu_item m[NUM_SAVES+2];
212         char filename[NUM_SAVES+1][30];
213         char desc[NUM_SAVES+1][DESC_LENGTH+16];
214         char id[5];
215         int valid=0;
216         
217         for (i=0;i<NUM_SAVES; i++ )     {
218                 sc_bmp[i] = NULL;
219                 if ( !multi )
220                         #ifndef MACINTOSH
221                         sprintf( filename[i], "%s.sg%x", Players[Player_num].callsign, i );
222                         #else
223                         sprintf( filename[i], ":Players:%s.sg%x", Players[Player_num].callsign, i );
224                         #endif
225                 else
226                         #ifndef MACINTOSH
227                         sprintf( filename[i], "%s.mg%x", Players[Player_num].callsign, i );
228                         #else
229                         sprintf( filename[i], ":Players:%s.mg%x", Players[Player_num].callsign, i );
230                         #endif
231                 valid = 0;
232                 fp = fopen( filename[i], "rb" );
233                 if ( fp ) {
234                         //Read id
235                         fread( id, sizeof(char)*4, 1, fp );
236                         if ( !memcmp( id, dgss_id, 4 )) {
237                                 //Read version
238                                 fread( &version, sizeof(int), 1, fp );
239                                 if (version >= STATE_COMPATIBLE_VERSION)        {
240                                         // Read description
241                                         fread( desc[i], sizeof(char)*DESC_LENGTH, 1, fp );
242                                         //rpad_string( desc[i], DESC_LENGTH-1 );
243                                         // Read thumbnail
244                                         //sc_bmp[i] = gr_create_bitmap(THUMBNAIL_W,THUMBNAIL_H );
245                                         //fread( sc_bmp[i]->bm_data, THUMBNAIL_W * THUMBNAIL_H, 1, fp );
246                                         valid = 1;
247                                 }
248                         } 
249                         fclose(fp);
250                 }
251                 if (!valid) {
252                         strcpy( desc[i], TXT_EMPTY );
253                         //rpad_string( desc[i], DESC_LENGTH-1 );
254                 }
255                 m[i].type = NM_TYPE_INPUT_MENU; m[i].text = desc[i]; m[i].text_len = DESC_LENGTH-1;
256         }
257
258         sc_last_item = -1;
259         choice = newmenu_do1( NULL, "Save Game", NUM_SAVES, m, NULL, state_default_item );
260
261         for (i=0; i<NUM_SAVES; i++ )    {
262                 if ( sc_bmp[i] )
263                         gr_free_bitmap( sc_bmp[i] );
264         }
265
266         if (choice > -1) {
267                 strcpy( fname, filename[choice] );
268                 strcpy( dsc, desc[choice] );
269                 state_default_item = choice;
270                 return choice+1;
271         }
272         return 0;
273 }
274
275 int RestoringMenu=0;
276 extern int Current_display_mode;
277
278 int state_get_restore_file(char * fname, int multi)
279 {
280         FILE * fp;
281         int i, choice, version, nsaves;
282         newmenu_item m[NUM_SAVES+2];
283         char filename[NUM_SAVES+1][30];
284         char desc[NUM_SAVES+1][DESC_LENGTH + 16];
285         char id[5];
286         int valid;
287
288         nsaves=0;
289         m[0].type = NM_TYPE_TEXT; m[0].text = "\n\n\n\n";       
290         for (i=0;i<NUM_SAVES+1; i++ )   {
291                 sc_bmp[i] = NULL;
292                 if (!multi)
293                         #ifndef MACINTOSH
294                         sprintf( filename[i], "%s.sg%x", Players[Player_num].callsign, i );
295                         #else
296                         sprintf( filename[i], ":Players:%s.sg%x", Players[Player_num].callsign, i );
297                         #endif
298                 else
299                         #ifndef MACINTOSH
300                         sprintf( filename[i], "%s.mg%x", Players[Player_num].callsign, i );
301                         #else
302                         sprintf( filename[i], ":Players:%s.mg%x", Players[Player_num].callsign, i );
303                         #endif
304                 valid = 0;
305                 fp = fopen( filename[i], "rb" );
306                 if ( fp ) {
307                         //Read id
308                         fread( id, sizeof(char)*4, 1, fp );
309                         if ( !memcmp( id, dgss_id, 4 )) {
310                                 //Read version
311                                 fread( &version, sizeof(int), 1, fp );
312                                 if (version >= STATE_COMPATIBLE_VERSION)        {
313                                         // Read description
314                                         fread( desc[i], sizeof(char)*DESC_LENGTH, 1, fp );
315                                         //rpad_string( desc[i], DESC_LENGTH-1 );
316                                         m[i+1].type = NM_TYPE_MENU; m[i+1].text = desc[i];
317                                         // Read thumbnail
318                                         sc_bmp[i] = gr_create_bitmap(THUMBNAIL_W,THUMBNAIL_H );
319                                         fread( sc_bmp[i]->bm_data, THUMBNAIL_W * THUMBNAIL_H, 1, fp );
320                                         if (version >= 9) {
321                                                 ubyte pal[256*3];
322                                                 fread( pal, 3, 256, fp);
323                                                 gr_remap_bitmap_good( sc_bmp[i], pal, -1, -1 );
324                                         }
325                                         nsaves++;
326                                         valid = 1;
327                                 } 
328                         }
329                         fclose(fp);
330                 } 
331                 if (!valid) {
332                         strcpy( desc[i], TXT_EMPTY );
333                         //rpad_string( desc[i], DESC_LENGTH-1 );
334                         m[i+1].type = NM_TYPE_TEXT; m[i+1].text = desc[i];
335                 }
336         }
337
338         if ( nsaves < 1 )       {
339                 nm_messagebox( NULL, 1, "Ok", "No saved games were found!" );
340                 return 0;
341         }
342
343         if (Current_display_mode == 3)  //restore menu won't fit on 640x400
344                 VR_screen_flags ^= VRF_COMPATIBLE_MENUS;
345
346         sc_last_item = -1;
347
348 #if defined(WINDOWS) || defined(MACINTOSH)
349         Hack_DblClick_MenuMode = 1;
350 #endif
351
352    RestoringMenu=1;
353         choice = newmenu_do3( NULL, "Select Game to Restore", NUM_SAVES+2, m, state_callback, state_default_item+1, NULL, 190, -1 );
354    RestoringMenu=0;
355
356 #if defined(WINDOWS) || defined(MACINTOSH)
357         Hack_DblClick_MenuMode = 0;
358 #endif
359
360         if (Current_display_mode == 3)  //set flag back
361                 VR_screen_flags ^= VRF_COMPATIBLE_MENUS;
362
363
364         for (i=0; i<NUM_SAVES+1; i++ )  {
365                 if ( sc_bmp[i] )
366                         gr_free_bitmap( sc_bmp[i] );
367         }
368
369         if (choice > 0) {
370                 strcpy( fname, filename[choice-1] );
371                 if (choice != NUM_SAVES+1)              //no new default when restore from autosave
372                         state_default_item = choice - 1;
373                 return choice;
374         }
375         return 0;
376 }
377
378 #define DESC_OFFSET     8
379
380 //      -----------------------------------------------------------------------------------
381 //      Return true if the file named *filename exists, else return false.
382 int file_exists(char *filename)
383 {
384         FILE    *fp;
385
386         if ((fp = fopen(filename, "rb")) != NULL) {
387                 fclose(fp);
388                 return 1;
389         }
390
391         return 0;
392 }
393
394 #define CF_BUF_SIZE     1024
395
396 //      -----------------------------------------------------------------------------------
397 //      Imagine if C had a function to copy a file...
398 int copy_file(char *old_file, char *new_file)
399 {
400         byte    buf[CF_BUF_SIZE];
401         FILE    *in_file, *out_file;
402
403         out_file = fopen(new_file, "wb");
404
405         if (out_file == NULL)
406                 return -1;
407
408         in_file = fopen(old_file, "rb");
409
410         if (in_file == NULL)
411                 return -2;
412
413         while (!feof(in_file)) {
414                 int bytes_read;
415
416                 bytes_read = fread(buf, 1, CF_BUF_SIZE, in_file);
417                 if (ferror(in_file))
418                         Error("Cannot read from file <%s>: %s", old_file, strerror(errno));
419
420                 Assert(bytes_read == CF_BUF_SIZE || feof(in_file));
421
422                 fwrite(buf, 1, bytes_read, out_file);
423
424                 if (ferror(out_file))
425                         Error("Cannot write to file <%s>: %s", out_file, strerror(errno));
426         }
427
428         if (fclose(in_file)) {
429                 fclose(out_file);
430                 return -3;
431         }
432
433         if (fclose(out_file))
434                 return -4;
435
436         return 0;
437 }
438
439 #ifndef MACINTOSH
440 #define SECRETB_FILENAME        "secret.sgb"
441 #define SECRETC_FILENAME        "secret.sgc"
442 #else
443 #define SECRETB_FILENAME        ":Players:secret.sgb"
444 #define SECRETC_FILENAME        ":Players:secret.sgc"
445 #endif
446
447 extern int Final_boss_is_dead;
448
449 //      -----------------------------------------------------------------------------------
450 //      blind_save means don't prompt user for any info.
451 int state_save_all(int between_levels, int secret_save, char *filename_override)
452 {
453         int     rval, filenum = -1;
454
455         char    filename[128], desc[DESC_LENGTH+1];
456
457         Assert(between_levels == 0);    //between levels save ripped out
458
459 #ifdef NETWORK
460         if ( Game_mode & GM_MULTI )     {
461                         multi_initiate_save_game();
462                 return 0;
463         }
464 #endif
465
466         if ((Current_level_num < 0) && (secret_save == 0)) {
467                 HUD_init_message( "Can't save in secret level!" );
468                 return 0;
469         }
470
471         if (Final_boss_is_dead)         //don't allow save while final boss is dying
472                 return 0;
473
474         mprintf(( 0, "CL=%d, NL=%d\n", Current_level_num, Next_level_num ));
475         
476         //      If this is a secret save and the control center has been destroyed, don't allow
477         //      return to the base level.
478         if (secret_save && (Control_center_destroyed)) {
479                 mprintf((0, "Deleting secret.sgb so player can't return to base level.\n"));
480                 unlink(SECRETB_FILENAME);
481                 return 0;
482         }
483
484         stop_time();
485
486         if (secret_save == 1) {
487                 filename_override = filename;
488                 sprintf(filename_override, SECRETB_FILENAME);
489         } else if (secret_save == 2) {
490                 filename_override = filename;
491                 sprintf(filename_override, SECRETC_FILENAME);
492         } else {
493                 if (filename_override) {
494                         strcpy( filename, filename_override);
495                         sprintf(desc, "[autosave backup]");
496                 } else if (!(filenum = state_get_save_file(filename,desc,0))) {
497                         start_time();
498                         return 0;
499                 }
500         }
501                 
502         //      MK, 1/1/96
503         //      If not in multiplayer, do special secret level stuff.
504         //      If secret.sgc exists, then copy it to Nsecret.sgc (where N = filenum).
505         //      If it doesn't exist, then delete Nsecret.sgc
506         if (!secret_save && !(Game_mode & GM_MULTI)) {
507                 int     rval;
508                 char    temp_fname[32], fc;
509
510                 if (filenum != -1) {
511
512                         if (filenum >= 10)
513                                 fc = (filenum-10) + 'a';
514                         else
515                                 fc = '0' + filenum;
516
517                         #ifndef MACINTOSH
518                         sprintf(temp_fname, "%csecret.sgc", fc);
519                         #else
520                         sprintf(temp_fname, ":Players:%csecret.sgc", fc);
521                         #endif
522
523                         mprintf((0, "Trying to copy secret.sgc to %s.\n", temp_fname));
524
525                         if (file_exists(temp_fname)) {
526                                 mprintf((0, "Deleting file %s\n", temp_fname));
527                                 rval = unlink(temp_fname);
528                                 Assert(rval == 0);      //      Oops, error deleting file in temp_fname.
529                         }
530
531                         if (file_exists(SECRETC_FILENAME)) {
532                                 mprintf((0, "Copying secret.sgc to %s.\n", temp_fname));
533                                 rval = copy_file(SECRETC_FILENAME, temp_fname);
534                                 Assert(rval == 0);      //      Oops, error copying temp_fname to secret.sgc!
535                         }
536                 }
537         }
538
539         //      Save file we're going to save over in last slot and call "[autosave backup]"
540         if (!filename_override) {
541                 FILE    *tfp;
542         
543                 tfp = fopen( filename, "r+b" );
544
545                 if ( tfp ) {
546                         char    newname[128];
547
548                         #ifndef MACINTOSH
549                         sprintf( newname, "%s.sg%x", Players[Player_num].callsign, NUM_SAVES );
550                         #else
551                         sprintf( newname, ":Players:%s.sg%x", Players[Player_num].callsign, NUM_SAVES );
552                         #endif
553                         
554                         fseek( tfp, DESC_OFFSET, SEEK_SET);
555                         fwrite( "[autosave backup]", sizeof(char)*DESC_LENGTH, 1, tfp );
556                         fclose(tfp);
557                         unlink(newname);
558                         rename(filename, newname);
559                 }
560         }
561         
562         rval = state_save_all_sub(filename, desc, between_levels);
563
564         return rval;
565 }
566
567 extern  fix     Flash_effect, Time_flash_last_played;
568
569
570 int state_save_all_sub(char *filename, char *desc, int between_levels)
571 {
572         int i,j;
573         FILE * fp;
574         grs_canvas * cnv;
575         #ifdef POLY_ACC
576         grs_canvas cnv2,*save_cnv2;
577         #endif
578         ubyte *pal;
579
580         Assert(between_levels == 0);    //between levels save ripped out
581
582 /*      if ( Game_mode & GM_MULTI )     {
583                 {
584                 start_time();
585                 return 0;
586                 }
587         }*/
588
589         #if defined(MACINTOSH) && !defined(NDEBUG) 
590         if ( strncmp(filename, ":Players:", 9) )
591                 Int3();
592         #endif
593
594         fp = fopen( filename, "wb" );
595         if ( !fp ) {
596                 if ( !(Game_mode & GM_MULTI) )
597                         nm_messagebox(NULL, 1, TXT_OK, "Error writing savegame.\nPossibly out of disk\nspace.");
598                 start_time();
599                 return 0;
600         }
601
602 //Save id
603         fwrite( dgss_id, sizeof(char)*4, 1, fp );
604
605 //Save version
606         i = STATE_VERSION;
607         fwrite( &i, sizeof(int), 1, fp );
608
609 //Save description
610         fwrite( desc, sizeof(char)*DESC_LENGTH, 1, fp );
611         
612 // Save the current screen shot...
613
614         cnv = gr_create_canvas( THUMBNAIL_W, THUMBNAIL_H );
615         if ( cnv )
616         {
617                 #ifdef WINDOWS
618                         dd_grs_canvas *cnv_save;
619                         cnv_save = dd_grd_curcanv;
620                 #else
621                         grs_canvas * cnv_save;
622                         cnv_save = grd_curcanv;
623                 #endif
624
625                 #ifndef MACINTOSH
626                 
627                         #if defined(POLY_ACC)
628                         
629                                         PA_DFX (pa_fool_to_backbuffer());
630                         
631                                         //for poly_acc, we render the frame to the normal render buffer
632                                         //so that this doesn't show, we create yet another canvas to save
633                                         //and restore what's on the render buffer
634                                         PA_DFX (pa_alpha_always());     
635                                         PA_DFX (pa_set_front_to_read());
636                                         gr_init_sub_canvas( &cnv2, &VR_render_buffer[0], 0, 0, THUMBNAIL_W, THUMBNAIL_H );
637                                         save_cnv2 = gr_create_canvas2(THUMBNAIL_W, THUMBNAIL_H, cnv2.cv_bitmap.bm_type);
638                                         gr_set_current_canvas( save_cnv2 );
639                                         PA_DFX (pa_set_front_to_read());
640                                         gr_bitmap(0,0,&cnv2.cv_bitmap);
641                                         gr_set_current_canvas( &cnv2 );
642                         #else
643                                         gr_set_current_canvas( cnv );
644                         #endif
645                         
646                                         PA_DFX (pa_set_backbuffer_current());
647                                         render_frame(0, 0);
648                                         PA_DFX (pa_alpha_always());  
649                         
650                         #if defined(POLY_ACC)
651                                         #ifndef MACINTOSH
652                                         screen_shot_pa(cnv,&cnv2);
653                                         #else
654                                         if ( PAEnabled )
655                                                 screen_shot_pa(cnv,&cnv2);
656                                         #endif
657                         #endif
658                         
659                                         pal = gr_palette;
660                         
661                                         fwrite( cnv->cv_bitmap.bm_data, THUMBNAIL_W*THUMBNAIL_H, 1, fp );
662                         
663                         #if defined(POLY_ACC)
664                                         PA_DFX (pa_alpha_always());     
665                                         PA_DFX (pa_set_frontbuffer_current());
666                                         PA_DFX(gr_bitmap(0,0,&save_cnv2->cv_bitmap));
667                                         PA_DFX (pa_set_backbuffer_current());
668                                         gr_bitmap(0,0,&save_cnv2->cv_bitmap);
669                                         gr_free_canvas(save_cnv2);
670                                         PA_DFX (pa_fool_to_offscreen());
671                         
672                         #endif
673                 
674                 #else   // macintosh stuff below
675                 {
676                         #if defined(POLY_ACC)
677                                 int     savePAEnabled = PAEnabled;
678                                 PAEnabled = false;
679                         #endif
680
681                         gr_set_current_canvas( cnv );
682                         render_frame(0, 0);
683                         pal = gr_palette;
684                         fwrite( cnv->cv_bitmap.bm_data, THUMBNAIL_W*THUMBNAIL_H, 1, fp );
685                         
686                         #if defined(POLY_ACC)
687                                 PAEnabled = savePAEnabled;
688                         #endif
689                 }       
690                 #endif  // end of ifndef macintosh
691                 
692                 
693                 WINDOS(
694                         dd_gr_set_current_canvas(cnv_save),
695                         gr_set_current_canvas(cnv_save)
696                 );
697                 gr_free_canvas( cnv );
698                 fwrite( pal, 3, 256, fp);
699         }
700         else
701         {
702                 ubyte color = 0;
703                 for ( i=0; i<THUMBNAIL_W*THUMBNAIL_H; i++ )
704                         fwrite( &color, sizeof(ubyte), 1, fp );         
705         } 
706
707 // Save the Between levels flag...
708         fwrite( &between_levels, sizeof(int), 1, fp );
709
710 // Save the mission info...
711         mprintf ((0,"HEY! Mission name is %s\n",Mission_list[Current_mission_num].filename));
712         fwrite( &Mission_list[Current_mission_num], sizeof(char)*9, 1, fp );
713
714 //Save level info
715         fwrite( &Current_level_num, sizeof(int), 1, fp );
716         fwrite( &Next_level_num, sizeof(int), 1, fp );
717
718 //Save GameTime
719         fwrite( &GameTime, sizeof(fix), 1, fp );
720
721 // If coop save, save all
722 #ifdef NETWORK
723    if (Game_mode & GM_MULTI_COOP)
724          {
725                 fwrite (&state_game_id,sizeof(int),1,fp);
726                 fwrite (&Netgame,sizeof(netgame_info),1,fp);            
727                 fwrite (&NetPlayers,sizeof(AllNetPlayers_info),1,fp);
728                 fwrite (&N_players,sizeof(int),1,fp);
729                 fwrite (&Player_num,sizeof(int),1,fp);
730                 for (i=0;i<N_players;i++)
731                  fwrite (&Players[i],sizeof(player),1,fp);
732
733 #ifdef RISKY_PROPOSITION
734            fwrite (&robot_controlled[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
735            fwrite (&robot_agitation[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
736            fwrite (&robot_controlled_time[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
737            fwrite (&robot_last_send_time[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
738            fwrite (&robot_last_message_time[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
739            fwrite (&robot_send_pending[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
740            fwrite (&robot_fired[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
741  
742       for (i=0;i<MAX_ROBOTS_CONTROLLED;i++)
743                    fwrite (robot_fire_buf[i][0],18+3,1,fp);
744 #endif
745
746          }
747 #endif
748
749 //Save player info
750         fwrite( &Players[Player_num], sizeof(player), 1, fp );
751
752 // Save the current weapon info
753         fwrite( &Primary_weapon, sizeof(byte), 1, fp );
754         fwrite( &Secondary_weapon, sizeof(byte), 1, fp );
755
756 // Save the difficulty level
757         fwrite( &Difficulty_level, sizeof(int), 1, fp );
758 // Save cheats enabled
759         fwrite (&Cheats_enabled,sizeof(int),1,fp);
760
761         if ( !between_levels )  {
762
763         //Finish all morph objects
764                 for (i=0; i<=Highest_object_index; i++ )        {
765                         if ( (Objects[i].type != OBJ_NONE) && (Objects[i].render_type==RT_MORPH))       {
766                                 morph_data *md;
767                                 md = find_morph_data(&Objects[i]);
768                                 if (md) {                                       
769                                         md->obj->control_type = md->morph_save_control_type;
770                                         md->obj->movement_type = md->morph_save_movement_type;
771                                         md->obj->render_type = RT_POLYOBJ;
772                                         md->obj->mtype.phys_info = md->morph_save_phys_info;
773                                         md->obj = NULL;
774                                 } else {                                                //maybe loaded half-morphed from disk
775                                         Objects[i].flags |= OF_SHOULD_BE_DEAD;
776                                         Objects[i].render_type = RT_POLYOBJ;
777                                         Objects[i].control_type = CT_NONE;
778                                         Objects[i].movement_type = MT_NONE;
779                                 }
780                         }
781                 }
782         
783         //Save object info
784                 i = Highest_object_index+1;
785                 fwrite( &i, sizeof(int), 1, fp );
786                 fwrite( Objects, sizeof(object)*i, 1, fp );
787                 
788         //Save wall info
789                 i = Num_walls;
790                 fwrite( &i, sizeof(int), 1, fp );
791                 fwrite( Walls, sizeof(wall)*i, 1, fp );
792
793         //Save exploding wall info
794                 i = MAX_EXPLODING_WALLS;
795                 fwrite( &i, sizeof(int), 1, fp);
796                 fwrite( expl_wall_list, sizeof(*expl_wall_list), i, fp );
797         
798         //Save door info
799                 i = Num_open_doors;
800                 fwrite( &i, sizeof(int), 1, fp );
801                 fwrite( ActiveDoors, sizeof(active_door)*i, 1, fp );
802         
803         //Save cloaking wall info
804                 i = Num_cloaking_walls;
805                 fwrite( &i, sizeof(int), 1, fp );
806                 fwrite( CloakingWalls, sizeof(cloaking_wall), i, fp );
807         
808         //Save trigger info
809                 fwrite( &Num_triggers, sizeof(int), 1, fp );
810                 fwrite( Triggers, sizeof(trigger)*Num_triggers, 1, fp );
811         
812         //Save tmap info
813                 for (i=0; i<=Highest_segment_index; i++ )       {
814                         for (j=0; j<6; j++ )    {
815                                 fwrite( &Segments[i].sides[j].wall_num, sizeof(short), 1, fp );
816                                 fwrite( &Segments[i].sides[j].tmap_num, sizeof(short), 1, fp );
817                                 fwrite( &Segments[i].sides[j].tmap_num2, sizeof(short), 1, fp );
818                         }
819                 }
820         
821         // Save the fuelcen info
822                 fwrite( &Control_center_destroyed, sizeof(int), 1, fp );
823                 fwrite( &Countdown_timer, sizeof(int), 1, fp );
824                 fwrite( &Num_robot_centers, sizeof(int), 1, fp );
825                 fwrite( RobotCenters, sizeof(matcen_info)*Num_robot_centers, 1, fp );
826                 fwrite( &ControlCenterTriggers, sizeof(control_center_triggers), 1, fp );
827                 fwrite( &Num_fuelcenters, sizeof(int), 1, fp );
828                 fwrite( Station, sizeof(FuelCenter)*Num_fuelcenters, 1, fp );
829         
830         // Save the control cen info
831                 fwrite( &Control_center_been_hit, sizeof(int), 1, fp );
832                 fwrite( &Control_center_player_been_seen, sizeof(int), 1, fp );
833                 fwrite( &Control_center_next_fire_time, sizeof(int), 1, fp );
834                 fwrite( &Control_center_present, sizeof(int), 1, fp );
835                 fwrite( &Dead_controlcen_object_num, sizeof(int), 1, fp );
836         
837         // Save the AI state
838                 ai_save_state( fp );
839         
840         // Save the automap visited info
841                 fwrite( Automap_visited, sizeof(ubyte)*MAX_SEGMENTS, 1, fp );
842
843         }
844         fwrite( &state_game_id, sizeof(uint), 1, fp );
845         fwrite( &Laser_rapid_fire, sizeof(int), 1, fp );
846         fwrite( &Lunacy, sizeof(int), 1, fp );          //      Yes, writing this twice.  Removed the Ugly robot system, but didn't want to change savegame format.
847         fwrite( &Lunacy, sizeof(int), 1, fp );
848
849         // Save automap marker info
850
851         fwrite(MarkerObject,sizeof(MarkerObject),1,fp);
852         fwrite(MarkerOwner,sizeof(MarkerOwner),1,fp);
853         fwrite(MarkerMessage,sizeof(MarkerMessage),1,fp);
854
855         fwrite (&Afterburner_charge,sizeof(fix),1,fp);
856
857         //save last was super information
858         fwrite(&Primary_last_was_super,sizeof(Primary_last_was_super),1,fp);
859         fwrite(&Secondary_last_was_super,sizeof(Secondary_last_was_super),1,fp);
860
861         //      Save flash effect stuff
862         fwrite( &Flash_effect, sizeof(int), 1, fp );
863         fwrite( &Time_flash_last_played, sizeof(int), 1, fp );
864         fwrite( &PaletteRedAdd, sizeof(int), 1, fp);
865         fwrite( &PaletteGreenAdd, sizeof(int), 1, fp);
866         fwrite( &PaletteBlueAdd, sizeof(int), 1, fp);
867
868         fwrite(Light_subtracted, sizeof(Light_subtracted[0]), MAX_SEGMENTS, fp);
869
870         fwrite(&First_secret_visit, sizeof(First_secret_visit), 1, fp);
871
872         fwrite(&Omega_charge, sizeof(Omega_charge), 1, fp);
873         
874         if ( ferror(fp) ) {
875                 if ( !(Game_mode & GM_MULTI) ) {
876                         nm_messagebox(NULL, 1, TXT_OK, "Error writing savegame.\nPossibly out of disk\nspace.");
877                         fclose(fp);
878                         unlink(filename);
879                 }
880         } else  {
881                 fclose(fp);
882
883                 #ifdef MACINTOSH                // set the type and creator of the saved game file
884                 {
885                         FInfo finfo;
886                         OSErr err;
887                         Str255 pfilename;
888         
889                         strcpy(pfilename, filename);
890                         c2pstr(pfilename);
891                         err = HGetFInfo(0, 0, pfilename, &finfo);
892                         finfo.fdType = 'SVGM';
893                         finfo.fdCreator = 'DCT2';
894                         err = HSetFInfo(0, 0, pfilename, &finfo);
895                 }
896                 #endif
897         }
898         
899         start_time();
900
901         return 1;
902 }
903
904 //      -----------------------------------------------------------------------------------
905 //      Set the player's position from the globals Secret_return_segment and Secret_return_orient.
906 void set_pos_from_return_segment(void)
907 {
908         int     plobjnum = Players[Player_num].objnum;
909
910         compute_segment_center(&Objects[plobjnum].pos, &Segments[Secret_return_segment]);
911         obj_relink(plobjnum, Secret_return_segment);
912         reset_player_object();
913         Objects[plobjnum].orient = Secret_return_orient;
914 }
915
916 //      -----------------------------------------------------------------------------------
917 int state_restore_all(int in_game, int secret_restore, char *filename_override)
918 {
919         char filename[128];
920         int     filenum = -1;
921
922 #ifdef NETWORK
923         if ( Game_mode & GM_MULTI )     {
924 #ifdef MULTI_SAVE
925                         multi_initiate_restore_game();
926 #endif
927                 return 0;
928         }
929 #endif
930
931         if (in_game && (Current_level_num < 0) && (secret_restore == 0)) {
932                 HUD_init_message( "Can't restore in secret level!" );
933                 return 0;
934         }
935
936         if ( Newdemo_state == ND_STATE_RECORDING )
937                 newdemo_stop_recording();
938
939         if ( Newdemo_state != ND_STATE_NORMAL )
940                 return 0;
941
942         stop_time();
943
944         if (filename_override) {
945                 strcpy(filename, filename_override);
946                 filenum = NUM_SAVES+1;          //      So we don't trigger autosave
947         } else if (!(filenum = state_get_restore_file(filename, 0)))    {
948                 start_time();
949                 return 0;
950         }
951         
952         //      MK, 1/1/96
953         //      If not in multiplayer, do special secret level stuff.
954         //      If Nsecret.sgc (where N = filenum) exists, then copy it to secret.sgc.
955         //      If it doesn't exist, then delete secret.sgc
956         if (!secret_restore && !(Game_mode & GM_MULTI)) {
957                 int     rval;
958                 char    temp_fname[32], fc;
959
960                 if (filenum != -1) {
961                         if (filenum >= 10)
962                                 fc = (filenum-10) + 'a';
963                         else
964                                 fc = '0' + filenum;
965                         
966                         #ifndef MACINTOSH
967                         sprintf(temp_fname, "%csecret.sgc", fc);
968                         #else
969                         sprintf(temp_fname, ":Players:%csecret.sgc", fc);
970                         #endif
971
972                         mprintf((0, "Trying to copy %s to secret.sgc.\n", temp_fname));
973
974                         if (file_exists(temp_fname)) {
975                                 mprintf((0, "Copying %s to secret.sgc\n", temp_fname));
976                                 rval = copy_file(temp_fname, SECRETC_FILENAME);
977                                 Assert(rval == 0);      //      Oops, error copying temp_fname to secret.sgc!
978                         } else
979                                 unlink(SECRETC_FILENAME);
980                 }
981         }
982
983         //      Changed, 11/15/95, MK, don't to autosave if restoring from main menu.
984         if ((filenum != (NUM_SAVES+1)) && in_game) {
985                 char    temp_filename[128];
986                 mprintf((0, "Doing autosave, filenum = %i, != %i!\n", filenum, NUM_SAVES+1));
987                 #ifndef MACINTOSH
988                 sprintf( temp_filename, "%s.sg%x", Players[Player_num].callsign, NUM_SAVES );
989                 #else
990                 sprintf( temp_filename, ":Players:%s.sg%x", Players[Player_num].callsign, NUM_SAVES );
991                 #endif          
992                 state_save_all(!in_game, secret_restore, temp_filename);
993         }
994
995         if ( !secret_restore && in_game ) {
996                 int choice;
997                 choice =  nm_messagebox( NULL, 2, "Yes", "No", "Restore Game?" );
998                 if ( choice != 0 )      {
999                         start_time();
1000                         return 0;
1001                 }
1002         }
1003
1004         start_time();
1005
1006         return state_restore_all_sub(filename, 0, secret_restore);
1007 }
1008
1009 extern void reset_player_object(void);
1010 extern void init_player_stats_new_ship(void);
1011
1012 void ShowLevelIntro(int level_num);
1013
1014 extern void do_cloak_invul_secret_stuff(fix old_gametime);
1015 extern void copy_defaults_to_robot(object *objp);
1016
1017 int state_restore_all_sub(char *filename, int multi, int secret_restore)
1018 {
1019         int ObjectStartLocation;
1020         int version,i, j, segnum,found;
1021         object * obj;
1022         FILE *fp;
1023         int current_level, next_level;
1024         int between_levels;
1025         char mission[16];
1026         char desc[DESC_LENGTH+1];
1027         char id[5];
1028         char org_callsign[CALLSIGN_LEN+16];
1029         int nplayers;   //,playid[12],mynum;
1030         player restore_players[MAX_PLAYERS];
1031         fix     old_gametime = GameTime;
1032         
1033         #if defined(MACINTOSH) && !defined(NDEBUG) 
1034         if ( strncmp(filename, ":Players:", 9) )
1035                 Int3();
1036         #endif
1037
1038         fp = fopen( filename, "rb" );
1039         if ( !fp ) return 0;
1040
1041 //Read id
1042         fread( id, sizeof(char)*4, 1, fp );
1043         if ( memcmp( id, dgss_id, 4 )) {
1044                 fclose(fp);
1045                 return 0;
1046         }
1047
1048 //Read version
1049         fread( &version, sizeof(int), 1, fp );
1050         if (version < STATE_COMPATIBLE_VERSION) {
1051                 fclose(fp);
1052                 return 0;
1053         }
1054
1055 // Read description
1056         fread( desc, sizeof(char)*DESC_LENGTH, 1, fp );
1057
1058 // Skip the current screen shot...
1059         fseek( fp, THUMBNAIL_W*THUMBNAIL_H, SEEK_CUR );
1060
1061 // And now...skip the goddamn palette stuff that somebody forgot to add
1062         fseek( fp, 768, SEEK_CUR );
1063
1064 // Read the Between levels flag...
1065         fread( &between_levels, sizeof(int), 1, fp );
1066
1067         Assert(between_levels == 0);    //between levels save ripped out
1068
1069 // Read the mission info...
1070         fread( mission, sizeof(char)*9, 1, fp );
1071         mprintf ((0,"Missionname to load = %s\n",mission));
1072
1073         if (!load_mission_by_name( mission ))   {
1074                 nm_messagebox( NULL, 1, "Ok", "Error!\nUnable to load mission\n'%s'\n", mission );
1075                 fclose(fp);
1076                 return 0;
1077         }
1078
1079 //Read level info
1080         fread( &current_level, sizeof(int), 1, fp );
1081         fread( &next_level, sizeof(int), 1, fp );
1082
1083 //Restore GameTime
1084         fread( &GameTime, sizeof(fix), 1, fp );
1085
1086 // Start new game....
1087         if (!multi)     {
1088                 Game_mode = GM_NORMAL;
1089                 Function_mode = FMODE_GAME;
1090 #ifdef NETWORK
1091                 change_playernum_to(0);
1092 #endif
1093                 strcpy( org_callsign, Players[0].callsign );
1094                 N_players = 1;
1095                 if (!secret_restore) {
1096                         InitPlayerObject();                             //make sure player's object set up
1097                         init_player_stats_game();               //clear all stats
1098                 }
1099         } else {
1100                 strcpy( org_callsign, Players[Player_num].callsign );
1101         }
1102
1103 #ifdef NETWORK
1104    if (Game_mode & GM_MULTI)
1105          {
1106                 fread (&state_game_id,sizeof(int),1,fp);
1107                 fread (&Netgame,sizeof(netgame_info),1,fp);             
1108                 fread (&NetPlayers,sizeof(AllNetPlayers_info),1,fp);
1109                 fread (&nplayers,sizeof(N_players),1,fp);
1110                 fread (&Player_num,sizeof(Player_num),1,fp);
1111                 for (i=0;i<nplayers;i++)
1112                  fread (&restore_players[i],sizeof(player),1,fp);
1113 #ifdef RISKY_PROPOSITION
1114            fread (&robot_controlled[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
1115            fread (&robot_agitation[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
1116            fread (&robot_controlled_time[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
1117            fread (&robot_last_send_time[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
1118            fread (&robot_last_message_time[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
1119            fread (&robot_send_pending[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
1120            fread (&robot_fired[0],4*MAX_ROBOTS_CONTROLLED,1,fp);
1121  
1122       for (i=0;i<MAX_ROBOTS_CONTROLLED;i++)
1123                    fread (&robot_fire_buf[i][0],21,1,fp);
1124 #endif
1125
1126            for (i=0;i<nplayers;i++)
1127                  {
1128                   found=0;
1129                   for (j=0;j<nplayers;j++)
1130                          {
1131            if ((!strcmp (restore_players[i].callsign,Players[j].callsign)) && Players[j].connected==1)
1132                                  found=1;
1133                          }
1134                   restore_players[i].connected=found;
1135             }
1136                 memcpy (&Players,&restore_players,sizeof(player)*nplayers);
1137                 N_players=nplayers;
1138                
1139       if (network_i_am_master())
1140                  {
1141                   for (i=0;i<N_players;i++)
1142                         {
1143                          if (i==Player_num)
1144                                 continue;
1145                  Players[i].connected=0;        
1146                         }
1147                  }
1148                  
1149                 //Viewer = ConsoleObject = &Objects[Players[Player_num].objnum];
1150          }
1151
1152 #endif
1153
1154 //Read player info
1155
1156         {
1157                 StartNewLevelSub(current_level, 1, secret_restore);
1158
1159                 if (secret_restore) {
1160                         player  dummy_player;
1161
1162                         fread( &dummy_player, sizeof(player), 1, fp );
1163                         if (secret_restore == 1) {              //      This means he didn't die, so he keeps what he got in the secret level.
1164                                 Players[Player_num].level = dummy_player.level;
1165                                 Players[Player_num].last_score = dummy_player.last_score;
1166                                 Players[Player_num].time_level = dummy_player.time_level;
1167
1168                                 Players[Player_num].num_robots_level = dummy_player.num_robots_level;
1169                                 Players[Player_num].num_robots_total = dummy_player.num_robots_total;
1170                                 Players[Player_num].hostages_rescued_total = dummy_player.hostages_rescued_total;
1171                                 Players[Player_num].hostages_total = dummy_player.hostages_total;
1172                                 Players[Player_num].hostages_on_board = dummy_player.hostages_on_board;
1173                                 Players[Player_num].hostages_level = dummy_player.hostages_level;
1174                                 Players[Player_num].homing_object_dist = dummy_player.homing_object_dist;
1175                                 Players[Player_num].hours_level = dummy_player.hours_level;
1176                                 Players[Player_num].hours_total = dummy_player.hours_total;
1177                                 do_cloak_invul_secret_stuff(old_gametime);
1178                         } else {
1179                                 Players[Player_num] = dummy_player;
1180                         }
1181                 } else {
1182                         fread( &Players[Player_num], sizeof(player), 1, fp );
1183                 }
1184         }
1185         strcpy( Players[Player_num].callsign, org_callsign );
1186
1187 // Set the right level
1188         if ( between_levels )
1189                 Players[Player_num].level = next_level;
1190
1191 // Restore the weapon states
1192         fread( &Primary_weapon, sizeof(byte), 1, fp );
1193         fread( &Secondary_weapon, sizeof(byte), 1, fp );
1194
1195         select_weapon(Primary_weapon, 0, 0, 0);
1196         select_weapon(Secondary_weapon, 1, 0, 0);
1197
1198 // Restore the difficulty level
1199         fread( &Difficulty_level, sizeof(int), 1, fp );
1200
1201 // Restore the cheats enabled flag
1202  
1203    fread (&Cheats_enabled,sizeof(int),1,fp);
1204
1205         if ( !between_levels )  {
1206                 Do_appearance_effect = 0;                       // Don't do this for middle o' game stuff.
1207
1208                 ObjectStartLocation = ftell( fp );
1209                 //Clear out all the objects from the lvl file
1210                 for (segnum=0; segnum <= Highest_segment_index; segnum++)
1211                         Segments[segnum].objects = -1;
1212                 reset_objects(1);
1213         
1214                 //Read objects, and pop 'em into their respective segments.
1215                 fread( &i, sizeof(int), 1, fp );
1216                 Highest_object_index = i-1;
1217                 fread( Objects, sizeof(object)*i, 1, fp );
1218         
1219                 Object_next_signature = 0;
1220                 for (i=0; i<=Highest_object_index; i++ )        {
1221                         obj = &Objects[i];
1222                         obj->rtype.pobj_info.alt_textures = -1;
1223                         segnum = obj->segnum;
1224                         obj->next = obj->prev = obj->segnum = -1;
1225                         if ( obj->type != OBJ_NONE )    {
1226                                 obj_link(i,segnum);
1227                                 if ( obj->signature > Object_next_signature )
1228                                         Object_next_signature = obj->signature;
1229                         }
1230
1231                         //look for, and fix, boss with bogus shields
1232                         if (obj->type == OBJ_ROBOT && Robot_info[obj->id].boss_flag) {
1233                                 fix save_shields = obj->shields;
1234
1235                                 copy_defaults_to_robot(obj);            //calculate starting shields
1236
1237                                 //if in valid range, use loaded shield value
1238                                 if (save_shields > 0 && save_shields <= obj->shields)
1239                                         obj->shields = save_shields;
1240                                 else
1241                                         obj->shields /= 2;  //give player a break
1242                         }
1243
1244                 }       
1245                 special_reset_objects();
1246                 Object_next_signature++;
1247         
1248                 //      1 = Didn't die on secret level.
1249                 //      2 = Died on secret level.
1250                 if (secret_restore && (Current_level_num >= 0)) {
1251                         set_pos_from_return_segment();
1252                         if (secret_restore == 2)
1253                                 init_player_stats_new_ship();
1254                 }
1255
1256                 //Restore wall info
1257                 fread( &i, sizeof(int), 1, fp );
1258                 Num_walls = i;
1259                 fread( Walls, sizeof(wall)*Num_walls, 1, fp );
1260
1261                 //now that we have the walls, check if any sounds are linked to
1262                 //walls that are now open
1263                 for (i=0;i<Num_walls;i++) {
1264                         if (Walls[i].type == WALL_OPEN)
1265                                 digi_kill_sound_linked_to_segment(Walls[i].segnum,Walls[i].sidenum,-1); //-1 means kill any sound
1266                 }
1267
1268                 //Restore exploding wall info
1269                 if (version >= 10) {
1270                         fread( &i, sizeof(int), 1, fp );
1271                         fread( expl_wall_list, sizeof(*expl_wall_list), i, fp );
1272                 }
1273
1274                 //Restore door info
1275                 fread( &i, sizeof(int), 1, fp );
1276                 Num_open_doors = i;
1277                 fread( ActiveDoors, sizeof(active_door)*Num_open_doors, 1, fp );
1278         
1279                 if (version >= 14) {            //Restore cloaking wall info
1280                         fread( &i, sizeof(int), 1, fp );
1281                         Num_cloaking_walls = i;
1282                         fread( CloakingWalls, sizeof(cloaking_wall), Num_cloaking_walls, fp );
1283                 }
1284         
1285                 //Restore trigger info
1286                 fread( &Num_triggers, sizeof(int), 1, fp );
1287                 fread( Triggers, sizeof(trigger)*Num_triggers, 1, fp );
1288         
1289                 //Restore tmap info
1290                 for (i=0; i<=Highest_segment_index; i++ )       {
1291                         for (j=0; j<6; j++ )    {
1292                                 fread( &Segments[i].sides[j].wall_num, sizeof(short), 1, fp );
1293                                 fread( &Segments[i].sides[j].tmap_num, sizeof(short), 1, fp );
1294                                 fread( &Segments[i].sides[j].tmap_num2, sizeof(short), 1, fp );
1295                         }
1296                 }
1297         
1298                 //Restore the fuelcen info
1299                 fread( &Control_center_destroyed, sizeof(int), 1, fp );
1300                 fread( &Countdown_timer, sizeof(int), 1, fp );
1301                 fread( &Num_robot_centers, sizeof(int), 1, fp );
1302                 fread( RobotCenters, sizeof(matcen_info)*Num_robot_centers, 1, fp );
1303                 fread( &ControlCenterTriggers, sizeof(control_center_triggers), 1, fp );
1304                 fread( &Num_fuelcenters, sizeof(int), 1, fp );
1305                 fread( Station, sizeof(FuelCenter)*Num_fuelcenters, 1, fp );
1306         
1307                 // Restore the control cen info
1308                 fread( &Control_center_been_hit, sizeof(int), 1, fp );
1309                 fread( &Control_center_player_been_seen, sizeof(int), 1, fp );
1310                 fread( &Control_center_next_fire_time, sizeof(int), 1, fp );
1311                 fread( &Control_center_present, sizeof(int), 1, fp );
1312                 fread( &Dead_controlcen_object_num, sizeof(int), 1, fp );
1313         
1314                 // Restore the AI state
1315                 ai_restore_state( fp, version );
1316         
1317                 // Restore the automap visited info
1318                 fread( Automap_visited, sizeof(ubyte)*MAX_SEGMENTS, 1, fp );
1319
1320                 //      Restore hacked up weapon system stuff.
1321                 Fusion_next_sound_time = GameTime;
1322                 Auto_fire_fusion_cannon_time = 0;
1323                 Next_laser_fire_time = GameTime;
1324                 Next_missile_fire_time = GameTime;
1325                 Last_laser_fired_time = GameTime;
1326
1327         }
1328         state_game_id = 0;
1329
1330         if ( version >= 7 )     {
1331                 fread( &state_game_id, sizeof(uint), 1, fp );
1332                 fread( &Laser_rapid_fire, sizeof(int), 1, fp );
1333                 fread( &Lunacy, sizeof(int), 1, fp );           //      Yes, writing this twice.  Removed the Ugly robot system, but didn't want to change savegame format.
1334                 fread( &Lunacy, sizeof(int), 1, fp );
1335                 if ( Lunacy )
1336                         do_lunacy_on();
1337         }
1338
1339         if (version >= 17) {
1340                 fread(MarkerObject,sizeof(MarkerObject),1,fp);
1341                 fread(MarkerOwner,sizeof(MarkerOwner),1,fp);
1342                 fread(MarkerMessage,sizeof(MarkerMessage),1,fp);
1343         }
1344         else {
1345                 int num,dummy;
1346
1347                 // skip dummy info
1348
1349                 fread (&num,sizeof(int),1,fp);                  //was NumOfMarkers
1350                 fread (&dummy,sizeof(int),1,fp);                        //was CurMarker
1351
1352                 fseek( fp, num * (sizeof(vms_vector) + 40), SEEK_CUR );
1353
1354                 for (num=0;num<NUM_MARKERS;num++)
1355                         MarkerObject[num] = -1;
1356         }
1357
1358         if (version>=11)
1359                 if (secret_restore != 1)
1360                         fread (&Afterburner_charge,sizeof(fix),1,fp);
1361                 else {
1362                         fix     dummy_fix;
1363                         fread (&dummy_fix,sizeof(fix),1,fp);
1364                 }
1365
1366         if (version>=12) {
1367                 //read last was super information
1368                 fread(&Primary_last_was_super,sizeof(Primary_last_was_super),1,fp);
1369                 fread(&Secondary_last_was_super,sizeof(Secondary_last_was_super),1,fp);
1370         }
1371
1372         if (version >= 12) {
1373                 fread( &Flash_effect, sizeof(int), 1, fp );
1374                 fread( &Time_flash_last_played, sizeof(int), 1, fp );
1375                 fread( &PaletteRedAdd, sizeof(int), 1, fp);
1376                 fread( &PaletteGreenAdd, sizeof(int), 1, fp);
1377                 fread( &PaletteBlueAdd, sizeof(int), 1, fp);
1378         } else {
1379                 Flash_effect = 0;
1380                 Time_flash_last_played = 0;
1381                 PaletteRedAdd = 0;
1382                 PaletteGreenAdd = 0;
1383                 PaletteBlueAdd = 0;
1384         }
1385
1386         //      Load Light_subtracted
1387         if (version >= 16) {
1388                 fread(Light_subtracted, sizeof(Light_subtracted[0]), MAX_SEGMENTS, fp);
1389                 apply_all_changed_light();
1390                 compute_all_static_light();     //      set static_light field in segment struct.  See note at that function.
1391         } else {
1392                 int     i;
1393                 for (i=0; i<=Highest_segment_index; i++)
1394                         Light_subtracted[i] = 0;
1395         }
1396    
1397         if (!secret_restore) {
1398                 if (version >= 20) {
1399                         fread(&First_secret_visit, sizeof(First_secret_visit), 1, fp);
1400                         mprintf((0, "File: [%s] Read First_secret_visit: New value = %i\n", filename, First_secret_visit));
1401                 } else
1402                         First_secret_visit = 1;
1403         } else
1404                 First_secret_visit = 0;
1405
1406         if (version >= 22)
1407         {
1408                 if (secret_restore != 1)
1409                         fread (&Omega_charge,sizeof(fix),1,fp);
1410                 else {
1411                         fix     dummy_fix;
1412                         fread (&dummy_fix,sizeof(fix),1,fp);
1413                 }
1414         }
1415
1416         fclose(fp);
1417  
1418 #ifdef NETWORK
1419    if (Game_mode & GM_MULTI)   // Get rid of ships that aren't 
1420          {                                                                       // connected in the restored game
1421                 for (i=0;i<nplayers;i++)
1422                  {
1423                   mprintf ((0,"Testing %s = %d\n",Players[i].callsign,Players[i].connected));
1424                   if (Players[i].connected!=1)
1425                    {
1426                     network_disconnect_player (i);
1427                create_player_appearance_effect(&Objects[Players[i].objnum]);
1428                          mprintf ((0,"Killing player ship %s!\n",Players[i].callsign));
1429               }
1430                  }
1431                         
1432          }
1433 #endif
1434
1435 // Load in bitmaps, etc..
1436 //!!    piggy_load_level_data();        //already done by StartNewLevelSub()
1437
1438         return 1;
1439 }
1440
1441 //      When loading a saved game, segp->static_light is bogus.
1442 //      This is because apply_all_changed_light, which is supposed to properly update this value,
1443 //      cannot do so because it needs the original light cast from a light which is no longer there.
1444 //      That is, a light has been blown out, so the texture remaining casts 0 light, but the static light
1445 //      which is present in the static_light field contains the light cast from that light.
1446 void compute_all_static_light(void)
1447 {
1448         int     i, j, k;
1449
1450         for (i=0; i<=Highest_segment_index; i++) {
1451                 fix     total_light;
1452                 segment *segp;
1453
1454                 segp = &Segments[i];
1455                 total_light = 0;
1456
1457                 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
1458                         side    *sidep;
1459
1460                         sidep = &segp->sides[j];
1461
1462                         for (k=0; k<4; k++)
1463                                 total_light += sidep->uvls[k].l;
1464                 }
1465
1466                 Segment2s[i].static_light = total_light/(MAX_SIDES_PER_SEGMENT*4);
1467         }
1468
1469 }
1470
1471
1472 int state_get_game_id(char *filename)
1473 {
1474         int version;
1475         FILE *fp;
1476         int between_levels;
1477         char mission[16];
1478         char desc[DESC_LENGTH+1];
1479         char id[5];
1480         int dumbint;
1481
1482 mprintf((0, "Restoring multigame from [%s]\n", filename));
1483
1484         fp = fopen( filename, "rb" );
1485         if ( !fp ) return 0;
1486
1487 //Read id
1488         fread( id, sizeof(char)*4, 1, fp );
1489         if ( memcmp( id, dgss_id, 4 )) {
1490                 fclose(fp);
1491                 return 0;
1492         }
1493
1494 //Read version
1495         fread( &version, sizeof(int), 1, fp );
1496         if (version < STATE_COMPATIBLE_VERSION) {
1497                 fclose(fp);
1498                 return 0;
1499         }
1500
1501 // Read description
1502         fread( desc, sizeof(char)*DESC_LENGTH, 1, fp );
1503
1504 // Skip the current screen shot...
1505         fseek( fp, THUMBNAIL_W*THUMBNAIL_H, SEEK_CUR );
1506
1507 // And now...skip the palette stuff that somebody forgot to add
1508         fseek( fp, 768, SEEK_CUR );
1509
1510 // Read the Between levels flag...
1511         fread( &between_levels, sizeof(int), 1, fp );
1512
1513         Assert(between_levels == 0);    //between levels save ripped out
1514
1515 // Read the mission info...
1516         fread( mission, sizeof(char)*9, 1, fp );
1517 //Read level info
1518         fread( &dumbint, sizeof(int), 1, fp );
1519         fread( &dumbint, sizeof(int), 1, fp );
1520
1521 //Restore GameTime
1522         fread( &dumbint, sizeof(fix), 1, fp );
1523
1524         fread (&state_game_id,sizeof(int),1,fp);
1525
1526         return (state_game_id);
1527  }
1528
1529 #if defined(POLY_ACC)
1530 //void screen_shot_pa(ubyte *dst,ushort *src)
1531 //{
1532 //    //ushort *src = pa_get_buffer_address(0),
1533 //    ushort *s;
1534 //    fix u, v, du, dv;
1535 //    int ui, w, h;
1536 //
1537 //    pa_flush();
1538 //
1539 //    du = (640.0 / (float)THUMBNAIL_W) * 65536.0;
1540 //    dv = (480.0 / (float)THUMBNAIL_H) * 65536.0;
1541 //
1542 //    for(v = h = 0; h != THUMBNAIL_H; ++h)
1543 //    {
1544 //        s = src + f2i(v) * 640;
1545 //        v += dv;
1546 //        for(u = w = 0; w != THUMBNAIL_W; ++w)
1547 //        {
1548 //            ui = f2i(u);
1549 //            *dst++ = gr_find_closest_color((s[ui] >> 9) & 0x3e, (s[ui] >> 4) & 0x3e, (s[ui] << 1) & 0x3e);
1550 //            u += du;
1551 //        }
1552 //    }
1553 //}
1554
1555 void screen_shot_pa(grs_canvas *dcanv,grs_canvas *scanv)
1556 {
1557 #if !defined(MACINTOSH)
1558         ubyte *dst;
1559         ushort *src;
1560         int x,y;
1561
1562         Assert(scanv->cv_w == dcanv->cv_w && scanv->cv_h == dcanv->cv_h);
1563
1564         pa_flush();
1565
1566         src = (ushort *) scanv->cv_bitmap.bm_data;
1567         dst = dcanv->cv_bitmap.bm_data;
1568
1569         #ifdef PA_3DFX_VOODOO
1570    src=(ushort *)pa_set_back_to_read();
1571         #endif
1572
1573         for (y=0; y<scanv->cv_h; y++) {
1574                 for (x=0; x<scanv->cv_w; x++) {
1575                         #ifdef PA_3DFX_VOODOO
1576                         *dst++ = gr_find_closest_color((*src >> 10) & 0x3e, (*src >> 5) & 0x3f, (*src << 1) & 0x3e);
1577                         #else
1578                         *dst++ = gr_find_closest_color((*src >> 9) & 0x3e, (*src >> 4) & 0x3e, (*src << 1) & 0x3e);
1579                         #endif
1580
1581                         src++;
1582                 }
1583                 src = (ushort *) (((ubyte *) src) + (scanv->cv_bitmap.bm_rowsize - (scanv->cv_bitmap.bm_w*PA_BPP)));
1584                 dst += dcanv->cv_bitmap.bm_rowsize - dcanv->cv_bitmap.bm_w;
1585         }
1586         #ifdef PA_3DFX_VOODOO
1587         pa_set_front_to_read();
1588         #endif
1589 #endif
1590 }
1591 #endif
1592