rnd-19981029-1
[rocksndiamonds.git] / src / files.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  files.h                                                 *
12 ***********************************************************/
13
14 #include <ctype.h>
15
16 #include "files.h"
17 #include "tools.h"
18 #include "misc.h"
19 #include "tape.h"
20 #include "joystick.h"
21
22 boolean LoadLevelInfo()
23 {
24   int i;
25   char filename[MAX_FILENAME_LEN];
26   char cookie[MAX_FILENAME_LEN];
27   FILE *file;
28
29   sprintf(filename,"%s/%s",level_directory,LEVDIR_FILENAME);
30
31   if (!(file=fopen(filename,"r")))
32   {
33     Error(ERR_WARN, "cannot read level info '%s'", filename);
34     return(FALSE);
35   }
36
37   fscanf(file,"%s\n",cookie);
38   if (strcmp(cookie,LEVELDIR_COOKIE))   /* ungültiges Format? */
39   {
40     Error(ERR_WARN, "wrong format of level info file");
41     fclose(file);
42     return(FALSE);
43   }
44
45   num_leveldirs = 0;
46   leveldir_nr = 0;
47   for(i=0;i<MAX_LEVDIR_ENTRIES;i++)
48   {
49     fscanf(file,"%s",leveldir[i].filename);
50     fscanf(file,"%s",leveldir[i].name);
51     fscanf(file,"%d",&leveldir[i].levels);
52     fscanf(file,"%d",&leveldir[i].readonly);
53     if (feof(file))
54       break;
55
56     num_leveldirs++;
57   }
58
59   if (!num_leveldirs)
60   {
61     Error(ERR_WARN, "empty level info '%s'", filename);
62     return(FALSE);
63   }
64
65   return(TRUE);
66 }
67
68 void LoadLevel(int level_nr)
69 {
70   int i,x,y;
71   char filename[MAX_FILENAME_LEN];
72   char cookie[MAX_FILENAME_LEN];
73   FILE *file;
74
75   sprintf(filename,"%s/%s/%d",
76           level_directory,leveldir[leveldir_nr].filename,level_nr);
77
78   if (!(file = fopen(filename,"r")))
79     Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
80   else
81   {
82     fgets(cookie,LEVEL_COOKIE_LEN,file);
83     fgetc(file);
84
85     if (strcmp(cookie,LEVEL_COOKIE))    /* ungültiges Format? */
86     {
87       Error(ERR_WARN, "wrong format of level file '%s'", filename);
88       fclose(file);
89       file = NULL;
90     }
91   }
92
93   if (file)
94   {
95     lev_fieldx = level.fieldx = fgetc(file);
96     lev_fieldy = level.fieldy = fgetc(file);
97
98     level.time          = (fgetc(file)<<8) | fgetc(file);
99     level.edelsteine    = (fgetc(file)<<8) | fgetc(file);
100     for(i=0;i<MAX_LEVNAMLEN;i++)
101       level.name[i]     = fgetc(file);
102     level.name[MAX_LEVNAMLEN-1] = 0;
103     for(i=0;i<MAX_LEVSCORE_ENTRIES;i++)
104       level.score[i]    = fgetc(file);
105     for(i=0;i<4;i++)
106       for(y=0;y<3;y++)
107         for(x=0;x<3;x++)
108           level.mampfer_inhalt[i][x][y] = fgetc(file);
109     level.tempo_amoebe  = fgetc(file);
110     level.dauer_sieb    = fgetc(file);
111     level.dauer_ablenk  = fgetc(file);
112     level.amoebe_inhalt = fgetc(file);
113
114     for(i=0;i<NUM_FREE_LVHD_BYTES;i++)  /* Rest frei / Headergröße 80 Bytes */
115       fgetc(file);
116
117     for(y=0;y<MAX_LEV_FIELDY;y++) 
118       for(x=0;x<MAX_LEV_FIELDX;x++) 
119         Feld[x][y] = Ur[x][y] = EL_ERDREICH;
120
121     for(y=0;y<lev_fieldy;y++) 
122       for(x=0;x<lev_fieldx;x++) 
123         Feld[x][y] = Ur[x][y] = fgetc(file);
124
125     fclose(file);
126
127     if (level.time<=10) /* Mindestspieldauer */
128       level.time = 10;
129   }
130   else
131   {
132     lev_fieldx = level.fieldx = STD_LEV_FIELDX;
133     lev_fieldy = level.fieldy = STD_LEV_FIELDY;
134
135     level.time          = 100;
136     level.edelsteine    = 0;
137     strncpy(level.name,"Nameless Level",MAX_LEVNAMLEN-1);
138     for(i=0;i<MAX_LEVSCORE_ENTRIES;i++)
139       level.score[i]    = 10;
140     for(i=0;i<4;i++)
141       for(y=0;y<3;y++)
142         for(x=0;x<3;x++)
143           level.mampfer_inhalt[i][x][y] = EL_FELSBROCKEN;
144     level.tempo_amoebe  = 10;
145     level.dauer_sieb    = 10;
146     level.dauer_ablenk  = 10;
147     level.amoebe_inhalt = EL_DIAMANT;
148
149     for(y=0;y<STD_LEV_FIELDY;y++) 
150       for(x=0;x<STD_LEV_FIELDX;x++) 
151         Feld[x][y] = Ur[x][y] = EL_ERDREICH;
152     Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
153     Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
154       Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
155   }
156 }
157
158 void SaveLevel(int level_nr)
159 {
160   int i,x,y;
161   char filename[MAX_FILENAME_LEN];
162   FILE *file;
163
164   sprintf(filename,"%s/%s/%d",
165           level_directory,leveldir[leveldir_nr].filename,level_nr);
166
167   if (!(file=fopen(filename,"w")))
168   {
169     Error(ERR_WARN, "cannot save level file '%s'", filename);
170     return;
171   }
172
173   fputs(LEVEL_COOKIE,file);             /* Formatkennung */
174   fputc(0x0a,file);
175
176   fputc(level.fieldx,file);
177   fputc(level.fieldy,file);
178   fputc(level.time / 256,file);
179   fputc(level.time % 256,file);
180   fputc(level.edelsteine / 256,file);
181   fputc(level.edelsteine % 256,file);
182
183   for(i=0;i<MAX_LEVNAMLEN;i++)
184     fputc(level.name[i],file);
185   for(i=0;i<MAX_LEVSCORE_ENTRIES;i++)
186     fputc(level.score[i],file);
187   for(i=0;i<4;i++)
188     for(y=0;y<3;y++)
189       for(x=0;x<3;x++)
190         fputc(level.mampfer_inhalt[i][x][y],file);
191   fputc(level.tempo_amoebe,file);
192   fputc(level.dauer_sieb,file);
193   fputc(level.dauer_ablenk,file);
194   fputc(level.amoebe_inhalt,file);
195
196   for(i=0;i<NUM_FREE_LVHD_BYTES;i++)    /* Rest frei / Headergröße 80 Bytes */
197     fputc(0,file);
198
199   for(y=0;y<lev_fieldy;y++) 
200     for(x=0;x<lev_fieldx;x++) 
201       fputc(Ur[x][y],file);
202
203   fclose(file);
204
205   chmod(filename, LEVEL_PERMS);
206 }
207
208 void LoadLevelTape(int level_nr)
209 {
210   int i;
211   char filename[MAX_FILENAME_LEN];
212   char cookie[MAX_FILENAME_LEN];
213   FILE *file;
214   boolean levelrec_10 = FALSE;
215
216 #ifndef MSDOS
217   sprintf(filename,"%s/%s/%d.tape",
218           level_directory,leveldir[leveldir_nr].filename,level_nr);
219 #else
220   sprintf(filename,"%s/%s/%d.tap",
221           level_directory,leveldir[leveldir_nr].filename,level_nr);
222 #endif
223
224   if ((file=fopen(filename,"r")))
225   {
226     fgets(cookie,LEVELREC_COOKIE_LEN,file);
227     fgetc(file);
228     if (!strcmp(cookie,LEVELREC_COOKIE_10))     /* old 1.0 tape format */
229       levelrec_10 = TRUE;
230     else if (strcmp(cookie,LEVELREC_COOKIE))    /* unknown tape format */
231     {
232       Error(ERR_WARN, "wrong format of level recording file '%s'", filename);
233       fclose(file);
234       file = NULL;
235     }
236   }
237
238   if (!file)
239     return;
240
241   tape.random_seed =
242     (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
243   tape.date =
244     (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
245   tape.length =
246     (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
247
248   tape.level_nr = level_nr;
249   tape.counter = 0;
250   tape.changed = FALSE;
251
252   tape.recording = FALSE;
253   tape.playing = FALSE;
254   tape.pausing = FALSE;
255
256   for(i=0;i<tape.length;i++)
257   {
258     int j;
259
260     if (i >= MAX_TAPELEN)
261       break;
262
263     for(j=0; j<MAX_PLAYERS; j++)
264     {
265       if (levelrec_10 && j>0)
266       {
267         tape.pos[i].action[j] = MV_NO_MOVING;
268         continue;
269       }
270       tape.pos[i].action[j] = fgetc(file);
271     }
272
273     tape.pos[i].delay = fgetc(file);
274
275     if (feof(file))
276       break;
277   }
278
279   fclose(file);
280
281   if (i != tape.length)
282     Error(ERR_WARN, "level recording file '%s' corrupted", filename);
283
284   tape.length_seconds = GetTapeLength();
285 }
286
287 void SaveLevelTape(int level_nr)
288 {
289   int i;
290   char filename[MAX_FILENAME_LEN];
291   FILE *file;
292   boolean new_tape = TRUE;
293
294 #ifndef MSDOS
295   sprintf(filename,"%s/%s/%d.tape",
296           level_directory,leveldir[leveldir_nr].filename,level_nr);
297 #else
298   sprintf(filename,"%s/%s/%d.tap",
299           level_directory,leveldir[leveldir_nr].filename,level_nr);
300 #endif
301
302   /* Testen, ob bereits eine Aufnahme existiert */
303   if ((file=fopen(filename,"r")))
304   {
305     new_tape = FALSE;
306     fclose(file);
307
308     if (!Request("Replace old tape ?",REQ_ASK))
309       return;
310   }
311
312   if (!(file=fopen(filename,"w")))
313   {
314     Error(ERR_WARN, "cannot save level recording file '%s'", filename);
315     return;
316   }
317
318   fputs(LEVELREC_COOKIE,file);          /* Formatkennung */
319   fputc(0x0a,file);
320
321   fputc((tape.random_seed >> 24) & 0xff,file);
322   fputc((tape.random_seed >> 16) & 0xff,file);
323   fputc((tape.random_seed >>  8) & 0xff,file);
324   fputc((tape.random_seed >>  0) & 0xff,file);
325
326   fputc((tape.date >>  24) & 0xff,file);
327   fputc((tape.date >>  16) & 0xff,file);
328   fputc((tape.date >>   8) & 0xff,file);
329   fputc((tape.date >>   0) & 0xff,file);
330
331   fputc((tape.length >>  24) & 0xff,file);
332   fputc((tape.length >>  16) & 0xff,file);
333   fputc((tape.length >>   8) & 0xff,file);
334   fputc((tape.length >>   0) & 0xff,file);
335
336   for(i=0;i<tape.length;i++)
337   {
338     int j;
339
340     for(j=0; j<MAX_PLAYERS; j++)
341       fputc(tape.pos[i].action[j],file);
342
343     fputc(tape.pos[i].delay,file);
344   }
345
346   fclose(file);
347
348   chmod(filename, LEVREC_PERMS);
349
350   tape.changed = FALSE;
351
352   if (new_tape)
353     Request("tape saved !",REQ_CONFIRM);
354 }
355
356 boolean CreateNewScoreFile()
357 {
358   int i,j,k;
359   char filename[MAX_FILENAME_LEN];
360   char empty_alias[MAX_NAMELEN];
361   FILE *file;
362
363   sprintf(filename,"%s/%s/%s",
364           level_directory,leveldir[leveldir_nr].filename,SCORE_FILENAME);
365
366   if (!(file=fopen(filename,"w")))
367     return(FALSE);
368
369   for(i=0;i<MAX_NAMELEN;i++)
370     empty_alias[i] = 0;
371   strncpy(empty_alias,EMPTY_ALIAS,MAX_NAMELEN-1);
372
373   fputs(SCORE_COOKIE,file);             /* Formatkennung */
374   for(i=0;i<leveldir[leveldir_nr].levels;i++)
375   {
376     for(j=0;j<MAX_SCORE_ENTRIES;j++)
377     {
378       for(k=0;k<MAX_NAMELEN;k++)
379         fputc(empty_alias[k],file);
380       fputc(0,file);
381       fputc(0,file);
382     }
383   }
384   fclose(file);
385
386   chmod(filename, SCORE_PERMS);
387   return(TRUE);
388 }
389
390 void LoadScore(int level_nr)
391 {
392   int i,j;
393   char filename[MAX_FILENAME_LEN];
394   char cookie[MAX_FILENAME_LEN];
395   FILE *file;
396
397   sprintf(filename,"%s/%s/%s",
398           level_directory,leveldir[leveldir_nr].filename,SCORE_FILENAME);
399
400   if (!(file = fopen(filename,"r")))
401   {
402     if (!CreateNewScoreFile())
403       Error(ERR_WARN, "cannot create score file '%s'", filename);
404     else if (!(file = fopen(filename,"r"))) 
405       Error(ERR_WARN, "cannot read score for level %d", level_nr);
406   }
407
408   if (file)
409   {
410     fgets(cookie,SCORE_COOKIE_LEN,file);
411     if (strcmp(cookie,SCORE_COOKIE))    /* ungültiges Format? */
412     {
413       Error(ERR_WARN, "wrong format of score file '%s'", filename);
414       fclose(file);
415       file = NULL;
416     }
417   }
418
419   if (file)
420   {
421     fseek(file,
422           SCORE_COOKIE_LEN-1+level_nr*(MAX_SCORE_ENTRIES*(MAX_NAMELEN+2)),
423           SEEK_SET);
424     for(i=0;i<MAX_SCORE_ENTRIES;i++)
425     {
426       for(j=0;j<MAX_NAMELEN;j++)
427         highscore[i].Name[j] = fgetc(file);
428       highscore[i].Score = (fgetc(file)<<8) | fgetc(file);
429     }
430     fclose(file);
431   }
432   else
433   {
434     for(i=0;i<MAX_SCORE_ENTRIES;i++)
435     {
436       strcpy(highscore[i].Name,EMPTY_ALIAS);
437       highscore[i].Score = 0;
438     }
439   }
440 }
441
442 void SaveScore(int level_nr)
443 {
444   int i,j;
445   char filename[MAX_FILENAME_LEN];
446   FILE *file;
447
448   sprintf(filename,"%s/%s/%s",
449           level_directory,leveldir[leveldir_nr].filename,SCORE_FILENAME);
450
451   if (!(file=fopen(filename,"r+")))
452   {
453     Error(ERR_WARN, "cannot save score for level %d", level_nr);
454     return;
455   }
456
457   fseek(file,
458         SCORE_COOKIE_LEN-1+level_nr*(MAX_SCORE_ENTRIES*(MAX_NAMELEN+2)),
459         SEEK_SET);
460   for(i=0;i<MAX_SCORE_ENTRIES;i++)
461   {
462     for(j=0;j<MAX_NAMELEN;j++)
463       fputc(highscore[i].Name[j],file);
464     fputc(highscore[i].Score / 256,file);
465     fputc(highscore[i].Score % 256,file);
466   }
467   fclose(file);
468 }
469
470
471
472 #if 0
473
474 void LoadJoystickData()
475 {
476   int i;
477   char cookie[256];
478   FILE *file;
479
480   if (joystick_status==JOYSTICK_OFF)
481     return;
482
483 #ifndef MSDOS
484   if (!(file=fopen(JOYDAT_FILE,"r")))
485     return;
486
487   fscanf(file,"%s",cookie);
488   if (strcmp(cookie,JOYSTICK_COOKIE))   /* ungültiges Format? */
489   {
490     Error(ERR_WARN, "wrong format of joystick file '%s'", JOYDAT_FILE);
491     fclose(file);
492     return;
493   }
494
495   for(i=0;i<2;i++)
496   {
497     fscanf(file,"%s",cookie);
498     fscanf(file, "%d %d %d \n",
499            &joystick[i].xleft, &joystick[i].xmiddle, &joystick[i].xright);
500     fscanf(file, "%d %d %d \n",
501            &joystick[i].yupper, &joystick[i].ymiddle, &joystick[i].ylower);
502   }
503   fclose(file);
504
505   CheckJoystickData();
506 #else
507   load_joystick_data(JOYDAT_FILE);
508 #endif
509 }
510
511 void SaveJoystickData()
512 {
513   int i;
514   FILE *file;
515
516   if (joystick_status==JOYSTICK_OFF)
517     return;
518
519 #ifndef MSDOS
520   CheckJoystickData();
521
522   if (!(file=fopen(JOYDAT_FILE,"w")))
523   {
524     Error(ERR_WARN, "cannot save joystick calibration data to file '%s'",
525           JOYDAT_FILE);
526     return;
527   }
528
529   fprintf(file,"%s\n",JOYSTICK_COOKIE); /* Formatkennung */
530   for(i=0;i<2;i++)
531   {
532     fprintf(file,"JOYSTICK_%d_DATA\n",i);
533     fprintf(file, "%d %d %d \n",
534             joystick[i].xleft, joystick[i].xmiddle, joystick[i].xright);
535     fprintf(file, "%d %d %d \n",
536             joystick[i].yupper, joystick[i].ymiddle, joystick[i].ylower);
537   }
538   fclose(file);
539
540   chmod(JOYDAT_FILE, JOYDAT_PERMS);
541 #else
542   save_joystick_data(JOYDAT_FILE);
543 #endif
544
545 }
546
547 #endif
548
549
550
551 /* ------------------------------------------------------------------------- */
552 /* new setup functions                                                       */
553 /* ------------------------------------------------------------------------- */
554
555 #define MAX_LINE_LEN                    1000
556 #define MAX_SETUP_TOKEN_LEN             100
557 #define MAX_SETUP_VALUE_LEN             100
558
559 #define TOKEN_STR_FILE_IDENTIFIER       "file_identifier"
560 #define TOKEN_STR_LAST_LEVEL_SERIES     "last_level_series"
561 #define TOKEN_STR_ALIAS_NAME            "alias_name"
562
563 #define TOKEN_STR_PLAYER_PREFIX         "player_"
564 #define TOKEN_VALUE_POSITION            30
565 #define TOKEN_INVALID                   -1
566 #define TOKEN_IGNORE                    -99
567
568 #define SETUP_TOKEN_ALIAS_NAME          100
569
570 #define SETUP_TOKEN_SOUND               0
571 #define SETUP_TOKEN_SOUND_LOOPS         1
572 #define SETUP_TOKEN_SOUND_MUSIC         2
573 #define SETUP_TOKEN_SOUND_SIMPLE        3
574 #define SETUP_TOKEN_TOONS               4
575 #define SETUP_TOKEN_DOUBLE_BUFFERING    5
576 #define SETUP_TOKEN_SCROLL_DELAY        6
577 #define SETUP_TOKEN_SOFT_SCROLLING      7
578 #define SETUP_TOKEN_FADING              8
579 #define SETUP_TOKEN_AUTORECORD          9
580 #define SETUP_TOKEN_QUICK_DOORS         10
581 #define SETUP_TOKEN_ALIAS_NAMES         11
582
583 #define SETUP_TOKEN_USE_JOYSTICK        12
584 #define SETUP_TOKEN_JOY_DEVICE_NAME     13
585 #define SETUP_TOKEN_JOY_XLEFT           14
586 #define SETUP_TOKEN_JOY_XMIDDLE         15
587 #define SETUP_TOKEN_JOY_XRIGHT          16
588 #define SETUP_TOKEN_JOY_YUPPER          17
589 #define SETUP_TOKEN_JOY_YMIDDLE         18
590 #define SETUP_TOKEN_JOY_YLOWER          19
591 #define SETUP_TOKEN_JOY_SNAP            20
592 #define SETUP_TOKEN_JOY_BOMB            21
593 #define SETUP_TOKEN_KEY_LEFT            22
594 #define SETUP_TOKEN_KEY_RIGHT           23
595 #define SETUP_TOKEN_KEY_UP              24
596 #define SETUP_TOKEN_KEY_DOWN            25
597 #define SETUP_TOKEN_KEY_SNAP            26
598 #define SETUP_TOKEN_KEY_BOMB            27
599
600 #define NUM_SETUP_TOKENS                28
601
602 #define FIRST_GLOBAL_SETUP_TOKEN        SETUP_TOKEN_SOUND
603 #define LAST_GLOBAL_SETUP_TOKEN         SETUP_TOKEN_ALIAS_NAMES
604
605 #define FIRST_PLAYER_SETUP_TOKEN        SETUP_TOKEN_USE_JOYSTICK
606 #define LAST_PLAYER_SETUP_TOKEN         SETUP_TOKEN_KEY_BOMB
607
608 #define TYPE_BOOLEAN                    1
609 #define TYPE_SWITCH                     2
610 #define TYPE_KEYSYM                     3
611 #define TYPE_INTEGER                    4
612 #define TYPE_STRING                     5
613
614 static struct SetupInfo si;
615 static struct SetupInputInfo sii;
616 static struct
617 {
618   int type;
619   void *value;
620   char *text;
621 } token_info[] =
622 {
623   { TYPE_SWITCH,  &si.sound,            "sound"                         },
624   { TYPE_SWITCH,  &si.sound_loops,      "repeating_sound_loops"         },
625   { TYPE_SWITCH,  &si.sound_music,      "background_music"              },
626   { TYPE_SWITCH,  &si.sound_simple,     "simple_sound_effects"          },
627   { TYPE_SWITCH,  &si.toons,            "toons"                         },
628   { TYPE_SWITCH,  &si.double_buffering, "double_buffering"              },
629   { TYPE_SWITCH,  &si.scroll_delay,     "scroll_delay"                  },
630   { TYPE_SWITCH,  &si.soft_scrolling,   "soft_scrolling"                },
631   { TYPE_SWITCH,  &si.fading,           "screen_fading"                 },
632   { TYPE_SWITCH,  &si.autorecord,       "automatic_tape_recording"      },
633   { TYPE_SWITCH,  &si.quick_doors,      "quick_doors"                   },
634   { TYPE_STRING,  &si.alias_name,       "alias_name"                    },
635
636   /* for each player: */
637   { TYPE_BOOLEAN, &sii.use_joystick,    ".use_joystick"                 },
638   { TYPE_STRING,  &sii.joy.device_name, ".joy.device_name"              },
639   { TYPE_INTEGER, &sii.joy.xleft,       ".joy.xleft"                    },
640   { TYPE_INTEGER, &sii.joy.xmiddle,     ".joy.xmiddle"                  },
641   { TYPE_INTEGER, &sii.joy.xright,      ".joy.xright"                   },
642   { TYPE_INTEGER, &sii.joy.yupper,      ".joy.yupper"                   },
643   { TYPE_INTEGER, &sii.joy.ymiddle,     ".joy.ymiddle"                  },
644   { TYPE_INTEGER, &sii.joy.ylower,      ".joy.ylower"                   },
645   { TYPE_INTEGER, &sii.joy.snap,        ".joy.snap_field"               },
646   { TYPE_INTEGER, &sii.joy.bomb,        ".joy.place_bomb"               },
647   { TYPE_KEYSYM,  &sii.key.left,        ".key.move_left"                },
648   { TYPE_KEYSYM,  &sii.key.right,       ".key.move_right"               },
649   { TYPE_KEYSYM,  &sii.key.up,          ".key.move_up"                  },
650   { TYPE_KEYSYM,  &sii.key.down,        ".key.move_down"                },
651   { TYPE_KEYSYM,  &sii.key.snap,        ".key.snap_field"               },
652   { TYPE_KEYSYM,  &sii.key.bomb,        ".key.place_bomb"               }
653 };
654
655 static char *string_tolower(char *s)
656 {
657   static char s_lower[100];
658   int i;
659
660   if (strlen(s) >= 100)
661     return s;
662
663   strcpy(s_lower, s);
664
665   for (i=0; i<strlen(s_lower); i++)
666     s_lower[i] = tolower(s_lower[i]);
667
668   return s_lower;
669 }
670
671 static int get_string_integer_value(char *s)
672 {
673   static char *number_text[][3] =
674   {
675     { "0", "zero", "null", },
676     { "1", "one", "first" },
677     { "2", "two", "second" },
678     { "3", "three", "third" },
679     { "4", "four", "fourth" },
680     { "5", "five", "fifth" },
681     { "6", "six", "sixth" },
682     { "7", "seven", "seventh" },
683     { "8", "eight", "eighth" },
684     { "9", "nine", "ninth" },
685     { "10", "ten", "tenth" },
686     { "11", "eleven", "eleventh" },
687     { "12", "twelve", "twelfth" },
688   };
689
690   int i, j;
691
692   for (i=0; i<13; i++)
693     for (j=0; j<3; j++)
694       if (strcmp(string_tolower(s), number_text[i][j]) == 0)
695         return i;
696
697   return atoi(s);
698 }
699
700 static boolean get_string_boolean_value(char *s)
701 {
702   if (strcmp(string_tolower(s), "true") == 0 ||
703       strcmp(string_tolower(s), "yes") == 0 ||
704       strcmp(string_tolower(s), "on") == 0 ||
705       get_string_integer_value(s) == 1)
706     return TRUE;
707   else
708     return FALSE;
709 }
710
711
712
713 #if 0
714
715 static char *getSetupToken(int token_nr)
716 {
717   return token_info[token_nr].text;
718 }
719
720 static char *getSetupValue(int token_nr, boolean token_value)
721 {
722   return (token_value == TRUE ? "true" : "false");
723
724   /*
725   if (token_value == TRUE)
726     return token_info[token_nr].value_true;
727   else
728     return token_info[token_nr].value_false;
729   */
730
731 }
732
733 #endif
734
735
736
737 static char *getFormattedSetupEntry(char *token, char *value)
738 {
739   int i;
740   static char entry[MAX_LINE_LEN];
741
742   sprintf(entry, "%s:", token);
743   for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
744     entry[i] = ' ';
745   entry[i] = '\0';
746
747   strcat(entry, value);
748
749   return entry;
750 }
751
752
753
754 #if 0
755
756 static char *getSetupEntry(char *prefix, int token_nr, int token_value)
757 {
758   int i;
759   static char entry[MAX_LINE_LEN];
760
761   sprintf(entry, "%s%s:", prefix, getSetupToken(token_nr));
762   for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
763     entry[i] = ' ';
764   entry[i] = '\0';
765
766   strcat(entry, getSetupValue(token_nr, token_value));
767
768   return entry;
769 }
770
771 static char *getSetupEntryWithComment(char *prefix,int token_nr, KeySym keysym)
772 {
773   int i;
774   static char entry[MAX_LINE_LEN];
775   char *keyname = getKeyNameFromKeySym(keysym);
776
777   sprintf(entry, "%s%s:", prefix, getSetupToken(token_nr));
778   for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
779     entry[i] = ' ';
780   entry[i] = '\0';
781
782   strcat(entry, getX11KeyNameFromKeySym(keysym));
783   for (i=strlen(entry); i<50; i++)
784     entry[i] = ' ';
785   entry[i] = '\0';
786
787   /* add comment, if useful */
788   if (strcmp(keyname, "(undefined)") != 0 &&
789       strcmp(keyname, "(unknown)") != 0)
790   {
791     strcat(entry, "# ");
792     strcat(entry, keyname);
793   }
794
795   return entry;
796 }
797
798 #endif
799
800
801 static void freeSetupFileList(struct SetupFileList *setup_file_list)
802 {
803   if (!setup_file_list)
804     return;
805
806   if (setup_file_list->token)
807     free(setup_file_list->token);
808   if (setup_file_list->value)
809     free(setup_file_list->value);
810   if (setup_file_list->next)
811     freeSetupFileList(setup_file_list->next);
812   free(setup_file_list);
813 }
814
815 static struct SetupFileList *newSetupFileList(char *token, char *value)
816 {
817   struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
818
819   new->token = checked_malloc(strlen(token) + 1);
820   strcpy(new->token, token);
821
822   new->value = checked_malloc(strlen(value) + 1);
823   strcpy(new->value, value);
824
825   new->next = NULL;
826
827   return new;
828 }
829
830 static char *getSetupFileListEntry(struct SetupFileList *setup_file_list,
831                                    char *token)
832 {
833   if (!setup_file_list)
834     return NULL;
835
836   if (strcmp(setup_file_list->token, token) == 0)
837     return setup_file_list->value;
838   else
839     return getSetupFileListEntry(setup_file_list->next, token);
840 }
841
842 boolean setSetupFileListEntry(struct SetupFileList *setup_file_list,
843                               char *token, char *value)
844 {
845   if (!setup_file_list)
846     return FALSE;
847
848   if (strcmp(setup_file_list->token, token) == 0)
849   {
850     free(setup_file_list->value);
851     setup_file_list->value = checked_malloc(strlen(value) + 1);
852     strcpy(setup_file_list->value, value);
853
854     return TRUE;
855   }
856   else
857     return setSetupFileListEntry(setup_file_list->next, token, value);
858 }
859
860 void updateSetupFileListEntry(struct SetupFileList *setup_file_list,
861                               char *token, char *value)
862 {
863   if (!setup_file_list)
864     return;
865
866   if (getSetupFileListEntry(setup_file_list, token) != NULL)
867     setSetupFileListEntry(setup_file_list, token, value);
868   else
869   {
870     struct SetupFileList *list_entry = setup_file_list;
871
872     while (list_entry->next)
873       list_entry = list_entry->next;
874
875     list_entry->next = newSetupFileList(token, value);
876   }
877 }
878
879 #ifdef DEBUG
880 static void printSetupFileList(struct SetupFileList *setup_file_list)
881 {
882   if (!setup_file_list)
883     return;
884
885   printf("token: '%s'\n", setup_file_list->token);
886   printf("value: '%s'\n", setup_file_list->value);
887
888   printSetupFileList(setup_file_list->next);
889 }
890 #endif
891
892 static struct SetupFileList *loadSetupFileList(char *filename)
893 {
894   int line_len;
895   char line[MAX_LINE_LEN];
896   char *token, *value, *line_ptr;
897   struct SetupFileList *setup_file_list = newSetupFileList("", "");
898   struct SetupFileList *first_valid_list_entry;
899
900   FILE *file;
901
902   if (!(file = fopen(filename, "r")))
903   {
904     Error(ERR_WARN, "cannot open setup file '%s'", filename);
905     return NULL;
906   }
907
908   while(!feof(file))
909   {
910     /* read next line of input file */
911     if (!fgets(line, MAX_LINE_LEN, file))
912       break;
913
914     /* cut trailing comment or whitespace from input line */
915     for (line_ptr = line; *line_ptr; line_ptr++)
916     {
917       if (*line_ptr == '#' || *line_ptr == '\n')
918       {
919         *line_ptr = '\0';
920         break;
921       }
922     }
923
924     /* cut trailing whitespaces from input line */
925     for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--)
926       if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0')
927         *line_ptr = '\0';
928
929     /* ignore empty lines */
930     if (*line == '\0')
931       continue;
932
933     line_len = strlen(line);
934
935     /* cut leading whitespaces from token */
936     for (token = line; *token; token++)
937       if (*token != ' ' && *token != '\t')
938         break;
939
940     /* find end of token */
941     for (line_ptr = token; *line_ptr; line_ptr++)
942     {
943       if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
944       {
945         *line_ptr = '\0';
946         break;
947       }
948     }
949
950     if (line_ptr < line + line_len)
951       value = line_ptr + 1;
952     else
953       value = "\0";
954
955     /* cut leading whitespaces from value */
956     for (; *value; value++)
957       if (*value != ' ' && *value != '\t')
958         break;
959
960     if (*token && *value)
961       updateSetupFileListEntry(setup_file_list, token, value);
962   }
963
964   fclose(file);
965
966   first_valid_list_entry = setup_file_list->next;
967
968   /* free empty list header */
969   setup_file_list->next = NULL;
970   freeSetupFileList(setup_file_list);
971
972   if (!first_valid_list_entry)
973     Error(ERR_WARN, "setup file is empty");
974
975   return first_valid_list_entry;
976 }
977
978 static void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
979                                          char *identifier)
980 {
981   if (!setup_file_list)
982     return;
983
984   if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
985   {
986     if (strcmp(setup_file_list->value, identifier) != 0)
987     {
988       Error(ERR_WARN, "setup file has wrong version");
989       return;
990     }
991     else
992       return;
993   }
994
995   if (setup_file_list->next)
996     checkSetupFileListIdentifier(setup_file_list->next, identifier);
997   else
998   {
999     Error(ERR_WARN, "setup file has no version information");
1000     return;
1001   }
1002 }
1003
1004 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
1005 {
1006   int i;
1007   int token_nr = TOKEN_INVALID;
1008   int player_nr = 0;
1009   char *token;
1010   char *token_value;
1011   boolean token_boolean_value;
1012   int token_integer_value;
1013   int token_player_prefix_len;
1014
1015   if (!setup_file_list)
1016     return;
1017
1018   token = setup_file_list->token;
1019   token_value = setup_file_list->value;
1020   token_boolean_value = get_string_boolean_value(token_value);
1021   token_integer_value = get_string_integer_value(token_value);
1022
1023   token_player_prefix_len = strlen(TOKEN_STR_PLAYER_PREFIX);
1024
1025   if (strncmp(token, TOKEN_STR_PLAYER_PREFIX,
1026               token_player_prefix_len) == 0)
1027   {
1028     token += token_player_prefix_len;
1029
1030     if (*token >= '0' && *token <= '9')
1031     {
1032       player_nr = ((int)(*token - '0') - 1 + MAX_PLAYERS) % MAX_PLAYERS;
1033       token++;
1034     }
1035   }
1036
1037   for (i=0; i<NUM_SETUP_TOKENS; i++)
1038   {
1039     if (strcmp(token, token_info[i].text) == 0)
1040     {
1041       token_nr = i;
1042       break;
1043     }
1044   }
1045
1046   if (strcmp(token, TOKEN_STR_FILE_IDENTIFIER) == 0)
1047     token_nr = TOKEN_IGNORE;
1048   else if (strcmp(token, TOKEN_STR_ALIAS_NAME) == 0)
1049     token_nr = SETUP_TOKEN_ALIAS_NAME;
1050
1051   switch (token_nr)
1052   {
1053     case SETUP_TOKEN_SOUND:
1054       setup.sound = token_boolean_value;
1055       break;
1056     case SETUP_TOKEN_SOUND_LOOPS:
1057       setup.sound_loops = token_boolean_value;
1058       break;
1059     case SETUP_TOKEN_SOUND_MUSIC:
1060       setup.sound_music = token_boolean_value;
1061       break;
1062     case SETUP_TOKEN_SOUND_SIMPLE:
1063       setup.sound_simple = token_boolean_value;
1064       break;
1065     case SETUP_TOKEN_TOONS:
1066       setup.toons = token_boolean_value;
1067       break;
1068     case SETUP_TOKEN_DOUBLE_BUFFERING:
1069       setup.double_buffering = token_boolean_value;
1070       break;
1071     case SETUP_TOKEN_SCROLL_DELAY:
1072       setup.scroll_delay = token_boolean_value;
1073       break;
1074     case SETUP_TOKEN_SOFT_SCROLLING:
1075       setup.soft_scrolling = token_boolean_value;
1076       break;
1077     case SETUP_TOKEN_FADING:
1078       setup.fading = token_boolean_value;
1079       break;
1080     case SETUP_TOKEN_AUTORECORD:
1081       setup.autorecord = token_boolean_value;
1082       break;
1083     case SETUP_TOKEN_QUICK_DOORS:
1084       setup.quick_doors = token_boolean_value;
1085       break;
1086
1087     case SETUP_TOKEN_ALIAS_NAME:
1088       strncpy(setup.alias_name, token_value, MAX_NAMELEN-1);
1089       setup.alias_name[MAX_NAMELEN-1] = '\0';
1090       break;
1091
1092     case SETUP_TOKEN_USE_JOYSTICK:
1093       setup.input[player_nr].use_joystick = token_boolean_value;
1094       break;
1095     case SETUP_TOKEN_JOY_DEVICE_NAME:
1096       strncpy(setup.input[player_nr].joy.device_name, token_value,
1097               MAX_FILENAME_LEN-1);
1098       setup.input[player_nr].joy.device_name[MAX_FILENAME_LEN-1] = '\0';
1099       break;
1100     case SETUP_TOKEN_JOY_SNAP:
1101       setup.input[player_nr].joy.snap = getJoySymbolFromJoyName(token_value);
1102       break;
1103     case SETUP_TOKEN_JOY_XLEFT:
1104       setup.input[player_nr].joy.xleft = token_integer_value;
1105       break;
1106     case SETUP_TOKEN_JOY_XMIDDLE:
1107       setup.input[player_nr].joy.xmiddle = token_integer_value;
1108       break;
1109     case SETUP_TOKEN_JOY_XRIGHT:
1110       setup.input[player_nr].joy.xright = token_integer_value;
1111       break;
1112     case SETUP_TOKEN_JOY_YUPPER:
1113       setup.input[player_nr].joy.yupper = token_integer_value;
1114       break;
1115     case SETUP_TOKEN_JOY_YMIDDLE:
1116       setup.input[player_nr].joy.ymiddle = token_integer_value;
1117       break;
1118     case SETUP_TOKEN_JOY_YLOWER:
1119       setup.input[player_nr].joy.ylower = token_integer_value;
1120       break;
1121     case SETUP_TOKEN_JOY_BOMB:
1122       setup.input[player_nr].joy.bomb = getJoySymbolFromJoyName(token_value);
1123       break;
1124     case SETUP_TOKEN_KEY_LEFT:
1125       setup.input[player_nr].key.left = getKeySymFromX11KeyName(token_value);
1126       break;
1127     case SETUP_TOKEN_KEY_RIGHT:
1128       setup.input[player_nr].key.right = getKeySymFromX11KeyName(token_value);
1129       break;
1130     case SETUP_TOKEN_KEY_UP:
1131       setup.input[player_nr].key.up = getKeySymFromX11KeyName(token_value);
1132       break;
1133     case SETUP_TOKEN_KEY_DOWN:
1134       setup.input[player_nr].key.down = getKeySymFromX11KeyName(token_value);
1135       break;
1136     case SETUP_TOKEN_KEY_SNAP:
1137       setup.input[player_nr].key.snap = getKeySymFromX11KeyName(token_value);
1138       break;
1139     case SETUP_TOKEN_KEY_BOMB:
1140       setup.input[player_nr].key.bomb = getKeySymFromX11KeyName(token_value);
1141       break;
1142
1143     case TOKEN_INVALID:
1144       Error(ERR_WARN, "unknown token '%s' not recognized", token);
1145       break;
1146
1147     case TOKEN_IGNORE:
1148     default:
1149       break;
1150   }
1151
1152   decodeSetupFileList(setup_file_list->next);
1153 }
1154
1155 int getLevelSeriesNrFromLevelSeriesName(char *level_series_name)
1156 {
1157   int i;
1158
1159   if (!level_series_name)
1160     return 0;
1161
1162   for (i=0; i<num_leveldirs; i++)
1163     if (strcmp(level_series_name, leveldir[i].filename) == 0)
1164       return i;
1165
1166   return 0;
1167 }
1168
1169 int getLastPlayedLevelOfLevelSeries(char *level_series_name)
1170 {
1171   char *token_value;
1172   int level_series_nr = getLevelSeriesNrFromLevelSeriesName(level_series_name);
1173   int last_level_nr = 0;
1174
1175   if (!level_series_name)
1176     return 0;
1177
1178   token_value = getSetupFileListEntry(level_setup_list, level_series_name);
1179
1180   if (token_value)
1181   {
1182     int highest_level_nr = leveldir[level_series_nr].levels - 1;
1183
1184     last_level_nr = atoi(token_value);
1185
1186     if (last_level_nr < 0)
1187       last_level_nr = 0;
1188     if (last_level_nr > highest_level_nr)
1189       last_level_nr = highest_level_nr;
1190   }
1191
1192   return last_level_nr;
1193 }
1194
1195 void LoadSetup()
1196 {
1197   int i;
1198   char filename[MAX_FILENAME_LEN];
1199   struct SetupFileList *setup_file_list = NULL;
1200
1201   /* always start with reliable default setup values */
1202
1203   setup.sound = TRUE;
1204   setup.sound_loops = FALSE;
1205   setup.sound_music = FALSE;
1206   setup.sound_simple = FALSE;
1207   setup.toons = TRUE;
1208   setup.double_buffering = TRUE;
1209   setup.direct_draw = !setup.double_buffering;
1210   setup.scroll_delay = FALSE;
1211   setup.soft_scrolling = TRUE;
1212   setup.fading = FALSE;
1213   setup.autorecord = FALSE;
1214   setup.quick_doors = FALSE;
1215
1216   strncpy(setup.login_name, GetLoginName(), MAX_NAMELEN-1);
1217   setup.login_name[MAX_NAMELEN-1] = '\0';
1218   strncpy(setup.alias_name, GetLoginName(), MAX_NAMELEN-1);
1219   setup.alias_name[MAX_NAMELEN-1] = '\0';
1220
1221   for (i=0; i<MAX_PLAYERS; i++)
1222   {
1223     setup.input[i].use_joystick = FALSE;
1224     strcpy(setup.input[i].joy.device_name, joystick_device_name[i]);
1225     setup.input[i].joy.xleft   = JOYSTICK_XLEFT;
1226     setup.input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
1227     setup.input[i].joy.xright  = JOYSTICK_XRIGHT;
1228     setup.input[i].joy.yupper  = JOYSTICK_YUPPER;
1229     setup.input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
1230     setup.input[i].joy.ylower  = JOYSTICK_YLOWER;
1231     setup.input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
1232     setup.input[i].joy.bomb  = (i == 0 ? JOY_BUTTON_2 : 0);
1233     setup.input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KEY_UNDEFINDED);
1234     setup.input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KEY_UNDEFINDED);
1235     setup.input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KEY_UNDEFINDED);
1236     setup.input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KEY_UNDEFINDED);
1237     setup.input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KEY_UNDEFINDED);
1238     setup.input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KEY_UNDEFINDED);
1239   }
1240
1241   sprintf(filename, "%s/%s", SETUP_PATH, SETUP_FILENAME);
1242
1243   setup_file_list = loadSetupFileList(filename);
1244
1245   if (setup_file_list)
1246   {
1247
1248 #if 0
1249     printSetupFileList(setup_file_list);
1250 #endif
1251
1252     checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE);
1253     decodeSetupFileList(setup_file_list);
1254
1255     setup.direct_draw = !setup.double_buffering;
1256
1257     freeSetupFileList(setup_file_list);
1258   }
1259   else
1260     Error(ERR_WARN, "using default setup values");
1261 }
1262
1263
1264 #if 0
1265
1266 void SaveSetup()
1267 {
1268   int i;
1269   char filename[MAX_FILENAME_LEN];
1270   FILE *file;
1271
1272   sprintf(filename, "%s/%s", SETUP_PATH, SETUP_FILENAME);
1273
1274   if (!(file = fopen(filename, "w")))
1275   {
1276     Error(ERR_WARN, "cannot write setup file '%s'", filename);
1277     return;
1278   }
1279
1280   fprintf(file, "%s:              %s\n",
1281           TOKEN_STR_FILE_IDENTIFIER, SETUP_COOKIE);
1282
1283   fprintf(file, "\n");
1284
1285   fprintf(file, "%s\n",
1286           getSetupEntry("", SETUP_TOKEN_SOUND,
1287                         setup.sound));
1288   fprintf(file, "%s\n",
1289           getSetupEntry("", SETUP_TOKEN_SOUND_LOOPS,
1290                         setup.sound_loops));
1291   fprintf(file, "%s\n",
1292           getSetupEntry("", SETUP_TOKEN_SOUND_MUSIC,
1293                         setup.sound_music));
1294   fprintf(file, "%s\n",
1295           getSetupEntry("", SETUP_TOKEN_SOUND_SIMPLE,
1296                         setup.sound_simple));
1297   fprintf(file, "%s\n",
1298           getSetupEntry("", SETUP_TOKEN_TOONS,
1299                         setup.toons));
1300   fprintf(file, "%s\n",
1301           getSetupEntry("", SETUP_TOKEN_DIRECT_DRAW,
1302                         setup.direct_draw));
1303   fprintf(file, "%s\n",
1304           getSetupEntry("", SETUP_TOKEN_SCROLL_DELAY,
1305                         setup.scroll_delay));
1306   fprintf(file, "%s\n",
1307           getSetupEntry("", SETUP_TOKEN_SOFT_SCROLLING,
1308                         setup.soft_scrolling));
1309   fprintf(file, "%s\n",
1310           getSetupEntry("", SETUP_TOKEN_FADING,
1311                         setup.fading));
1312   fprintf(file, "%s\n",
1313           getSetupEntry("", SETUP_TOKEN_AUTORECORD,
1314                         setup.autorecord));
1315   fprintf(file, "%s\n",
1316           getSetupEntry("", SETUP_TOKEN_QUICK_DOORS,
1317                         setup.quick_doors));
1318
1319   fprintf(file, "\n");
1320
1321   fprintf(file, "%s\n",
1322           getFormattedSetupEntry(TOKEN_STR_ALIAS_NAME,
1323                                  setup.alias_name));
1324
1325   for (i=0; i<MAX_PLAYERS; i++)
1326   {
1327     char prefix[30];
1328
1329     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, i + 1);
1330
1331     fprintf(file, "\n");
1332
1333     fprintf(file, "%s\n",
1334             getSetupEntry(prefix, SETUP_TOKEN_USE_JOYSTICK,
1335                           setup.input[i].use_joystick));
1336
1337     fprintf(file, "%s%s:      %s\n", prefix,
1338             getSetupToken(SETUP_TOKEN_JOY_DEVICE_NAME),
1339             setup.input[i].joy.device_name);
1340
1341     fprintf(file, "%s%s:      %d\n", prefix,
1342             getSetupToken(SETUP_TOKEN_JOY_XLEFT),
1343             setup.input[i].joy.xleft);
1344     fprintf(file, "%s%s:      %d\n", prefix,
1345             getSetupToken(SETUP_TOKEN_JOY_XMIDDLE),
1346             setup.input[i].joy.xmiddle);
1347     fprintf(file, "%s%s:      %d\n", prefix,
1348             getSetupToken(SETUP_TOKEN_JOY_XRIGHT),
1349             setup.input[i].joy.xright);
1350     fprintf(file, "%s%s:      %d\n", prefix,
1351             getSetupToken(SETUP_TOKEN_JOY_YUPPER),
1352             setup.input[i].joy.yupper);
1353     fprintf(file, "%s%s:      %d\n", prefix,
1354             getSetupToken(SETUP_TOKEN_JOY_YMIDDLE),
1355             setup.input[i].joy.ymiddle);
1356     fprintf(file, "%s%s:      %d\n", prefix,
1357             getSetupToken(SETUP_TOKEN_JOY_YLOWER),
1358             setup.input[i].joy.ylower);
1359     fprintf(file, "%s%s:      %s\n", prefix,
1360             getSetupToken(SETUP_TOKEN_JOY_SNAP),
1361             getJoyNameFromJoySymbol(setup.input[i].joy.snap));
1362     fprintf(file, "%s%s:      %s\n", prefix,
1363             getSetupToken(SETUP_TOKEN_JOY_BOMB),
1364             getJoyNameFromJoySymbol(setup.input[i].joy.bomb));
1365
1366     fprintf(file, "%s\n",
1367             getSetupEntryWithComment(prefix, SETUP_TOKEN_KEY_LEFT,
1368                                      setup.input[i].key.left));
1369     fprintf(file, "%s\n",
1370             getSetupEntryWithComment(prefix, SETUP_TOKEN_KEY_RIGHT,
1371                                      setup.input[i].key.right));
1372     fprintf(file, "%s\n",
1373             getSetupEntryWithComment(prefix, SETUP_TOKEN_KEY_UP,
1374                                      setup.input[i].key.up));
1375     fprintf(file, "%s\n",
1376             getSetupEntryWithComment(prefix, SETUP_TOKEN_KEY_DOWN,
1377                                      setup.input[i].key.down));
1378     fprintf(file, "%s\n",
1379             getSetupEntryWithComment(prefix, SETUP_TOKEN_KEY_SNAP,
1380                                      setup.input[i].key.snap));
1381     fprintf(file, "%s\n",
1382             getSetupEntryWithComment(prefix, SETUP_TOKEN_KEY_BOMB,
1383                                      setup.input[i].key.bomb));
1384   }
1385
1386   fclose(file);
1387
1388   chmod(filename, SETUP_PERMS);
1389 }
1390
1391 #endif
1392
1393
1394
1395 static char *getSetupLine(char *prefix, int token_nr)
1396 {
1397   int i;
1398   static char entry[MAX_LINE_LEN];
1399   int token_type = token_info[token_nr].type;
1400   void *token_value = token_info[token_nr].value;
1401   char *token_text = token_info[token_nr].text;
1402
1403   /* start with the prefix, token and some spaces to format output line */
1404   sprintf(entry, "%s%s:", prefix, token_text);
1405   for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
1406     strcat(entry, " ");
1407
1408   /* continue with the token's value (which can have different types) */
1409   switch (token_type)
1410   {
1411     case TYPE_BOOLEAN:
1412       strcat(entry, (*(boolean *)token_value ? "true" : "false"));
1413       break;
1414
1415     case TYPE_SWITCH:
1416       strcat(entry, (*(boolean *)token_value ? "on" : "off"));
1417       break;
1418
1419     case TYPE_KEYSYM:
1420       {
1421         KeySym keysym = *(KeySym *)token_value;
1422         char *keyname = getKeyNameFromKeySym(keysym);
1423
1424         strcat(entry, getX11KeyNameFromKeySym(keysym));
1425         for (i=strlen(entry); i<50; i++)
1426           strcat(entry, " ");
1427
1428         /* add comment, if useful */
1429         if (strcmp(keyname, "(undefined)") != 0 &&
1430             strcmp(keyname, "(unknown)") != 0)
1431         {
1432           strcat(entry, "# ");
1433           strcat(entry, keyname);
1434         }
1435       }
1436       break;
1437
1438     case TYPE_INTEGER:
1439       {
1440         char buffer[MAX_LINE_LEN];
1441
1442         sprintf(buffer, "%d", *(int *)token_value);
1443         strcat(entry, buffer);
1444       }
1445       break;
1446
1447     case TYPE_STRING:
1448       strcat(entry, *(char **)token_value);
1449       break;
1450
1451     default:
1452       break;
1453   }
1454
1455   return entry;
1456 }
1457
1458 void SaveSetup()
1459 {
1460   int i, pnr;
1461   char filename[MAX_FILENAME_LEN];
1462   FILE *file;
1463
1464   sprintf(filename, "%s/%s", SETUP_PATH, SETUP_FILENAME);
1465
1466   if (!(file = fopen(filename, "w")))
1467   {
1468     Error(ERR_WARN, "cannot write setup file '%s'", filename);
1469     return;
1470   }
1471
1472   fprintf(file, "%s:              %s\n",
1473           TOKEN_STR_FILE_IDENTIFIER, SETUP_COOKIE);
1474
1475   fprintf(file, "\n");
1476
1477   for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
1478     fprintf(file, "%s\n", getSetupLine("", i));
1479
1480   for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1481   {
1482     char prefix[30];
1483
1484     sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, i + 1);
1485     fprintf(file, "\n");
1486
1487     for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
1488     {
1489       sii = setup.input[pnr];
1490       fprintf(file, "%s\n", getSetupLine(prefix, i));
1491     }
1492   }
1493
1494   fclose(file);
1495
1496   chmod(filename, SETUP_PERMS);
1497 }
1498
1499 void LoadLevelSetup()
1500 {
1501   char filename[MAX_FILENAME_LEN];
1502
1503   /* always start with reliable default setup values */
1504
1505   leveldir_nr = 0;
1506   level_nr = 0;
1507
1508   sprintf(filename, "%s/%s", SETUP_PATH, LEVELSETUP_FILENAME);
1509
1510   if (level_setup_list)
1511     freeSetupFileList(level_setup_list);
1512
1513   level_setup_list = loadSetupFileList(filename);
1514
1515   if (level_setup_list)
1516   {
1517     char *last_level_series =
1518       getSetupFileListEntry(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
1519
1520     leveldir_nr = getLevelSeriesNrFromLevelSeriesName(last_level_series);
1521     level_nr = getLastPlayedLevelOfLevelSeries(last_level_series);
1522
1523 #if 0
1524     printSetupFileList(level_setup_list);
1525 #endif
1526
1527     checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
1528   }
1529   else
1530     Error(ERR_WARN, "using default setup values");
1531 }
1532
1533 void SaveLevelSetup()
1534 {
1535   char filename[MAX_FILENAME_LEN];
1536   struct SetupFileList *list_entry = level_setup_list;
1537   FILE *file;
1538
1539   updateSetupFileListEntry(level_setup_list,
1540                            TOKEN_STR_LAST_LEVEL_SERIES,
1541                            leveldir[leveldir_nr].filename);
1542
1543   updateSetupFileListEntry(level_setup_list,
1544                            leveldir[leveldir_nr].filename,
1545                            int2str(level_nr, 0));
1546
1547   sprintf(filename, "%s/%s", SETUP_PATH, LEVELSETUP_FILENAME);
1548
1549   if (!(file = fopen(filename, "w")))
1550   {
1551     Error(ERR_WARN, "cannot write setup file '%s'", filename);
1552     return;
1553   }
1554
1555   fprintf(file, "%s:              %s\n\n",
1556           TOKEN_STR_FILE_IDENTIFIER, LEVELSETUP_COOKIE);
1557
1558   while (list_entry)
1559   {
1560     if (strcmp(list_entry->token, TOKEN_STR_FILE_IDENTIFIER) != 0)
1561       fprintf(file, "%s\n",
1562               getFormattedSetupEntry(list_entry->token, list_entry->value));
1563
1564     /* just to make things nicer :) */
1565     if (strcmp(list_entry->token, TOKEN_STR_LAST_LEVEL_SERIES) == 0)
1566       fprintf(file, "\n");
1567
1568     list_entry = list_entry->next;
1569   }
1570
1571   fclose(file);
1572
1573   chmod(filename, SETUP_PERMS);
1574 }