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 ***********************************************************/
25 #define MAX_LINE_LEN 1000
27 static char *getGlobalDataDir()
32 static char *getUserDataDir()
34 static char *userdata_dir = NULL;
38 char *home_dir = getHomeDir();
39 char *data_dir = USERDATA_DIRECTORY;
41 userdata_dir = checked_malloc(strlen(home_dir) + strlen(data_dir) + 2);
42 sprintf(userdata_dir, "%s/%s", home_dir, data_dir);
48 static char *getSetupDir()
50 return getUserDataDir();
53 static char *getTapeDir(char *level_subdir)
55 static char *tape_dir = NULL;
56 char *data_dir = getUserDataDir();
57 char *tape_subdir = TAPES_DIRECTORY;
62 tape_dir = checked_malloc(strlen(data_dir) + strlen(tape_subdir) +
63 strlen(level_subdir) + 3);
64 sprintf(tape_dir, "%s/%s%s%s", data_dir, tape_subdir,
65 (strlen(level_subdir) > 0 ? "/" : ""), level_subdir);
70 static char *getScoreDir(char *level_subdir)
72 static char *score_dir = NULL;
73 char *data_dir = getGlobalDataDir();
74 char *score_subdir = SCORES_DIRECTORY;
79 score_dir = checked_malloc(strlen(data_dir) + strlen(score_subdir) +
80 strlen(level_subdir) + 3);
81 sprintf(score_dir, "%s/%s%s%s", data_dir, score_subdir,
82 (strlen(level_subdir) > 0 ? "/" : ""), level_subdir);
87 static void createDirectory(char *dir, char *text)
89 if (access(dir, F_OK) != 0)
90 if (mkdir(dir, USERDATA_DIR_MODE) != 0)
91 Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
94 static void InitUserDataDirectory()
96 createDirectory(getUserDataDir(), "user data");
99 static void InitTapeDirectory(char *level_subdir)
101 createDirectory(getTapeDir(""), "main tape");
102 createDirectory(getTapeDir(level_subdir), "level tape");
105 static void InitScoreDirectory(char *level_subdir)
107 createDirectory(getScoreDir(""), "main score");
108 createDirectory(getScoreDir(level_subdir), "level score");
111 void LoadLevel(int level_nr)
114 char filename[MAX_FILENAME_LEN];
115 char cookie[MAX_FILENAME_LEN];
118 sprintf(filename, "%s/%s/%d",
119 options.level_directory, leveldir[leveldir_nr].filename, level_nr);
121 if (!(file = fopen(filename, "r")))
122 Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
125 fgets(cookie, LEVEL_COOKIE_LEN, file);
128 if (strcmp(cookie,LEVEL_COOKIE))
130 Error(ERR_WARN, "wrong format of level file '%s'", filename);
138 lev_fieldx = level.fieldx = fgetc(file);
139 lev_fieldy = level.fieldy = fgetc(file);
141 level.time = (fgetc(file)<<8) | fgetc(file);
142 level.edelsteine = (fgetc(file)<<8) | fgetc(file);
143 for(i=0; i<MAX_LEVNAMLEN; i++)
144 level.name[i] = fgetc(file);
145 level.name[MAX_LEVNAMLEN-1] = 0;
146 for(i=0; i<MAX_LEVSCORE_ENTRIES; i++)
147 level.score[i] = fgetc(file);
151 level.mampfer_inhalt[i][x][y] = fgetc(file);
152 level.tempo_amoebe = fgetc(file);
153 level.dauer_sieb = fgetc(file);
154 level.dauer_ablenk = fgetc(file);
155 level.amoebe_inhalt = fgetc(file);
157 for(i=0; i<NUM_FREE_LVHD_BYTES; i++) /* Rest frei / Headergröße 80 Bytes */
160 for(y=0; y<MAX_LEV_FIELDY; y++)
161 for(x=0; x<MAX_LEV_FIELDX; x++)
162 Feld[x][y] = Ur[x][y] = EL_ERDREICH;
164 for(y=0; y<lev_fieldy; y++)
165 for(x=0; x<lev_fieldx; x++)
166 Feld[x][y] = Ur[x][y] = fgetc(file);
170 if (level.time <= 10) /* Mindestspieldauer */
175 lev_fieldx = level.fieldx = STD_LEV_FIELDX;
176 lev_fieldy = level.fieldy = STD_LEV_FIELDY;
179 level.edelsteine = 0;
180 strcpy(level.name, "Nameless Level");
181 for(i=0; i<MAX_LEVSCORE_ENTRIES; i++)
186 level.mampfer_inhalt[i][x][y] = EL_FELSBROCKEN;
187 level.tempo_amoebe = 10;
188 level.dauer_sieb = 10;
189 level.dauer_ablenk = 10;
190 level.amoebe_inhalt = EL_DIAMANT;
192 for(y=0; y<STD_LEV_FIELDY; y++)
193 for(x=0; x<STD_LEV_FIELDX; x++)
194 Feld[x][y] = Ur[x][y] = EL_ERDREICH;
195 Feld[0][0] = Ur[0][0] = EL_SPIELFIGUR;
196 Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
197 Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_AUSGANG_ZU;
201 void SaveLevel(int level_nr)
204 char filename[MAX_FILENAME_LEN];
207 sprintf(filename, "%s/%s/%d",
208 options.level_directory, leveldir[leveldir_nr].filename, level_nr);
210 if (!(file = fopen(filename, "w")))
212 Error(ERR_WARN, "cannot save level file '%s'", filename);
216 fputs(LEVEL_COOKIE,file); /* Formatkennung */
219 fputc(level.fieldx, file);
220 fputc(level.fieldy, file);
221 fputc(level.time / 256, file);
222 fputc(level.time % 256, file);
223 fputc(level.edelsteine / 256, file);
224 fputc(level.edelsteine % 256, file);
226 for(i=0; i<MAX_LEVNAMLEN; i++)
227 fputc(level.name[i], file);
228 for(i=0; i<MAX_LEVSCORE_ENTRIES; i++)
229 fputc(level.score[i], file);
233 fputc(level.mampfer_inhalt[i][x][y], file);
234 fputc(level.tempo_amoebe, file);
235 fputc(level.dauer_sieb, file);
236 fputc(level.dauer_ablenk, file);
237 fputc(level.amoebe_inhalt, file);
239 for(i=0; i<NUM_FREE_LVHD_BYTES; i++) /* Rest frei / Headergröße 80 Bytes */
242 for(y=0; y<lev_fieldy; y++)
243 for(x=0; x<lev_fieldx; x++)
244 fputc(Ur[x][y], file);
248 chmod(filename, LEVEL_PERMS);
251 void LoadTape(int level_nr)
254 char filename[MAX_FILENAME_LEN];
255 char cookie[MAX_FILENAME_LEN];
257 boolean levelrec_10 = FALSE;
259 sprintf(filename, "%s/%d.%s",
260 getTapeDir(leveldir[leveldir_nr].filename),
261 level_nr, TAPEFILE_EXTENSION);
263 if ((file = fopen(filename, "r")))
265 fgets(cookie, LEVELREC_COOKIE_LEN, file);
267 if (!strcmp(cookie, LEVELREC_COOKIE_10)) /* old 1.0 tape format */
269 else if (strcmp(cookie, LEVELREC_COOKIE)) /* unknown tape format */
271 Error(ERR_WARN, "wrong format of level recording file '%s'", filename);
281 (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
283 (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
285 (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file);
287 tape.level_nr = level_nr;
289 tape.changed = FALSE;
291 tape.recording = FALSE;
292 tape.playing = FALSE;
293 tape.pausing = FALSE;
295 for(i=0; i<tape.length; i++)
299 if (i >= MAX_TAPELEN)
302 for(j=0; j<MAX_PLAYERS; j++)
304 if (levelrec_10 && j > 0)
306 tape.pos[i].action[j] = MV_NO_MOVING;
309 tape.pos[i].action[j] = fgetc(file);
312 tape.pos[i].delay = fgetc(file);
316 /* eliminate possible diagonal moves in old tapes */
317 /* this is only for backward compatibility */
319 byte joy_dir[4] = { JOY_LEFT, JOY_RIGHT, JOY_UP, JOY_DOWN };
320 byte action = tape.pos[i].action[0];
321 int k, num_moves = 0;
325 if (action & joy_dir[k])
327 tape.pos[i + num_moves].action[0] = joy_dir[k];
329 tape.pos[i + num_moves].delay = 0;
338 tape.length += num_moves;
348 if (i != tape.length)
349 Error(ERR_WARN, "level recording file '%s' corrupted", filename);
351 tape.length_seconds = GetTapeLength();
354 void SaveTape(int level_nr)
357 char filename[MAX_FILENAME_LEN];
359 boolean new_tape = TRUE;
361 sprintf(filename, "%s/%d.%s",
362 getTapeDir(leveldir[leveldir_nr].filename),
363 level_nr, TAPEFILE_EXTENSION);
365 InitTapeDirectory(leveldir[leveldir_nr].filename);
367 /* Testen, ob bereits eine Aufnahme existiert */
368 if ((file = fopen(filename, "r")))
373 if (!Request("Replace old tape ?", REQ_ASK))
377 if (!(file = fopen(filename, "w")))
379 Error(ERR_WARN, "cannot save level recording file '%s'", filename);
383 fputs(LEVELREC_COOKIE, file); /* Formatkennung */
386 fputc((tape.random_seed >> 24) & 0xff,file);
387 fputc((tape.random_seed >> 16) & 0xff,file);
388 fputc((tape.random_seed >> 8) & 0xff,file);
389 fputc((tape.random_seed >> 0) & 0xff,file);
391 fputc((tape.date >> 24) & 0xff,file);
392 fputc((tape.date >> 16) & 0xff,file);
393 fputc((tape.date >> 8) & 0xff,file);
394 fputc((tape.date >> 0) & 0xff,file);
396 fputc((tape.length >> 24) & 0xff,file);
397 fputc((tape.length >> 16) & 0xff,file);
398 fputc((tape.length >> 8) & 0xff,file);
399 fputc((tape.length >> 0) & 0xff,file);
401 for(i=0; i<tape.length; i++)
405 for(j=0; j<MAX_PLAYERS; j++)
406 fputc(tape.pos[i].action[j], file);
408 fputc(tape.pos[i].delay, file);
413 chmod(filename, LEVREC_PERMS);
415 tape.changed = FALSE;
418 Request("tape saved !",REQ_CONFIRM);
421 void LoadScore(int level_nr)
424 char filename[MAX_FILENAME_LEN];
425 char cookie[MAX_FILENAME_LEN];
426 char line[MAX_LINE_LEN];
430 /* start with empty score table */
431 for(i=0; i<MAX_SCORE_ENTRIES; i++)
433 strcpy(highscore[i].Name, EMPTY_ALIAS);
434 highscore[i].Score = 0;
437 sprintf(filename, "%s/%d.%s",
438 getScoreDir(leveldir[leveldir_nr].filename),
439 level_nr, SCOREFILE_EXTENSION);
441 if (!(file = fopen(filename, "r")))
444 fgets(cookie, SCORE_COOKIE_LEN, file);
446 if (strcmp(cookie, SCORE_COOKIE) != 0)
448 Error(ERR_WARN, "wrong format of score file '%s'", filename);
453 for(i=0; i<MAX_SCORE_ENTRIES; i++)
455 fscanf(file, "%d", &highscore[i].Score);
456 fgets(line, MAX_LINE_LEN, file);
458 if (line[strlen(line)-1] == '\n')
459 line[strlen(line)-1] = '\0';
461 for (line_ptr = line; *line_ptr; line_ptr++)
463 if (*line_ptr != ' ' && *line_ptr != '\t' && *line_ptr != '\0')
465 strncpy(highscore[i].Name, line_ptr, MAX_NAMELEN - 1);
466 highscore[i].Name[MAX_NAMELEN - 1] = '\0';
475 void SaveScore(int level_nr)
478 char filename[MAX_FILENAME_LEN];
481 sprintf(filename, "%s/%d.%s",
482 getScoreDir(leveldir[leveldir_nr].filename),
483 level_nr, SCOREFILE_EXTENSION);
485 InitScoreDirectory(leveldir[leveldir_nr].filename);
487 if (!(file = fopen(filename, "w")))
489 Error(ERR_WARN, "cannot save score for level %d", level_nr);
493 fprintf(file, "%s\n\n", SCORE_COOKIE);
495 for(i=0; i<MAX_SCORE_ENTRIES; i++)
496 fprintf(file, "%d %s\n", highscore[i].Score, highscore[i].Name);
500 chmod(filename, SCORE_PERMS);
503 #define TOKEN_STR_FILE_IDENTIFIER "file_identifier"
504 #define TOKEN_STR_LAST_LEVEL_SERIES "last_level_series"
505 #define TOKEN_STR_PLAYER_PREFIX "player_"
507 #define TOKEN_VALUE_POSITION 30
510 #define SETUP_TOKEN_PLAYER_NAME 0
511 #define SETUP_TOKEN_SOUND 1
512 #define SETUP_TOKEN_SOUND_LOOPS 2
513 #define SETUP_TOKEN_SOUND_MUSIC 3
514 #define SETUP_TOKEN_SOUND_SIMPLE 4
515 #define SETUP_TOKEN_TOONS 5
516 #define SETUP_TOKEN_DOUBLE_BUFFERING 6
517 #define SETUP_TOKEN_SCROLL_DELAY 7
518 #define SETUP_TOKEN_SOFT_SCROLLING 8
519 #define SETUP_TOKEN_FADING 9
520 #define SETUP_TOKEN_AUTORECORD 10
521 #define SETUP_TOKEN_QUICK_DOORS 11
522 #define SETUP_TOKEN_TEAM_MODE 12
525 #define SETUP_TOKEN_USE_JOYSTICK 13
526 #define SETUP_TOKEN_JOY_DEVICE_NAME 14
527 #define SETUP_TOKEN_JOY_XLEFT 15
528 #define SETUP_TOKEN_JOY_XMIDDLE 16
529 #define SETUP_TOKEN_JOY_XRIGHT 17
530 #define SETUP_TOKEN_JOY_YUPPER 18
531 #define SETUP_TOKEN_JOY_YMIDDLE 19
532 #define SETUP_TOKEN_JOY_YLOWER 20
533 #define SETUP_TOKEN_JOY_SNAP 21
534 #define SETUP_TOKEN_JOY_BOMB 22
535 #define SETUP_TOKEN_KEY_LEFT 23
536 #define SETUP_TOKEN_KEY_RIGHT 24
537 #define SETUP_TOKEN_KEY_UP 25
538 #define SETUP_TOKEN_KEY_DOWN 26
539 #define SETUP_TOKEN_KEY_SNAP 27
540 #define SETUP_TOKEN_KEY_BOMB 28
542 /* level directory info */
543 #define LEVELINFO_TOKEN_NAME 29
544 #define LEVELINFO_TOKEN_LEVELS 30
545 #define LEVELINFO_TOKEN_SORT_PRIORITY 31
546 #define LEVELINFO_TOKEN_READONLY 32
548 #define FIRST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_PLAYER_NAME
549 #define LAST_GLOBAL_SETUP_TOKEN SETUP_TOKEN_TEAM_MODE
551 #define FIRST_PLAYER_SETUP_TOKEN SETUP_TOKEN_USE_JOYSTICK
552 #define LAST_PLAYER_SETUP_TOKEN SETUP_TOKEN_KEY_BOMB
554 #define FIRST_LEVELINFO_TOKEN LEVELINFO_TOKEN_NAME
555 #define LAST_LEVELINFO_TOKEN LEVELINFO_TOKEN_READONLY
557 #define TYPE_BOOLEAN 1
558 #define TYPE_SWITCH 2
559 #define TYPE_KEYSYM 3
560 #define TYPE_INTEGER 4
561 #define TYPE_STRING 5
563 static struct SetupInfo si;
564 static struct SetupInputInfo sii;
565 struct LevelDirInfo ldi;
574 { TYPE_STRING, &si.player_name, "player_name" },
575 { TYPE_SWITCH, &si.sound, "sound" },
576 { TYPE_SWITCH, &si.sound_loops, "repeating_sound_loops" },
577 { TYPE_SWITCH, &si.sound_music, "background_music" },
578 { TYPE_SWITCH, &si.sound_simple, "simple_sound_effects" },
579 { TYPE_SWITCH, &si.toons, "toons" },
580 { TYPE_SWITCH, &si.double_buffering, "double_buffering" },
581 { TYPE_SWITCH, &si.scroll_delay, "scroll_delay" },
582 { TYPE_SWITCH, &si.soft_scrolling, "soft_scrolling" },
583 { TYPE_SWITCH, &si.fading, "screen_fading" },
584 { TYPE_SWITCH, &si.autorecord, "automatic_tape_recording" },
585 { TYPE_SWITCH, &si.quick_doors, "quick_doors" },
586 { TYPE_SWITCH, &si.team_mode, "team_mode" },
589 { TYPE_BOOLEAN, &sii.use_joystick, ".use_joystick" },
590 { TYPE_STRING, &sii.joy.device_name, ".joy.device_name" },
591 { TYPE_INTEGER, &sii.joy.xleft, ".joy.xleft" },
592 { TYPE_INTEGER, &sii.joy.xmiddle, ".joy.xmiddle" },
593 { TYPE_INTEGER, &sii.joy.xright, ".joy.xright" },
594 { TYPE_INTEGER, &sii.joy.yupper, ".joy.yupper" },
595 { TYPE_INTEGER, &sii.joy.ymiddle, ".joy.ymiddle" },
596 { TYPE_INTEGER, &sii.joy.ylower, ".joy.ylower" },
597 { TYPE_INTEGER, &sii.joy.snap, ".joy.snap_field" },
598 { TYPE_INTEGER, &sii.joy.bomb, ".joy.place_bomb" },
599 { TYPE_KEYSYM, &sii.key.left, ".key.move_left" },
600 { TYPE_KEYSYM, &sii.key.right, ".key.move_right" },
601 { TYPE_KEYSYM, &sii.key.up, ".key.move_up" },
602 { TYPE_KEYSYM, &sii.key.down, ".key.move_down" },
603 { TYPE_KEYSYM, &sii.key.snap, ".key.snap_field" },
604 { TYPE_KEYSYM, &sii.key.bomb, ".key.place_bomb" },
606 /* level directory info */
607 { TYPE_STRING, &ldi.name, "name" },
608 { TYPE_INTEGER, &ldi.levels, "levels" },
609 { TYPE_INTEGER, &ldi.sort_priority, "sort_priority" },
610 { TYPE_BOOLEAN, &ldi.readonly, "readonly" }
613 static char *string_tolower(char *s)
615 static char s_lower[100];
618 if (strlen(s) >= 100)
623 for (i=0; i<strlen(s_lower); i++)
624 s_lower[i] = tolower(s_lower[i]);
629 static int get_string_integer_value(char *s)
631 static char *number_text[][3] =
633 { "0", "zero", "null", },
634 { "1", "one", "first" },
635 { "2", "two", "second" },
636 { "3", "three", "third" },
637 { "4", "four", "fourth" },
638 { "5", "five", "fifth" },
639 { "6", "six", "sixth" },
640 { "7", "seven", "seventh" },
641 { "8", "eight", "eighth" },
642 { "9", "nine", "ninth" },
643 { "10", "ten", "tenth" },
644 { "11", "eleven", "eleventh" },
645 { "12", "twelve", "twelfth" },
652 if (strcmp(string_tolower(s), number_text[i][j]) == 0)
658 static boolean get_string_boolean_value(char *s)
660 if (strcmp(string_tolower(s), "true") == 0 ||
661 strcmp(string_tolower(s), "yes") == 0 ||
662 strcmp(string_tolower(s), "on") == 0 ||
663 get_string_integer_value(s) == 1)
669 static char *getFormattedSetupEntry(char *token, char *value)
672 static char entry[MAX_LINE_LEN];
674 sprintf(entry, "%s:", token);
675 for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
679 strcat(entry, value);
684 static void freeSetupFileList(struct SetupFileList *setup_file_list)
686 if (!setup_file_list)
689 if (setup_file_list->token)
690 free(setup_file_list->token);
691 if (setup_file_list->value)
692 free(setup_file_list->value);
693 if (setup_file_list->next)
694 freeSetupFileList(setup_file_list->next);
695 free(setup_file_list);
698 static struct SetupFileList *newSetupFileList(char *token, char *value)
700 struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
702 new->token = checked_malloc(strlen(token) + 1);
703 strcpy(new->token, token);
705 new->value = checked_malloc(strlen(value) + 1);
706 strcpy(new->value, value);
713 static char *getTokenValue(struct SetupFileList *setup_file_list,
716 if (!setup_file_list)
719 if (strcmp(setup_file_list->token, token) == 0)
720 return setup_file_list->value;
722 return getTokenValue(setup_file_list->next, token);
725 static void setTokenValue(struct SetupFileList *setup_file_list,
726 char *token, char *value)
728 if (!setup_file_list)
731 if (strcmp(setup_file_list->token, token) == 0)
733 free(setup_file_list->value);
734 setup_file_list->value = checked_malloc(strlen(value) + 1);
735 strcpy(setup_file_list->value, value);
737 else if (setup_file_list->next == NULL)
738 setup_file_list->next = newSetupFileList(token, value);
740 setTokenValue(setup_file_list->next, token, value);
744 static void printSetupFileList(struct SetupFileList *setup_file_list)
746 if (!setup_file_list)
749 printf("token: '%s'\n", setup_file_list->token);
750 printf("value: '%s'\n", setup_file_list->value);
752 printSetupFileList(setup_file_list->next);
756 static struct SetupFileList *loadSetupFileList(char *filename)
759 char line[MAX_LINE_LEN];
760 char *token, *value, *line_ptr;
761 struct SetupFileList *setup_file_list = newSetupFileList("", "");
762 struct SetupFileList *first_valid_list_entry;
766 if (!(file = fopen(filename, "r")))
768 Error(ERR_WARN, "cannot open setup/info file '%s'", filename);
774 /* read next line of input file */
775 if (!fgets(line, MAX_LINE_LEN, file))
778 /* cut trailing comment or whitespace from input line */
779 for (line_ptr = line; *line_ptr; line_ptr++)
781 if (*line_ptr == '#' || *line_ptr == '\n')
788 /* cut trailing whitespaces from input line */
789 for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--)
790 if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0')
793 /* ignore empty lines */
797 line_len = strlen(line);
799 /* cut leading whitespaces from token */
800 for (token = line; *token; token++)
801 if (*token != ' ' && *token != '\t')
804 /* find end of token */
805 for (line_ptr = token; *line_ptr; line_ptr++)
807 if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
814 if (line_ptr < line + line_len)
815 value = line_ptr + 1;
819 /* cut leading whitespaces from value */
820 for (; *value; value++)
821 if (*value != ' ' && *value != '\t')
824 if (*token && *value)
825 setTokenValue(setup_file_list, token, value);
830 first_valid_list_entry = setup_file_list->next;
832 /* free empty list header */
833 setup_file_list->next = NULL;
834 freeSetupFileList(setup_file_list);
836 if (first_valid_list_entry == NULL)
837 Error(ERR_WARN, "setup/info file '%s' is empty", filename);
839 return first_valid_list_entry;
842 static void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
845 if (!setup_file_list)
848 if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
850 if (strcmp(setup_file_list->value, identifier) != 0)
852 Error(ERR_WARN, "setup/info file has wrong version");
859 if (setup_file_list->next)
860 checkSetupFileListIdentifier(setup_file_list->next, identifier);
863 Error(ERR_WARN, "setup/info file has no version information");
868 static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi)
870 ldi->name = getStringCopy("non-existing");
872 ldi->sort_priority = 999; /* default: least priority */
873 ldi->readonly = TRUE;
876 static void setSetupInfoToDefaults(struct SetupInfo *si)
880 si->player_name = getStringCopy(getLoginName());
883 si->sound_loops = FALSE;
884 si->sound_music = FALSE;
885 si->sound_simple = FALSE;
887 si->double_buffering = TRUE;
888 si->direct_draw = !si->double_buffering;
889 si->scroll_delay = FALSE;
890 si->soft_scrolling = TRUE;
892 si->autorecord = FALSE;
893 si->quick_doors = FALSE;
895 for (i=0; i<MAX_PLAYERS; i++)
897 si->input[i].use_joystick = FALSE;
898 si->input[i].joy.device_name = getStringCopy(joystick_device_name[i]);
899 si->input[i].joy.xleft = JOYSTICK_XLEFT;
900 si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
901 si->input[i].joy.xright = JOYSTICK_XRIGHT;
902 si->input[i].joy.yupper = JOYSTICK_YUPPER;
903 si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
904 si->input[i].joy.ylower = JOYSTICK_YLOWER;
905 si->input[i].joy.snap = (i == 0 ? JOY_BUTTON_1 : 0);
906 si->input[i].joy.bomb = (i == 0 ? JOY_BUTTON_2 : 0);
907 si->input[i].key.left = (i == 0 ? DEFAULT_KEY_LEFT : KEY_UNDEFINDED);
908 si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KEY_UNDEFINDED);
909 si->input[i].key.up = (i == 0 ? DEFAULT_KEY_UP : KEY_UNDEFINDED);
910 si->input[i].key.down = (i == 0 ? DEFAULT_KEY_DOWN : KEY_UNDEFINDED);
911 si->input[i].key.snap = (i == 0 ? DEFAULT_KEY_SNAP : KEY_UNDEFINDED);
912 si->input[i].key.bomb = (i == 0 ? DEFAULT_KEY_BOMB : KEY_UNDEFINDED);
916 static void setSetupInfo(int token_nr, char *token_value)
918 int token_type = token_info[token_nr].type;
919 void *setup_value = token_info[token_nr].value;
921 if (token_value == NULL)
924 /* set setup field to corresponding token value */
929 *(boolean *)setup_value = get_string_boolean_value(token_value);
933 *(KeySym *)setup_value = getKeySymFromX11KeyName(token_value);
937 *(int *)setup_value = get_string_integer_value(token_value);
941 if (*(char **)setup_value != NULL)
942 free(*(char **)setup_value);
943 *(char **)setup_value = getStringCopy(token_value);
951 static void decodeSetupFileList(struct SetupFileList *setup_file_list)
955 if (!setup_file_list)
958 /* handle global setup values */
960 for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
961 setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
964 /* handle player specific setup values */
965 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
969 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
971 sii = setup.input[pnr];
972 for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
974 char full_token[100];
976 sprintf(full_token, "%s%s", prefix, token_info[i].text);
977 setSetupInfo(i, getTokenValue(setup_file_list, full_token));
979 setup.input[pnr] = sii;
983 int getLevelSeriesNrFromLevelSeriesName(char *level_series_name)
987 if (!level_series_name)
990 for (i=0; i<num_leveldirs; i++)
991 if (strcmp(level_series_name, leveldir[i].filename) == 0)
997 int getLastPlayedLevelOfLevelSeries(char *level_series_name)
1000 int level_series_nr = getLevelSeriesNrFromLevelSeriesName(level_series_name);
1001 int last_level_nr = 0;
1003 if (!level_series_name)
1006 token_value = getTokenValue(level_setup_list, level_series_name);
1010 int highest_level_nr = leveldir[level_series_nr].levels - 1;
1012 last_level_nr = atoi(token_value);
1014 if (last_level_nr < 0)
1016 if (last_level_nr > highest_level_nr)
1017 last_level_nr = highest_level_nr;
1020 return last_level_nr;
1023 void LoadLevelInfo()
1026 struct stat file_status;
1027 char *level_directory = options.level_directory;
1028 char *directory = NULL;
1029 char *filename = NULL;
1030 struct SetupFileList *setup_file_list = NULL;
1031 struct dirent *dir_entry;
1032 int i, num_entries = 0;
1034 if ((dir = opendir(level_directory)) == NULL)
1035 Error(ERR_EXIT, "cannot read level directory '%s'", level_directory);
1037 while (num_entries < MAX_LEVDIR_ENTRIES)
1039 if ((dir_entry = readdir(dir)) == NULL) /* last directory entry */
1042 /* skip entries for current and parent directory */
1043 if (strcmp(dir_entry->d_name, ".") == 0 ||
1044 strcmp(dir_entry->d_name, "..") == 0)
1047 /* find out if directory entry is itself a directory */
1048 directory = getPath2(level_directory, dir_entry->d_name);
1049 if (stat(directory, &file_status) != 0 || /* cannot stat file */
1050 (file_status.st_mode & S_IFMT) != S_IFDIR) /* not a directory */
1056 if (strlen(dir_entry->d_name) >= MAX_LEVDIR_FILENAME)
1058 Error(ERR_WARN, "filename of level directory '%s' too long -- ignoring",
1063 filename = getPath2(directory, LEVELINFO_FILENAME);
1064 setup_file_list = loadSetupFileList(filename);
1066 if (setup_file_list)
1068 checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE);
1069 setLevelDirInfoToDefaults(&leveldir[num_entries]);
1071 ldi = leveldir[num_entries];
1072 for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
1073 setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
1074 leveldir[num_entries] = ldi;
1076 leveldir[num_entries].filename = getStringCopy(dir_entry->d_name);
1078 freeSetupFileList(setup_file_list);
1082 Error(ERR_WARN, "ignoring level directory '%s'", directory);
1088 if (num_entries == MAX_LEVDIR_ENTRIES)
1089 Error(ERR_WARN, "using %d level directories -- ignoring the rest",
1094 num_leveldirs = num_entries;
1098 Error(ERR_EXIT, "cannot find any valid level series in directory '%s'",
1104 char filename[MAX_FILENAME_LEN];
1105 struct SetupFileList *setup_file_list = NULL;
1107 /* always start with reliable default setup values */
1108 setSetupInfoToDefaults(&setup);
1110 sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME);
1112 setup_file_list = loadSetupFileList(filename);
1114 if (setup_file_list)
1116 checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE);
1117 decodeSetupFileList(setup_file_list);
1119 setup.direct_draw = !setup.double_buffering;
1121 freeSetupFileList(setup_file_list);
1123 /* needed to work around problems with fixed length strings */
1124 if (strlen(setup.player_name) >= MAX_NAMELEN)
1125 setup.player_name[MAX_NAMELEN - 1] = '\0';
1126 else if (strlen(setup.player_name) < MAX_NAMELEN - 1)
1128 char *new_name = checked_malloc(MAX_NAMELEN);
1130 strcpy(new_name, setup.player_name);
1131 free(setup.player_name);
1132 setup.player_name = new_name;
1136 Error(ERR_WARN, "using default setup values");
1139 static char *getSetupLine(char *prefix, int token_nr)
1142 static char entry[MAX_LINE_LEN];
1143 int token_type = token_info[token_nr].type;
1144 void *setup_value = token_info[token_nr].value;
1145 char *token_text = token_info[token_nr].text;
1147 /* start with the prefix, token and some spaces to format output line */
1148 sprintf(entry, "%s%s:", prefix, token_text);
1149 for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
1152 /* continue with the token's value (which can have different types) */
1156 strcat(entry, (*(boolean *)setup_value ? "true" : "false"));
1160 strcat(entry, (*(boolean *)setup_value ? "on" : "off"));
1165 KeySym keysym = *(KeySym *)setup_value;
1166 char *keyname = getKeyNameFromKeySym(keysym);
1168 strcat(entry, getX11KeyNameFromKeySym(keysym));
1169 for (i=strlen(entry); i<50; i++)
1172 /* add comment, if useful */
1173 if (strcmp(keyname, "(undefined)") != 0 &&
1174 strcmp(keyname, "(unknown)") != 0)
1176 strcat(entry, "# ");
1177 strcat(entry, keyname);
1184 char buffer[MAX_LINE_LEN];
1186 sprintf(buffer, "%d", *(int *)setup_value);
1187 strcat(entry, buffer);
1192 strcat(entry, *(char **)setup_value);
1205 char filename[MAX_FILENAME_LEN];
1208 sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME);
1210 InitUserDataDirectory();
1212 if (!(file = fopen(filename, "w")))
1214 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1218 fprintf(file, "%s\n",
1219 getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, SETUP_COOKIE));
1220 fprintf(file, "\n");
1222 /* handle global setup values */
1224 for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
1226 fprintf(file, "%s\n", getSetupLine("", i));
1228 /* just to make things nicer :) */
1229 if (i == SETUP_TOKEN_PLAYER_NAME)
1230 fprintf(file, "\n");
1233 /* handle player specific setup values */
1234 for (pnr=0; pnr<MAX_PLAYERS; pnr++)
1238 sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
1239 fprintf(file, "\n");
1241 sii = setup.input[pnr];
1242 for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
1243 fprintf(file, "%s\n", getSetupLine(prefix, i));
1248 chmod(filename, SETUP_PERMS);
1251 void LoadLevelSetup()
1253 char filename[MAX_FILENAME_LEN];
1255 /* always start with reliable default setup values */
1260 sprintf(filename, "%s/%s", getSetupDir(), LEVELSETUP_FILENAME);
1262 if (level_setup_list)
1263 freeSetupFileList(level_setup_list);
1265 level_setup_list = loadSetupFileList(filename);
1267 if (level_setup_list)
1269 char *last_level_series =
1270 getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
1272 leveldir_nr = getLevelSeriesNrFromLevelSeriesName(last_level_series);
1273 level_nr = getLastPlayedLevelOfLevelSeries(last_level_series);
1275 checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
1279 level_setup_list = newSetupFileList(TOKEN_STR_FILE_IDENTIFIER,
1281 Error(ERR_WARN, "using default setup values");
1285 void SaveLevelSetup()
1287 char filename[MAX_FILENAME_LEN];
1288 struct SetupFileList *list_entry = level_setup_list;
1291 setTokenValue(level_setup_list,
1292 TOKEN_STR_LAST_LEVEL_SERIES, leveldir[leveldir_nr].filename);
1294 setTokenValue(level_setup_list,
1295 leveldir[leveldir_nr].filename, int2str(level_nr, 0));
1297 sprintf(filename, "%s/%s", getSetupDir(), LEVELSETUP_FILENAME);
1299 InitUserDataDirectory();
1301 if (!(file = fopen(filename, "w")))
1303 Error(ERR_WARN, "cannot write setup file '%s'", filename);
1307 fprintf(file, "%s: %s\n\n",
1308 TOKEN_STR_FILE_IDENTIFIER, LEVELSETUP_COOKIE);
1312 if (strcmp(list_entry->token, TOKEN_STR_FILE_IDENTIFIER) != 0)
1313 fprintf(file, "%s\n",
1314 getFormattedSetupEntry(list_entry->token, list_entry->value));
1316 /* just to make things nicer :) */
1317 if (strcmp(list_entry->token, TOKEN_STR_LAST_LEVEL_SERIES) == 0)
1318 fprintf(file, "\n");
1320 list_entry = list_entry->next;
1325 chmod(filename, SETUP_PERMS);