1 /*
2  * Triplane Classic - a side-scrolling dogfighting game.
3  * Copyright (C) 1996,1997,2009  Dodekaedron Software Creations Oy
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * tjt@users.sourceforge.net
19  */
20 
21 #include <triplane.h>
22 #include <SDL.h>
23 #include <SDL_endian.h>
24 #include "io/sound.h"
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 
33 
34 //\\ Keys
35 
36 Uint8 *key = SDL_GetKeyState(NULL);
37 struct keymap player_keys[4];
38 
39 //\\ Rosterdata
40 
41 struct rosteri roster[MAX_PLAYERS_IN_ROSTER];
42 
43 //\\ Game config
44 
45 struct configuration config;
46 
47 /*
48  * Find settings directory and create it if necessary. Directories are
49  * tried in the following order:
50  *
51  * "$TRIPLANE_HOME/"
52  * "$HOME/.triplane/" (created if missing)
53  * "" (current directory)
54  *
55  * @param pointer to FILENAME_MAX bytes where settings directory path
56  * can be written. Note that it conveniently includes trailing slash
57  * when needed for easy concatenation.
58  *
59  */
find_settings_directory(char * dir)60 static void find_settings_directory(char *dir) {
61     char *home;
62 
63     home = getenv("TRIPLANE_HOME");
64     if (home) {
65         strncpy(dir, home, FILENAME_MAX - 1);
66         strncat(dir, "/", FILENAME_MAX - 1);
67         return;
68     }
69 
70     home = getenv("HOME");
71     if (home) {
72         int ret;
73         struct stat st;
74 
75         strncpy(dir, home, FILENAME_MAX - 1);
76         strncat(dir, "/.triplane", FILENAME_MAX - 1);
77         ret = stat(dir, &st);
78         if (ret) {
79             ret = mkdir(dir, 0755);
80             if (ret) {
81                 fprintf(stderr, "Failed to create settings directory \"%s\".\n", dir);
82                 exit(1);
83             }
84         }
85         strncat(dir, "/", FILENAME_MAX - 1);
86         return;
87     }
88 
89     strncpy(dir, "", FILENAME_MAX - 1);
90 }
91 
92 /*
93  * Open file in settings directory.
94  *
95  * @param filename settings file name relative to settings directory
96  * @param mode mode to use for opening the file
97  * @return return value of fopen
98  */
settings_open(const char * filename,const char * mode)99 FILE *settings_open(const char *filename, const char *mode) {
100     char buf[FILENAME_MAX];
101     FILE *fp;
102 
103     find_settings_directory(buf);
104     strncat(buf, filename, FILENAME_MAX - 1);
105     fp = fopen(buf, mode);
106     return fp;
107 }
108 
wait_relase(void)109 void wait_relase(void) {
110     int c = 0;
111 
112     while (c != SDLK_LAST) {
113         update_key_state();
114         for (c = 0; c < SDLK_LAST; c++)
115             if (key[c] && c != SDLK_NUMLOCK && c != SDLK_CAPSLOCK && c != SDLK_SCROLLOCK)
116                 break;
117     }
118 
119 }
120 
select_key(int player,int old)121 int select_key(int player, int old) {
122     int c;
123     int flag = 1;
124 
125     while (flag) {
126         if (key[SDLK_ESCAPE])
127             flag = 0;
128 
129         update_key_state();
130 
131         for (c = 0; c < SDLK_LAST; c++)
132             if (key[c] && c != SDLK_NUMLOCK && c != SDLK_CAPSLOCK && c != SDLK_SCROLLOCK)
133                 break;
134 
135         if (c != SDLK_LAST)
136             if ((c != SDLK_ESCAPE) && (c != SDLK_PAUSE)) {
137                 wait_relase();
138                 return c;
139             }
140         if (player == 100)
141             return 100;
142     }
143 
144     wait_relase();
145     return old;
146 
147 }
148 
swap_roster_endianes(void)149 void swap_roster_endianes(void) {
150     int l, l2, l3;
151 
152     for (l = 0; l < MAX_PLAYERS_IN_ROSTER; l++) {
153         roster[l].solo_mis_flown = SDL_SwapLE32(roster[l].solo_mis_flown);
154         roster[l].solo_mis_success = SDL_SwapLE32(roster[l].solo_mis_success);
155         roster[l].solo_mis_drops = SDL_SwapLE32(roster[l].solo_mis_drops);
156         roster[l].solo_mis_shotsf = SDL_SwapLE32(roster[l].solo_mis_shotsf);
157         roster[l].solo_mis_shotshit = SDL_SwapLE32(roster[l].solo_mis_shotshit);
158         roster[l].solo_mis_bombs = SDL_SwapLE32(roster[l].solo_mis_bombs);
159         roster[l].solo_mis_bombshit = SDL_SwapLE32(roster[l].solo_mis_bombshit);
160         roster[l].solo_mis_totals = SDL_SwapLE32(roster[l].solo_mis_totals);
161         roster[l].solo_mis_dropped = SDL_SwapLE32(roster[l].solo_mis_dropped);
162 
163         for (l2 = 0; l2 < 4; l2++)
164             for (l3 = 0; l3 < 7; l3++)
165                 roster[l].solo_mis_scores[l2][l3] = SDL_SwapLE32(roster[l].solo_mis_scores[l2][l3]);
166 
167         roster[l].multi_mis_flown = SDL_SwapLE32(roster[l].multi_mis_flown);
168         roster[l].multi_mis_success = SDL_SwapLE32(roster[l].multi_mis_success);
169         roster[l].multi_mis_drops = SDL_SwapLE32(roster[l].multi_mis_drops);
170         roster[l].multi_mis_shotsf = SDL_SwapLE32(roster[l].multi_mis_shotsf);
171         roster[l].multi_mis_shotshit = SDL_SwapLE32(roster[l].multi_mis_shotshit);
172         roster[l].multi_mis_bombs = SDL_SwapLE32(roster[l].multi_mis_bombs);
173         roster[l].multi_mis_bombshit = SDL_SwapLE32(roster[l].multi_mis_bombshit);
174         roster[l].multi_mis_totals = SDL_SwapLE32(roster[l].multi_mis_totals);
175         roster[l].multi_mis_dropped = SDL_SwapLE32(roster[l].multi_mis_dropped);
176 
177         roster[l].up = SDL_SwapLE32(roster[l].up);
178         roster[l].down = SDL_SwapLE32(roster[l].down);
179         roster[l].roll = SDL_SwapLE32(roster[l].roll);
180         roster[l].power = SDL_SwapLE32(roster[l].power);
181         roster[l].guns = SDL_SwapLE32(roster[l].guns);
182         roster[l].bombs = SDL_SwapLE32(roster[l].bombs);
183     }
184 }
185 
convert_dos_roster(struct dos_roster * droster)186 void convert_dos_roster(struct dos_roster *droster) {
187     int l, l2, l3;
188 
189     for (l = 0; l < MAX_PLAYERS_IN_ROSTER; l++) {
190         strncpy(roster[l].pilotname, droster[l].pilotname, 31);
191         roster[l].pilotname[31] = 0;
192 
193         roster[l].solo_mis_flown = droster[l].solo_mis_flown;
194         roster[l].solo_mis_success = droster[l].solo_mis_success;
195         roster[l].solo_mis_drops = droster[l].solo_mis_drops;
196         roster[l].solo_mis_shotsf = droster[l].solo_mis_shotsf;
197         roster[l].solo_mis_shotshit = droster[l].solo_mis_shotshit;
198         roster[l].solo_mis_bombs = droster[l].solo_mis_bombs;
199         roster[l].solo_mis_bombshit = droster[l].solo_mis_bombshit;
200         roster[l].solo_mis_totals = droster[l].solo_mis_totals;
201         roster[l].solo_mis_dropped = droster[l].solo_mis_dropped;
202 
203         for (l2 = 0; l2 < 4; l2++)
204             for (l3 = 0; l3 < 7; l3++)
205                 roster[l].solo_mis_scores[l2][l3] = droster[l].solo_mis_scores[l2][l3];
206 
207         roster[l].multi_mis_flown = droster[l].multi_mis_flown;
208         roster[l].multi_mis_success = droster[l].multi_mis_success;
209         roster[l].multi_mis_drops = droster[l].multi_mis_drops;
210         roster[l].multi_mis_shotsf = droster[l].multi_mis_shotsf;
211         roster[l].multi_mis_shotshit = droster[l].multi_mis_shotshit;
212         roster[l].multi_mis_bombs = droster[l].multi_mis_bombs;
213         roster[l].multi_mis_bombshit = droster[l].multi_mis_bombshit;
214         roster[l].multi_mis_totals = droster[l].multi_mis_totals;
215         roster[l].multi_mis_dropped = droster[l].multi_mis_dropped;
216 
217         roster[l].up = SDLK_x;
218         roster[l].down = SDLK_w;
219         roster[l].roll = SDLK_s;
220         roster[l].power = SDLK_TAB;
221         roster[l].guns = SDLK_2;
222         roster[l].bombs = SDLK_1;
223     }
224 }
225 
swap_keyset_endianes(void)226 void swap_keyset_endianes(void) {
227     int i;
228 
229     for (i = 0; i < 4; i++) {
230         player_keys[i].up = SDL_SwapLE32(player_keys[i].up);
231         player_keys[i].down = SDL_SwapLE32(player_keys[i].down);
232         player_keys[i].roll = SDL_SwapLE32(player_keys[i].roll);
233         player_keys[i].power = SDL_SwapLE32(player_keys[i].power);
234         player_keys[i].guns = SDL_SwapLE32(player_keys[i].guns);
235         player_keys[i].bombs = SDL_SwapLE32(player_keys[i].bombs);
236     }
237 }
238 
save_keyset(void)239 void save_keyset(void) {
240     FILE *faili;
241 
242     faili = settings_open("keyset.dta", "wb");
243     if (faili == NULL) {
244         printf("Unable to write keyboard data\n");
245     } else {
246         swap_keyset_endianes();
247         fwrite(player_keys, sizeof(player_keys), 1, faili);
248         fclose(faili);
249         swap_keyset_endianes();
250     }
251 }
252 
load_keyset(void)253 void load_keyset(void) {
254     FILE *faili;
255 
256     if ((faili = settings_open("keyset.dta", "rb")) == NULL) {
257         player_keys[0].up = SDLK_x;
258         player_keys[0].down = SDLK_w;
259         player_keys[0].roll = SDLK_s;
260         player_keys[0].power = SDLK_TAB;
261         player_keys[0].guns = SDLK_2;
262         player_keys[0].bombs = SDLK_1;
263 
264         player_keys[2].up = SDLK_v;
265         player_keys[2].down = SDLK_t;
266         player_keys[2].roll = SDLK_g;
267         player_keys[2].power = SDLK_j;
268         player_keys[2].guns = SDLK_h;
269         player_keys[2].bombs = SDLK_y;
270 
271         player_keys[3].up = SDLK_COMMA;
272         player_keys[3].down = SDLK_o;
273         player_keys[3].roll = SDLK_l;
274         player_keys[3].power = 40;
275         player_keys[3].guns = 39;
276         player_keys[3].bombs = SDLK_p;
277 
278         player_keys[1].up = SDLK_DOWN;
279         player_keys[1].down = SDLK_UP;
280         player_keys[1].roll = SDLK_KP5;
281         player_keys[1].power = SDLK_KP_PLUS;
282         player_keys[1].guns = SDLK_HOME;
283         player_keys[1].bombs = SDLK_LEFT;
284 
285         save_keyset();
286     } else {
287         fread(player_keys, sizeof(player_keys), 1, faili);
288         fclose(faili);
289         swap_keyset_endianes();
290     }
291 }
292 
load_roster(void)293 void load_roster(void) {
294     int l, l2, l3;
295     FILE *faili;
296 
297     if ((faili = settings_open(ROSTER_FILENAME, "rb")) == NULL) {
298         if ((faili = settings_open(ROSTER_FILENAME, "wb")) == NULL) {
299             printf("\n\nError writing file: %s\n", ROSTER_FILENAME);
300             exit(1);
301         }
302 
303         for (l = 0; l < MAX_PLAYERS_IN_ROSTER; l++) {
304             roster[l].pilotname[0] = 0;
305             roster[l].solo_mis_flown = 0;
306             roster[l].solo_mis_success = 0;
307             roster[l].solo_mis_drops = 0;
308             roster[l].solo_mis_shotsf = 0;
309             roster[l].solo_mis_shotshit = 0;
310             roster[l].solo_mis_bombs = 0;
311             roster[l].solo_mis_bombshit = 0;
312             roster[l].solo_mis_totals = 0;
313             roster[l].solo_mis_dropped = 0;
314 
315             for (l2 = 0; l2 < 4; l2++)
316                 for (l3 = 0; l3 < 7; l3++)
317                     roster[l].solo_mis_scores[l2][l3] = 0;
318 
319             roster[l].multi_mis_flown = 0;
320             roster[l].multi_mis_success = 0;
321             roster[l].multi_mis_drops = 0;
322             roster[l].multi_mis_shotsf = 0;
323             roster[l].multi_mis_shotshit = 0;
324             roster[l].multi_mis_bombs = 0;
325             roster[l].multi_mis_bombshit = 0;
326             roster[l].multi_mis_totals = 0;
327             roster[l].multi_mis_dropped = 0;
328 
329             roster[l].up = SDLK_x;
330             roster[l].down = SDLK_w;
331             roster[l].roll = SDLK_s;
332             roster[l].power = SDLK_TAB;
333             roster[l].guns = SDLK_2;
334             roster[l].bombs = SDLK_1;
335 
336         }
337 
338         swap_roster_endianes();
339         fwrite(&roster, sizeof(roster), 1, faili);
340         fclose(faili);
341         swap_roster_endianes();
342     } else {
343         struct stat sb;
344         struct dos_roster droster[MAX_PLAYERS_IN_ROSTER];
345         fstat(fileno(faili), &sb);
346 
347         if (sb.st_size != sizeof(droster)) {
348             struct rosteri_header hdr;
349             int ret;
350 
351             ret = fread(&hdr, sizeof(hdr), 1, faili);
352             if (ret != 1) {
353                 printf("failed to read roster.dta header\n");
354                 exit(1);
355             }
356             hdr.magic = SDL_SwapLE32(hdr.magic);
357             hdr.version = SDL_SwapLE32(hdr.version);
358             if (hdr.magic != ROSTERI_MAGIC) {
359                 printf("invalid roster.dta magic %08x, expected %08x\n", hdr.magic, ROSTERI_MAGIC);
360                 exit(1);
361             }
362             if (hdr.version != ROSTERI_VERSION) {
363                 printf("unsupported roster.dta version %08x\n", hdr.version);
364                 exit(1);
365             }
366             fread(&roster, sizeof(roster), 1, faili);
367         } else {
368             fread(&droster, sizeof(droster), 1, faili);
369             printf("Converting roster from DOS format.\n");
370             convert_dos_roster((struct dos_roster *) &droster);
371         }
372         fclose(faili);
373         swap_roster_endianes();
374     }
375 }
376 
save_roster(void)377 void save_roster(void) {
378     FILE *faili;
379 
380     if ((faili = settings_open(ROSTER_FILENAME, "wb")) == NULL) {
381         printf("\n\nError writing file: %s\n", ROSTER_FILENAME);
382         exit(1);
383     }
384 
385     {
386         struct rosteri_header hdr;
387         hdr.magic = SDL_SwapLE32(ROSTERI_MAGIC);
388         hdr.version = SDL_SwapLE32(ROSTERI_VERSION);
389         fwrite(&hdr, sizeof(hdr), 1, faili);
390     }
391     swap_roster_endianes();
392     fwrite(&roster, sizeof(roster), 1, faili);
393     fclose(faili);
394     swap_roster_endianes();
395 }
396 
swap_config_endianes(void)397 void swap_config_endianes(void) {
398     int i;
399     config.current_multilevel = SDL_SwapLE32(config.current_multilevel);
400     for (i = 0; i < 4; i++) {
401         config.player_type[i] = SDL_SwapLE32(config.player_type[i]);
402         config.player_number[i] = SDL_SwapLE32(config.player_number[i]);
403     }
404 
405     // Graphics
406     config.shots_visible = SDL_SwapLE32(config.shots_visible);
407     config.it_shots_visible = SDL_SwapLE32(config.it_shots_visible);
408     config.aa_mg_shots_visible = SDL_SwapLE32(config.aa_mg_shots_visible);
409     config.flags = SDL_SwapLE32(config.flags);
410     config.flames = SDL_SwapLE32(config.flames);
411     config.structure_smoke = SDL_SwapLE32(config.structure_smoke);
412     config.svga = SDL_SwapLE32(config.svga);
413 
414     // Audio
415     config.sound_on = SDL_SwapLE32(config.sound_on);
416     config.music_on = SDL_SwapLE32(config.music_on);
417     config.sfx_on = SDL_SwapLE32(config.sfx_on);
418     config.explosion_sounds = SDL_SwapLE32(config.explosion_sounds);
419     config.gunshot_sounds = SDL_SwapLE32(config.gunshot_sounds);
420     config.ground_i_sounds = SDL_SwapLE32(config.ground_i_sounds);
421     config.explosion_sounds = SDL_SwapLE32(config.explosion_sounds);
422     config.splash = SDL_SwapLE32(config.splash);
423     config.infantry_sounds = SDL_SwapLE32(config.infantry_sounds);
424 
425     // General Flying
426     config.poweronoff = SDL_SwapLE32(config.poweronoff);
427     config.powerrev = SDL_SwapLE32(config.powerrev);
428 
429     // Multiplayer Game
430     config.all_planes_are = SDL_SwapLE32(config.all_planes_are);
431     config.nocollision = SDL_SwapLE32(config.nocollision);
432     config.partcollision = SDL_SwapLE32(config.partcollision);
433     config.stop = SDL_SwapLE32(config.stop);
434     config.alliance = SDL_SwapLE32(config.alliance);
435     config.aa_mgs = SDL_SwapLE32(config.aa_mgs);
436     config.it_guns = SDL_SwapLE32(config.it_guns);
437     config.infantry = SDL_SwapLE32(config.infantry);
438     config.unlimited_ammo = SDL_SwapLE32(config.unlimited_ammo);
439     config.unlimited_gas = SDL_SwapLE32(config.unlimited_gas);
440 
441     config.joystick[0] = SDL_SwapLE32(config.joystick[0]);
442     config.joystick_calibrated[0] = SDL_SwapLE32(config.joystick_calibrated[0]);
443 
444     config.joystick[1] = SDL_SwapLE32(config.joystick[1]);
445     config.joystick_calibrated[1] = SDL_SwapLE32(config.joystick_calibrated[1]);
446 }
447 
load_config(void)448 void load_config(void) {
449     int laskuri;
450     FILE *faili;
451 
452     config.current_multilevel = 0;
453 
454     for (laskuri = 0; laskuri < 4; laskuri++) {
455         config.player_type[laskuri] = 0;
456         config.player_number[laskuri] = -1;
457 
458     }
459 
460     // Graphics
461     config.shots_visible = 1;
462     config.it_shots_visible = 1;
463     config.aa_mg_shots_visible = 1;
464     config.flags = 1;
465     config.flames = 1;
466     config.structure_smoke = 0;
467     config.svga = 1;
468 
469     // Audio
470     config.sound_on = 1;
471     config.music_on = 1;
472     config.sfx_on = 1;
473     config.explosion_sounds = 1;
474     config.gunshot_sounds = 1;
475     config.ground_i_sounds = 1;
476     config.explosion_sounds = 1;
477     config.splash = 1;
478     config.infantry_sounds = 1;
479 
480     // General Flying
481     config.poweronoff = 0;
482     config.powerrev = 0;
483 
484     // Multiplayer Game
485     config.all_planes_are = 0;
486     config.nocollision = 0;
487     config.partcollision = 0;
488     config.stop = 0;
489     config.alliance = 0;
490     config.aa_mgs = 1;
491     config.it_guns = 1;
492     config.infantry = 1;
493     config.unlimited_ammo = 0;
494     config.unlimited_gas = 0;
495 
496     config.joystick[0] = -1;
497     config.joystick_calibrated[0] = 0;
498 
499     config.joystick[1] = -1;
500     config.joystick_calibrated[1] = 0;
501 
502     faili = settings_open(CONFIGURATION_FILENAME, "rb");
503 
504     if (faili != NULL) {
505         fread(&config, sizeof(config), 1, faili);
506         fclose(faili);
507         swap_config_endianes();
508     }
509 
510     is_there_sound = config.sound_on;
511 }
512 
save_config(void)513 void save_config(void) {
514     FILE *faili;
515 
516     swap_config_endianes();
517     faili = settings_open(CONFIGURATION_FILENAME, "wb");
518     fwrite(&config, sizeof(config), 1, faili);
519     fclose(faili);
520     swap_config_endianes();
521 }
522