]> icculus.org git repositories - btb/d2x.git/blob - main/playsave.c
new mission-specific cfg file, holds highest level.
[btb/d2x.git] / main / playsave.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  *
16  * Functions to load & save player's settings (*.plr file)
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <conf.h>
22 #endif
23
24 #ifdef WINDOWS
25 #include "desw.h"
26 #include <mmsystem.h>
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31 #if !defined(_MSC_VER) && !defined(macintosh)
32 #include <unistd.h>
33 #endif
34 #ifndef _WIN32_WCE
35 #include <errno.h>
36 #endif
37
38 #include <physfs.h>
39
40 #include "error.h"
41
42 #include "strutil.h"
43 #include "game.h"
44 #include "gameseq.h"
45 #include "player.h"
46 #include "playsave.h"
47 #include "joy.h"
48 #include "kconfig.h"
49 #include "digi.h"
50 #include "newmenu.h"
51 #include "joydefs.h"
52 #include "palette.h"
53 #include "multi.h"
54 #include "menu.h"
55 #include "config.h"
56 #include "text.h"
57 #include "mono.h"
58 #include "state.h"
59 #include "gauges.h"
60 #include "screens.h"
61 #include "powerup.h"
62 #include "makesig.h"
63 #include "byteswap.h"
64 #include "escort.h"
65
66 #include "physfsx.h"
67
68 #define SAVE_FILE_ID                    MAKE_SIG('D','P','L','R')
69
70 #ifdef MACINTOSH
71         #include <Files.h>
72         #include <Errors.h>                     // mac doesn't have "normal" error numbers -- must use mac equivs
73         #ifndef ENOENT
74                 #define ENOENT fnfErr
75         #endif
76         #include "isp.h"
77 #elif defined(_WIN32_WCE)
78 # define errno -1
79 # define ENOENT -1
80 # define strerror(x) "Unknown Error"
81 #endif
82
83
84 #define PLAYER_FILE_VERSION     25 //increment this every time the player file changes
85
86 //version 5  ->  6: added new highest level information
87 //version 6  ->  7: stripped out the old saved_game array.
88 //version 7  ->  8: added reticle flag, & window size
89 //version 8  ->  9: removed player_struct_version
90 //version 9  -> 10: added default display mode
91 //version 10 -> 11: added all toggles in toggle menu
92 //version 11 -> 12: added weapon ordering
93 //version 12 -> 13: added more keys
94 //version 13 -> 14: took out marker key
95 //version 14 -> 15: added guided in big window
96 //version 15 -> 16: added small windows in cockpit
97 //version 16 -> 17: ??
98 //version 17 -> 18: save guidebot name
99 //version 18 -> 19: added automap-highres flag
100 //version 19 -> 20: added kconfig data for windows joysticks
101 //version 20 -> 21: save seperate config types for DOS & Windows
102 //version 21 -> 22: save lifetime netstats 
103 //version 22 -> 23: ??
104 //version 23 -> 24: add name of joystick for windows version.
105 //version 24 -> 25: removed kconfig data, joy name, guidebot name, joy sensitivity, cockpit views, netstats, taunt macros, highest levels
106
107 #define COMPATIBLE_PLAYER_FILE_VERSION          17
108
109
110 int Default_leveling_on=1;
111
112
113 int new_player_config()
114 {
115         Player_default_difficulty = 1;
116         Auto_leveling_on = Default_leveling_on = 1;
117
118         return 1;
119 }
120
121 extern int Guided_in_big_window,Automap_always_hires;
122
123 uint32_t legacy_display_mode[] = { SM(320,200), SM(640,480), SM(320,400), SM(640,400), SM(800,600), SM(1024,768), SM(1280,1024) };
124
125 //read in the player's saved games.  returns errno (0 == no error)
126 int read_player_file()
127 {
128         #ifdef MACINTOSH
129         char filename[FILENAME_LEN+15];
130         #else
131         char filename[FILENAME_LEN];
132         #endif
133         PHYSFS_file *file;
134         int id, i;
135         short player_file_version;
136         int rewrite_it=0;
137         int swap = 0;
138
139         Assert(Player_num>=0 && Player_num<MAX_PLAYERS);
140
141         sprintf(filename, PLAYER_DIR "%.8s.plr", Players[Player_num].callsign);
142
143         if (!PHYSFS_exists(filename))
144                 return ENOENT;
145
146         file = PHYSFSX_openReadBuffered(filename);
147
148 #if 0
149 #ifndef MACINTOSH
150         //check filename
151         if (file && isatty(fileno(file))) {
152                 //if the callsign is the name of a tty device, prepend a char
153                 PHYSFS_close(file);
154                 sprintf(filename, PLAYER_DIR "$%.7s.plr",Players[Player_num].callsign);
155                 file = PHYSFSX_openReadBuffered(filename);
156         }
157 #endif
158 #endif
159
160         if (!file)
161                 goto read_player_file_failed;
162
163         PHYSFS_readSLE32(file, &id);
164
165         // SWAPINT added here because old versions of d2x
166         // used the wrong byte order.
167         if (id!=SAVE_FILE_ID && id!=SWAPINT(SAVE_FILE_ID)) {
168                 nm_messagebox(TXT_ERROR, 1, TXT_OK, "Invalid player file");
169                 PHYSFS_close(file);
170                 return -1;
171         }
172
173         player_file_version = cfile_read_short(file);
174
175         if (player_file_version > 255) // bigendian file?
176                 swap = 1;
177
178         if (swap)
179                 player_file_version = SWAPSHORT(player_file_version);
180
181         if (player_file_version<COMPATIBLE_PLAYER_FILE_VERSION) {
182                 nm_messagebox(TXT_ERROR, 1, TXT_OK, TXT_ERROR_PLR_VERSION);
183                 PHYSFS_close(file);
184                 return -1;
185         }
186
187         Game_window_w = cfile_read_short(file);
188         Game_window_h = cfile_read_short(file);
189
190         if (swap) {
191                 Game_window_w = SWAPSHORT(Game_window_w);
192                 Game_window_h = SWAPSHORT(Game_window_h);
193         }
194
195         Player_default_difficulty = cfile_read_byte(file);
196         Default_leveling_on       = cfile_read_byte(file);
197         Reticle_on                = cfile_read_byte(file);
198         Cockpit_mode              = cfile_read_byte(file);
199
200         i                         = cfile_read_byte(file);
201         Default_display_mode = legacy_display_mode[i];
202
203         Missile_view_enabled      = cfile_read_byte(file);
204         Headlight_active_default  = cfile_read_byte(file);
205         Guided_in_big_window      = cfile_read_byte(file);
206                 
207         if (player_file_version >= 19)
208                 Automap_always_hires = cfile_read_byte(file);
209
210         Auto_leveling_on = Default_leveling_on;
211
212         if (!PHYSFS_close(file))
213                 goto read_player_file_failed;
214
215         if (rewrite_it)
216                 write_player_file();
217
218         return EZERO;
219
220  read_player_file_failed:
221         nm_messagebox(TXT_ERROR, 1, TXT_OK, "%s\n\n%s", "Error reading PLR file", PHYSFS_getLastError());
222         if (file)
223                 PHYSFS_close(file);
224
225         return -1;
226 }
227
228
229 extern int Cockpit_mode_save;
230
231
232 //write out player's saved games.  returns errno (0 == no error)
233 int write_player_file()
234 {
235         char filename[FILENAME_LEN+15];
236         PHYSFS_file *file;
237         int i;
238
239 //      #ifdef APPLE_DEMO               // no saving of player files in Apple OEM version
240 //      return 0;
241 //      #endif
242
243         WriteConfigFile();
244
245         sprintf(filename, PLAYER_DIR "%s.plr", Players[Player_num].callsign);
246         file = PHYSFSX_openWriteBuffered(filename);
247
248 #if 0 //ndef MACINTOSH
249         //check filename
250         if (file && isatty(fileno(file))) {
251
252                 //if the callsign is the name of a tty device, prepend a char
253
254                 PHYSFS_close(file);
255                 sprintf(filename, PLAYER_DIR "$%.7s.plr", Players[Player_num].callsign);
256                 file = PHYSFSX_openWriteBuffered(filename);
257         }
258 #endif
259
260         if (!file)
261                 return -1;
262
263         //Write out player's info
264         PHYSFS_writeULE32(file, SAVE_FILE_ID);
265         PHYSFS_writeULE16(file, PLAYER_FILE_VERSION);
266
267         PHYSFS_writeULE16(file, Game_window_w);
268         PHYSFS_writeULE16(file, Game_window_h);
269
270         PHYSFSX_writeU8(file, Player_default_difficulty);
271         PHYSFSX_writeU8(file, Auto_leveling_on);
272         PHYSFSX_writeU8(file, Reticle_on);
273         PHYSFSX_writeU8(file, (Cockpit_mode_save!=-1)?Cockpit_mode_save:Cockpit_mode);  //if have saved mode, write it instead of letterbox/rear view
274
275         for (i = 0; i < (sizeof(legacy_display_mode) / sizeof(uint32_t)); i++) {
276                 if (legacy_display_mode[i] == Current_display_mode)
277                         break;
278         }
279         PHYSFSX_writeU8(file, i);
280
281         PHYSFSX_writeU8(file, Missile_view_enabled);
282         PHYSFSX_writeU8(file, Headlight_active_default);
283         PHYSFSX_writeU8(file, Guided_in_big_window);
284         PHYSFSX_writeU8(file, Automap_always_hires);
285
286         if (!PHYSFS_close(file))
287                 goto write_player_file_failed;
288
289         #ifdef MACINTOSH                // set filetype and creator for playerfile
290         {
291                 FInfo finfo;
292                 Str255 pfilename;
293                 OSErr err;
294
295                 strcpy(pfilename, filename);
296                 c2pstr(pfilename);
297                 err = HGetFInfo(0, 0, pfilename, &finfo);
298                 finfo.fdType = 'PLYR';
299                 finfo.fdCreator = 'DCT2';
300                 err = HSetFInfo(0, 0, pfilename, &finfo);
301         }
302         #endif
303
304         return EZERO;
305
306  write_player_file_failed:
307         nm_messagebox(TXT_ERROR, 1, TXT_OK, "%s\n\n%s", TXT_ERROR_WRITING_PLR, PHYSFS_getLastError());
308         if (file)
309         {
310                 PHYSFS_close(file);
311                 PHYSFS_delete(filename);        //delete bogus file
312         }
313
314         return -1;
315 }
316
317 //update the player's highest level.  returns errno (0 == no error)
318 int update_player_file()
319 {
320         int ret;
321
322         if ((ret=read_player_file()) != EZERO)
323                 if (ret != ENOENT)              //if file doesn't exist, that's ok
324                         return ret;
325
326         return write_player_file();
327 }
328
329 int get_lifetime_checksum (int a,int b)
330  {
331   int num;
332
333   // confusing enough to beat amateur disassemblers? Lets hope so
334
335   num=(a<<8 ^ b);
336   num^=(a | b);
337   num*=num>>2;
338   return (num);
339  }
340   
341