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 #define MAX_LINE_LEN 1000
24 static char *getGlobalDataDir()
29 static char *getUserDataDir()
31 static char *userdata_dir = NULL;
35 char *home_dir = getHomeDir();
36 char *data_dir = USERDATA_DIRECTORY;
38 userdata_dir = checked_malloc(strlen(home_dir) + strlen(data_dir) + 2);
39 sprintf(userdata_dir, "%s/%s", home_dir, data_dir);
45 static char *getSetupDir()
47 return getUserDataDir();
50 static char *getTapeDir(char *level_subdir)
52 static char *tape_dir = NULL;
53 char *data_dir = getUserDataDir();
54 char *tape_subdir = TAPES_DIRECTORY;
59 tape_dir = checked_malloc(strlen(data_dir) + strlen(tape_subdir) +
60 strlen(level_subdir) + 3);
61 sprintf(tape_dir, "%s/%s%s%s", data_dir, tape_subdir,
62 (strlen(level_subdir) > 0 ? "/" : ""), level_subdir);
67 static char *getScoreDir(char *level_subdir)
69 static char *score_dir = NULL;
70 char *data_dir = getGlobalDataDir();
71 char *score_subdir = SCORES_DIRECTORY;
76 score_dir = checked_malloc(strlen(data_dir) + strlen(score_subdir) +
77 strlen(level_subdir) + 3);
78 sprintf(score_dir, "%s/%s%s%s", data_dir, score_subdir,
79 (strlen(level_subdir) > 0 ? "/" : ""), level_subdir);
84 static void createDirectory(char *dir, char *text)
86 if (access(dir, F_OK) != 0)
87 if (mkdir(dir, USERDATA_DIR_MODE) != 0)
88 Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
91 static void InitUserDataDirectory()
93 createDirectory(getUserDataDir(), "user data");
96 static void InitTapeDirectory(char *level_subdir)
98 createDirectory(getTapeDir(""), "main tape");
99 createDirectory(getTapeDir(level_subdir), "level tape");
102 static void InitScoreDirectory(char *level_subdir)
104 createDirectory(getScoreDir(""), "main score");
105 createDirectory(getScoreDir(level_subdir), "level score");
108 boolean LoadLevelInfo()
111 char filename[MAX_FILENAME_LEN];
112 char cookie[MAX_FILENAME_LEN];
115 sprintf(filename, "%s/%s", options.level_directory, LEVDIR_FILENAME);
117 if (!(file = fopen(filename, "r")))
119 Error(ERR_WARN, "cannot read level info '%s'", filename);
123 fscanf(file, "%s\n", cookie);
124 if (strcmp(cookie, LEVELDIR_COOKIE))
126 Error(ERR_WARN, "wrong format of level info file");
133 for(i=0; i<MAX_LEVDIR_ENTRIES; i++)
135 fscanf(file, "%s", leveldir[i].filename);
136 fscanf(file, "%s", leveldir[i].name);
137 fscanf(file, "%d", &leveldir[i].levels);
138 fscanf(file, "%d", &leveldir[i].readonly);
147 Error(ERR_WARN, "empty level info '%s'", filename);
154 void LoadLevel(int level_nr)
157 char filename[MAX_FILENAME_LEN];
158 char cookie[MAX_FILENAME_LEN];
161 sprintf(filename, "%s/%s/%d",
162 options.level_directory, leveldir[leveldir_nr].filename, level_nr);
164 if (!(file = fopen(filename, "r")))
165 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
168 fgets(cookie, LEVEL_COOKIE_LEN, file);
171 if (strcmp(cookie,LEVEL_COOKIE))
173 Error(ERR_WARN, "wrong format of level file '%s'", filename);
181 lev_fieldx = level.fieldx = fgetc(file);
182 lev_fieldy = level.fieldy = fgetc(file);
184 level.time = (fgetc(file)<<8) | fgetc(file);
185 level.edelsteine = (fgetc(file)<<8) | fgetc(file);
186 for(i=0; i<MAX_LEVNAMLEN; i++)
187 level.name[i] = fgetc(file);
188 level.name[MAX_LEVNAMLEN-1] = 0;
189 for(i=0; i<MAX_LEVSCORE_ENTRIES; i++)
190 level.score[i] = fgetc(file);
194 level.mampfer_inhalt[i][x][y] = fgetc(file);
195 level.tempo_amoebe = fgetc(file);
196 level.dauer_sieb = fgetc(file);
197 level.dauer_ablenk = fgetc(file);
198 level.amoebe_inhalt = fgetc(file);
200 for(i=0; i<NUM_FREE_LVHD_BYTES; i++) /* Rest frei / Headergröße 80 Bytes */
203 for(y=0; y<MAX_LEV_FIELDY; y++)
204 for(x=0; x<MAX_LEV_FIELDX; x++)
205 Feld[x][y] = Ur[x][y] = EL_ERDREICH;
207 for(y=0; y<lev_fieldy; y++)
208 for(x=0; x<lev_fieldx; x++)
209 Feld[x][y] = Ur[x][y] = fgetc(file);
213 if (level.time <= 10) /* Mindestspieldauer */
218 lev_fieldx = level.fieldx = STD_LEV_FIELDX;
219 lev_fieldy = level.fieldy = STD_LEV_FIELDY;
222 level.edelsteine = 0;
223 strcpy(level.name, "Nameless Level");
224 for(i=0; i<MAX_LEVSCORE_ENTRIES; i++)
229 level.mampfer_inhalt[i][x][y] = EL_FELSBROCKEN;
230 level.tempo_amoebe = 10;
231 level.dauer_sieb = 10;
232 level.dauer_ablenk = 10;
233 level.amoebe_inhalt = EL_DIAMANT;
235 for(y=0; y<STD_LEV_FIELDY; y++)
236 for(x=0; x<STD_LEV_FIELDX; x++)
237 Feld[x][y] = Ur[x][y] = EL_ERDREICH;
238 Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
239 Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
240 Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
244 void SaveLevel(int level_nr)
247 char filename[MAX_FILENAME_LEN];
250 sprintf(filename, "%s/%s/%d",
251 options.level_directory, leveldir[leveldir_nr].filename, level_nr);
253 if (!(file = fopen(filename, "w")))
255 Error(ERR_WARN, "cannot save level file '%s'", filename);
259 fputs(LEVEL_COOKIE,file); /* Formatkennung */
262 fputc(level.fieldx, file);
263 fputc(level.fieldy, file);
264 fputc(level.time / 256, file);
265 fputc(level.time % 256, file);
266 fputc(level.edelsteine / 256, file);
267 fputc(level.edelsteine % 256, file);
269 for(i=0; i<MAX_LEVNAMLEN; i++)
270 fputc(level.name[i], file);
271 for(i=0; i<MAX_LEVSCORE_ENTRIES; i++)
272 fputc(level.score[i], file);
276 fputc(level.mampfer_inhalt[i][x][y], file);
277 fputc(level.tempo_amoebe, file);
278 fputc(level.dauer_sieb, file);
279 fputc(level.dauer_ablenk, file);
280 fputc(level.amoebe_inhalt, file);
282 for(i=0; i<NUM_FREE_LVHD_BYTES; i++) /* Rest frei / Headergröße 80 Bytes */
285 for(y=0; y<lev_fieldy; y++)
286 for(x=0; x<lev_fieldx; x++)
287 fputc(Ur[x][y], file);
291 chmod(filename, LEVEL_PERMS);
294 void LoadTape(int level_nr)
297 char filename[MAX_FILENAME_LEN];
298 char cookie[MAX_FILENAME_LEN];
300 boolean levelrec_10 = FALSE;
302 sprintf(filename, "%s/%d.%s",
303 getTapeDir(leveldir[leveldir_nr].filename),
304 level_nr, TAPEFILE_EXTENSION);
306 if ((file = fopen(filename, "r")))
308 fgets(cookie, LEVELREC_COOKIE_LEN, file);
310 if (!strcmp(cookie, LEVELREC_COOKIE_10)) /* old 1.0 tape format */
312 else if (strcmp(cookie, LEVELREC_COOKIE)) /* unknown tape format */
314 Error(ERR_WARN, "wrong format of level recording file '%s'", filename);
324 (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
326 (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
328 (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
330 tape.level_nr = level_nr;
332 tape.changed = FALSE;
334 tape.recording = FALSE;
335 tape.playing = FALSE;
336 tape.pausing = FALSE;
338 for(i=0; i<tape.length; i++)
342 if (i >= MAX_TAPELEN)
345 for(j=0; j<MAX_PLAYERS; j++)
347 if (levelrec_10 && j > 0)
349 tape.pos[i].action[j] = MV_NO_MOVING;
352 tape.pos[i].action[j] = fgetc(file);
355 tape.pos[i].delay = fgetc(file);
359 /* eliminate possible diagonal moves in old tapes */
360 /* this is only for backward compatibility */
362 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
363 byte action = tape.pos[i].action[0];
364 int k, num_moves = 0;
368 if (action & joy_dir[k])
370 tape.pos[i + num_moves].action[0] = joy_dir[k];
372 tape.pos[i + num_moves].delay = 0;
381 tape.length += num_moves;
391 if (i != tape.length)
392 Error(ERR_WARN, "level recording file '%s' corrupted", filename);
394 tape.length_seconds = GetTapeLength();
397 void SaveTape(int level_nr)
400 char filename[MAX_FILENAME_LEN];
402 boolean new_tape = TRUE;
404 sprintf(filename, "%s/%d.%s",
405 getTapeDir(leveldir[leveldir_nr].filename),
406 level_nr, TAPEFILE_EXTENSION);
408 InitTapeDirectory(leveldir[leveldir_nr].filename);
410 /* Testen, ob bereits eine Aufnahme existiert */
411 if ((file = fopen(filename, "r")))
416 if (!Request("Replace old tape ?", REQ_ASK))
420 if (!(file = fopen(filename, "w")))
422 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
426 fputs(LEVELREC_COOKIE, file); /* Formatkennung */
429 fputc((tape.random_seed >> 24) & 0xff,file);
430 fputc((tape.random_seed >> 16) & 0xff,file);
431 fputc((tape.random_seed >> 8) & 0xff,file);
432 fputc((tape.random_seed >> 0) & 0xff,file);
434 fputc((tape.date >> 24) & 0xff,file);
435 fputc((tape.date >> 16) & 0xff,file);
436 fputc((tape.date >> 8) & 0xff,file);
437 fputc((tape.date >> 0) & 0xff,file);
439 fputc((tape.length >> 24) & 0xff,file);
440 fputc((tape.length >> 16) & 0xff,file);
441 fputc((tape.length >> 8) & 0xff,file);
442 fputc((tape.length >> 0) & 0xff,file);
444 for(i=0; i<tape.length; i++)
448 for(j=0; j<MAX_PLAYERS; j++)
449 fputc(tape.pos[i].action[j], file);
451 fputc(tape.pos[i].delay, file);
456 chmod(filename, LEVREC_PERMS);
458 tape.changed = FALSE;
461 Request("tape saved !",REQ_CONFIRM);
464 void LoadScore(int level_nr)
467 char filename[MAX_FILENAME_LEN];
468 char cookie[MAX_FILENAME_LEN];
469 char line[MAX_LINE_LEN];
473 /* start with empty score table */
474 for(i=0; i<MAX_SCORE_ENTRIES; i++)
476 strcpy(highscore[i].Name, EMPTY_ALIAS);
477 highscore[i].Score = 0;
480 sprintf(filename, "%s/%d.%s",
481 getScoreDir(leveldir[leveldir_nr].filename),
482 level_nr, SCOREFILE_EXTENSION);
484 if (!(file = fopen(filename, "r")))
487 fgets(cookie, SCORE_COOKIE_LEN, file);
489 if (strcmp(cookie, SCORE_COOKIE) != 0)
491 Error(ERR_WARN, "wrong format of score file '%s'", filename);
496 for(i=0; i<MAX_SCORE_ENTRIES; i++)
500 fscanf(file, "%d", &position_nr);
501 fscanf(file, "%d", &highscore[i].Score);
502 fgets(line, MAX_LINE_LEN, file);
504 if (line[strlen(line)-1] == '\n')
505 line[strlen(line)-1] = '\0';
507 for (line_ptr = line; *line_ptr; line_ptr++)
509 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
511 strncpy(highscore[i].Name, line_ptr, MAX_NAMELEN - 1);
512 highscore[i].Name[MAX_NAMELEN - 1] = '\0';
521 void SaveScore(int level_nr)
524 char filename[MAX_FILENAME_LEN];
527 sprintf(filename, "%s/%d.%s",
528 getScoreDir(leveldir[leveldir_nr].filename),
529 level_nr, SCOREFILE_EXTENSION);
531 InitScoreDirectory(leveldir[leveldir_nr].filename);
533 if (!(file = fopen(filename, "w")))
535 Error(ERR_WARN, "cannot save score for level %d", level_nr);
539 fprintf(file, "%s\n\n", SCORE_COOKIE);
541 for(i=0; i<MAX_SCORE_ENTRIES; i++)
542 fprintf(file, "%d %d %s\n", i+1, highscore[i].Score, highscore[i].Name);
546 chmod(filename, SCORE_PERMS);
549 #define TOKEN_STR_FILE_IDENTIFIER "file_identifier"
550 #define TOKEN_STR_LAST_LEVEL_SERIES "last_level_series"
551 #define TOKEN_STR_PLAYER_PREFIX "player_"
553 #define TOKEN_VALUE_POSITION 30
555 #define SETUP_TOKEN_SOUND 0
556 #define SETUP_TOKEN_SOUND_LOOPS 1
557 #define SETUP_TOKEN_SOUND_MUSIC 2
558 #define SETUP_TOKEN_SOUND_SIMPLE 3
559 #define SETUP_TOKEN_TOONS 4
560 #define SETUP_TOKEN_DOUBLE_BUFFERING 5
561 #define SETUP_TOKEN_SCROLL_DELAY 6
562 #define SETUP_TOKEN_SOFT_SCROLLING 7
563 #define SETUP_TOKEN_FADING 8
564 #define SETUP_TOKEN_AUTORECORD 9
565 #define SETUP_TOKEN_QUICK_DOORS 10
566 #define SETUP_TOKEN_TEAM_MODE 11
567 #define SETUP_TOKEN_ALIAS_NAME 12
569 #define SETUP_TOKEN_USE_JOYSTICK 13
570 #define SETUP_TOKEN_JOY_DEVICE_NAME 14
571 #define SETUP_TOKEN_JOY_XLEFT 15
572 #define SETUP_TOKEN_JOY_XMIDDLE 16
573 #define SETUP_TOKEN_JOY_XRIGHT 17
574 #define SETUP_TOKEN_JOY_YUPPER 18
575 #define SETUP_TOKEN_JOY_YMIDDLE 19
576 #define SETUP_TOKEN_JOY_YLOWER 20
577 #define SETUP_TOKEN_JOY_SNAP 21
578 #define SETUP_TOKEN_JOY_BOMB 22
579 #define SETUP_TOKEN_KEY_LEFT 23
580 #define SETUP_TOKEN_KEY_RIGHT 24
581 #define SETUP_TOKEN_KEY_UP 25
582 #define SETUP_TOKEN_KEY_DOWN 26
583 #define SETUP_TOKEN_KEY_SNAP 27
584 #define SETUP_TOKEN_KEY_BOMB 28
586 #define NUM_SETUP_TOKENS 29
588 #define FIRST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_SOUND
589 #define LAST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_ALIAS_NAME
591 #define FIRST_PLAYER_SETUP_TOKEN SETUP_TOKEN_USE_JOYSTICK
592 #define LAST_PLAYER_SETUP_TOKEN SETUP_TOKEN_KEY_BOMB
594 #define TYPE_BOOLEAN 1
595 #define TYPE_SWITCH 2
596 #define TYPE_KEYSYM 3
597 #define TYPE_INTEGER 4
598 #define TYPE_STRING 5
600 static struct SetupInfo si;
601 static struct SetupInputInfo sii;
609 { TYPE_SWITCH, &si.sound, "sound" },
610 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
611 { TYPE_SWITCH, &si.sound_music, "background_music" },
612 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
613 { TYPE_SWITCH, &si.toons, "toons" },
614 { TYPE_SWITCH, &si.double_buffering, "double_buffering" },
615 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
616 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
617 { TYPE_SWITCH, &si.fading, "screen_fading" },
618 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
619 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
620 { TYPE_SWITCH, &si.team_mode, "team_mode" },
621 { TYPE_STRING, &si.alias_name, "alias_name" },
623 /* for each player: */
624 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
625 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
626 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
627 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
628 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
629 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
630 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
631 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
632 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
633 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
634 { TYPE_KEYSYM, &sii.key.left, ".key.move_left" },
635 { TYPE_KEYSYM, &sii.key.right, ".key.move_right" },
636 { TYPE_KEYSYM, &sii.key.up, ".key.move_up" },
637 { TYPE_KEYSYM, &sii.key.down, ".key.move_down" },
638 { TYPE_KEYSYM, &sii.key.snap, ".key.snap_field" },
639 { TYPE_KEYSYM, &sii.key.bomb, ".key.place_bomb" }
642 static char *string_tolower(char *s)
644 static char s_lower[100];
647 if (strlen(s) >= 100)
652 for (i=0; i<strlen(s_lower); i++)
653 s_lower[i] = tolower(s_lower[i]);
658 static int get_string_integer_value(char *s)
660 static char *number_text[][3] =
662 { "0", "zero", "null", },
663 { "1", "one", "first" },
664 { "2", "two", "second" },
665 { "3", "three", "third" },
666 { "4", "four", "fourth" },
667 { "5", "five", "fifth" },
668 { "6", "six", "sixth" },
669 { "7", "seven", "seventh" },
670 { "8", "eight", "eighth" },
671 { "9", "nine", "ninth" },
672 { "10", "ten", "tenth" },
673 { "11", "eleven", "eleventh" },
674 { "12", "twelve", "twelfth" },
681 if (strcmp(string_tolower(s), number_text[i][j]) == 0)
687 static boolean get_string_boolean_value(char *s)
689 if (strcmp(string_tolower(s), "true") == 0 ||
690 strcmp(string_tolower(s), "yes") == 0 ||
691 strcmp(string_tolower(s), "on") == 0 ||
692 get_string_integer_value(s) == 1)
698 static char *getFormattedSetupEntry(char *token, char *value)
701 static char entry[MAX_LINE_LEN];
703 sprintf(entry, "%s:", token);
704 for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
708 strcat(entry, value);
713 static void freeSetupFileList(struct SetupFileList *setup_file_list)
715 if (!setup_file_list)
718 if (setup_file_list->token)
719 free(setup_file_list->token);
720 if (setup_file_list->value)
721 free(setup_file_list->value);
722 if (setup_file_list->next)
723 freeSetupFileList(setup_file_list->next);
724 free(setup_file_list);
727 static struct SetupFileList *newSetupFileList(char *token, char *value)
729 struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
731 new->token = checked_malloc(strlen(token) + 1);
732 strcpy(new->token, token);
734 new->value = checked_malloc(strlen(value) + 1);
735 strcpy(new->value, value);
742 static char *getTokenValue(struct SetupFileList *setup_file_list,
745 if (!setup_file_list)
748 if (strcmp(setup_file_list->token, token) == 0)
749 return setup_file_list->value;
751 return getTokenValue(setup_file_list->next, token);
754 static void setTokenValue(struct SetupFileList *setup_file_list,
755 char *token, char *value)
757 if (!setup_file_list)
760 if (strcmp(setup_file_list->token, token) == 0)
762 free(setup_file_list->value);
763 setup_file_list->value = checked_malloc(strlen(value) + 1);
764 strcpy(setup_file_list->value, value);
766 else if (setup_file_list->next == NULL)
767 setup_file_list->next = newSetupFileList(token, value);
769 setTokenValue(setup_file_list->next, token, value);
773 static void printSetupFileList(struct SetupFileList *setup_file_list)
775 if (!setup_file_list)
778 printf("token: '%s'\n", setup_file_list->token);
779 printf("value: '%s'\n", setup_file_list->value);
781 printSetupFileList(setup_file_list->next);
785 static struct SetupFileList *loadSetupFileList(char *filename)
788 char line[MAX_LINE_LEN];
789 char *token, *value, *line_ptr;
790 struct SetupFileList *setup_file_list = newSetupFileList("", "");
791 struct SetupFileList *first_valid_list_entry;
795 if (!(file = fopen(filename, "r")))
797 Error(ERR_WARN, "cannot open setup file '%s'", filename);
803 /* read next line of input file */
804 if (!fgets(line, MAX_LINE_LEN, file))
807 /* cut trailing comment or whitespace from input line */
808 for (line_ptr = line; *line_ptr; line_ptr++)
810 if (*line_ptr == '#' || *line_ptr == '\n')
817 /* cut trailing whitespaces from input line */
818 for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--)
819 if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0')
822 /* ignore empty lines */
826 line_len = strlen(line);
828 /* cut leading whitespaces from token */
829 for (token = line; *token; token++)
830 if (*token != ' ' && *token != '\t')
833 /* find end of token */
834 for (line_ptr = token; *line_ptr; line_ptr++)
836 if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
843 if (line_ptr < line + line_len)
844 value = line_ptr + 1;
848 /* cut leading whitespaces from value */
849 for (; *value; value++)
850 if (*value != ' ' && *value != '\t')
853 if (*token && *value)
854 setTokenValue(setup_file_list, token, value);
859 first_valid_list_entry = setup_file_list->next;
861 /* free empty list header */
862 setup_file_list->next = NULL;
863 freeSetupFileList(setup_file_list);
865 if (!first_valid_list_entry)
866 Error(ERR_WARN, "setup file is empty");
868 return first_valid_list_entry;
871 static void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
874 if (!setup_file_list)
877 if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
879 if (strcmp(setup_file_list->value, identifier) != 0)
881 Error(ERR_WARN, "setup file has wrong version");
888 if (setup_file_list->next)
889 checkSetupFileListIdentifier(setup_file_list->next, identifier);
892 Error(ERR_WARN, "setup file has no version information");
897 static void setSetupInfoToDefaults(struct SetupInfo *si)
902 si->sound_loops = FALSE;
903 si->sound_music = FALSE;
904 si->sound_simple = FALSE;
906 si->double_buffering = TRUE;
907 si->direct_draw = !si->double_buffering;
908 si->scroll_delay = FALSE;
909 si->soft_scrolling = TRUE;
911 si->autorecord = FALSE;
912 si->quick_doors = FALSE;
914 strncpy(si->login_name, getLoginName(), MAX_NAMELEN-1);
915 si->login_name[MAX_NAMELEN-1] = '\0';
916 strncpy(si->alias_name, getLoginName(), MAX_NAMELEN-1);
917 si->alias_name[MAX_NAMELEN-1] = '\0';
919 for (i=0; i<MAX_PLAYERS; i++)
921 si->input[i].use_joystick = FALSE;
922 strcpy(si->input[i].joy.device_name, joystick_device_name[i]);
923 si->input[i].joy.xleft = JOYSTICK_XLEFT;
924 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
925 si->input[i].joy.xright = JOYSTICK_XRIGHT;
926 si->input[i].joy.yupper = JOYSTICK_YUPPER;
927 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
928 si->input[i].joy.ylower = JOYSTICK_YLOWER;
929 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
930 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
931 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KEY_UNDEFINDED);
932 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KEY_UNDEFINDED);
933 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KEY_UNDEFINDED);
934 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KEY_UNDEFINDED);
935 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KEY_UNDEFINDED);
936 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KEY_UNDEFINDED);
940 static void setSetupInfo(int token_nr, char *token_value)
942 int token_type = token_info[token_nr].type;
943 void *setup_value = token_info[token_nr].value;
945 if (token_value == NULL)
948 /* set setup field to corresponding token value */
953 *(boolean *)setup_value = get_string_boolean_value(token_value);
957 *(KeySym *)setup_value = getKeySymFromX11KeyName(token_value);
961 *(int *)setup_value = get_string_integer_value(token_value);
965 strcpy((char *)setup_value, token_value);
973 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
977 if (!setup_file_list)
980 /* handle global setup values */
982 for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
983 setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
986 /* handle player specific setup values */
987 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
991 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
993 sii = setup.input[pnr];
994 for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
996 char full_token[100];
998 sprintf(full_token, "%s%s", prefix, token_info[i].text);
999 setSetupInfo(i, getTokenValue(setup_file_list, full_token));
1001 setup.input[pnr] = sii;
1005 int getLevelSeriesNrFromLevelSeriesName(char *level_series_name)
1009 if (!level_series_name)
1012 for (i=0; i<num_leveldirs; i++)
1013 if (strcmp(level_series_name, leveldir[i].filename) == 0)
1019 int getLastPlayedLevelOfLevelSeries(char *level_series_name)
1022 int level_series_nr = getLevelSeriesNrFromLevelSeriesName(level_series_name);
1023 int last_level_nr = 0;
1025 if (!level_series_name)
1028 token_value = getTokenValue(level_setup_list, level_series_name);
1032 int highest_level_nr = leveldir[level_series_nr].levels - 1;
1034 last_level_nr = atoi(token_value);
1036 if (last_level_nr < 0)
1038 if (last_level_nr > highest_level_nr)
1039 last_level_nr = highest_level_nr;
1042 return last_level_nr;
1047 char filename[MAX_FILENAME_LEN];
1048 struct SetupFileList *setup_file_list = NULL;
1050 /* always start with reliable default setup values */
1051 setSetupInfoToDefaults(&setup);
1053 sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME);
1055 setup_file_list = loadSetupFileList(filename);
1057 if (setup_file_list)
1059 checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE);
1060 decodeSetupFileList(setup_file_list);
1062 setup.direct_draw = !setup.double_buffering;
1064 freeSetupFileList(setup_file_list);
1067 Error(ERR_WARN, "using default setup values");
1070 static char *getSetupLine(char *prefix, int token_nr)
1073 static char entry[MAX_LINE_LEN];
1074 int token_type = token_info[token_nr].type;
1075 void *setup_value = token_info[token_nr].value;
1076 char *token_text = token_info[token_nr].text;
1078 /* start with the prefix, token and some spaces to format output line */
1079 sprintf(entry, "%s%s:", prefix, token_text);
1080 for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
1083 /* continue with the token's value (which can have different types) */
1087 strcat(entry, (*(boolean *)setup_value ? "true" : "false"));
1091 strcat(entry, (*(boolean *)setup_value ? "on" : "off"));
1096 KeySym keysym = *(KeySym *)setup_value;
1097 char *keyname = getKeyNameFromKeySym(keysym);
1099 strcat(entry, getX11KeyNameFromKeySym(keysym));
1100 for (i=strlen(entry); i<50; i++)
1103 /* add comment, if useful */
1104 if (strcmp(keyname, "(undefined)") != 0 &&
1105 strcmp(keyname, "(unknown)") != 0)
1107 strcat(entry, "# ");
1108 strcat(entry, keyname);
1115 char buffer[MAX_LINE_LEN];
1117 sprintf(buffer, "%d", *(int *)setup_value);
1118 strcat(entry, buffer);
1123 strcat(entry, (char *)setup_value);
1136 char filename[MAX_FILENAME_LEN];
1139 sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME);
1141 InitUserDataDirectory();
1143 if (!(file = fopen(filename, "w")))
1145 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1149 fprintf(file, "%s\n",
1150 getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, SETUP_COOKIE));
1151 fprintf(file, "\n");
1153 /* handle global setup values */
1155 for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
1157 /* just to make things nicer :) */
1158 if (i == SETUP_TOKEN_ALIAS_NAME)
1159 fprintf(file, "\n");
1161 fprintf(file, "%s\n", getSetupLine("", i));
1164 /* handle player specific setup values */
1165 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1169 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1170 fprintf(file, "\n");
1172 sii = setup.input[pnr];
1173 for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
1174 fprintf(file, "%s\n", getSetupLine(prefix, i));
1179 chmod(filename, SETUP_PERMS);
1182 void LoadLevelSetup()
1184 char filename[MAX_FILENAME_LEN];
1186 /* always start with reliable default setup values */
1191 sprintf(filename, "%s/%s", getSetupDir(), LEVELSETUP_FILENAME);
1193 if (level_setup_list)
1194 freeSetupFileList(level_setup_list);
1196 level_setup_list = loadSetupFileList(filename);
1198 if (level_setup_list)
1200 char *last_level_series =
1201 getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
1203 leveldir_nr = getLevelSeriesNrFromLevelSeriesName(last_level_series);
1204 level_nr = getLastPlayedLevelOfLevelSeries(last_level_series);
1206 checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
1209 Error(ERR_WARN, "using default setup values");
1212 void SaveLevelSetup()
1214 char filename[MAX_FILENAME_LEN];
1215 struct SetupFileList *list_entry = level_setup_list;
1218 setTokenValue(level_setup_list,
1219 TOKEN_STR_LAST_LEVEL_SERIES, leveldir[leveldir_nr].filename);
1221 setTokenValue(level_setup_list,
1222 leveldir[leveldir_nr].filename, int2str(level_nr, 0));
1224 sprintf(filename, "%s/%s", getSetupDir(), LEVELSETUP_FILENAME);
1226 InitUserDataDirectory();
1228 if (!(file = fopen(filename, "w")))
1230 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1234 fprintf(file, "%s: %s\n\n",
1235 TOKEN_STR_FILE_IDENTIFIER, LEVELSETUP_COOKIE);
1239 if (strcmp(list_entry->token, TOKEN_STR_FILE_IDENTIFIER) != 0)
1240 fprintf(file, "%s\n",
1241 getFormattedSetupEntry(list_entry->token, list_entry->value));
1243 /* just to make things nicer :) */
1244 if (strcmp(list_entry->token, TOKEN_STR_LAST_LEVEL_SERIES) == 0)
1245 fprintf(file, "\n");
1247 list_entry = list_entry->next;
1252 chmod(filename, SETUP_PERMS);