1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-98 Artsoft Entertainment *
8 * phone: ++49 +521 290471 *
9 * email: aeglos@valinor.owl.de *
10 *----------------------------------------------------------*
12 ***********************************************************/
22 static char *getUserdataDir()
24 static char *userdata_dir = NULL;
28 char *home_dir = getHomeDir();
29 char *data_dir = USERDATA_DIRECTORY;
31 userdata_dir = checked_malloc(strlen(home_dir) + strlen(data_dir) + 2);
32 sprintf(userdata_dir, "%s/%s", home_dir, data_dir);
38 static char *getSetupDir()
40 return getUserdataDir();
43 static char *getTapeDir(char *level_subdir)
45 static char *tape_dir = NULL;
46 char *data_dir = getUserdataDir();
47 char *tape_subdir = TAPEDATA_DIRECTORY;
52 tape_dir = checked_malloc(strlen(data_dir) + strlen(tape_subdir) +
53 strlen(level_subdir) + 3);
54 sprintf(tape_dir, "%s/%s%s%s", data_dir, tape_subdir,
55 (strlen(level_subdir) > 0 ? "/" : ""), level_subdir);
60 static void createDirectory(char *dir, char *text)
62 if (access(dir, F_OK) != 0)
63 if (mkdir(dir, USERDATA_DIR_MODE) != 0)
64 Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
67 void InitUserdataDirectory()
69 createDirectory(getUserdataDir(), "user data");
72 static void InitTapeDirectory(char *level_subdir)
74 createDirectory(getTapeDir(""), "main tape data");
75 createDirectory(getTapeDir(level_subdir), "level tape data");
78 boolean LoadLevelInfo()
81 char filename[MAX_FILENAME_LEN];
82 char cookie[MAX_FILENAME_LEN];
85 sprintf(filename,"%s/%s",level_directory,LEVDIR_FILENAME);
87 if (!(file=fopen(filename,"r")))
89 Error(ERR_WARN, "cannot read level info '%s'", filename);
93 fscanf(file,"%s\n",cookie);
94 if (strcmp(cookie,LEVELDIR_COOKIE)) /* ungültiges Format? */
96 Error(ERR_WARN, "wrong format of level info file");
103 for(i=0;i<MAX_LEVDIR_ENTRIES;i++)
105 fscanf(file,"%s",leveldir[i].filename);
106 fscanf(file,"%s",leveldir[i].name);
107 fscanf(file,"%d",&leveldir[i].levels);
108 fscanf(file,"%d",&leveldir[i].readonly);
117 Error(ERR_WARN, "empty level info '%s'", filename);
124 void LoadLevel(int level_nr)
127 char filename[MAX_FILENAME_LEN];
128 char cookie[MAX_FILENAME_LEN];
131 sprintf(filename,"%s/%s/%d",
132 level_directory,leveldir[leveldir_nr].filename,level_nr);
134 if (!(file = fopen(filename,"r")))
135 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
138 fgets(cookie,LEVEL_COOKIE_LEN,file);
141 if (strcmp(cookie,LEVEL_COOKIE)) /* ungültiges Format? */
143 Error(ERR_WARN, "wrong format of level file '%s'", filename);
151 lev_fieldx = level.fieldx = fgetc(file);
152 lev_fieldy = level.fieldy = fgetc(file);
154 level.time = (fgetc(file)<<8) | fgetc(file);
155 level.edelsteine = (fgetc(file)<<8) | fgetc(file);
156 for(i=0;i<MAX_LEVNAMLEN;i++)
157 level.name[i] = fgetc(file);
158 level.name[MAX_LEVNAMLEN-1] = 0;
159 for(i=0;i<MAX_LEVSCORE_ENTRIES;i++)
160 level.score[i] = fgetc(file);
164 level.mampfer_inhalt[i][x][y] = fgetc(file);
165 level.tempo_amoebe = fgetc(file);
166 level.dauer_sieb = fgetc(file);
167 level.dauer_ablenk = fgetc(file);
168 level.amoebe_inhalt = fgetc(file);
170 for(i=0;i<NUM_FREE_LVHD_BYTES;i++) /* Rest frei / Headergröße 80 Bytes */
173 for(y=0;y<MAX_LEV_FIELDY;y++)
174 for(x=0;x<MAX_LEV_FIELDX;x++)
175 Feld[x][y] = Ur[x][y] = EL_ERDREICH;
177 for(y=0;y<lev_fieldy;y++)
178 for(x=0;x<lev_fieldx;x++)
179 Feld[x][y] = Ur[x][y] = fgetc(file);
183 if (level.time<=10) /* Mindestspieldauer */
188 lev_fieldx = level.fieldx = STD_LEV_FIELDX;
189 lev_fieldy = level.fieldy = STD_LEV_FIELDY;
192 level.edelsteine = 0;
193 strncpy(level.name,"Nameless Level",MAX_LEVNAMLEN-1);
194 for(i=0;i<MAX_LEVSCORE_ENTRIES;i++)
199 level.mampfer_inhalt[i][x][y] = EL_FELSBROCKEN;
200 level.tempo_amoebe = 10;
201 level.dauer_sieb = 10;
202 level.dauer_ablenk = 10;
203 level.amoebe_inhalt = EL_DIAMANT;
205 for(y=0;y<STD_LEV_FIELDY;y++)
206 for(x=0;x<STD_LEV_FIELDX;x++)
207 Feld[x][y] = Ur[x][y] = EL_ERDREICH;
208 Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
209 Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
210 Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
214 void SaveLevel(int level_nr)
217 char filename[MAX_FILENAME_LEN];
220 sprintf(filename,"%s/%s/%d",
221 level_directory,leveldir[leveldir_nr].filename,level_nr);
223 if (!(file=fopen(filename,"w")))
225 Error(ERR_WARN, "cannot save level file '%s'", filename);
229 fputs(LEVEL_COOKIE,file); /* Formatkennung */
232 fputc(level.fieldx,file);
233 fputc(level.fieldy,file);
234 fputc(level.time / 256,file);
235 fputc(level.time % 256,file);
236 fputc(level.edelsteine / 256,file);
237 fputc(level.edelsteine % 256,file);
239 for(i=0;i<MAX_LEVNAMLEN;i++)
240 fputc(level.name[i],file);
241 for(i=0;i<MAX_LEVSCORE_ENTRIES;i++)
242 fputc(level.score[i],file);
246 fputc(level.mampfer_inhalt[i][x][y],file);
247 fputc(level.tempo_amoebe,file);
248 fputc(level.dauer_sieb,file);
249 fputc(level.dauer_ablenk,file);
250 fputc(level.amoebe_inhalt,file);
252 for(i=0;i<NUM_FREE_LVHD_BYTES;i++) /* Rest frei / Headergröße 80 Bytes */
255 for(y=0;y<lev_fieldy;y++)
256 for(x=0;x<lev_fieldx;x++)
257 fputc(Ur[x][y],file);
261 chmod(filename, LEVEL_PERMS);
264 void LoadLevelTape(int level_nr)
267 char filename[MAX_FILENAME_LEN];
268 char cookie[MAX_FILENAME_LEN];
270 boolean levelrec_10 = FALSE;
272 sprintf(filename, "%s/%d.%s",
273 getTapeDir(leveldir[leveldir_nr].filename),
274 level_nr, TAPEFILE_EXTENSION);
276 if ((file = fopen(filename, "r")))
278 fgets(cookie, LEVELREC_COOKIE_LEN, file);
280 if (!strcmp(cookie, LEVELREC_COOKIE_10)) /* old 1.0 tape format */
282 else if (strcmp(cookie, LEVELREC_COOKIE)) /* unknown tape format */
284 Error(ERR_WARN, "wrong format of level recording file '%s'", filename);
294 (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
296 (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
298 (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
300 tape.level_nr = level_nr;
302 tape.changed = FALSE;
304 tape.recording = FALSE;
305 tape.playing = FALSE;
306 tape.pausing = FALSE;
308 for(i=0; i<tape.length; i++)
312 if (i >= MAX_TAPELEN)
315 for(j=0; j<MAX_PLAYERS; j++)
317 if (levelrec_10 && j > 0)
319 tape.pos[i].action[j] = MV_NO_MOVING;
322 tape.pos[i].action[j] = fgetc(file);
325 tape.pos[i].delay = fgetc(file);
329 /* eliminate possible diagonal moves in old tapes */
330 /* this is only for backward compatibility */
332 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
333 byte action = tape.pos[i].action[0];
334 int k, num_moves = 0;
338 if (action & joy_dir[k])
340 tape.pos[i + num_moves].action[0] = joy_dir[k];
342 tape.pos[i + num_moves].delay = 0;
351 tape.length += num_moves;
361 if (i != tape.length)
362 Error(ERR_WARN, "level recording file '%s' corrupted", filename);
364 tape.length_seconds = GetTapeLength();
367 void SaveLevelTape(int level_nr)
370 char filename[MAX_FILENAME_LEN];
372 boolean new_tape = TRUE;
374 sprintf(filename, "%s/%d.%s",
375 getTapeDir(leveldir[leveldir_nr].filename),
376 level_nr, TAPEFILE_EXTENSION);
378 InitTapeDirectory(leveldir[leveldir_nr].filename);
380 /* Testen, ob bereits eine Aufnahme existiert */
381 if ((file = fopen(filename, "r")))
386 if (!Request("Replace old tape ?", REQ_ASK))
390 if (!(file = fopen(filename, "w")))
392 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
396 fputs(LEVELREC_COOKIE, file); /* Formatkennung */
399 fputc((tape.random_seed >> 24) & 0xff,file);
400 fputc((tape.random_seed >> 16) & 0xff,file);
401 fputc((tape.random_seed >> 8) & 0xff,file);
402 fputc((tape.random_seed >> 0) & 0xff,file);
404 fputc((tape.date >> 24) & 0xff,file);
405 fputc((tape.date >> 16) & 0xff,file);
406 fputc((tape.date >> 8) & 0xff,file);
407 fputc((tape.date >> 0) & 0xff,file);
409 fputc((tape.length >> 24) & 0xff,file);
410 fputc((tape.length >> 16) & 0xff,file);
411 fputc((tape.length >> 8) & 0xff,file);
412 fputc((tape.length >> 0) & 0xff,file);
414 for(i=0; i<tape.length; i++)
418 for(j=0; j<MAX_PLAYERS; j++)
419 fputc(tape.pos[i].action[j], file);
421 fputc(tape.pos[i].delay, file);
426 chmod(filename, LEVREC_PERMS);
428 tape.changed = FALSE;
431 Request("tape saved !",REQ_CONFIRM);
434 boolean CreateNewScoreFile()
437 char filename[MAX_FILENAME_LEN];
438 char empty_alias[MAX_NAMELEN];
441 sprintf(filename,"%s/%s/%s",
442 level_directory,leveldir[leveldir_nr].filename,SCORE_FILENAME);
444 if (!(file=fopen(filename,"w")))
447 for(i=0;i<MAX_NAMELEN;i++)
449 strncpy(empty_alias,EMPTY_ALIAS,MAX_NAMELEN-1);
451 fputs(SCORE_COOKIE,file); /* Formatkennung */
452 for(i=0;i<leveldir[leveldir_nr].levels;i++)
454 for(j=0;j<MAX_SCORE_ENTRIES;j++)
456 for(k=0;k<MAX_NAMELEN;k++)
457 fputc(empty_alias[k],file);
464 chmod(filename, SCORE_PERMS);
468 void LoadScore(int level_nr)
471 char filename[MAX_FILENAME_LEN];
472 char cookie[MAX_FILENAME_LEN];
475 sprintf(filename,"%s/%s/%s",
476 level_directory,leveldir[leveldir_nr].filename,SCORE_FILENAME);
478 if (!(file = fopen(filename,"r")))
480 if (!CreateNewScoreFile())
481 Error(ERR_WARN, "cannot create score file '%s'", filename);
482 else if (!(file = fopen(filename,"r")))
483 Error(ERR_WARN, "cannot read score for level %d", level_nr);
488 fgets(cookie,SCORE_COOKIE_LEN,file);
489 if (strcmp(cookie,SCORE_COOKIE)) /* ungültiges Format? */
491 Error(ERR_WARN, "wrong format of score file '%s'", filename);
500 SCORE_COOKIE_LEN-1+level_nr*(MAX_SCORE_ENTRIES*(MAX_NAMELEN+2)),
502 for(i=0;i<MAX_SCORE_ENTRIES;i++)
504 for(j=0;j<MAX_NAMELEN;j++)
505 highscore[i].Name[j] = fgetc(file);
506 highscore[i].Score = (fgetc(file)<<8) | fgetc(file);
512 for(i=0;i<MAX_SCORE_ENTRIES;i++)
514 strcpy(highscore[i].Name,EMPTY_ALIAS);
515 highscore[i].Score = 0;
520 void SaveScore(int level_nr)
523 char filename[MAX_FILENAME_LEN];
526 sprintf(filename,"%s/%s/%s",
527 level_directory,leveldir[leveldir_nr].filename,SCORE_FILENAME);
529 if (!(file=fopen(filename,"r+")))
531 Error(ERR_WARN, "cannot save score for level %d", level_nr);
536 SCORE_COOKIE_LEN-1+level_nr*(MAX_SCORE_ENTRIES*(MAX_NAMELEN+2)),
538 for(i=0;i<MAX_SCORE_ENTRIES;i++)
540 for(j=0;j<MAX_NAMELEN;j++)
541 fputc(highscore[i].Name[j],file);
542 fputc(highscore[i].Score / 256,file);
543 fputc(highscore[i].Score % 256,file);
548 #define MAX_LINE_LEN 1000
550 #define TOKEN_STR_FILE_IDENTIFIER "file_identifier"
551 #define TOKEN_STR_LAST_LEVEL_SERIES "last_level_series"
552 #define TOKEN_STR_PLAYER_PREFIX "player_"
554 #define TOKEN_VALUE_POSITION 30
556 #define SETUP_TOKEN_SOUND 0
557 #define SETUP_TOKEN_SOUND_LOOPS 1
558 #define SETUP_TOKEN_SOUND_MUSIC 2
559 #define SETUP_TOKEN_SOUND_SIMPLE 3
560 #define SETUP_TOKEN_TOONS 4
561 #define SETUP_TOKEN_DOUBLE_BUFFERING 5
562 #define SETUP_TOKEN_SCROLL_DELAY 6
563 #define SETUP_TOKEN_SOFT_SCROLLING 7
564 #define SETUP_TOKEN_FADING 8
565 #define SETUP_TOKEN_AUTORECORD 9
566 #define SETUP_TOKEN_QUICK_DOORS 10
567 #define SETUP_TOKEN_TEAM_MODE 11
568 #define SETUP_TOKEN_ALIAS_NAME 12
570 #define SETUP_TOKEN_USE_JOYSTICK 13
571 #define SETUP_TOKEN_JOY_DEVICE_NAME 14
572 #define SETUP_TOKEN_JOY_XLEFT 15
573 #define SETUP_TOKEN_JOY_XMIDDLE 16
574 #define SETUP_TOKEN_JOY_XRIGHT 17
575 #define SETUP_TOKEN_JOY_YUPPER 18
576 #define SETUP_TOKEN_JOY_YMIDDLE 19
577 #define SETUP_TOKEN_JOY_YLOWER 20
578 #define SETUP_TOKEN_JOY_SNAP 21
579 #define SETUP_TOKEN_JOY_BOMB 22
580 #define SETUP_TOKEN_KEY_LEFT 23
581 #define SETUP_TOKEN_KEY_RIGHT 24
582 #define SETUP_TOKEN_KEY_UP 25
583 #define SETUP_TOKEN_KEY_DOWN 26
584 #define SETUP_TOKEN_KEY_SNAP 27
585 #define SETUP_TOKEN_KEY_BOMB 28
587 #define NUM_SETUP_TOKENS 29
589 #define FIRST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_SOUND
590 #define LAST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_ALIAS_NAME
592 #define FIRST_PLAYER_SETUP_TOKEN SETUP_TOKEN_USE_JOYSTICK
593 #define LAST_PLAYER_SETUP_TOKEN SETUP_TOKEN_KEY_BOMB
595 #define TYPE_BOOLEAN 1
596 #define TYPE_SWITCH 2
597 #define TYPE_KEYSYM 3
598 #define TYPE_INTEGER 4
599 #define TYPE_STRING 5
601 static struct SetupInfo si;
602 static struct SetupInputInfo sii;
610 { TYPE_SWITCH, &si.sound, "sound" },
611 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
612 { TYPE_SWITCH, &si.sound_music, "background_music" },
613 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
614 { TYPE_SWITCH, &si.toons, "toons" },
615 { TYPE_SWITCH, &si.double_buffering, "double_buffering" },
616 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
617 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
618 { TYPE_SWITCH, &si.fading, "screen_fading" },
619 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
620 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
621 { TYPE_SWITCH, &si.team_mode, "team_mode" },
622 { TYPE_STRING, &si.alias_name, "alias_name" },
624 /* for each player: */
625 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
626 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
627 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
628 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
629 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
630 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
631 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
632 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
633 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
634 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
635 { TYPE_KEYSYM, &sii.key.left, ".key.move_left" },
636 { TYPE_KEYSYM, &sii.key.right, ".key.move_right" },
637 { TYPE_KEYSYM, &sii.key.up, ".key.move_up" },
638 { TYPE_KEYSYM, &sii.key.down, ".key.move_down" },
639 { TYPE_KEYSYM, &sii.key.snap, ".key.snap_field" },
640 { TYPE_KEYSYM, &sii.key.bomb, ".key.place_bomb" }
643 static char *string_tolower(char *s)
645 static char s_lower[100];
648 if (strlen(s) >= 100)
653 for (i=0; i<strlen(s_lower); i++)
654 s_lower[i] = tolower(s_lower[i]);
659 static int get_string_integer_value(char *s)
661 static char *number_text[][3] =
663 { "0", "zero", "null", },
664 { "1", "one", "first" },
665 { "2", "two", "second" },
666 { "3", "three", "third" },
667 { "4", "four", "fourth" },
668 { "5", "five", "fifth" },
669 { "6", "six", "sixth" },
670 { "7", "seven", "seventh" },
671 { "8", "eight", "eighth" },
672 { "9", "nine", "ninth" },
673 { "10", "ten", "tenth" },
674 { "11", "eleven", "eleventh" },
675 { "12", "twelve", "twelfth" },
682 if (strcmp(string_tolower(s), number_text[i][j]) == 0)
688 static boolean get_string_boolean_value(char *s)
690 if (strcmp(string_tolower(s), "true") == 0 ||
691 strcmp(string_tolower(s), "yes") == 0 ||
692 strcmp(string_tolower(s), "on") == 0 ||
693 get_string_integer_value(s) == 1)
699 static char *getFormattedSetupEntry(char *token, char *value)
702 static char entry[MAX_LINE_LEN];
704 sprintf(entry, "%s:", token);
705 for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
709 strcat(entry, value);
714 static void freeSetupFileList(struct SetupFileList *setup_file_list)
716 if (!setup_file_list)
719 if (setup_file_list->token)
720 free(setup_file_list->token);
721 if (setup_file_list->value)
722 free(setup_file_list->value);
723 if (setup_file_list->next)
724 freeSetupFileList(setup_file_list->next);
725 free(setup_file_list);
728 static struct SetupFileList *newSetupFileList(char *token, char *value)
730 struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
732 new->token = checked_malloc(strlen(token) + 1);
733 strcpy(new->token, token);
735 new->value = checked_malloc(strlen(value) + 1);
736 strcpy(new->value, value);
743 static char *getTokenValue(struct SetupFileList *setup_file_list,
746 if (!setup_file_list)
749 if (strcmp(setup_file_list->token, token) == 0)
750 return setup_file_list->value;
752 return getTokenValue(setup_file_list->next, token);
755 static void setTokenValue(struct SetupFileList *setup_file_list,
756 char *token, char *value)
758 if (!setup_file_list)
761 if (strcmp(setup_file_list->token, token) == 0)
763 free(setup_file_list->value);
764 setup_file_list->value = checked_malloc(strlen(value) + 1);
765 strcpy(setup_file_list->value, value);
767 else if (setup_file_list->next == NULL)
768 setup_file_list->next = newSetupFileList(token, value);
770 setTokenValue(setup_file_list->next, token, value);
774 static void printSetupFileList(struct SetupFileList *setup_file_list)
776 if (!setup_file_list)
779 printf("token: '%s'\n", setup_file_list->token);
780 printf("value: '%s'\n", setup_file_list->value);
782 printSetupFileList(setup_file_list->next);
786 static struct SetupFileList *loadSetupFileList(char *filename)
789 char line[MAX_LINE_LEN];
790 char *token, *value, *line_ptr;
791 struct SetupFileList *setup_file_list = newSetupFileList("", "");
792 struct SetupFileList *first_valid_list_entry;
796 if (!(file = fopen(filename, "r")))
798 Error(ERR_WARN, "cannot open setup file '%s'", filename);
804 /* read next line of input file */
805 if (!fgets(line, MAX_LINE_LEN, file))
808 /* cut trailing comment or whitespace from input line */
809 for (line_ptr = line; *line_ptr; line_ptr++)
811 if (*line_ptr == '#' || *line_ptr == '\n')
818 /* cut trailing whitespaces from input line */
819 for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--)
820 if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0')
823 /* ignore empty lines */
827 line_len = strlen(line);
829 /* cut leading whitespaces from token */
830 for (token = line; *token; token++)
831 if (*token != ' ' && *token != '\t')
834 /* find end of token */
835 for (line_ptr = token; *line_ptr; line_ptr++)
837 if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
844 if (line_ptr < line + line_len)
845 value = line_ptr + 1;
849 /* cut leading whitespaces from value */
850 for (; *value; value++)
851 if (*value != ' ' && *value != '\t')
854 if (*token && *value)
855 setTokenValue(setup_file_list, token, value);
860 first_valid_list_entry = setup_file_list->next;
862 /* free empty list header */
863 setup_file_list->next = NULL;
864 freeSetupFileList(setup_file_list);
866 if (!first_valid_list_entry)
867 Error(ERR_WARN, "setup file is empty");
869 return first_valid_list_entry;
872 static void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
875 if (!setup_file_list)
878 if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
880 if (strcmp(setup_file_list->value, identifier) != 0)
882 Error(ERR_WARN, "setup file has wrong version");
889 if (setup_file_list->next)
890 checkSetupFileListIdentifier(setup_file_list->next, identifier);
893 Error(ERR_WARN, "setup file has no version information");
898 static void setSetupInfoToDefaults(struct SetupInfo *si)
903 si->sound_loops = FALSE;
904 si->sound_music = FALSE;
905 si->sound_simple = FALSE;
907 si->double_buffering = TRUE;
908 si->direct_draw = !si->double_buffering;
909 si->scroll_delay = FALSE;
910 si->soft_scrolling = TRUE;
912 si->autorecord = FALSE;
913 si->quick_doors = FALSE;
915 strncpy(si->login_name, getLoginName(), MAX_NAMELEN-1);
916 si->login_name[MAX_NAMELEN-1] = '\0';
917 strncpy(si->alias_name, getLoginName(), MAX_NAMELEN-1);
918 si->alias_name[MAX_NAMELEN-1] = '\0';
920 for (i=0; i<MAX_PLAYERS; i++)
922 si->input[i].use_joystick = FALSE;
923 strcpy(si->input[i].joy.device_name, joystick_device_name[i]);
924 si->input[i].joy.xleft = JOYSTICK_XLEFT;
925 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
926 si->input[i].joy.xright = JOYSTICK_XRIGHT;
927 si->input[i].joy.yupper = JOYSTICK_YUPPER;
928 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
929 si->input[i].joy.ylower = JOYSTICK_YLOWER;
930 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
931 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
932 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KEY_UNDEFINDED);
933 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KEY_UNDEFINDED);
934 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KEY_UNDEFINDED);
935 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KEY_UNDEFINDED);
936 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KEY_UNDEFINDED);
937 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KEY_UNDEFINDED);
941 static void setSetupInfo(int token_nr, char *token_value)
943 int token_type = token_info[token_nr].type;
944 void *setup_value = token_info[token_nr].value;
946 if (token_value == NULL)
949 /* set setup field to corresponding token value */
954 *(boolean *)setup_value = get_string_boolean_value(token_value);
958 *(KeySym *)setup_value = getKeySymFromX11KeyName(token_value);
962 *(int *)setup_value = get_string_integer_value(token_value);
966 strcpy((char *)setup_value, token_value);
974 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
978 if (!setup_file_list)
981 /* handle global setup values */
983 for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
984 setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
987 /* handle player specific setup values */
988 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
992 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
994 sii = setup.input[pnr];
995 for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
997 char full_token[100];
999 sprintf(full_token, "%s%s", prefix, token_info[i].text);
1000 setSetupInfo(i, getTokenValue(setup_file_list, full_token));
1002 setup.input[pnr] = sii;
1006 int getLevelSeriesNrFromLevelSeriesName(char *level_series_name)
1010 if (!level_series_name)
1013 for (i=0; i<num_leveldirs; i++)
1014 if (strcmp(level_series_name, leveldir[i].filename) == 0)
1020 int getLastPlayedLevelOfLevelSeries(char *level_series_name)
1023 int level_series_nr = getLevelSeriesNrFromLevelSeriesName(level_series_name);
1024 int last_level_nr = 0;
1026 if (!level_series_name)
1029 token_value = getTokenValue(level_setup_list, level_series_name);
1033 int highest_level_nr = leveldir[level_series_nr].levels - 1;
1035 last_level_nr = atoi(token_value);
1037 if (last_level_nr < 0)
1039 if (last_level_nr > highest_level_nr)
1040 last_level_nr = highest_level_nr;
1043 return last_level_nr;
1048 char filename[MAX_FILENAME_LEN];
1049 struct SetupFileList *setup_file_list = NULL;
1051 /* always start with reliable default setup values */
1052 setSetupInfoToDefaults(&setup);
1054 sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME);
1056 setup_file_list = loadSetupFileList(filename);
1058 if (setup_file_list)
1060 checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE);
1061 decodeSetupFileList(setup_file_list);
1063 setup.direct_draw = !setup.double_buffering;
1065 freeSetupFileList(setup_file_list);
1068 Error(ERR_WARN, "using default setup values");
1071 static char *getSetupLine(char *prefix, int token_nr)
1074 static char entry[MAX_LINE_LEN];
1075 int token_type = token_info[token_nr].type;
1076 void *setup_value = token_info[token_nr].value;
1077 char *token_text = token_info[token_nr].text;
1079 /* start with the prefix, token and some spaces to format output line */
1080 sprintf(entry, "%s%s:", prefix, token_text);
1081 for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
1084 /* continue with the token's value (which can have different types) */
1088 strcat(entry, (*(boolean *)setup_value ? "true" : "false"));
1092 strcat(entry, (*(boolean *)setup_value ? "on" : "off"));
1097 KeySym keysym = *(KeySym *)setup_value;
1098 char *keyname = getKeyNameFromKeySym(keysym);
1100 strcat(entry, getX11KeyNameFromKeySym(keysym));
1101 for (i=strlen(entry); i<50; i++)
1104 /* add comment, if useful */
1105 if (strcmp(keyname, "(undefined)") != 0 &&
1106 strcmp(keyname, "(unknown)") != 0)
1108 strcat(entry, "# ");
1109 strcat(entry, keyname);
1116 char buffer[MAX_LINE_LEN];
1118 sprintf(buffer, "%d", *(int *)setup_value);
1119 strcat(entry, buffer);
1124 strcat(entry, (char *)setup_value);
1137 char filename[MAX_FILENAME_LEN];
1140 sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME);
1142 if (!(file = fopen(filename, "w")))
1144 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1148 fprintf(file, "%s\n",
1149 getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, SETUP_COOKIE));
1150 fprintf(file, "\n");
1152 /* handle global setup values */
1154 for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
1156 /* just to make things nicer :) */
1157 if (i == SETUP_TOKEN_ALIAS_NAME)
1158 fprintf(file, "\n");
1160 fprintf(file, "%s\n", getSetupLine("", i));
1163 /* handle player specific setup values */
1164 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1168 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1169 fprintf(file, "\n");
1171 sii = setup.input[pnr];
1172 for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
1173 fprintf(file, "%s\n", getSetupLine(prefix, i));
1178 chmod(filename, SETUP_PERMS);
1181 void LoadLevelSetup()
1183 char filename[MAX_FILENAME_LEN];
1185 /* always start with reliable default setup values */
1190 sprintf(filename, "%s/%s", getSetupDir(), LEVELSETUP_FILENAME);
1192 if (level_setup_list)
1193 freeSetupFileList(level_setup_list);
1195 level_setup_list = loadSetupFileList(filename);
1197 if (level_setup_list)
1199 char *last_level_series =
1200 getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
1202 leveldir_nr = getLevelSeriesNrFromLevelSeriesName(last_level_series);
1203 level_nr = getLastPlayedLevelOfLevelSeries(last_level_series);
1205 checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
1208 Error(ERR_WARN, "using default setup values");
1211 void SaveLevelSetup()
1213 char filename[MAX_FILENAME_LEN];
1214 struct SetupFileList *list_entry = level_setup_list;
1217 setTokenValue(level_setup_list,
1218 TOKEN_STR_LAST_LEVEL_SERIES, leveldir[leveldir_nr].filename);
1220 setTokenValue(level_setup_list,
1221 leveldir[leveldir_nr].filename, int2str(level_nr, 0));
1223 sprintf(filename, "%s/%s", getSetupDir(), LEVELSETUP_FILENAME);
1225 if (!(file = fopen(filename, "w")))
1227 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1231 fprintf(file, "%s: %s\n\n",
1232 TOKEN_STR_FILE_IDENTIFIER, LEVELSETUP_COOKIE);
1236 if (strcmp(list_entry->token, TOKEN_STR_FILE_IDENTIFIER) != 0)
1237 fprintf(file, "%s\n",
1238 getFormattedSetupEntry(list_entry->token, list_entry->value));
1240 /* just to make things nicer :) */
1241 if (strcmp(list_entry->token, TOKEN_STR_LAST_LEVEL_SERIES) == 0)
1242 fprintf(file, "\n");
1244 list_entry = list_entry->next;
1249 chmod(filename, SETUP_PERMS);