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