rnd-20020323-2-src
authorHolger Schemel <info@artsoft.org>
Sat, 23 Mar 2002 14:20:09 +0000 (15:20 +0100)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:36:28 +0000 (10:36 +0200)
23 files changed:
src/Makefile
src/events.c
src/files.c
src/files.h
src/game.c
src/init.c
src/joystick.c [deleted file]
src/joystick.h [deleted file]
src/libgame/Makefile
src/libgame/joystick.c [new file with mode: 0644]
src/libgame/joystick.h [new file with mode: 0644]
src/libgame/libgame.h
src/libgame/misc.c
src/libgame/misc.h
src/libgame/setup.c [new file with mode: 0644]
src/libgame/setup.h [new file with mode: 0644]
src/libgame/system.c
src/libgame/system.h
src/libgame/types.h
src/main.c
src/main.h
src/screens.c
src/tools.c

index f4f503fc9cf2555e6242422fe1ab605f6af7a198..5b8f1366c4a6ea44dc438636a6c26f1c60c243c7 100644 (file)
@@ -125,7 +125,6 @@ SRCS =      main.c          \
        editor.c        \
        files.c         \
        tape.c          \
-       joystick.c      \
        cartoons.c      \
        network.c       \
        netserv.c
@@ -139,7 +138,6 @@ OBJS =      main.o          \
        editor.o        \
        files.o         \
        tape.o          \
-       joystick.o      \
        cartoons.o      \
        network.o       \
        netserv.o
index fd8c35132206c56097d8a6bb099ca81ab23c972b..652ff31da2097c2690414392f1d62cfc29242e21 100644 (file)
@@ -21,7 +21,6 @@
 #include "editor.h"
 #include "files.h"
 #include "tape.h"
-#include "joystick.h"
 #include "network.h"
 
 /* values for key_status */
@@ -304,8 +303,8 @@ void HandleFocusEvent(FocusChangeEvent *event)
     int i;
 
     KeyboardAutoRepeatOn();
-    old_joystick_status = joystick_status;
-    joystick_status = JOYSTICK_OFF;
+    old_joystick_status = joystick.status;
+    joystick.status = JOYSTICK_NOT_AVAILABLE;
 
     /* simulate key release events for still pressed keys */
     key_joystick_mapping = 0;
@@ -336,7 +335,7 @@ void HandleFocusEvent(FocusChangeEvent *event)
       KeyboardAutoRepeatOff();
     }
     if (old_joystick_status != -1)
-      joystick_status = old_joystick_status;
+      joystick.status = old_joystick_status;
   }
 }
 
index d214bf99cb5c53cdef8302312b033f01a8d2ac80..00e471610249cdc40baee8b5a824528d8ee443a2 100644 (file)
@@ -12,7 +12,6 @@
 ***********************************************************/
 
 #include <ctype.h>
-#include <dirent.h>
 #include <sys/stat.h>
 
 #include "libgame/libgame.h"
@@ -20,7 +19,7 @@
 #include "files.h"
 #include "tools.h"
 #include "tape.h"
-#include "joystick.h"
+
 
 #define CHUNK_ID_LEN           4       /* IFF style chunk id length  */
 #define CHUNK_SIZE_UNDEFINED   0       /* undefined chunk size == 0  */
 #define LEVEL_COOKIE_TMPL      "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_x.x"
 #define TAPE_COOKIE_TMPL       "ROCKSNDIAMONDS_TAPE_FILE_VERSION_x.x"
 #define SCORE_COOKIE           "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
-#define SETUP_COOKIE           "ROCKSNDIAMONDS_SETUP_FILE_VERSION_1.2"
-#define LEVELSETUP_COOKIE      "ROCKSNDIAMONDS_LEVELSETUP_FILE_VERSION_1.2"
-#define LEVELINFO_COOKIE       "ROCKSNDIAMONDS_LEVELINFO_FILE_VERSION_1.2"
-
-/* file names and filename extensions */
-#if !defined(PLATFORM_MSDOS)
-#define LEVELSETUP_DIRECTORY   "levelsetup"
-#define SETUP_FILENAME         "setup.conf"
-#define LEVELSETUP_FILENAME    "levelsetup.conf"
-#define LEVELINFO_FILENAME     "levelinfo.conf"
-#define LEVELFILE_EXTENSION    "level"
-#define TAPEFILE_EXTENSION     "tape"
-#define SCOREFILE_EXTENSION    "score"
-#else
-#define LEVELSETUP_DIRECTORY   "lvlsetup"
-#define SETUP_FILENAME         "setup.cnf"
-#define LEVELSETUP_FILENAME    "lvlsetup.cnf"
-#define LEVELINFO_FILENAME     "lvlinfo.cnf"
-#define LEVELFILE_EXTENSION    "lvl"
-#define TAPEFILE_EXTENSION     "tap"
-#define SCOREFILE_EXTENSION    "sco"
-#endif
-
-/* sort priorities of level series (also used as level series classes) */
-#define LEVELCLASS_TUTORIAL_START      10
-#define LEVELCLASS_TUTORIAL_END                99
-#define LEVELCLASS_CLASSICS_START      100
-#define LEVELCLASS_CLASSICS_END                199
-#define LEVELCLASS_CONTRIBUTION_START  200
-#define LEVELCLASS_CONTRIBUTION_END    299
-#define LEVELCLASS_USER_START          300
-#define LEVELCLASS_USER_END            399
-#define LEVELCLASS_BD_START            400
-#define LEVELCLASS_BD_END              499
-#define LEVELCLASS_EM_START            500
-#define LEVELCLASS_EM_END              599
-#define LEVELCLASS_SP_START            600
-#define LEVELCLASS_SP_END              699
-#define LEVELCLASS_DX_START            700
-#define LEVELCLASS_DX_END              799
-
-#define LEVELCLASS_TUTORIAL            LEVELCLASS_TUTORIAL_START
-#define LEVELCLASS_CLASSICS            LEVELCLASS_CLASSICS_START
-#define LEVELCLASS_CONTRIBUTION                LEVELCLASS_CONTRIBUTION_START
-#define LEVELCLASS_USER                        LEVELCLASS_USER_START
-#define LEVELCLASS_BD                  LEVELCLASS_BD_START
-#define LEVELCLASS_EM                  LEVELCLASS_EM_START
-#define LEVELCLASS_SP                  LEVELCLASS_SP_START
-#define LEVELCLASS_DX                  LEVELCLASS_DX_START
-
-#define LEVELCLASS_UNDEFINED           999
-
-#define NUM_LEVELCLASS_DESC    8
-char *levelclass_desc[NUM_LEVELCLASS_DESC] =
-{
-  "Tutorial Levels",
-  "Classic Originals",
-  "Contributions",
-  "Private Levels",
-  "Boulderdash",
-  "Emerald Mine",
-  "Supaplex",
-  "DX Boulderdash"
-};
-
-#define IS_LEVELCLASS_TUTORIAL(p) \
-       ((p)->sort_priority >= LEVELCLASS_TUTORIAL_START && \
-        (p)->sort_priority <= LEVELCLASS_TUTORIAL_END)
-#define IS_LEVELCLASS_CLASSICS(p) \
-       ((p)->sort_priority >= LEVELCLASS_CLASSICS_START && \
-        (p)->sort_priority <= LEVELCLASS_CLASSICS_END)
-#define IS_LEVELCLASS_CONTRIBUTION(p) \
-       ((p)->sort_priority >= LEVELCLASS_CONTRIBUTION_START && \
-        (p)->sort_priority <= LEVELCLASS_CONTRIBUTION_END)
-#define IS_LEVELCLASS_USER(p) \
-       ((p)->sort_priority >= LEVELCLASS_USER_START && \
-        (p)->sort_priority <= LEVELCLASS_USER_END)
-#define IS_LEVELCLASS_BD(p) \
-       ((p)->sort_priority >= LEVELCLASS_BD_START && \
-        (p)->sort_priority <= LEVELCLASS_BD_END)
-#define IS_LEVELCLASS_EM(p) \
-       ((p)->sort_priority >= LEVELCLASS_EM_START && \
-        (p)->sort_priority <= LEVELCLASS_EM_END)
-#define IS_LEVELCLASS_SP(p) \
-       ((p)->sort_priority >= LEVELCLASS_SP_START && \
-        (p)->sort_priority <= LEVELCLASS_SP_END)
-#define IS_LEVELCLASS_DX(p) \
-       ((p)->sort_priority >= LEVELCLASS_DX_START && \
-        (p)->sort_priority <= LEVELCLASS_DX_END)
-
-#define LEVELCLASS(n)  (IS_LEVELCLASS_TUTORIAL(n) ? LEVELCLASS_TUTORIAL : \
-                        IS_LEVELCLASS_CLASSICS(n) ? LEVELCLASS_CLASSICS : \
-                        IS_LEVELCLASS_CONTRIBUTION(n) ? LEVELCLASS_CONTRIBUTION : \
-                        IS_LEVELCLASS_USER(n) ? LEVELCLASS_USER : \
-                        IS_LEVELCLASS_BD(n) ? LEVELCLASS_BD : \
-                        IS_LEVELCLASS_EM(n) ? LEVELCLASS_EM : \
-                        IS_LEVELCLASS_SP(n) ? LEVELCLASS_SP : \
-                        IS_LEVELCLASS_DX(n) ? LEVELCLASS_DX : \
-                        LEVELCLASS_UNDEFINED)
-
-#define LEVELCOLOR(n)  (IS_LEVELCLASS_TUTORIAL(n) ?            FC_BLUE : \
-                        IS_LEVELCLASS_CLASSICS(n) ?            FC_RED : \
-                        IS_LEVELCLASS_BD(n) ?                  FC_GREEN : \
-                        IS_LEVELCLASS_EM(n) ?                  FC_YELLOW : \
-                        IS_LEVELCLASS_SP(n) ?                  FC_GREEN : \
-                        IS_LEVELCLASS_DX(n) ?                  FC_YELLOW : \
-                        IS_LEVELCLASS_CONTRIBUTION(n) ?        FC_GREEN : \
-                        IS_LEVELCLASS_USER(n) ?                FC_RED : \
-                        FC_BLUE)
-
-#define LEVELSORTING(n)        (IS_LEVELCLASS_TUTORIAL(n) ?            0 : \
-                        IS_LEVELCLASS_CLASSICS(n) ?            1 : \
-                        IS_LEVELCLASS_BD(n) ?                  2 : \
-                        IS_LEVELCLASS_EM(n) ?                  3 : \
-                        IS_LEVELCLASS_SP(n) ?                  4 : \
-                        IS_LEVELCLASS_DX(n) ?                  5 : \
-                        IS_LEVELCLASS_CONTRIBUTION(n) ?        6 : \
-                        IS_LEVELCLASS_USER(n) ?                7 : \
-                        9)
-
-char *getLevelClassDescription(struct LevelDirInfo *ldi)
-{
-  int position = ldi->sort_priority / 100;
-
-  if (position >= 0 && position < NUM_LEVELCLASS_DESC)
-    return levelclass_desc[position];
-  else
-    return "Unknown Level Class";
-}
-
-static void SaveUserLevelInfo();               /* for 'InitUserLevelDir()' */
-static char *getSetupLine(char *, int);                /* for 'SaveUserLevelInfo()' */
-
-static char *getUserLevelDir(char *level_subdir)
-{
-  static char *userlevel_dir = NULL;
-  char *data_dir = getUserDataDir();
-  char *userlevel_subdir = LEVELS_DIRECTORY;
-
-  if (userlevel_dir)
-    free(userlevel_dir);
-
-  if (strlen(level_subdir) > 0)
-    userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir);
-  else
-    userlevel_dir = getPath2(data_dir, userlevel_subdir);
-
-  return userlevel_dir;
-}
-
-static char *getTapeDir(char *level_subdir)
-{
-  static char *tape_dir = NULL;
-  char *data_dir = getUserDataDir();
-  char *tape_subdir = TAPES_DIRECTORY;
-
-  if (tape_dir)
-    free(tape_dir);
-
-  if (strlen(level_subdir) > 0)
-    tape_dir = getPath3(data_dir, tape_subdir, level_subdir);
-  else
-    tape_dir = getPath2(data_dir, tape_subdir);
-
-  return tape_dir;
-}
-
-static char *getScoreDir(char *level_subdir)
-{
-  static char *score_dir = NULL;
-  char *data_dir = options.rw_base_directory;
-  char *score_subdir = SCORES_DIRECTORY;
 
-  if (score_dir)
-    free(score_dir);
-
-  if (strlen(level_subdir) > 0)
-    score_dir = getPath3(data_dir, score_subdir, level_subdir);
-  else
-    score_dir = getPath2(data_dir, score_subdir);
-
-  return score_dir;
-}
-
-static char *getLevelSetupDir(char *level_subdir)
-{
-  static char *levelsetup_dir = NULL;
-  char *data_dir = getUserDataDir();
-  char *levelsetup_subdir = LEVELSETUP_DIRECTORY;
-
-  if (levelsetup_dir)
-    free(levelsetup_dir);
-
-  if (strlen(level_subdir) > 0)
-    levelsetup_dir = getPath3(data_dir, levelsetup_subdir, level_subdir);
-  else
-    levelsetup_dir = getPath2(data_dir, levelsetup_subdir);
-
-  return levelsetup_dir;
-}
-
-static char *getLevelFilename(int nr)
-{
-  static char *filename = NULL;
-  char basename[MAX_FILENAME_LEN];
-
-  if (filename != NULL)
-    free(filename);
-
-  sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
-  filename = getPath3((leveldir_current->user_defined ?
-                      getUserLevelDir("") :
-                      options.level_directory),
-                     leveldir_current->fullpath,
-                     basename);
-
-  return filename;
-}
-
-static char *getTapeFilename(int nr)
-{
-  static char *filename = NULL;
-  char basename[MAX_FILENAME_LEN];
-
-  if (filename != NULL)
-    free(filename);
-
-  sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
-  filename = getPath2(getTapeDir(leveldir_current->filename), basename);
-
-  return filename;
-}
-
-static char *getScoreFilename(int nr)
-{
-  static char *filename = NULL;
-  char basename[MAX_FILENAME_LEN];
-
-  if (filename != NULL)
-    free(filename);
-
-  sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION);
-  filename = getPath2(getScoreDir(leveldir_current->filename), basename);
-
-  return filename;
-}
-
-static void InitTapeDirectory(char *level_subdir)
-{
-  createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
-  createDirectory(getTapeDir(""), "main tape", PERMS_PRIVATE);
-  createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE);
-}
-
-static void InitScoreDirectory(char *level_subdir)
-{
-  createDirectory(getScoreDir(""), "main score", PERMS_PUBLIC);
-  createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC);
-}
-
-static void InitUserLevelDirectory(char *level_subdir)
-{
-  if (access(getUserLevelDir(level_subdir), F_OK) != 0)
-  {
-    createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
-    createDirectory(getUserLevelDir(""), "main user level", PERMS_PRIVATE);
-    createDirectory(getUserLevelDir(level_subdir), "user level",PERMS_PRIVATE);
-
-    SaveUserLevelInfo();
-  }
-}
-
-static void InitLevelSetupDirectory(char *level_subdir)
-{
-  createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
-  createDirectory(getLevelSetupDir(""), "main level setup", PERMS_PRIVATE);
-  createDirectory(getLevelSetupDir(level_subdir), "level setup",PERMS_PRIVATE);
-}
-
-static void ReadChunk_VERS(FILE *file, int *file_version, int *game_version)
-{
-  int file_version_major, file_version_minor, file_version_patch;
-  int game_version_major, game_version_minor, game_version_patch;
-
-  file_version_major = fgetc(file);
-  file_version_minor = fgetc(file);
-  file_version_patch = fgetc(file);
-  fgetc(file);         /* not used */
-
-  game_version_major = fgetc(file);
-  game_version_minor = fgetc(file);
-  game_version_patch = fgetc(file);
-  fgetc(file);         /* not used */
-
-  *file_version = VERSION_IDENT(file_version_major,
-                               file_version_minor,
-                               file_version_patch);
-
-  *game_version = VERSION_IDENT(game_version_major,
-                               game_version_minor,
-                               game_version_patch);
-}
-
-static void WriteChunk_VERS(FILE *file, int file_version, int game_version)
-{
-  int file_version_major = VERSION_MAJOR(file_version);
-  int file_version_minor = VERSION_MINOR(file_version);
-  int file_version_patch = VERSION_PATCH(file_version);
-  int game_version_major = VERSION_MAJOR(game_version);
-  int game_version_minor = VERSION_MINOR(game_version);
-  int game_version_patch = VERSION_PATCH(game_version);
-
-  fputc(file_version_major, file);
-  fputc(file_version_minor, file);
-  fputc(file_version_patch, file);
-  fputc(0, file);      /* not used */
-
-  fputc(game_version_major, file);
-  fputc(game_version_minor, file);
-  fputc(game_version_patch, file);
-  fputc(0, file);      /* not used */
-}
 
 static void setLevelInfoToDefaults()
 {
@@ -1462,892 +1140,3 @@ void SaveScore(int level_nr)
 
   SetFilePermissions(filename, PERMS_PUBLIC);
 }
-
-/* ------------------------------------------------------------------------- */
-/* setup file stuff                                                          */
-/* ------------------------------------------------------------------------- */
-
-#define TOKEN_STR_LAST_LEVEL_SERIES    "last_level_series"
-#define TOKEN_STR_LAST_PLAYED_LEVEL    "last_played_level"
-#define TOKEN_STR_HANDICAP_LEVEL       "handicap_level"
-#define TOKEN_STR_PLAYER_PREFIX                "player_"
-
-/* global setup */
-#define SETUP_TOKEN_PLAYER_NAME                0
-#define SETUP_TOKEN_SOUND              1
-#define SETUP_TOKEN_SOUND_LOOPS                2
-#define SETUP_TOKEN_SOUND_MUSIC                3
-#define SETUP_TOKEN_SOUND_SIMPLE       4
-#define SETUP_TOKEN_SCROLL_DELAY       5
-#define SETUP_TOKEN_SOFT_SCROLLING     6
-#define SETUP_TOKEN_FADING             7
-#define SETUP_TOKEN_AUTORECORD         8
-#define SETUP_TOKEN_QUICK_DOORS                9
-#define SETUP_TOKEN_TEAM_MODE          10
-#define SETUP_TOKEN_HANDICAP           11
-#define SETUP_TOKEN_TIME_LIMIT         12
-#define SETUP_TOKEN_FULLSCREEN         13
-
-/* player setup */
-#define SETUP_TOKEN_USE_JOYSTICK       14
-#define SETUP_TOKEN_JOY_DEVICE_NAME    15
-#define SETUP_TOKEN_JOY_XLEFT          16
-#define SETUP_TOKEN_JOY_XMIDDLE                17
-#define SETUP_TOKEN_JOY_XRIGHT         18
-#define SETUP_TOKEN_JOY_YUPPER         19
-#define SETUP_TOKEN_JOY_YMIDDLE                20
-#define SETUP_TOKEN_JOY_YLOWER         21
-#define SETUP_TOKEN_JOY_SNAP           22
-#define SETUP_TOKEN_JOY_BOMB           23
-#define SETUP_TOKEN_KEY_LEFT           24
-#define SETUP_TOKEN_KEY_RIGHT          25
-#define SETUP_TOKEN_KEY_UP             26
-#define SETUP_TOKEN_KEY_DOWN           27
-#define SETUP_TOKEN_KEY_SNAP           28
-#define SETUP_TOKEN_KEY_BOMB           29
-
-/* level directory info */
-#define LEVELINFO_TOKEN_NAME           30
-#define LEVELINFO_TOKEN_NAME_SHORT     31
-#define LEVELINFO_TOKEN_NAME_SORTING   32
-#define LEVELINFO_TOKEN_AUTHOR         33
-#define LEVELINFO_TOKEN_IMPORTED_FROM  34
-#define LEVELINFO_TOKEN_LEVELS         35
-#define LEVELINFO_TOKEN_FIRST_LEVEL    36
-#define LEVELINFO_TOKEN_SORT_PRIORITY  37
-#define LEVELINFO_TOKEN_LEVEL_GROUP    38
-#define LEVELINFO_TOKEN_READONLY       39
-
-#define FIRST_GLOBAL_SETUP_TOKEN       SETUP_TOKEN_PLAYER_NAME
-#define LAST_GLOBAL_SETUP_TOKEN                SETUP_TOKEN_FULLSCREEN
-
-#define FIRST_PLAYER_SETUP_TOKEN       SETUP_TOKEN_USE_JOYSTICK
-#define LAST_PLAYER_SETUP_TOKEN                SETUP_TOKEN_KEY_BOMB
-
-#define FIRST_LEVELINFO_TOKEN          LEVELINFO_TOKEN_NAME
-#define LAST_LEVELINFO_TOKEN           LEVELINFO_TOKEN_READONLY
-
-static struct SetupInfo si;
-static struct SetupInputInfo sii;
-static struct LevelDirInfo ldi;
-static struct TokenInfo token_info[] =
-{
-  /* global setup */
-  { TYPE_STRING,  &si.player_name,     "player_name"                   },
-  { TYPE_SWITCH,  &si.sound,           "sound"                         },
-  { TYPE_SWITCH,  &si.sound_loops,     "repeating_sound_loops"         },
-  { TYPE_SWITCH,  &si.sound_music,     "background_music"              },
-  { TYPE_SWITCH,  &si.sound_simple,    "simple_sound_effects"          },
-  { TYPE_SWITCH,  &si.scroll_delay,    "scroll_delay"                  },
-  { TYPE_SWITCH,  &si.soft_scrolling,  "soft_scrolling"                },
-  { TYPE_SWITCH,  &si.fading,          "screen_fading"                 },
-  { TYPE_SWITCH,  &si.autorecord,      "automatic_tape_recording"      },
-  { TYPE_SWITCH,  &si.quick_doors,     "quick_doors"                   },
-  { TYPE_SWITCH,  &si.team_mode,       "team_mode"                     },
-  { TYPE_SWITCH,  &si.handicap,                "handicap"                      },
-  { TYPE_SWITCH,  &si.time_limit,      "time_limit"                    },
-  { TYPE_SWITCH,  &si.fullscreen,      "fullscreen"                    },
-
-  /* player setup */
-  { TYPE_BOOLEAN, &sii.use_joystick,   ".use_joystick"                 },
-  { TYPE_STRING,  &sii.joy.device_name,        ".joy.device_name"              },
-  { TYPE_INTEGER, &sii.joy.xleft,      ".joy.xleft"                    },
-  { TYPE_INTEGER, &sii.joy.xmiddle,    ".joy.xmiddle"                  },
-  { TYPE_INTEGER, &sii.joy.xright,     ".joy.xright"                   },
-  { TYPE_INTEGER, &sii.joy.yupper,     ".joy.yupper"                   },
-  { TYPE_INTEGER, &sii.joy.ymiddle,    ".joy.ymiddle"                  },
-  { TYPE_INTEGER, &sii.joy.ylower,     ".joy.ylower"                   },
-  { TYPE_INTEGER, &sii.joy.snap,       ".joy.snap_field"               },
-  { TYPE_INTEGER, &sii.joy.bomb,       ".joy.place_bomb"               },
-  { TYPE_KEY,     &sii.key.left,       ".key.move_left"                },
-  { TYPE_KEY,     &sii.key.right,      ".key.move_right"               },
-  { TYPE_KEY,     &sii.key.up,         ".key.move_up"                  },
-  { TYPE_KEY,     &sii.key.down,       ".key.move_down"                },
-  { TYPE_KEY,     &sii.key.snap,       ".key.snap_field"               },
-  { TYPE_KEY,     &sii.key.bomb,       ".key.place_bomb"               },
-
-  /* level directory info */
-  { TYPE_STRING,  &ldi.name,           "name"                          },
-  { TYPE_STRING,  &ldi.name_short,     "name_short"                    },
-  { TYPE_STRING,  &ldi.name_sorting,   "name_sorting"                  },
-  { TYPE_STRING,  &ldi.author,         "author"                        },
-  { TYPE_STRING,  &ldi.imported_from,  "imported_from"                 },
-  { TYPE_INTEGER, &ldi.levels,         "levels"                        },
-  { TYPE_INTEGER, &ldi.first_level,    "first_level"                   },
-  { TYPE_INTEGER, &ldi.sort_priority,  "sort_priority"                 },
-  { TYPE_BOOLEAN, &ldi.level_group,    "level_group"                   },
-  { TYPE_BOOLEAN, &ldi.readonly,       "readonly"                      }
-};
-
-static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi)
-{
-  ldi->filename = NULL;
-  ldi->fullpath = NULL;
-  ldi->basepath = NULL;
-  ldi->name = getStringCopy(ANONYMOUS_NAME);
-  ldi->name_short = NULL;
-  ldi->name_sorting = NULL;
-  ldi->author = getStringCopy(ANONYMOUS_NAME);
-  ldi->imported_from = NULL;
-  ldi->levels = 0;
-  ldi->first_level = 0;
-  ldi->last_level = 0;
-  ldi->sort_priority = LEVELCLASS_UNDEFINED;   /* default: least priority */
-  ldi->level_group = FALSE;
-  ldi->parent_link = FALSE;
-  ldi->user_defined = FALSE;
-  ldi->readonly = TRUE;
-  ldi->color = 0;
-  ldi->class_desc = NULL;
-  ldi->handicap_level = 0;
-  ldi->cl_first = -1;
-  ldi->cl_cursor = -1;
-
-  ldi->node_parent = NULL;
-  ldi->node_group = NULL;
-  ldi->next = NULL;
-}
-
-static void setLevelDirInfoToDefaultsFromParent(struct LevelDirInfo *ldi,
-                                               struct LevelDirInfo *parent)
-{
-  if (parent == NULL)
-  {
-    setLevelDirInfoToDefaults(ldi);
-    return;
-  }
-
-  /* first copy all values from the parent structure ... */
-  *ldi = *parent;
-
-  /* ... then set all fields to default that cannot be inherited from parent.
-     This is especially important for all those fields that can be set from
-     the 'levelinfo.conf' config file, because the function 'setSetupInfo()'
-     calls 'free()' for all already set token values which requires that no
-     other structure's pointer may point to them!
-  */
-
-  ldi->filename = NULL;
-  ldi->fullpath = NULL;
-  ldi->basepath = NULL;
-  ldi->name = getStringCopy(ANONYMOUS_NAME);
-  ldi->name_short = NULL;
-  ldi->name_sorting = NULL;
-  ldi->author = getStringCopy(parent->author);
-  ldi->imported_from = getStringCopy(parent->imported_from);
-
-  ldi->level_group = FALSE;
-  ldi->parent_link = FALSE;
-
-  ldi->node_parent = parent;
-  ldi->node_group = NULL;
-  ldi->next = NULL;
-}
-
-static void setSetupInfoToDefaults(struct SetupInfo *si)
-{
-  int i;
-
-  si->player_name = getStringCopy(getLoginName());
-
-  si->sound = TRUE;
-  si->sound_loops = TRUE;
-  si->sound_music = TRUE;
-  si->sound_simple = TRUE;
-  si->toons = TRUE;
-  si->double_buffering = TRUE;
-  si->direct_draw = !si->double_buffering;
-  si->scroll_delay = TRUE;
-  si->soft_scrolling = TRUE;
-  si->fading = FALSE;
-  si->autorecord = TRUE;
-  si->quick_doors = FALSE;
-  si->team_mode = FALSE;
-  si->handicap = TRUE;
-  si->time_limit = TRUE;
-  si->fullscreen = FALSE;
-
-  for (i=0; i<MAX_PLAYERS; i++)
-  {
-    si->input[i].use_joystick = FALSE;
-    si->input[i].joy.device_name = getStringCopy(joystick_device_name[i]);
-    si->input[i].joy.xleft   = JOYSTICK_XLEFT;
-    si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
-    si->input[i].joy.xright  = JOYSTICK_XRIGHT;
-    si->input[i].joy.yupper  = JOYSTICK_YUPPER;
-    si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
-    si->input[i].joy.ylower  = JOYSTICK_YLOWER;
-    si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
-    si->input[i].joy.bomb  = (i == 0 ? JOY_BUTTON_2 : 0);
-    si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
-    si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
-    si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
-    si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
-    si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
-    si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
-  }
-}
-
-static void setSetupInfo(int token_nr, char *token_value)
-{
-  int token_type = token_info[token_nr].type;
-  void *setup_value = token_info[token_nr].value;
-
-  if (token_value == NULL)
-    return;
-
-  /* set setup field to corresponding token value */
-  switch (token_type)
-  {
-    case TYPE_BOOLEAN:
-    case TYPE_SWITCH:
-      *(boolean *)setup_value = get_string_boolean_value(token_value);
-      break;
-
-    case TYPE_KEY:
-      *(Key *)setup_value = getKeyFromX11KeyName(token_value);
-      break;
-
-    case TYPE_INTEGER:
-      *(int *)setup_value = get_string_integer_value(token_value);
-      break;
-
-    case TYPE_STRING:
-      if (*(char **)setup_value != NULL)
-       free(*(char **)setup_value);
-      *(char **)setup_value = getStringCopy(token_value);
-      break;
-
-    default:
-      break;
-  }
-}
-
-static void decodeSetupFileList(struct SetupFileList *setup_file_list)
-{
-  int i, pnr;
-
-  if (!setup_file_list)
-    return;
-
-  /* handle global setup values */
-  si = setup;
-  for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
-    setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
-  setup = si;
-
-  /* handle player specific setup values */
-  for (pnr=0; pnr<MAX_PLAYERS; pnr++)
-  {
-    char prefix[30];
-
-    sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
-
-    sii = setup.input[pnr];
-    for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
-    {
-      char full_token[100];
-
-      sprintf(full_token, "%s%s", prefix, token_info[i].text);
-      setSetupInfo(i, getTokenValue(setup_file_list, full_token));
-    }
-    setup.input[pnr] = sii;
-  }
-}
-
-static int compareLevelDirInfoEntries(const void *object1, const void *object2)
-{
-  const struct LevelDirInfo *entry1 = *((struct LevelDirInfo **)object1);
-  const struct LevelDirInfo *entry2 = *((struct LevelDirInfo **)object2);
-  int compare_result;
-
-  if (entry1->parent_link || entry2->parent_link)
-    compare_result = (entry1->parent_link ? -1 : +1);
-  else if (entry1->sort_priority == entry2->sort_priority)
-  {
-    char *name1 = getStringToLower(entry1->name_sorting);
-    char *name2 = getStringToLower(entry2->name_sorting);
-
-    compare_result = strcmp(name1, name2);
-
-    free(name1);
-    free(name2);
-  }
-  else if (LEVELSORTING(entry1) == LEVELSORTING(entry2))
-    compare_result = entry1->sort_priority - entry2->sort_priority;
-  else
-    compare_result = LEVELSORTING(entry1) - LEVELSORTING(entry2);
-
-  return compare_result;
-}
-
-static void createParentLevelDirNode(struct LevelDirInfo *node_parent)
-{
-  struct LevelDirInfo *leveldir_new = newLevelDirInfo();
-
-  setLevelDirInfoToDefaults(leveldir_new);
-
-  leveldir_new->node_parent = node_parent;
-  leveldir_new->parent_link = TRUE;
-
-  leveldir_new->name = ".. (parent directory)";
-  leveldir_new->name_short = getStringCopy(leveldir_new->name);
-  leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
-
-  leveldir_new->filename = "..";
-  leveldir_new->fullpath = getStringCopy(node_parent->fullpath);
-
-  leveldir_new->sort_priority = node_parent->sort_priority;
-  leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
-
-  pushLevelDirInfo(&node_parent->node_group, leveldir_new);
-}
-
-static void LoadLevelInfoFromLevelDir(struct LevelDirInfo **node_first,
-                                     struct LevelDirInfo *node_parent,
-                                     char *level_directory)
-{
-  DIR *dir;
-  struct dirent *dir_entry;
-  boolean valid_entry_found = FALSE;
-
-  if ((dir = opendir(level_directory)) == NULL)
-  {
-    Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
-    return;
-  }
-
-  while ((dir_entry = readdir(dir)) != NULL)   /* loop until last dir entry */
-  {
-    struct SetupFileList *setup_file_list = NULL;
-    struct stat file_status;
-    char *directory_name = dir_entry->d_name;
-    char *directory_path = getPath2(level_directory, directory_name);
-    char *filename = NULL;
-
-    /* skip entries for current and parent directory */
-    if (strcmp(directory_name, ".")  == 0 ||
-       strcmp(directory_name, "..") == 0)
-    {
-      free(directory_path);
-      continue;
-    }
-
-    /* find out if directory entry is itself a directory */
-    if (stat(directory_path, &file_status) != 0 ||     /* cannot stat file */
-       (file_status.st_mode & S_IFMT) != S_IFDIR)      /* not a directory */
-    {
-      free(directory_path);
-      continue;
-    }
-
-    filename = getPath2(directory_path, LEVELINFO_FILENAME);
-    setup_file_list = loadSetupFileList(filename);
-
-    if (setup_file_list)
-    {
-      struct LevelDirInfo *leveldir_new = newLevelDirInfo();
-      int i;
-
-      checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE);
-      setLevelDirInfoToDefaultsFromParent(leveldir_new, node_parent);
-
-      /* set all structure fields according to the token/value pairs */
-      ldi = *leveldir_new;
-      for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
-       setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text));
-      *leveldir_new = ldi;
-
-      DrawInitText(leveldir_new->name, 150, FC_YELLOW);
-
-      if (leveldir_new->name_short == NULL)
-       leveldir_new->name_short = getStringCopy(leveldir_new->name);
-
-      if (leveldir_new->name_sorting == NULL)
-       leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
-
-      leveldir_new->filename = getStringCopy(directory_name);
-
-      if (node_parent == NULL)         /* top level group */
-      {
-       leveldir_new->basepath = level_directory;
-       leveldir_new->fullpath = leveldir_new->filename;
-      }
-      else                             /* sub level group */
-      {
-       leveldir_new->basepath = node_parent->basepath;
-       leveldir_new->fullpath = getPath2(node_parent->fullpath,
-                                         directory_name);
-      }
-
-      if (leveldir_new->levels < 1)
-       leveldir_new->levels = 1;
-
-      leveldir_new->last_level =
-       leveldir_new->first_level + leveldir_new->levels - 1;
-
-      leveldir_new->user_defined =
-       (leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
-
-      leveldir_new->color = LEVELCOLOR(leveldir_new);
-      leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
-
-      leveldir_new->handicap_level =   /* set handicap to default value */
-       (leveldir_new->user_defined ?
-        leveldir_new->last_level :
-        leveldir_new->first_level);
-
-      pushLevelDirInfo(node_first, leveldir_new);
-
-      freeSetupFileList(setup_file_list);
-      valid_entry_found = TRUE;
-
-      if (leveldir_new->level_group)
-      {
-       /* create node to link back to current level directory */
-       createParentLevelDirNode(leveldir_new);
-
-       /* step into sub-directory and look for more level series */
-       LoadLevelInfoFromLevelDir(&leveldir_new->node_group,
-                                 leveldir_new, directory_path);
-      }
-    }
-    else
-      Error(ERR_WARN, "ignoring level directory '%s'", directory_path);
-
-    free(directory_path);
-    free(filename);
-  }
-
-  closedir(dir);
-
-  if (!valid_entry_found)
-    Error(ERR_WARN, "cannot find any valid level series in directory '%s'",
-         level_directory);
-}
-
-void LoadLevelInfo()
-{
-  InitUserLevelDirectory(getLoginName());
-
-  DrawInitText("Loading level series:", 120, FC_GREEN);
-
-  LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
-  LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(""));
-
-  leveldir_current = getFirstValidLevelSeries(leveldir_first);
-
-  if (leveldir_first == NULL)
-    Error(ERR_EXIT, "cannot find any valid level series in any directory");
-
-  sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries);
-
-#if 0
-  dumpLevelDirInfo(leveldir_first, 0);
-#endif
-}
-
-static void SaveUserLevelInfo()
-{
-  char *filename;
-  FILE *file;
-  int i;
-
-  filename = getPath2(getUserLevelDir(getLoginName()), LEVELINFO_FILENAME);
-
-  if (!(file = fopen(filename, MODE_WRITE)))
-  {
-    Error(ERR_WARN, "cannot write level info file '%s'", filename);
-    free(filename);
-    return;
-  }
-
-  /* always start with reliable default values */
-  setLevelDirInfoToDefaults(&ldi);
-
-  ldi.name = getLoginName();
-  ldi.author = getRealName();
-  ldi.levels = 100;
-  ldi.first_level = 1;
-  ldi.sort_priority = LEVELCLASS_USER_START;
-  ldi.readonly = FALSE;
-
-  fprintf(file, "%s\n\n",
-         getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE));
-
-  for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
-    if (i != LEVELINFO_TOKEN_NAME_SHORT &&
-       i != LEVELINFO_TOKEN_NAME_SORTING &&
-       i != LEVELINFO_TOKEN_IMPORTED_FROM)
-      fprintf(file, "%s\n", getSetupLine("", i));
-
-  fclose(file);
-  free(filename);
-
-  SetFilePermissions(filename, PERMS_PRIVATE);
-}
-
-void LoadSetup()
-{
-  char *filename;
-  struct SetupFileList *setup_file_list = NULL;
-
-  /* always start with reliable default values */
-  setSetupInfoToDefaults(&setup);
-
-  filename = getPath2(getSetupDir(), SETUP_FILENAME);
-
-  setup_file_list = loadSetupFileList(filename);
-
-  if (setup_file_list)
-  {
-    checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE);
-    decodeSetupFileList(setup_file_list);
-
-    setup.direct_draw = !setup.double_buffering;
-
-    freeSetupFileList(setup_file_list);
-
-    /* needed to work around problems with fixed length strings */
-    if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
-      setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
-    else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
-    {
-      char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
-
-      strcpy(new_name, setup.player_name);
-      free(setup.player_name);
-      setup.player_name = new_name;
-    }
-  }
-  else
-    Error(ERR_WARN, "using default setup values");
-
-  free(filename);
-}
-
-static char *getSetupLine(char *prefix, int token_nr)
-{
-  int i;
-  static char entry[MAX_LINE_LEN];
-  int token_type = token_info[token_nr].type;
-  void *setup_value = token_info[token_nr].value;
-  char *token_text = token_info[token_nr].text;
-
-  /* start with the prefix, token and some spaces to format output line */
-  sprintf(entry, "%s%s:", prefix, token_text);
-  for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
-    strcat(entry, " ");
-
-  /* continue with the token's value (which can have different types) */
-  switch (token_type)
-  {
-    case TYPE_BOOLEAN:
-      strcat(entry, (*(boolean *)setup_value ? "true" : "false"));
-      break;
-
-    case TYPE_SWITCH:
-      strcat(entry, (*(boolean *)setup_value ? "on" : "off"));
-      break;
-
-    case TYPE_KEY:
-      {
-       Key key = *(Key *)setup_value;
-       char *keyname = getKeyNameFromKey(key);
-
-       strcat(entry, getX11KeyNameFromKey(key));
-       for (i=strlen(entry); i<50; i++)
-         strcat(entry, " ");
-
-       /* add comment, if useful */
-       if (strcmp(keyname, "(undefined)") != 0 &&
-           strcmp(keyname, "(unknown)") != 0)
-       {
-         strcat(entry, "# ");
-         strcat(entry, keyname);
-       }
-      }
-      break;
-
-    case TYPE_INTEGER:
-      {
-       char buffer[MAX_LINE_LEN];
-
-       sprintf(buffer, "%d", *(int *)setup_value);
-       strcat(entry, buffer);
-      }
-      break;
-
-    case TYPE_STRING:
-      strcat(entry, *(char **)setup_value);
-      break;
-
-    default:
-      break;
-  }
-
-  return entry;
-}
-
-void SaveSetup()
-{
-  int i, pnr;
-  char *filename;
-  FILE *file;
-
-  InitUserDataDirectory();
-
-  filename = getPath2(getSetupDir(), SETUP_FILENAME);
-
-  if (!(file = fopen(filename, MODE_WRITE)))
-  {
-    Error(ERR_WARN, "cannot write setup file '%s'", filename);
-    free(filename);
-    return;
-  }
-
-  fprintf(file, "%s\n",
-         getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, SETUP_COOKIE));
-  fprintf(file, "\n");
-
-  /* handle global setup values */
-  si = setup;
-  for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
-  {
-    fprintf(file, "%s\n", getSetupLine("", i));
-
-    /* just to make things nicer :) */
-    if (i == SETUP_TOKEN_PLAYER_NAME)
-      fprintf(file, "\n");
-  }
-
-  /* handle player specific setup values */
-  for (pnr=0; pnr<MAX_PLAYERS; pnr++)
-  {
-    char prefix[30];
-
-    sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
-    fprintf(file, "\n");
-
-    sii = setup.input[pnr];
-    for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
-      fprintf(file, "%s\n", getSetupLine(prefix, i));
-  }
-
-  fclose(file);
-  free(filename);
-
-  SetFilePermissions(filename, PERMS_PRIVATE);
-}
-
-void LoadLevelSetup_LastSeries()
-{
-  char *filename;
-  struct SetupFileList *level_setup_list = NULL;
-
-  /* always start with reliable default values */
-  leveldir_current = getFirstValidLevelSeries(leveldir_first);
-
-  /* ----------------------------------------------------------------------- */
-  /* ~/.rocksndiamonds/levelsetup.conf                                       */
-  /* ----------------------------------------------------------------------- */
-
-  filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
-
-  if ((level_setup_list = loadSetupFileList(filename)))
-  {
-    char *last_level_series =
-      getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
-
-    leveldir_current = getLevelDirInfoFromFilename(last_level_series);
-    if (leveldir_current == NULL)
-      leveldir_current = leveldir_first;
-
-    checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
-
-    freeSetupFileList(level_setup_list);
-  }
-  else
-    Error(ERR_WARN, "using default setup values");
-
-  free(filename);
-}
-
-void SaveLevelSetup_LastSeries()
-{
-  char *filename;
-  char *level_subdir = leveldir_current->filename;
-  FILE *file;
-
-  /* ----------------------------------------------------------------------- */
-  /* ~/.rocksndiamonds/levelsetup.conf                                       */
-  /* ----------------------------------------------------------------------- */
-
-  InitUserDataDirectory();
-
-  filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
-
-  if (!(file = fopen(filename, MODE_WRITE)))
-  {
-    Error(ERR_WARN, "cannot write setup file '%s'", filename);
-    free(filename);
-    return;
-  }
-
-  fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
-                                                LEVELSETUP_COOKIE));
-  fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES,
-                                              level_subdir));
-
-  fclose(file);
-  free(filename);
-
-  SetFilePermissions(filename, PERMS_PRIVATE);
-}
-
-static void checkSeriesInfo()
-{
-  static char *level_directory = NULL;
-  DIR *dir;
-  struct dirent *dir_entry;
-
-  /* check for more levels besides the 'levels' field of 'levelinfo.conf' */
-
-  level_directory = getPath2((leveldir_current->user_defined ?
-                             getUserLevelDir("") :
-                             options.level_directory),
-                            leveldir_current->fullpath);
-
-  if ((dir = opendir(level_directory)) == NULL)
-  {
-    Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
-    return;
-  }
-
-  while ((dir_entry = readdir(dir)) != NULL)   /* last directory entry */
-  {
-    if (strlen(dir_entry->d_name) > 4 &&
-       dir_entry->d_name[3] == '.' &&
-       strcmp(&dir_entry->d_name[4], LEVELFILE_EXTENSION) == 0)
-    {
-      char levelnum_str[4];
-      int levelnum_value;
-
-      strncpy(levelnum_str, dir_entry->d_name, 3);
-      levelnum_str[3] = '\0';
-
-      levelnum_value = atoi(levelnum_str);
-
-      if (levelnum_value < leveldir_current->first_level)
-      {
-       Error(ERR_WARN, "additional level %d found", levelnum_value);
-       leveldir_current->first_level = levelnum_value;
-      }
-      else if (levelnum_value > leveldir_current->last_level)
-      {
-       Error(ERR_WARN, "additional level %d found", levelnum_value);
-       leveldir_current->last_level = levelnum_value;
-      }
-    }
-  }
-
-  closedir(dir);
-}
-
-void LoadLevelSetup_SeriesInfo()
-{
-  char *filename;
-  struct SetupFileList *level_setup_list = NULL;
-  char *level_subdir = leveldir_current->filename;
-
-  /* always start with reliable default values */
-  level_nr = leveldir_current->first_level;
-
-  checkSeriesInfo(leveldir_current);
-
-  /* ----------------------------------------------------------------------- */
-  /* ~/.rocksndiamonds/levelsetup/<level series>/levelsetup.conf             */
-  /* ----------------------------------------------------------------------- */
-
-  level_subdir = leveldir_current->filename;
-
-  filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME);
-
-  if ((level_setup_list = loadSetupFileList(filename)))
-  {
-    char *token_value;
-
-    token_value = getTokenValue(level_setup_list, TOKEN_STR_LAST_PLAYED_LEVEL);
-
-    if (token_value)
-    {
-      level_nr = atoi(token_value);
-
-      if (level_nr < leveldir_current->first_level)
-       level_nr = leveldir_current->first_level;
-      if (level_nr > leveldir_current->last_level)
-       level_nr = leveldir_current->last_level;
-    }
-
-    token_value = getTokenValue(level_setup_list, TOKEN_STR_HANDICAP_LEVEL);
-
-    if (token_value)
-    {
-      int level_nr = atoi(token_value);
-
-      if (level_nr < leveldir_current->first_level)
-       level_nr = leveldir_current->first_level;
-      if (level_nr > leveldir_current->last_level + 1)
-       level_nr = leveldir_current->last_level;
-
-      if (leveldir_current->user_defined)
-       level_nr = leveldir_current->last_level;
-
-      leveldir_current->handicap_level = level_nr;
-    }
-
-    checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
-
-    freeSetupFileList(level_setup_list);
-  }
-  else
-    Error(ERR_WARN, "using default setup values");
-
-  free(filename);
-}
-
-void SaveLevelSetup_SeriesInfo()
-{
-  char *filename;
-  char *level_subdir = leveldir_current->filename;
-  char *level_nr_str = int2str(level_nr, 0);
-  char *handicap_level_str = int2str(leveldir_current->handicap_level, 0);
-  FILE *file;
-
-  /* ----------------------------------------------------------------------- */
-  /* ~/.rocksndiamonds/levelsetup/<level series>/levelsetup.conf             */
-  /* ----------------------------------------------------------------------- */
-
-  InitLevelSetupDirectory(level_subdir);
-
-  filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME);
-
-  if (!(file = fopen(filename, MODE_WRITE)))
-  {
-    Error(ERR_WARN, "cannot write setup file '%s'", filename);
-    free(filename);
-    return;
-  }
-
-  fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
-                                                LEVELSETUP_COOKIE));
-  fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_LEVEL,
-                                              level_nr_str));
-  fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL,
-                                              handicap_level_str));
-
-  fclose(file);
-  free(filename);
-
-  SetFilePermissions(filename, PERMS_PRIVATE);
-}
index bd593b5a8d5db3a349550cede2d9db8a9ab96eee..994ac1daabb47cae8f1f950e26ecd8ec9fff7317 100644 (file)
@@ -26,12 +26,4 @@ void DumpTape(struct TapeInfo *);
 void LoadScore(int);
 void SaveScore(int);
 
-void LoadLevelInfo(void);
-void LoadSetup(void);
-void SaveSetup(void);
-void LoadLevelSetup_LastSeries(void);
-void SaveLevelSetup_LastSeries(void);
-void LoadLevelSetup_SeriesInfo(void);
-void SaveLevelSetup_SeriesInfo(void);
-
 #endif /* FILES_H */
index 2acc4c9453c5fa649aa42c2fb4f8c1a8078bf1f8..fcfeb740e3afd3230aa60028092df703164bbb15 100644 (file)
@@ -19,7 +19,6 @@
 #include "init.h"
 #include "files.h"
 #include "tape.h"
-#include "joystick.h"
 #include "network.h"
 
 /* this switch controls how rocks move horizontally */
index 8cdbae4d60fb96a928fb0d5eb7ecd52e56b75b54..df4099e162cedaa88202b97e56f9446deff7a692 100644 (file)
@@ -21,7 +21,6 @@
 #include "tape.h"
 #include "tools.h"
 #include "files.h"
-#include "joystick.h"
 #include "network.h"
 #include "netserv.h"
 
@@ -84,10 +83,7 @@ void InitPlayerInfo()
   local_player = &stored_player[0];
 
   for (i=0; i<MAX_PLAYERS; i++)
-  {
-    stored_player[i].joystick_fd = -1; /* joystick device closed */
     stored_player[i].connected = FALSE;
-  }
 
   local_player->connected = TRUE;
 
@@ -155,10 +151,13 @@ void InitJoysticks()
 
   int i;
 
-  if (global_joystick_status == JOYSTICK_OFF)
-    return;
+  /* always start with reliable default values */
+  joystick.status = JOYSTICK_NOT_AVAILABLE;
+  for (i=0; i<MAX_PLAYERS; i++)
+    joystick.fd[i] = -1;               /* joystick device closed */
 
-  joystick_status = JOYSTICK_OFF;
+  if (global_joystick_status == JOYSTICK_NOT_AVAILABLE)
+    return;
 
 #if defined(TARGET_SDL)
 
@@ -182,7 +181,7 @@ void InitJoysticks()
       joystick_nr = -1;
 
     /* misuse joystick file descriptor variable to store joystick number */
-    stored_player[i].joystick_fd = joystick_nr;
+    joystick.fd[i] = joystick_nr;
 
     /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
     if (Check_SDL_JoystickOpened(joystick_nr))
@@ -197,7 +196,7 @@ void InitJoysticks()
       continue;
     }
 
-    joystick_status = JOYSTICK_AVAILABLE;
+    joystick.status = JOYSTICK_ACTIVATED;
   }
 
 #else /* !TARGET_SDL */
@@ -208,10 +207,10 @@ void InitJoysticks()
     char *device_name = setup.input[i].joy.device_name;
 
     /* this allows subsequent calls to 'InitJoysticks' for re-initialization */
-    if (stored_player[i].joystick_fd != -1)
+    if (joystick.fd[i] != -1)
     {
-      close(stored_player[i].joystick_fd);
-      stored_player[i].joystick_fd = -1;
+      close(joystick.fd[i]);
+      joystick.fd[i] = -1;
     }
 
     if (!setup.input[i].use_joystick)
@@ -223,13 +222,13 @@ void InitJoysticks()
       continue;
     }
 
-    if ((stored_player[i].joystick_fd = open(device_name, O_RDONLY)) < 0)
+    if ((joystick.fd[i] = open(device_name, O_RDONLY)) < 0)
     {
       Error(ERR_WARN, "cannot open joystick device '%s'", device_name);
       continue;
     }
 
-    joystick_status = JOYSTICK_AVAILABLE;
+    joystick.status = JOYSTICK_ACTIVATED;
   }
 
 #else /* !PLATFORM_UNIX */
@@ -237,7 +236,7 @@ void InitJoysticks()
   /* try to access two joysticks; if that fails, try to access just one */
   if (install_joystick(JOY_TYPE_2PADS) == 0 ||
       install_joystick(JOY_TYPE_AUTODETECT) == 0)
-    joystick_status = JOYSTICK_AVAILABLE;
+    joystick.status = JOYSTICK_ACTIVATED;
 
   /*
   load_joystick_data(JOYSTICK_FILENAME);
@@ -252,7 +251,7 @@ void InitJoysticks()
       joystick_nr = -1;
 
     /* misuse joystick file descriptor variable to store joystick number */
-    stored_player[i].joystick_fd = joystick_nr;
+    joystick.fd[i] = joystick_nr;
   }
 #endif
 
diff --git a/src/joystick.c b/src/joystick.c
deleted file mode 100644 (file)
index 2ad9cb8..0000000
+++ /dev/null
@@ -1,521 +0,0 @@
-/***********************************************************
-* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
-*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment                      *
-*               Holger Schemel                             *
-*               Detmolder Strasse 189                      *
-*               33604 Bielefeld                            *
-*               Germany                                    *
-*               e-mail: info@artsoft.org                   *
-*----------------------------------------------------------*
-* joystick.c                                               *
-***********************************************************/
-
-#if defined(PLATFORM_FREEBSD)
-#include <machine/joystick.h>
-#endif
-
-#include "libgame/libgame.h"
-
-#include "joystick.h"
-
-#define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0
-#define TRANSLATE_JOYNAME_TO_JOYSYMBOL 1
-
-void translate_joyname(int *joysymbol, char **name, int mode)
-{
-  static struct
-  {
-    int joysymbol;
-    char *name;
-  } translate_joy[] =
-  {
-    { JOY_LEFT,                "joystick_left" },
-    { JOY_RIGHT,       "joystick_right" },
-    { JOY_UP,          "joystick_up" },
-    { JOY_DOWN,                "joystick_down" },
-    { JOY_BUTTON_1,    "joystick_button_1" },
-    { JOY_BUTTON_2,    "joystick_button_2" },
-  };
-
-  int i;
-
-  if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME)
-  {
-    *name = "[undefined]";
-
-    for (i=0; i<6; i++)
-    {
-      if (*joysymbol == translate_joy[i].joysymbol)
-      {
-       *name = translate_joy[i].name;
-       break;
-      }
-    }
-  }
-  else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL)
-  {
-    *joysymbol = 0;
-
-    for (i=0; i<6; i++)
-    {
-      if (strcmp(*name, translate_joy[i].name) == 0)
-      {
-       *joysymbol = translate_joy[i].joysymbol;
-       break;
-      }
-    }
-  }
-}
-
-char *getJoyNameFromJoySymbol(int joysymbol)
-{
-  char *name;
-
-  translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME);
-  return name;
-}
-
-int getJoySymbolFromJoyName(char *name)
-{
-  int joysymbol;
-
-  translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL);
-  return joysymbol;
-}
-
-int getJoystickNrFromDeviceName(char *device_name)
-{
-  char c;
-  int joystick_nr = 0;
-
-  if (device_name == NULL || device_name[0] == '\0')
-    return 0;
-
-  c = device_name[strlen(device_name) - 1];
-
-  if (c >= '0' && c <= '9')
-    joystick_nr = (int)(c - '0');
-
-  if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS)
-    joystick_nr = 0;
-
-  return joystick_nr;
-}
-
-#if !defined(PLATFORM_MSDOS)
-static int JoystickPosition(int middle, int margin, int actual)
-{
-  long range, pos;
-  int percentage;
-
-  if (margin < middle && actual > middle)
-    return 0;
-  if (margin > middle && actual < middle)
-    return 0;
-
-  range = ABS(margin - middle);
-  pos = ABS(actual - middle);
-  percentage = (int)(pos * 100 / range);
-
-  if (percentage > 100)
-    percentage = 100;
-
-  return percentage;
-}
-#endif
-
-#if defined(TARGET_SDL)
-
-static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
-static int sdl_js_axis[MAX_PLAYERS][2]   = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
-static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
-
-SDL_Joystick *Get_SDL_Joystick(int nr)
-{
-  return sdl_joystick[nr];
-}
-
-boolean Open_SDL_Joystick(int nr)
-{
-  if (nr < 0 || nr > MAX_PLAYERS)
-    return FALSE;
-
-  return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
-}
-
-void Close_SDL_Joystick(int nr)
-{
-  if (nr < 0 || nr > MAX_PLAYERS)
-    return;
-
-  SDL_JoystickClose(sdl_joystick[nr]);
-}
-
-boolean Check_SDL_JoystickOpened(int nr)
-{
-  if (nr < 0 || nr > MAX_PLAYERS)
-    return FALSE;
-
-  return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
-}
-
-void HandleJoystickEvent(Event *event)
-{
-  switch(event->type)
-  {
-    case SDL_JOYAXISMOTION:
-      if (event->jaxis.axis < 2)
-      {
-       sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
-
-#if 0
-       printf("js_%d %s-axis: %d\n",
-              event->jaxis.which,
-              (event->jaxis.axis == 0 ? "x" : "y"),
-              event->jaxis.value);
-#endif
-      }
-      break;
-
-    case SDL_JOYBUTTONDOWN:
-      if (event->jbutton.button < 2)
-      {
-       sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
-
-#if 0
-        printf("js_%d button %d: pressed\n",
-              event->jbutton.which,
-              event->jbutton.button);
-#endif
-      }
-      break;
-
-    case SDL_JOYBUTTONUP:
-      if (event->jbutton.button < 2)
-      {
-       sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
-
-#if 0
-        printf("js_%d button %d: released\n",
-              event->jbutton.which,
-              event->jbutton.button);
-#endif
-      }
-      break;
-
-    default:
-      break;
-  }
-}
-
-int Get_SDL_Joystick_Axis(int nr, int axis)
-{
-  if (nr < 0 || nr > MAX_PLAYERS)
-    return 0;
-
-  if (axis < 0 || axis > 1)
-    return 0;
-
-  return sdl_js_axis[nr][axis];
-}
-
-void CheckJoystickData()
-{
-}
-
-int Joystick(int player_nr)
-{
-  int joystick_nr = stored_player[player_nr].joystick_fd;
-  int js_x,js_y, js_b1,js_b2;
-  int left, right, up, down;
-  int result = 0;
-
-  if (joystick_status == JOYSTICK_OFF)
-    return 0;
-
-  if (game_status == SETUPINPUT)
-    return 0;
-
-  if (!setup.input[player_nr].use_joystick ||
-      !Check_SDL_JoystickOpened(joystick_nr))
-    return 0;
-
-  js_x  = sdl_js_axis[joystick_nr][0];
-  js_y  = sdl_js_axis[joystick_nr][1];
-
-  js_b1 = sdl_js_button[joystick_nr][0];
-  js_b2 = sdl_js_button[joystick_nr][1];
-
-
-
-#if 0
-  printf("JOYSTICK %d: js_x == %d, js_y == %d, js_b1 == %d, js_b2 == %d\n",
-        joystick_nr, js_x, js_y, js_b1, js_b2);
-#endif
-
-
-
-  left  = JoystickPosition(setup.input[player_nr].joy.xmiddle,
-                          setup.input[player_nr].joy.xleft,  js_x);
-  right = JoystickPosition(setup.input[player_nr].joy.xmiddle,
-                          setup.input[player_nr].joy.xright, js_x);
-  up    = JoystickPosition(setup.input[player_nr].joy.ymiddle,
-                          setup.input[player_nr].joy.yupper, js_y);
-  down  = JoystickPosition(setup.input[player_nr].joy.ymiddle,
-                          setup.input[player_nr].joy.ylower, js_y);
-
-  if (left > JOYSTICK_PERCENT)
-    result |= JOY_LEFT;
-  else if (right > JOYSTICK_PERCENT)
-    result |= JOY_RIGHT;
-  if (up > JOYSTICK_PERCENT)
-    result |= JOY_UP;
-  else if (down > JOYSTICK_PERCENT)
-    result |= JOY_DOWN;
-
-  if (js_b1)
-    result |= JOY_BUTTON_1;
-  if (js_b2)
-    result |= JOY_BUTTON_2;
-
-
-
-#if 0
-  printf("result == 0x%08x\n", result);
-#endif
-
-
-
-  return result;
-}
-
-#else /* !TARGET_SDL */
-
-void CheckJoystickData()
-{
-  int i;
-  int distance = 100;
-
-  for(i=0; i<MAX_PLAYERS; i++)
-  {
-    if (setup.input[i].joy.xmiddle <= distance)
-      setup.input[i].joy.xmiddle = distance;
-    if (setup.input[i].joy.ymiddle <= distance)
-      setup.input[i].joy.ymiddle = distance;
-
-    if (setup.input[i].joy.xleft >= setup.input[i].joy.xmiddle)
-      setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance;
-    if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle)
-      setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance;
-
-    if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle)
-      setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance;
-    if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle)
-      setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance;
-  }
-}
-
-#if defined(PLATFORM_UNIX)
-int Joystick(int player_nr)
-{
-#ifdef __FreeBSD__
-  struct joystick joy_ctrl;
-#else
-  struct joystick_control
-  {
-    int buttons;
-    int x;
-    int y;
-  } joy_ctrl;
-#endif
-
-  int joystick_fd = stored_player[player_nr].joystick_fd;
-  int js_x,js_y, js_b1,js_b2;
-  int left, right, up, down;
-  int result = 0;
-
-  if (joystick_status == JOYSTICK_OFF)
-    return 0;
-
-  if (game_status == SETUPINPUT)
-    return 0;
-
-  if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
-    return 0;
-
-  if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
-  {
-    Error(ERR_WARN, "cannot read joystick device '%s'",
-         setup.input[player_nr].joy.device_name);
-    joystick_status = JOYSTICK_OFF;
-    return 0;
-  }
-
-  js_x  = joy_ctrl.x;
-  js_y  = joy_ctrl.y;
-
-#ifdef __FreeBSD__
-  js_b1 = joy_ctrl.b1;
-  js_b2 = joy_ctrl.b2;
-#else
-  js_b1 = joy_ctrl.buttons & 1;
-  js_b2 = joy_ctrl.buttons & 2;
-#endif
-
-  left  = JoystickPosition(setup.input[player_nr].joy.xmiddle,
-                          setup.input[player_nr].joy.xleft,  js_x);
-  right = JoystickPosition(setup.input[player_nr].joy.xmiddle,
-                          setup.input[player_nr].joy.xright, js_x);
-  up    = JoystickPosition(setup.input[player_nr].joy.ymiddle,
-                          setup.input[player_nr].joy.yupper, js_y);
-  down  = JoystickPosition(setup.input[player_nr].joy.ymiddle,
-                          setup.input[player_nr].joy.ylower, js_y);
-
-  if (left > JOYSTICK_PERCENT)
-    result |= JOY_LEFT;
-  else if (right > JOYSTICK_PERCENT)
-    result |= JOY_RIGHT;
-  if (up > JOYSTICK_PERCENT)
-    result |= JOY_UP;
-  else if (down > JOYSTICK_PERCENT)
-    result |= JOY_DOWN;
-
-  if (js_b1)
-    result |= JOY_BUTTON_1;
-  if (js_b2)
-    result |= JOY_BUTTON_2;
-
-  return result;
-}
-
-#else /* PLATFORM_MSDOS */
-
-/* allegro global variables for joystick control */
-extern int num_joysticks;
-extern JOYSTICK_INFO joy[];
-
-int Joystick(int player_nr)
-{
-  int joystick_nr = stored_player[player_nr].joystick_fd;
-  int result = 0;
-
-  if (joystick_status == JOYSTICK_OFF)
-    return 0;
-
-  if (game_status == SETUPINPUT)
-    return 0;
-
-  if (joystick_nr < 0)
-    return 0;
-
-  /* the allegro global variable 'num_joysticks' contains the number
-     of joysticks found at initialization under MS-DOS / Windows */
-
-#if 0
-  if (joystick_nr >= num_joysticks || !setup.input[player_nr].use_joystick)
-    return 0;
-#else
-
-#if 1
-  if (joystick_nr >= num_joysticks ||
-      (game_status == PLAYING && !setup.input[player_nr].use_joystick))
-    return 0;
-#else
-  if (joystick_nr >= num_joysticks)
-    return 0;
-#endif
-
-#endif
-
-  poll_joystick();
-
-  if (joy[joystick_nr].stick[0].axis[0].d1)
-    result |= JOY_LEFT;
-  else if (joy[joystick_nr].stick[0].axis[0].d2)
-    result |= JOY_RIGHT;
-  if (joy[joystick_nr].stick[0].axis[1].d1)
-    result |= JOY_UP;
-  else if (joy[joystick_nr].stick[0].axis[1].d2)
-    result |= JOY_DOWN;
-
-  if (joy[joystick_nr].button[0].b)
-    result |= JOY_BUTTON_1;
-  if (joy[joystick_nr].button[1].b)
-    result |= JOY_BUTTON_2;
-
-  return result;
-}
-#endif /* PLATFORM_MSDOS */
-
-#endif /* !TARGET_SDL */
-
-int JoystickButton(int player_nr)
-{
-  static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 };
-  int joy_button = (Joystick(player_nr) & JOY_BUTTON);
-  int result;
-
-  if (joy_button)
-  {
-    if (last_joy_button[player_nr])
-      result = JOY_BUTTON_PRESSED;
-    else
-      result = JOY_BUTTON_NEW_PRESSED;
-  }
-  else
-  {
-    if (last_joy_button[player_nr])
-      result = JOY_BUTTON_NEW_RELEASED;
-    else
-      result = JOY_BUTTON_NOT_PRESSED;
-  }
-
-  last_joy_button[player_nr] = joy_button;
-  return result;
-}
-
-int AnyJoystick()
-{
-  int i;
-  int result = 0;
-
-  for (i=0; i<MAX_PLAYERS; i++)
-  {
-
-    /*
-    if (!setup.input[i].use_joystick)
-      continue;
-      */
-
-
-    result |= Joystick(i);
-  }
-
-  return result;
-}
-
-int AnyJoystickButton()
-{
-  int i;
-  int result;
-
-  for (i=0; i<MAX_PLAYERS; i++)
-  {
-
-    /*
-    if (!setup.input[i].use_joystick)
-      continue;
-      */
-
-    /*
-    result |= JoystickButton(i);
-    */
-
-    result = JoystickButton(i);
-    if (result != JOY_BUTTON_NOT_PRESSED)
-      break;
-  }
-
-  return result;
-}
diff --git a/src/joystick.h b/src/joystick.h
deleted file mode 100644 (file)
index 00fb483..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/***********************************************************
-* Rocks'n'Diamonds -- McDuffin Strikes Back!               *
-*----------------------------------------------------------*
-* (c) 1995-2001 Artsoft Entertainment                      *
-*               Holger Schemel                             *
-*               Detmolder Strasse 189                      *
-*               33604 Bielefeld                            *
-*               Germany                                    *
-*               e-mail: info@artsoft.org                   *
-*----------------------------------------------------------*
-* joystick.h                                               *
-***********************************************************/
-
-#ifndef JOYSTICK_H
-#define JOYSTICK_H
-
-#include "main.h"
-
-/* values for the joystick */
-#define JOYSTICK_OFF           0
-#define        JOYSTICK_AVAILABLE      1
-
-#ifdef __FreeBSD__
-#include <machine/joystick.h>
-#define DEV_JOYSTICK_0         "/dev/joy0"
-#define DEV_JOYSTICK_1         "/dev/joy1"
-#define DEV_JOYSTICK_2         "/dev/joy2"
-#define DEV_JOYSTICK_3         "/dev/joy3"
-#else
-#define DEV_JOYSTICK_0         "/dev/js0"
-#define DEV_JOYSTICK_1         "/dev/js1"
-#define DEV_JOYSTICK_2         "/dev/js2"
-#define DEV_JOYSTICK_3         "/dev/js3"
-#endif
-
-/* get these values from the program 'js' from the joystick package, */
-/* set JOYSTICK_PERCENT to a threshold appropriate for your joystick */
-
-#ifdef TARGET_SDL
-#define JOYSTICK_XLEFT         -32767
-#define JOYSTICK_XMIDDLE       0
-#define JOYSTICK_XRIGHT                32767
-#define JOYSTICK_YUPPER                -32767
-#define JOYSTICK_YMIDDLE       0
-#define JOYSTICK_YLOWER                32767
-#else
-#define JOYSTICK_XLEFT         30
-#define JOYSTICK_XMIDDLE       530
-#define JOYSTICK_XRIGHT                1250
-#define JOYSTICK_YUPPER                40
-#define JOYSTICK_YMIDDLE       680
-#define JOYSTICK_YLOWER                1440
-#endif
-
-#define JOYSTICK_PERCENT       25
-
-#define JOY_LEFT               MV_LEFT
-#define JOY_RIGHT              MV_RIGHT
-#define JOY_UP                 MV_UP
-#define JOY_DOWN               MV_DOWN
-#define JOY_BUTTON_1           (1<<4)
-#define JOY_BUTTON_2           (1<<5)
-#define JOY_BUTTON             (JOY_BUTTON_1 | JOY_BUTTON_2)
-
-#define JOY_BUTTON_NOT_PRESSED 0
-#define JOY_BUTTON_PRESSED     1
-#define JOY_BUTTON_NEW_PRESSED 2
-#define JOY_BUTTON_NEW_RELEASED        3
-
-#ifdef NO_JOYSTICK
-#define JOYSTICK_STATUS                JOYSTICK_OFF
-#else
-#define JOYSTICK_STATUS                JOYSTICK_AVAILABLE
-#endif
-
-
-#if defined(TARGET_SDL)
-SDL_Joystick *Get_SDL_Joystick(int);
-boolean Open_SDL_Joystick(int);
-void Close_SDL_Joystick(int);
-boolean Check_SDL_JoystickOpened(int);
-void HandleJoystickEvent(Event *);
-int Get_SDL_Joystick_Axis(int, int);
-#endif
-
-void CheckJoystickData(void);
-int Joystick(int);
-int JoystickButton(int);
-int AnyJoystick(void);
-int AnyJoystickButton(void);
-
-#endif /* JOYSTICK_H */
index b756b27d4f830429fc44b5b1498ba889f1d454be..07159642b635962d1368fe008de1400c52f9501d 100644 (file)
@@ -7,9 +7,11 @@ SRCS = system.c        \
        gadgets.c       \
        text.c          \
        sound.c         \
+       joystick.c      \
        pcx.c           \
        image.c         \
        random.c        \
+       setup.c         \
        misc.c          \
        msdos.c         \
        x11.c           \
@@ -19,9 +21,11 @@ OBJS =       system.o        \
        gadgets.o       \
        text.o          \
        sound.o         \
+       joystick.o      \
        pcx.o           \
        image.o         \
        random.o        \
+       setup.o         \
        misc.o          \
        msdos.o         \
        x11.o           \
diff --git a/src/libgame/joystick.c b/src/libgame/joystick.c
new file mode 100644 (file)
index 0000000..4bca889
--- /dev/null
@@ -0,0 +1,577 @@
+/***********************************************************
+* Artsoft Retro-Game Library                               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* joystick.c                                               *
+***********************************************************/
+
+#if defined(PLATFORM_FREEBSD)
+#include <machine/joystick.h>
+#endif
+
+#include "joystick.h"
+#include "misc.h"
+
+
+#define TRANSLATE_JOYSYMBOL_TO_JOYNAME 0
+#define TRANSLATE_JOYNAME_TO_JOYSYMBOL 1
+
+#if 0
+static int joystick_device = 0;
+char *joystick_device_name[MAX_PLAYERS] =
+{
+  DEV_JOYSTICK_0,
+  DEV_JOYSTICK_1,
+  DEV_JOYSTICK_2,
+  DEV_JOYSTICK_3
+};
+#endif
+
+
+void translate_joyname(int *joysymbol, char **name, int mode)
+{
+  static struct
+  {
+    int joysymbol;
+    char *name;
+  } translate_joy[] =
+  {
+    { JOY_LEFT,                "joystick_left" },
+    { JOY_RIGHT,       "joystick_right" },
+    { JOY_UP,          "joystick_up" },
+    { JOY_DOWN,                "joystick_down" },
+    { JOY_BUTTON_1,    "joystick_button_1" },
+    { JOY_BUTTON_2,    "joystick_button_2" },
+  };
+
+  int i;
+
+  if (mode == TRANSLATE_JOYSYMBOL_TO_JOYNAME)
+  {
+    *name = "[undefined]";
+
+    for (i=0; i<6; i++)
+    {
+      if (*joysymbol == translate_joy[i].joysymbol)
+      {
+       *name = translate_joy[i].name;
+       break;
+      }
+    }
+  }
+  else if (mode == TRANSLATE_JOYNAME_TO_JOYSYMBOL)
+  {
+    *joysymbol = 0;
+
+    for (i=0; i<6; i++)
+    {
+      if (strcmp(*name, translate_joy[i].name) == 0)
+      {
+       *joysymbol = translate_joy[i].joysymbol;
+       break;
+      }
+    }
+  }
+}
+
+char *getJoyNameFromJoySymbol(int joysymbol)
+{
+  char *name;
+
+  translate_joyname(&joysymbol, &name, TRANSLATE_JOYSYMBOL_TO_JOYNAME);
+  return name;
+}
+
+int getJoySymbolFromJoyName(char *name)
+{
+  int joysymbol;
+
+  translate_joyname(&joysymbol, &name, TRANSLATE_JOYNAME_TO_JOYSYMBOL);
+  return joysymbol;
+}
+
+int getJoystickNrFromDeviceName(char *device_name)
+{
+  char c;
+  int joystick_nr = 0;
+
+  if (device_name == NULL || device_name[0] == '\0')
+    return 0;
+
+  c = device_name[strlen(device_name) - 1];
+
+  if (c >= '0' && c <= '9')
+    joystick_nr = (int)(c - '0');
+
+  if (joystick_nr < 0 || joystick_nr >= MAX_PLAYERS)
+    joystick_nr = 0;
+
+  return joystick_nr;
+}
+
+char *getDeviceNameFromJoystickNr(int joystick_nr)
+{
+  static char *joystick_device_name[MAX_PLAYERS] =
+  {
+    DEV_JOYSTICK_0,
+    DEV_JOYSTICK_1,
+    DEV_JOYSTICK_2,
+    DEV_JOYSTICK_3
+  };
+
+  return (joystick_nr >= 0 && joystick_nr <= 3 ?
+         joystick_device_name[joystick_nr] : "");
+}
+
+#if !defined(PLATFORM_MSDOS)
+static int JoystickPosition(int middle, int margin, int actual)
+{
+  long range, pos;
+  int percentage;
+
+  if (margin < middle && actual > middle)
+    return 0;
+  if (margin > middle && actual < middle)
+    return 0;
+
+  range = ABS(margin - middle);
+  pos = ABS(actual - middle);
+  percentage = (int)(pos * 100 / range);
+
+  if (percentage > 100)
+    percentage = 100;
+
+  return percentage;
+}
+#endif
+
+#if defined(TARGET_SDL)
+
+static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
+static int sdl_js_axis[MAX_PLAYERS][2]   = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
+static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
+
+SDL_Joystick *Get_SDL_Joystick(int nr)
+{
+  return sdl_joystick[nr];
+}
+
+boolean Open_SDL_Joystick(int nr)
+{
+  if (nr < 0 || nr > MAX_PLAYERS)
+    return FALSE;
+
+  return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
+}
+
+void Close_SDL_Joystick(int nr)
+{
+  if (nr < 0 || nr > MAX_PLAYERS)
+    return;
+
+  SDL_JoystickClose(sdl_joystick[nr]);
+}
+
+boolean Check_SDL_JoystickOpened(int nr)
+{
+  if (nr < 0 || nr > MAX_PLAYERS)
+    return FALSE;
+
+  return (SDL_JoystickOpened(nr) ? TRUE : FALSE);
+}
+
+void HandleJoystickEvent(Event *event)
+{
+  switch(event->type)
+  {
+    case SDL_JOYAXISMOTION:
+      if (event->jaxis.axis < 2)
+      {
+       sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
+
+#if 0
+       printf("js_%d %s-axis: %d\n",
+              event->jaxis.which,
+              (event->jaxis.axis == 0 ? "x" : "y"),
+              event->jaxis.value);
+#endif
+      }
+      break;
+
+    case SDL_JOYBUTTONDOWN:
+      if (event->jbutton.button < 2)
+      {
+       sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
+
+#if 0
+        printf("js_%d button %d: pressed\n",
+              event->jbutton.which,
+              event->jbutton.button);
+#endif
+      }
+      break;
+
+    case SDL_JOYBUTTONUP:
+      if (event->jbutton.button < 2)
+      {
+       sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
+
+#if 0
+        printf("js_%d button %d: released\n",
+              event->jbutton.which,
+              event->jbutton.button);
+#endif
+      }
+      break;
+
+    default:
+      break;
+  }
+}
+
+int Get_SDL_Joystick_Axis(int nr, int axis)
+{
+  if (nr < 0 || nr > MAX_PLAYERS)
+    return 0;
+
+  if (axis < 0 || axis > 1)
+    return 0;
+
+  return sdl_js_axis[nr][axis];
+}
+
+void CheckJoystickData()
+{
+}
+
+int Joystick(int player_nr)
+{
+#if 0
+  int joystick_nr = stored_player[player_nr].joystick_fd;
+#else
+  int joystick_nr = joystick.fd[player_nr];
+#endif
+  int js_x,js_y, js_b1,js_b2;
+  int left, right, up, down;
+  int result = 0;
+
+  if (joystick.status != JOYSTICK_ACTIVATED)
+    return 0;
+
+  if (!setup.input[player_nr].use_joystick ||
+      !Check_SDL_JoystickOpened(joystick_nr))
+    return 0;
+
+  js_x  = sdl_js_axis[joystick_nr][0];
+  js_y  = sdl_js_axis[joystick_nr][1];
+
+  js_b1 = sdl_js_button[joystick_nr][0];
+  js_b2 = sdl_js_button[joystick_nr][1];
+
+
+
+#if 0
+  printf("JOYSTICK %d: js_x == %d, js_y == %d, js_b1 == %d, js_b2 == %d\n",
+        joystick_nr, js_x, js_y, js_b1, js_b2);
+#endif
+
+
+
+  left  = JoystickPosition(setup.input[player_nr].joy.xmiddle,
+                          setup.input[player_nr].joy.xleft,  js_x);
+  right = JoystickPosition(setup.input[player_nr].joy.xmiddle,
+                          setup.input[player_nr].joy.xright, js_x);
+  up    = JoystickPosition(setup.input[player_nr].joy.ymiddle,
+                          setup.input[player_nr].joy.yupper, js_y);
+  down  = JoystickPosition(setup.input[player_nr].joy.ymiddle,
+                          setup.input[player_nr].joy.ylower, js_y);
+
+  if (left > JOYSTICK_PERCENT)
+    result |= JOY_LEFT;
+  else if (right > JOYSTICK_PERCENT)
+    result |= JOY_RIGHT;
+  if (up > JOYSTICK_PERCENT)
+    result |= JOY_UP;
+  else if (down > JOYSTICK_PERCENT)
+    result |= JOY_DOWN;
+
+  if (js_b1)
+    result |= JOY_BUTTON_1;
+  if (js_b2)
+    result |= JOY_BUTTON_2;
+
+
+
+#if 0
+  printf("result == 0x%08x\n", result);
+#endif
+
+
+
+  return result;
+}
+
+#else /* !TARGET_SDL */
+
+void CheckJoystickData()
+{
+  int i;
+  int distance = 100;
+
+  for(i=0; i<MAX_PLAYERS; i++)
+  {
+    if (setup.input[i].joy.xmiddle <= distance)
+      setup.input[i].joy.xmiddle = distance;
+    if (setup.input[i].joy.ymiddle <= distance)
+      setup.input[i].joy.ymiddle = distance;
+
+    if (setup.input[i].joy.xleft >= setup.input[i].joy.xmiddle)
+      setup.input[i].joy.xleft = setup.input[i].joy.xmiddle - distance;
+    if (setup.input[i].joy.xright <= setup.input[i].joy.xmiddle)
+      setup.input[i].joy.xright = setup.input[i].joy.xmiddle + distance;
+
+    if (setup.input[i].joy.yupper >= setup.input[i].joy.ymiddle)
+      setup.input[i].joy.yupper = setup.input[i].joy.ymiddle - distance;
+    if (setup.input[i].joy.ylower <= setup.input[i].joy.ymiddle)
+      setup.input[i].joy.ylower = setup.input[i].joy.ymiddle + distance;
+  }
+}
+
+#if defined(PLATFORM_UNIX)
+int Joystick(int player_nr)
+{
+#if defined(PLATFORM_FREEBSD)
+  struct joystick joy_ctrl;
+#else
+  struct joystick_control
+  {
+    int buttons;
+    int x;
+    int y;
+  } joy_ctrl;
+#endif
+
+#if 0
+  int joystick_fd = stored_player[player_nr].joystick_fd;
+#else
+  int joystick_fd = joystick.fd[player_nr];
+#endif
+  int js_x,js_y, js_b1,js_b2;
+  int left, right, up, down;
+  int result = 0;
+
+  if (joystick.status != JOYSTICK_ACTIVATED)
+    return 0;
+
+  if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
+    return 0;
+
+  if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
+  {
+    Error(ERR_WARN, "cannot read joystick device '%s'",
+         setup.input[player_nr].joy.device_name);
+    joystick.status = JOYSTICK_NOT_AVAILABLE;
+    return 0;
+  }
+
+  js_x  = joy_ctrl.x;
+  js_y  = joy_ctrl.y;
+
+#if defined(PLATFORM_FREEBSD)
+  js_b1 = joy_ctrl.b1;
+  js_b2 = joy_ctrl.b2;
+#else
+  js_b1 = joy_ctrl.buttons & 1;
+  js_b2 = joy_ctrl.buttons & 2;
+#endif
+
+  left  = JoystickPosition(setup.input[player_nr].joy.xmiddle,
+                          setup.input[player_nr].joy.xleft,  js_x);
+  right = JoystickPosition(setup.input[player_nr].joy.xmiddle,
+                          setup.input[player_nr].joy.xright, js_x);
+  up    = JoystickPosition(setup.input[player_nr].joy.ymiddle,
+                          setup.input[player_nr].joy.yupper, js_y);
+  down  = JoystickPosition(setup.input[player_nr].joy.ymiddle,
+                          setup.input[player_nr].joy.ylower, js_y);
+
+  if (left > JOYSTICK_PERCENT)
+    result |= JOY_LEFT;
+  else if (right > JOYSTICK_PERCENT)
+    result |= JOY_RIGHT;
+  if (up > JOYSTICK_PERCENT)
+    result |= JOY_UP;
+  else if (down > JOYSTICK_PERCENT)
+    result |= JOY_DOWN;
+
+  if (js_b1)
+    result |= JOY_BUTTON_1;
+  if (js_b2)
+    result |= JOY_BUTTON_2;
+
+  return result;
+}
+
+#else /* PLATFORM_MSDOS */
+
+/* allegro global variables for joystick control */
+extern int num_joysticks;
+extern JOYSTICK_INFO joy[];
+
+int Joystick(int player_nr)
+{
+#if 0
+  int joystick_nr = stored_player[player_nr].joystick_fd;
+#else
+  int joystick_nr = joystick.fd[player_nr];
+#endif
+  int result = 0;
+
+  if (joystick.status != JOYSTICK_ACTIVATED)
+    return 0;
+
+  if (joystick_nr < 0)
+    return 0;
+
+  /* the allegro global variable 'num_joysticks' contains the number
+     of joysticks found at initialization under MS-DOS / Windows */
+
+#if 0
+  if (joystick_nr >= num_joysticks || !setup.input[player_nr].use_joystick)
+    return 0;
+#else
+
+#if 1
+  /*
+  if (joystick_nr >= num_joysticks ||
+      (game_status == PLAYING && !setup.input[player_nr].use_joystick))
+    return 0;
+  */
+
+  if (joystick_nr >= num_joysticks || !setup.input[player_nr].use_joystick)
+    return 0;
+
+#else
+  if (joystick_nr >= num_joysticks)
+    return 0;
+#endif
+
+#endif
+
+  poll_joystick();
+
+  if (joy[joystick_nr].stick[0].axis[0].d1)
+    result |= JOY_LEFT;
+  else if (joy[joystick_nr].stick[0].axis[0].d2)
+    result |= JOY_RIGHT;
+  if (joy[joystick_nr].stick[0].axis[1].d1)
+    result |= JOY_UP;
+  else if (joy[joystick_nr].stick[0].axis[1].d2)
+    result |= JOY_DOWN;
+
+  if (joy[joystick_nr].button[0].b)
+    result |= JOY_BUTTON_1;
+  if (joy[joystick_nr].button[1].b)
+    result |= JOY_BUTTON_2;
+
+  return result;
+}
+#endif /* PLATFORM_MSDOS */
+
+#endif /* !TARGET_SDL */
+
+int JoystickButton(int player_nr)
+{
+  static int last_joy_button[MAX_PLAYERS] = { 0, 0, 0, 0 };
+  int joy_button = (Joystick(player_nr) & JOY_BUTTON);
+  int result;
+
+  if (joy_button)
+  {
+    if (last_joy_button[player_nr])
+      result = JOY_BUTTON_PRESSED;
+    else
+      result = JOY_BUTTON_NEW_PRESSED;
+  }
+  else
+  {
+    if (last_joy_button[player_nr])
+      result = JOY_BUTTON_NEW_RELEASED;
+    else
+      result = JOY_BUTTON_NOT_PRESSED;
+  }
+
+  last_joy_button[player_nr] = joy_button;
+  return result;
+}
+
+int AnyJoystick()
+{
+  int i;
+  int result = 0;
+
+  for (i=0; i<MAX_PLAYERS; i++)
+  {
+
+    /*
+    if (!setup.input[i].use_joystick)
+      continue;
+      */
+
+
+    result |= Joystick(i);
+  }
+
+  return result;
+}
+
+int AnyJoystickButton()
+{
+  int i;
+  int result;
+
+  for (i=0; i<MAX_PLAYERS; i++)
+  {
+
+    /*
+    if (!setup.input[i].use_joystick)
+      continue;
+      */
+
+    /*
+    result |= JoystickButton(i);
+    */
+
+    result = JoystickButton(i);
+    if (result != JOY_BUTTON_NOT_PRESSED)
+      break;
+  }
+
+  return result;
+}
+
+void DeactivateJoystickForCalibration()
+{
+  /* Temporarily deactivate joystick. This is needed for calibration
+     screens, where the player has to select a joystick device that
+     should be calibrated. If there is a totally uncalibrated joystick
+     active, it may be impossible (due to messed up input from joystick)
+     to select the joystick device to calibrate even when trying to use
+     the mouse or keyboard to select the device. */
+
+  if (joystick.status & JOYSTICK_AVAILABLE)
+    joystick.status &= ~JOYSTICK_ACTIVE;
+}
+
+void ActivateJoystickIfAvailable()
+{
+  /* reactivate temporarily deactivated joystick */
+
+  if (joystick.status & JOYSTICK_AVAILABLE)
+    joystick.status |= JOYSTICK_ACTIVE;
+}
diff --git a/src/libgame/joystick.h b/src/libgame/joystick.h
new file mode 100644 (file)
index 0000000..b1fca49
--- /dev/null
@@ -0,0 +1,102 @@
+/***********************************************************
+* Artsoft Retro-Game Library                               *
+*----------------------------------------------------------*
+* (c) 1995-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* joystick.h                                               *
+***********************************************************/
+
+#ifndef JOYSTICK_H
+#define JOYSTICK_H
+
+#include "system.h"
+
+/* values for the joystick */
+#define JOYSTICK_NOT_AVAILABLE 0
+#define        JOYSTICK_AVAILABLE      (1 << 0)
+#define        JOYSTICK_ACTIVE         (1 << 1)
+
+#define JOYSTICK_ACTIVATED     (JOYSTICK_AVAILABLE | JOYSTICK_ACTIVE)
+
+#if defined(PLATFORM_FREEBSD)
+#define DEV_JOYSTICK_0         "/dev/joy0"
+#define DEV_JOYSTICK_1         "/dev/joy1"
+#define DEV_JOYSTICK_2         "/dev/joy2"
+#define DEV_JOYSTICK_3         "/dev/joy3"
+#else
+#define DEV_JOYSTICK_0         "/dev/js0"
+#define DEV_JOYSTICK_1         "/dev/js1"
+#define DEV_JOYSTICK_2         "/dev/js2"
+#define DEV_JOYSTICK_3         "/dev/js3"
+#endif
+
+/* get these values from the program 'js' from the joystick package, */
+/* set JOYSTICK_PERCENT to a threshold appropriate for your joystick */
+
+#ifdef TARGET_SDL
+#define JOYSTICK_XLEFT         -32767
+#define JOYSTICK_XMIDDLE       0
+#define JOYSTICK_XRIGHT                32767
+#define JOYSTICK_YUPPER                -32767
+#define JOYSTICK_YMIDDLE       0
+#define JOYSTICK_YLOWER                32767
+#else
+#define JOYSTICK_XLEFT         30
+#define JOYSTICK_XMIDDLE       530
+#define JOYSTICK_XRIGHT                1250
+#define JOYSTICK_YUPPER                40
+#define JOYSTICK_YMIDDLE       680
+#define JOYSTICK_YLOWER                1440
+#endif
+
+#define JOYSTICK_PERCENT       25
+
+#define JOY_LEFT               MV_LEFT
+#define JOY_RIGHT              MV_RIGHT
+#define JOY_UP                 MV_UP
+#define JOY_DOWN               MV_DOWN
+#define JOY_BUTTON_1           (1 << 4)
+#define JOY_BUTTON_2           (1 << 5)
+#define JOY_BUTTON             (JOY_BUTTON_1 | JOY_BUTTON_2)
+
+#define JOY_BUTTON_NOT_PRESSED 0
+#define JOY_BUTTON_PRESSED     1
+#define JOY_BUTTON_NEW_PRESSED 2
+#define JOY_BUTTON_NEW_RELEASED        3
+
+#ifdef NO_JOYSTICK
+#define JOYSTICK_STATUS                JOYSTICK_NOT_AVAILABLE
+#else
+#define JOYSTICK_STATUS                JOYSTICK_AVAILABLE
+#endif
+
+
+char *getJoyNameFromJoySymbol(int);
+int getJoySymbolFromJoyName(char *);
+int getJoystickNrFromDeviceName(char *);
+char *getDeviceNameFromJoystickNr(int);
+
+#if defined(TARGET_SDL)
+SDL_Joystick *Get_SDL_Joystick(int);
+boolean Open_SDL_Joystick(int);
+void Close_SDL_Joystick(int);
+boolean Check_SDL_JoystickOpened(int);
+void HandleJoystickEvent(Event *);
+int Get_SDL_Joystick_Axis(int, int);
+#endif
+
+void CheckJoystickData(void);
+int Joystick(int);
+int JoystickButton(int);
+int AnyJoystick(void);
+int AnyJoystickButton(void);
+
+void DeactivateJoystickForCalibration();
+void ActivateJoystickIfAvailable();
+
+#endif /* JOYSTICK_H */
index 9c70978eb0fcec24806efd390d9bf3cfd9c21798..d16c32bf24d11ad9ec18c61c5ba902ead564ebd3 100644 (file)
 #include "gadgets.h"
 #include "text.h"
 #include "sound.h"
+#include "joystick.h"
 #include "image.h"
 #include "pcx.h"
+#include "setup.h"
 #include "misc.h"
 
 #endif /* LIBGAME_H */
index a78429b7c40c50cf3a65279150304c7e00f97c2d..9fc0cf0405cfb3bdc3e6e4308e1ddf43bfd2c092 100644 (file)
@@ -14,7 +14,9 @@
 #include <time.h>
 #include <sys/time.h>
 #include <sys/types.h>
+/*
 #include <sys/stat.h>
+*/
 #include <stdarg.h>
 #include <ctype.h>
 #include <string.h>
@@ -28,6 +30,7 @@
 #endif
 
 #include "misc.h"
+#include "setup.h"
 #include "random.h"
 
 
@@ -678,6 +681,26 @@ void *checked_realloc(void *ptr, unsigned long size)
   return ptr;
 }
 
+inline void swap_numbers(int *i1, int *i2)
+{
+  int help = *i1;
+
+  *i1 = *i2;
+  *i2 = help;
+}
+
+inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
+{
+  int help_x = *x1;
+  int help_y = *y1;
+
+  *x1 = *x2;
+  *x2 = help_x;
+
+  *y1 = *y2;
+  *y2 = help_y;
+}
+
 short getFile16BitInteger(FILE *file, int byte_order)
 {
   if (byte_order == BYTE_ORDER_BIG_ENDIAN)
@@ -1089,650 +1112,6 @@ char getCharFromKey(Key key)
   return letter;
 }
 
-/* ------------------------------------------------------------------------- */
-/* some functions to handle lists of level directories                       */
-/* ------------------------------------------------------------------------- */
-
-struct LevelDirInfo *newLevelDirInfo()
-{
-  return checked_calloc(sizeof(struct LevelDirInfo));
-}
-
-void pushLevelDirInfo(struct LevelDirInfo **node_first,
-                     struct LevelDirInfo *node_new)
-{
-  node_new->next = *node_first;
-  *node_first = node_new;
-}
-
-int numLevelDirInfo(struct LevelDirInfo *node)
-{
-  int num = 0;
-
-  while (node)
-  {
-    num++;
-    node = node->next;
-  }
-
-  return num;
-}
-
-boolean validLevelSeries(struct LevelDirInfo *node)
-{
-  return (node != NULL && !node->node_group && !node->parent_link);
-}
-
-struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *node)
-{
-  if (node == NULL)
-  {
-    if (leveldir_first)                /* start with first level directory entry */
-      return getFirstValidLevelSeries(leveldir_first);
-    else
-      return NULL;
-  }
-  else if (node->node_group)   /* enter level group (step down into tree) */
-    return getFirstValidLevelSeries(node->node_group);
-  else if (node->parent_link)  /* skip start entry of level group */
-  {
-    if (node->next)            /* get first real level series entry */
-      return getFirstValidLevelSeries(node->next);
-    else                       /* leave empty level group and go on */
-      return getFirstValidLevelSeries(node->node_parent->next);
-  }
-  else                         /* this seems to be a regular level series */
-    return node;
-}
-
-struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *node)
-{
-  if (node == NULL)
-    return NULL;
-
-  if (node->node_parent == NULL)               /* top level group */
-    return leveldir_first;
-  else                                         /* sub level group */
-    return node->node_parent->node_group;
-}
-
-int numLevelDirInfoInGroup(struct LevelDirInfo *node)
-{
-  return numLevelDirInfo(getLevelDirInfoFirstGroupEntry(node));
-}
-
-int posLevelDirInfo(struct LevelDirInfo *node)
-{
-  struct LevelDirInfo *node_cmp = getLevelDirInfoFirstGroupEntry(node);
-  int pos = 0;
-
-  while (node_cmp)
-  {
-    if (node_cmp == node)
-      return pos;
-
-    pos++;
-    node_cmp = node_cmp->next;
-  }
-
-  return 0;
-}
-
-struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *node, int pos)
-{
-  struct LevelDirInfo *node_default = node;
-  int pos_cmp = 0;
-
-  while (node)
-  {
-    if (pos_cmp == pos)
-      return node;
-
-    pos_cmp++;
-    node = node->next;
-  }
-
-  return node_default;
-}
-
-struct LevelDirInfo *getLevelDirInfoFromFilenameExt(struct LevelDirInfo *node,
-                                                   char *filename)
-{
-  if (filename == NULL)
-    return NULL;
-
-  while (node)
-  {
-    if (node->node_group)
-    {
-      struct LevelDirInfo *node_group;
-
-      node_group = getLevelDirInfoFromFilenameExt(node->node_group, filename);
-
-      if (node_group)
-       return node_group;
-    }
-    else if (!node->parent_link)
-    {
-      if (strcmp(filename, node->filename) == 0)
-       return node;
-    }
-
-    node = node->next;
-  }
-
-  return NULL;
-}
-
-struct LevelDirInfo *getLevelDirInfoFromFilename(char *filename)
-{
-  return getLevelDirInfoFromFilenameExt(leveldir_first, filename);
-}
-
-void dumpLevelDirInfo(struct LevelDirInfo *node, int depth)
-{
-  int i;
-
-  while (node)
-  {
-    for (i=0; i<depth * 3; i++)
-      printf(" ");
-
-    printf("filename == '%s'\n", node->filename);
-
-    if (node->node_group != NULL)
-      dumpLevelDirInfo(node->node_group, depth + 1);
-
-    node = node->next;
-  }
-}
-
-void sortLevelDirInfo(struct LevelDirInfo **node_first,
-                     int (*compare_function)(const void *, const void *))
-{
-  int num_nodes = numLevelDirInfo(*node_first);
-  struct LevelDirInfo **sort_array;
-  struct LevelDirInfo *node = *node_first;
-  int i = 0;
-
-  if (num_nodes == 0)
-    return;
-
-  /* allocate array for sorting structure pointers */
-  sort_array = checked_calloc(num_nodes * sizeof(struct LevelDirInfo *));
-
-  /* writing structure pointers to sorting array */
-  while (i < num_nodes && node)                /* double boundary check... */
-  {
-    sort_array[i] = node;
-
-    i++;
-    node = node->next;
-  }
-
-  /* sorting the structure pointers in the sorting array */
-  qsort(sort_array, num_nodes, sizeof(struct LevelDirInfo *),
-       compare_function);
-
-  /* update the linkage of list elements with the sorted node array */
-  for (i=0; i<num_nodes - 1; i++)
-    sort_array[i]->next = sort_array[i + 1];
-  sort_array[num_nodes - 1]->next = NULL;
-
-  /* update the linkage of the main list anchor pointer */
-  *node_first = sort_array[0];
-
-  free(sort_array);
-
-  /* now recursively sort the level group structures */
-  node = *node_first;
-  while (node)
-  {
-    if (node->node_group != NULL)
-      sortLevelDirInfo(&node->node_group, compare_function);
-
-    node = node->next;
-  }
-}
-
-inline void swap_numbers(int *i1, int *i2)
-{
-  int help = *i1;
-
-  *i1 = *i2;
-  *i2 = help;
-}
-
-inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2)
-{
-  int help_x = *x1;
-  int help_y = *y1;
-
-  *x1 = *x2;
-  *x2 = help_x;
-
-  *y1 = *y2;
-  *y2 = help_y;
-}
-
-
-/* ========================================================================= */
-/* some stuff from "files.c"                                                 */
-/* ========================================================================= */
-
-#if defined(PLATFORM_WIN32)
-#ifndef S_IRGRP
-#define S_IRGRP S_IRUSR
-#endif
-#ifndef S_IROTH
-#define S_IROTH S_IRUSR
-#endif
-#ifndef S_IWGRP
-#define S_IWGRP S_IWUSR
-#endif
-#ifndef S_IWOTH
-#define S_IWOTH S_IWUSR
-#endif
-#ifndef S_IXGRP
-#define S_IXGRP S_IXUSR
-#endif
-#ifndef S_IXOTH
-#define S_IXOTH S_IXUSR
-#endif
-#ifndef S_IRWXG
-#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
-#endif
-#ifndef S_ISGID
-#define S_ISGID 0
-#endif
-#endif /* PLATFORM_WIN32 */
-
-/* file permissions for newly written files */
-#define MODE_R_ALL             (S_IRUSR | S_IRGRP | S_IROTH)
-#define MODE_W_ALL             (S_IWUSR | S_IWGRP | S_IWOTH)
-#define MODE_X_ALL             (S_IXUSR | S_IXGRP | S_IXOTH)
-
-#define MODE_W_PRIVATE         (S_IWUSR)
-#define MODE_W_PUBLIC          (S_IWUSR | S_IWGRP)
-#define MODE_W_PUBLIC_DIR      (S_IWUSR | S_IWGRP | S_ISGID)
-
-#define DIR_PERMS_PRIVATE      (MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE)
-#define DIR_PERMS_PUBLIC       (MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR)
-
-#define FILE_PERMS_PRIVATE     (MODE_R_ALL | MODE_W_PRIVATE)
-#define FILE_PERMS_PUBLIC      (MODE_R_ALL | MODE_W_PUBLIC)
-
-char *getUserDataDir(void)
-{
-  static char *userdata_dir = NULL;
-
-  if (!userdata_dir)
-  {
-    char *home_dir = getHomeDir();
-    char *data_dir = program.userdata_directory;
-
-    userdata_dir = getPath2(home_dir, data_dir);
-  }
-
-  return userdata_dir;
-}
-
-char *getSetupDir()
-{
-  return getUserDataDir();
-}
-
-static mode_t posix_umask(mode_t mask)
-{
-#if defined(PLATFORM_UNIX)
-  return umask(mask);
-#else
-  return 0;
-#endif
-}
-
-static int posix_mkdir(const char *pathname, mode_t mode)
-{
-#if defined(PLATFORM_WIN32)
-  return mkdir(pathname);
-#else
-  return mkdir(pathname, mode);
-#endif
-}
-
-void createDirectory(char *dir, char *text, int permission_class)
-{
-  /* leave "other" permissions in umask untouched, but ensure group parts
-     of USERDATA_DIR_MODE are not masked */
-  mode_t dir_mode = (permission_class == PERMS_PRIVATE ?
-                    DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC);
-  mode_t normal_umask = posix_umask(0);
-  mode_t group_umask = ~(dir_mode & S_IRWXG);
-  posix_umask(normal_umask & group_umask);
-
-  if (access(dir, F_OK) != 0)
-    if (posix_mkdir(dir, dir_mode) != 0)
-      Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
-
-  posix_umask(normal_umask);           /* reset normal umask */
-}
-
-void InitUserDataDirectory()
-{
-  createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
-}
-
-void SetFilePermissions(char *filename, int permission_class)
-{
-  chmod(filename, (permission_class == PERMS_PRIVATE ?
-                  FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC));
-}
-
-int getFileVersionFromCookieString(const char *cookie)
-{
-  const char *ptr_cookie1, *ptr_cookie2;
-  const char *pattern1 = "_FILE_VERSION_";
-  const char *pattern2 = "?.?";
-  const int len_cookie = strlen(cookie);
-  const int len_pattern1 = strlen(pattern1);
-  const int len_pattern2 = strlen(pattern2);
-  const int len_pattern = len_pattern1 + len_pattern2;
-  int version_major, version_minor;
-
-  if (len_cookie <= len_pattern)
-    return -1;
-
-  ptr_cookie1 = &cookie[len_cookie - len_pattern];
-  ptr_cookie2 = &cookie[len_cookie - len_pattern2];
-
-  if (strncmp(ptr_cookie1, pattern1, len_pattern1) != 0)
-    return -1;
-
-  if (ptr_cookie2[0] < '0' || ptr_cookie2[0] > '9' ||
-      ptr_cookie2[1] != '.' ||
-      ptr_cookie2[2] < '0' || ptr_cookie2[2] > '9')
-    return -1;
-
-  version_major = ptr_cookie2[0] - '0';
-  version_minor = ptr_cookie2[2] - '0';
-
-  return VERSION_IDENT(version_major, version_minor, 0);
-}
-
-boolean checkCookieString(const char *cookie, const char *template)
-{
-  const char *pattern = "_FILE_VERSION_?.?";
-  const int len_cookie = strlen(cookie);
-  const int len_template = strlen(template);
-  const int len_pattern = strlen(pattern);
-
-  if (len_cookie != len_template)
-    return FALSE;
-
-  if (strncmp(cookie, template, len_cookie - len_pattern) != 0)
-    return FALSE;
-
-  return TRUE;
-}
-
-/* ------------------------------------------------------------------------- */
-/* setup file stuff                                                          */
-/* ------------------------------------------------------------------------- */
-
-static char *string_tolower(char *s)
-{
-  static char s_lower[100];
-  int i;
-
-  if (strlen(s) >= 100)
-    return s;
-
-  strcpy(s_lower, s);
-
-  for (i=0; i<strlen(s_lower); i++)
-    s_lower[i] = tolower(s_lower[i]);
-
-  return s_lower;
-}
-
-int get_string_integer_value(char *s)
-{
-  static char *number_text[][3] =
-  {
-    { "0", "zero", "null", },
-    { "1", "one", "first" },
-    { "2", "two", "second" },
-    { "3", "three", "third" },
-    { "4", "four", "fourth" },
-    { "5", "five", "fifth" },
-    { "6", "six", "sixth" },
-    { "7", "seven", "seventh" },
-    { "8", "eight", "eighth" },
-    { "9", "nine", "ninth" },
-    { "10", "ten", "tenth" },
-    { "11", "eleven", "eleventh" },
-    { "12", "twelve", "twelfth" },
-  };
-
-  int i, j;
-
-  for (i=0; i<13; i++)
-    for (j=0; j<3; j++)
-      if (strcmp(string_tolower(s), number_text[i][j]) == 0)
-       return i;
-
-  return atoi(s);
-}
-
-boolean get_string_boolean_value(char *s)
-{
-  if (strcmp(string_tolower(s), "true") == 0 ||
-      strcmp(string_tolower(s), "yes") == 0 ||
-      strcmp(string_tolower(s), "on") == 0 ||
-      get_string_integer_value(s) == 1)
-    return TRUE;
-  else
-    return FALSE;
-}
-
-char *getFormattedSetupEntry(char *token, char *value)
-{
-  int i;
-  static char entry[MAX_LINE_LEN];
-
-  sprintf(entry, "%s:", token);
-  for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
-    entry[i] = ' ';
-  entry[i] = '\0';
-
-  strcat(entry, value);
-
-  return entry;
-}
-
-void freeSetupFileList(struct SetupFileList *setup_file_list)
-{
-  if (!setup_file_list)
-    return;
-
-  if (setup_file_list->token)
-    free(setup_file_list->token);
-  if (setup_file_list->value)
-    free(setup_file_list->value);
-  if (setup_file_list->next)
-    freeSetupFileList(setup_file_list->next);
-  free(setup_file_list);
-}
-
-static struct SetupFileList *newSetupFileList(char *token, char *value)
-{
-  struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
-
-  new->token = checked_malloc(strlen(token) + 1);
-  strcpy(new->token, token);
-
-  new->value = checked_malloc(strlen(value) + 1);
-  strcpy(new->value, value);
-
-  new->next = NULL;
-
-  return new;
-}
-
-char *getTokenValue(struct SetupFileList *setup_file_list, char *token)
-{
-  if (!setup_file_list)
-    return NULL;
-
-  if (strcmp(setup_file_list->token, token) == 0)
-    return setup_file_list->value;
-  else
-    return getTokenValue(setup_file_list->next, token);
-}
-
-static void setTokenValue(struct SetupFileList *setup_file_list,
-                         char *token, char *value)
-{
-  if (!setup_file_list)
-    return;
-
-  if (strcmp(setup_file_list->token, token) == 0)
-  {
-    free(setup_file_list->value);
-    setup_file_list->value = checked_malloc(strlen(value) + 1);
-    strcpy(setup_file_list->value, value);
-  }
-  else if (setup_file_list->next == NULL)
-    setup_file_list->next = newSetupFileList(token, value);
-  else
-    setTokenValue(setup_file_list->next, token, value);
-}
-
-#ifdef DEBUG
-static void printSetupFileList(struct SetupFileList *setup_file_list)
-{
-  if (!setup_file_list)
-    return;
-
-  printf("token: '%s'\n", setup_file_list->token);
-  printf("value: '%s'\n", setup_file_list->value);
-
-  printSetupFileList(setup_file_list->next);
-}
-#endif
-
-struct SetupFileList *loadSetupFileList(char *filename)
-{
-  int line_len;
-  char line[MAX_LINE_LEN];
-  char *token, *value, *line_ptr;
-  struct SetupFileList *setup_file_list = newSetupFileList("", "");
-  struct SetupFileList *first_valid_list_entry;
-
-  FILE *file;
-
-  if (!(file = fopen(filename, MODE_READ)))
-  {
-    Error(ERR_WARN, "cannot open configuration file '%s'", filename);
-    return NULL;
-  }
-
-  while(!feof(file))
-  {
-    /* read next line of input file */
-    if (!fgets(line, MAX_LINE_LEN, file))
-      break;
-
-    /* cut trailing comment or whitespace from input line */
-    for (line_ptr = line; *line_ptr; line_ptr++)
-    {
-      if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r')
-      {
-       *line_ptr = '\0';
-       break;
-      }
-    }
-
-    /* cut trailing whitespaces from input line */
-    for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--)
-      if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0')
-       *line_ptr = '\0';
-
-    /* ignore empty lines */
-    if (*line == '\0')
-      continue;
-
-    line_len = strlen(line);
-
-    /* cut leading whitespaces from token */
-    for (token = line; *token; token++)
-      if (*token != ' ' && *token != '\t')
-       break;
-
-    /* find end of token */
-    for (line_ptr = token; *line_ptr; line_ptr++)
-    {
-      if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
-      {
-       *line_ptr = '\0';
-       break;
-      }
-    }
-
-    if (line_ptr < line + line_len)
-      value = line_ptr + 1;
-    else
-      value = "\0";
-
-    /* cut leading whitespaces from value */
-    for (; *value; value++)
-      if (*value != ' ' && *value != '\t')
-       break;
-
-    if (*token && *value)
-      setTokenValue(setup_file_list, token, value);
-  }
-
-  fclose(file);
-
-  first_valid_list_entry = setup_file_list->next;
-
-  /* free empty list header */
-  setup_file_list->next = NULL;
-  freeSetupFileList(setup_file_list);
-
-  if (first_valid_list_entry == NULL)
-    Error(ERR_WARN, "configuration file '%s' is empty", filename);
-
-  return first_valid_list_entry;
-}
-
-void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
-                                 char *identifier)
-{
-  if (!setup_file_list)
-    return;
-
-  if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
-  {
-    if (strcmp(setup_file_list->value, identifier) != 0)
-    {
-      Error(ERR_WARN, "configuration file has wrong version");
-      return;
-    }
-    else
-      return;
-  }
-
-  if (setup_file_list->next)
-    checkSetupFileListIdentifier(setup_file_list->next, identifier);
-  else
-  {
-    Error(ERR_WARN, "configuration file has no version information");
-    return;
-  }
-}
-
 
 /* ========================================================================= */
 /* functions only needed for non-Unix (non-command-line) systems */
index 6213ae1becb60e190251707fabe826ba1c3d5bdd..d90727d9416cd6c396a8c7ac91980513e915e4e2 100644 (file)
 #define MAX_FILENAME_LEN               256
 #define MAX_LINE_LEN                   1000
 
-/* values for setup file stuff */
-#define TYPE_BOOLEAN                   1
-#define TYPE_SWITCH                    2
-#define TYPE_KEY                       3
-#define TYPE_INTEGER                   4
-#define TYPE_STRING                    5
-
-#define TOKEN_STR_FILE_IDENTIFIER      "file_identifier"
-
-#define TOKEN_VALUE_POSITION           30
-
-struct SetupFileList
-{
-  char *token;
-  char *value;
-  struct SetupFileList *next;
-};
-
-struct TokenInfo
-{
-  int type;
-  void *value;
-  char *text;
-};
-
 void InitCounter(void);
 unsigned long Counter(void);
 void Delay(unsigned long);
@@ -106,6 +81,9 @@ void Error(int, char *, ...);
 void *checked_malloc(unsigned long);
 void *checked_calloc(unsigned long);
 void *checked_realloc(void *, unsigned long);
+inline void swap_numbers(int *, int *);
+inline void swap_number_pairs(int *, int *, int *, int *);
+
 short getFile16BitInteger(FILE *, int);
 void putFile16BitInteger(FILE *, short, int);
 int getFile32BitInteger(FILE *, int);
@@ -119,42 +97,6 @@ char *getKeyNameFromKey(Key);
 char *getX11KeyNameFromKey(Key);
 Key getKeyFromX11KeyName(char *);
 char getCharFromKey(Key);
-char *getJoyNameFromJoySymbol(int);
-int getJoySymbolFromJoyName(char *);
-int getJoystickNrFromDeviceName(char *);
-
-struct LevelDirInfo *newLevelDirInfo();
-void pushLevelDirInfo(struct LevelDirInfo **, struct LevelDirInfo *);
-int numLevelDirInfo(struct LevelDirInfo *);
-boolean validLevelSeries(struct LevelDirInfo *);
-struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *);
-struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *);
-int numLevelDirInfoInGroup(struct LevelDirInfo *);
-int posLevelDirInfo(struct LevelDirInfo *);
-struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *, int);
-struct LevelDirInfo *getLevelDirInfoFromFilename(char *);
-void dumpLevelDirInfo(struct LevelDirInfo *, int);
-void sortLevelDirInfo(struct LevelDirInfo **,
-                     int (*compare_function)(const void *, const void *));
-
-inline void swap_numbers(int *, int *);
-inline void swap_number_pairs(int *, int *, int *, int *);
-
-char *getUserDataDir(void);
-char *getSetupDir(void);
-void createDirectory(char *, char *, int);
-void InitUserDataDirectory(void);
-void SetFilePermissions(char *, int);
-int getFileVersionFromCookieString(const char *);
-boolean checkCookieString(const char *, const char *);
-
-int get_string_integer_value(char *);
-boolean get_string_boolean_value(char *);
-char *getFormattedSetupEntry(char *, char *);
-void freeSetupFileList(struct SetupFileList *);
-char *getTokenValue(struct SetupFileList *, char *);
-struct SetupFileList *loadSetupFileList(char *);
-void checkSetupFileListIdentifier(struct SetupFileList *, char *);
 
 #if !defined(PLATFORM_UNIX)
 void initErrorFile();
diff --git a/src/libgame/setup.c b/src/libgame/setup.c
new file mode 100644 (file)
index 0000000..d0f2bc0
--- /dev/null
@@ -0,0 +1,1848 @@
+/***********************************************************
+* Artsoft Retro-Game Library                               *
+*----------------------------------------------------------*
+* (c) 1994-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* setup.c                                                  *
+***********************************************************/
+
+#include <dirent.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "setup.h"
+#include "joystick.h"
+#include "text.h"
+#include "misc.h"
+
+
+/* file identifier strings */
+#define SETUP_COOKIE           "ROCKSNDIAMONDS_SETUP_FILE_VERSION_1.2"
+#define LEVELSETUP_COOKIE      "ROCKSNDIAMONDS_LEVELSETUP_FILE_VERSION_1.2"
+#define LEVELINFO_COOKIE       "ROCKSNDIAMONDS_LEVELINFO_FILE_VERSION_1.2"
+
+/* file names and filename extensions */
+#if !defined(PLATFORM_MSDOS)
+#define LEVELSETUP_DIRECTORY   "levelsetup"
+#define SETUP_FILENAME         "setup.conf"
+#define LEVELSETUP_FILENAME    "levelsetup.conf"
+#define LEVELINFO_FILENAME     "levelinfo.conf"
+#define LEVELFILE_EXTENSION    "level"
+#define TAPEFILE_EXTENSION     "tape"
+#define SCOREFILE_EXTENSION    "score"
+#else
+#define LEVELSETUP_DIRECTORY   "lvlsetup"
+#define SETUP_FILENAME         "setup.cnf"
+#define LEVELSETUP_FILENAME    "lvlsetup.cnf"
+#define LEVELINFO_FILENAME     "lvlinfo.cnf"
+#define LEVELFILE_EXTENSION    "lvl"
+#define TAPEFILE_EXTENSION     "tap"
+#define SCOREFILE_EXTENSION    "sco"
+#endif
+
+#define NUM_LEVELCLASS_DESC    8
+static char *levelclass_desc[NUM_LEVELCLASS_DESC] =
+{
+  "Tutorial Levels",
+  "Classic Originals",
+  "Contributions",
+  "Private Levels",
+  "Boulderdash",
+  "Emerald Mine",
+  "Supaplex",
+  "DX Boulderdash"
+};
+
+#define LEVELCOLOR(n)  (IS_LEVELCLASS_TUTORIAL(n) ?            FC_BLUE : \
+                        IS_LEVELCLASS_CLASSICS(n) ?            FC_RED : \
+                        IS_LEVELCLASS_BD(n) ?                  FC_GREEN : \
+                        IS_LEVELCLASS_EM(n) ?                  FC_YELLOW : \
+                        IS_LEVELCLASS_SP(n) ?                  FC_GREEN : \
+                        IS_LEVELCLASS_DX(n) ?                  FC_YELLOW : \
+                        IS_LEVELCLASS_CONTRIBUTION(n) ?        FC_GREEN : \
+                        IS_LEVELCLASS_USER(n) ?                FC_RED : \
+                        FC_BLUE)
+
+#define LEVELSORTING(n)        (IS_LEVELCLASS_TUTORIAL(n) ?            0 : \
+                        IS_LEVELCLASS_CLASSICS(n) ?            1 : \
+                        IS_LEVELCLASS_BD(n) ?                  2 : \
+                        IS_LEVELCLASS_EM(n) ?                  3 : \
+                        IS_LEVELCLASS_SP(n) ?                  4 : \
+                        IS_LEVELCLASS_DX(n) ?                  5 : \
+                        IS_LEVELCLASS_CONTRIBUTION(n) ?        6 : \
+                        IS_LEVELCLASS_USER(n) ?                7 : \
+                        9)
+
+/* values for setup file stuff */
+#define TYPE_BOOLEAN                   1
+#define TYPE_SWITCH                    2
+#define TYPE_KEY                       3
+#define TYPE_INTEGER                   4
+#define TYPE_STRING                    5
+
+#define TOKEN_STR_FILE_IDENTIFIER      "file_identifier"
+
+#define TOKEN_VALUE_POSITION           30
+
+struct SetupFileList
+{
+  char *token;
+  char *value;
+  struct SetupFileList *next;
+};
+
+struct TokenInfo
+{
+  int type;
+  void *value;
+  char *text;
+};
+
+
+/* ------------------------------------------------------------------------- */
+/* file functions                                                            */
+/* ------------------------------------------------------------------------- */
+
+/*
+int get_string_integer_value(char *);
+boolean get_string_boolean_value(char *);
+char *getFormattedSetupEntry(char *, char *);
+void freeSetupFileList(struct SetupFileList *);
+char *getTokenValue(struct SetupFileList *, char *);
+struct SetupFileList *loadSetupFileList(char *);
+void checkSetupFileListIdentifier(struct SetupFileList *, char *);
+*/
+
+char *getLevelClassDescription(struct LevelDirInfo *ldi)
+{
+  int position = ldi->sort_priority / 100;
+
+  if (position >= 0 && position < NUM_LEVELCLASS_DESC)
+    return levelclass_desc[position];
+  else
+    return "Unknown Level Class";
+}
+
+/* for 'InitUserLevelDir()' */
+static void SaveUserLevelInfo();
+
+/* for 'SaveUserLevelInfo()' */
+static char *getSetupLine(struct TokenInfo *, char *, int);
+
+static char *getUserLevelDir(char *level_subdir)
+{
+  static char *userlevel_dir = NULL;
+  char *data_dir = getUserDataDir();
+  char *userlevel_subdir = LEVELS_DIRECTORY;
+
+  if (userlevel_dir)
+    free(userlevel_dir);
+
+  if (strlen(level_subdir) > 0)
+    userlevel_dir = getPath3(data_dir, userlevel_subdir, level_subdir);
+  else
+    userlevel_dir = getPath2(data_dir, userlevel_subdir);
+
+  return userlevel_dir;
+}
+
+static char *getTapeDir(char *level_subdir)
+{
+  static char *tape_dir = NULL;
+  char *data_dir = getUserDataDir();
+  char *tape_subdir = TAPES_DIRECTORY;
+
+  if (tape_dir)
+    free(tape_dir);
+
+  if (strlen(level_subdir) > 0)
+    tape_dir = getPath3(data_dir, tape_subdir, level_subdir);
+  else
+    tape_dir = getPath2(data_dir, tape_subdir);
+
+  return tape_dir;
+}
+
+static char *getScoreDir(char *level_subdir)
+{
+  static char *score_dir = NULL;
+  char *data_dir = options.rw_base_directory;
+  char *score_subdir = SCORES_DIRECTORY;
+
+  if (score_dir)
+    free(score_dir);
+
+  if (strlen(level_subdir) > 0)
+    score_dir = getPath3(data_dir, score_subdir, level_subdir);
+  else
+    score_dir = getPath2(data_dir, score_subdir);
+
+  return score_dir;
+}
+
+static char *getLevelSetupDir(char *level_subdir)
+{
+  static char *levelsetup_dir = NULL;
+  char *data_dir = getUserDataDir();
+  char *levelsetup_subdir = LEVELSETUP_DIRECTORY;
+
+  if (levelsetup_dir)
+    free(levelsetup_dir);
+
+  if (strlen(level_subdir) > 0)
+    levelsetup_dir = getPath3(data_dir, levelsetup_subdir, level_subdir);
+  else
+    levelsetup_dir = getPath2(data_dir, levelsetup_subdir);
+
+  return levelsetup_dir;
+}
+
+char *getLevelFilename(int nr)
+{
+  static char *filename = NULL;
+  char basename[MAX_FILENAME_LEN];
+
+  if (filename != NULL)
+    free(filename);
+
+  sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+  filename = getPath3((leveldir_current->user_defined ?
+                      getUserLevelDir("") :
+                      options.level_directory),
+                     leveldir_current->fullpath,
+                     basename);
+
+  return filename;
+}
+
+char *getTapeFilename(int nr)
+{
+  static char *filename = NULL;
+  char basename[MAX_FILENAME_LEN];
+
+  if (filename != NULL)
+    free(filename);
+
+  sprintf(basename, "%03d.%s", nr, TAPEFILE_EXTENSION);
+  filename = getPath2(getTapeDir(leveldir_current->filename), basename);
+
+  return filename;
+}
+
+char *getScoreFilename(int nr)
+{
+  static char *filename = NULL;
+  char basename[MAX_FILENAME_LEN];
+
+  if (filename != NULL)
+    free(filename);
+
+  sprintf(basename, "%03d.%s", nr, SCOREFILE_EXTENSION);
+  filename = getPath2(getScoreDir(leveldir_current->filename), basename);
+
+  return filename;
+}
+
+void InitTapeDirectory(char *level_subdir)
+{
+  createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
+  createDirectory(getTapeDir(""), "main tape", PERMS_PRIVATE);
+  createDirectory(getTapeDir(level_subdir), "level tape", PERMS_PRIVATE);
+}
+
+void InitScoreDirectory(char *level_subdir)
+{
+  createDirectory(getScoreDir(""), "main score", PERMS_PUBLIC);
+  createDirectory(getScoreDir(level_subdir), "level score", PERMS_PUBLIC);
+}
+
+void InitUserLevelDirectory(char *level_subdir)
+{
+  if (access(getUserLevelDir(level_subdir), F_OK) != 0)
+  {
+    createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
+    createDirectory(getUserLevelDir(""), "main user level", PERMS_PRIVATE);
+    createDirectory(getUserLevelDir(level_subdir), "user level",PERMS_PRIVATE);
+
+    SaveUserLevelInfo();
+  }
+}
+
+void InitLevelSetupDirectory(char *level_subdir)
+{
+  createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
+  createDirectory(getLevelSetupDir(""), "main level setup", PERMS_PRIVATE);
+  createDirectory(getLevelSetupDir(level_subdir), "level setup",PERMS_PRIVATE);
+}
+
+void ReadChunk_VERS(FILE *file, int *file_version, int *game_version)
+{
+  int file_version_major, file_version_minor, file_version_patch;
+  int game_version_major, game_version_minor, game_version_patch;
+
+  file_version_major = fgetc(file);
+  file_version_minor = fgetc(file);
+  file_version_patch = fgetc(file);
+  fgetc(file);         /* not used */
+
+  game_version_major = fgetc(file);
+  game_version_minor = fgetc(file);
+  game_version_patch = fgetc(file);
+  fgetc(file);         /* not used */
+
+  *file_version = VERSION_IDENT(file_version_major,
+                               file_version_minor,
+                               file_version_patch);
+
+  *game_version = VERSION_IDENT(game_version_major,
+                               game_version_minor,
+                               game_version_patch);
+}
+
+void WriteChunk_VERS(FILE *file, int file_version, int game_version)
+{
+  int file_version_major = VERSION_MAJOR(file_version);
+  int file_version_minor = VERSION_MINOR(file_version);
+  int file_version_patch = VERSION_PATCH(file_version);
+  int game_version_major = VERSION_MAJOR(game_version);
+  int game_version_minor = VERSION_MINOR(game_version);
+  int game_version_patch = VERSION_PATCH(game_version);
+
+  fputc(file_version_major, file);
+  fputc(file_version_minor, file);
+  fputc(file_version_patch, file);
+  fputc(0, file);      /* not used */
+
+  fputc(game_version_major, file);
+  fputc(game_version_minor, file);
+  fputc(game_version_patch, file);
+  fputc(0, file);      /* not used */
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* some functions to handle lists of level directories                       */
+/* ------------------------------------------------------------------------- */
+
+struct LevelDirInfo *newLevelDirInfo()
+{
+  return checked_calloc(sizeof(struct LevelDirInfo));
+}
+
+void pushLevelDirInfo(struct LevelDirInfo **node_first,
+                     struct LevelDirInfo *node_new)
+{
+  node_new->next = *node_first;
+  *node_first = node_new;
+}
+
+int numLevelDirInfo(struct LevelDirInfo *node)
+{
+  int num = 0;
+
+  while (node)
+  {
+    num++;
+    node = node->next;
+  }
+
+  return num;
+}
+
+boolean validLevelSeries(struct LevelDirInfo *node)
+{
+  return (node != NULL && !node->node_group && !node->parent_link);
+}
+
+struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *node)
+{
+  if (node == NULL)
+  {
+    if (leveldir_first)                /* start with first level directory entry */
+      return getFirstValidLevelSeries(leveldir_first);
+    else
+      return NULL;
+  }
+  else if (node->node_group)   /* enter level group (step down into tree) */
+    return getFirstValidLevelSeries(node->node_group);
+  else if (node->parent_link)  /* skip start entry of level group */
+  {
+    if (node->next)            /* get first real level series entry */
+      return getFirstValidLevelSeries(node->next);
+    else                       /* leave empty level group and go on */
+      return getFirstValidLevelSeries(node->node_parent->next);
+  }
+  else                         /* this seems to be a regular level series */
+    return node;
+}
+
+struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *node)
+{
+  if (node == NULL)
+    return NULL;
+
+  if (node->node_parent == NULL)               /* top level group */
+    return leveldir_first;
+  else                                         /* sub level group */
+    return node->node_parent->node_group;
+}
+
+int numLevelDirInfoInGroup(struct LevelDirInfo *node)
+{
+  return numLevelDirInfo(getLevelDirInfoFirstGroupEntry(node));
+}
+
+int posLevelDirInfo(struct LevelDirInfo *node)
+{
+  struct LevelDirInfo *node_cmp = getLevelDirInfoFirstGroupEntry(node);
+  int pos = 0;
+
+  while (node_cmp)
+  {
+    if (node_cmp == node)
+      return pos;
+
+    pos++;
+    node_cmp = node_cmp->next;
+  }
+
+  return 0;
+}
+
+struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *node, int pos)
+{
+  struct LevelDirInfo *node_default = node;
+  int pos_cmp = 0;
+
+  while (node)
+  {
+    if (pos_cmp == pos)
+      return node;
+
+    pos_cmp++;
+    node = node->next;
+  }
+
+  return node_default;
+}
+
+struct LevelDirInfo *getLevelDirInfoFromFilenameExt(struct LevelDirInfo *node,
+                                                   char *filename)
+{
+  if (filename == NULL)
+    return NULL;
+
+  while (node)
+  {
+    if (node->node_group)
+    {
+      struct LevelDirInfo *node_group;
+
+      node_group = getLevelDirInfoFromFilenameExt(node->node_group, filename);
+
+      if (node_group)
+       return node_group;
+    }
+    else if (!node->parent_link)
+    {
+      if (strcmp(filename, node->filename) == 0)
+       return node;
+    }
+
+    node = node->next;
+  }
+
+  return NULL;
+}
+
+struct LevelDirInfo *getLevelDirInfoFromFilename(char *filename)
+{
+  return getLevelDirInfoFromFilenameExt(leveldir_first, filename);
+}
+
+void dumpLevelDirInfo(struct LevelDirInfo *node, int depth)
+{
+  int i;
+
+  while (node)
+  {
+    for (i=0; i<depth * 3; i++)
+      printf(" ");
+
+    printf("filename == '%s'\n", node->filename);
+
+    if (node->node_group != NULL)
+      dumpLevelDirInfo(node->node_group, depth + 1);
+
+    node = node->next;
+  }
+}
+
+void sortLevelDirInfo(struct LevelDirInfo **node_first,
+                     int (*compare_function)(const void *, const void *))
+{
+  int num_nodes = numLevelDirInfo(*node_first);
+  struct LevelDirInfo **sort_array;
+  struct LevelDirInfo *node = *node_first;
+  int i = 0;
+
+  if (num_nodes == 0)
+    return;
+
+  /* allocate array for sorting structure pointers */
+  sort_array = checked_calloc(num_nodes * sizeof(struct LevelDirInfo *));
+
+  /* writing structure pointers to sorting array */
+  while (i < num_nodes && node)                /* double boundary check... */
+  {
+    sort_array[i] = node;
+
+    i++;
+    node = node->next;
+  }
+
+  /* sorting the structure pointers in the sorting array */
+  qsort(sort_array, num_nodes, sizeof(struct LevelDirInfo *),
+       compare_function);
+
+  /* update the linkage of list elements with the sorted node array */
+  for (i=0; i<num_nodes - 1; i++)
+    sort_array[i]->next = sort_array[i + 1];
+  sort_array[num_nodes - 1]->next = NULL;
+
+  /* update the linkage of the main list anchor pointer */
+  *node_first = sort_array[0];
+
+  free(sort_array);
+
+  /* now recursively sort the level group structures */
+  node = *node_first;
+  while (node)
+  {
+    if (node->node_group != NULL)
+      sortLevelDirInfo(&node->node_group, compare_function);
+
+    node = node->next;
+  }
+}
+
+
+/* ========================================================================= */
+/* some stuff from "files.c"                                                 */
+/* ========================================================================= */
+
+#if defined(PLATFORM_WIN32)
+#ifndef S_IRGRP
+#define S_IRGRP S_IRUSR
+#endif
+#ifndef S_IROTH
+#define S_IROTH S_IRUSR
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP S_IWUSR
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH S_IWUSR
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP S_IXUSR
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH S_IXUSR
+#endif
+#ifndef S_IRWXG
+#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+#endif
+#ifndef S_ISGID
+#define S_ISGID 0
+#endif
+#endif /* PLATFORM_WIN32 */
+
+/* file permissions for newly written files */
+#define MODE_R_ALL             (S_IRUSR | S_IRGRP | S_IROTH)
+#define MODE_W_ALL             (S_IWUSR | S_IWGRP | S_IWOTH)
+#define MODE_X_ALL             (S_IXUSR | S_IXGRP | S_IXOTH)
+
+#define MODE_W_PRIVATE         (S_IWUSR)
+#define MODE_W_PUBLIC          (S_IWUSR | S_IWGRP)
+#define MODE_W_PUBLIC_DIR      (S_IWUSR | S_IWGRP | S_ISGID)
+
+#define DIR_PERMS_PRIVATE      (MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE)
+#define DIR_PERMS_PUBLIC       (MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR)
+
+#define FILE_PERMS_PRIVATE     (MODE_R_ALL | MODE_W_PRIVATE)
+#define FILE_PERMS_PUBLIC      (MODE_R_ALL | MODE_W_PUBLIC)
+
+char *getUserDataDir(void)
+{
+  static char *userdata_dir = NULL;
+
+  if (!userdata_dir)
+  {
+    char *home_dir = getHomeDir();
+    char *data_dir = program.userdata_directory;
+
+    userdata_dir = getPath2(home_dir, data_dir);
+  }
+
+  return userdata_dir;
+}
+
+char *getSetupDir()
+{
+  return getUserDataDir();
+}
+
+static mode_t posix_umask(mode_t mask)
+{
+#if defined(PLATFORM_UNIX)
+  return umask(mask);
+#else
+  return 0;
+#endif
+}
+
+static int posix_mkdir(const char *pathname, mode_t mode)
+{
+#if defined(PLATFORM_WIN32)
+  return mkdir(pathname);
+#else
+  return mkdir(pathname, mode);
+#endif
+}
+
+void createDirectory(char *dir, char *text, int permission_class)
+{
+  /* leave "other" permissions in umask untouched, but ensure group parts
+     of USERDATA_DIR_MODE are not masked */
+  mode_t dir_mode = (permission_class == PERMS_PRIVATE ?
+                    DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC);
+  mode_t normal_umask = posix_umask(0);
+  mode_t group_umask = ~(dir_mode & S_IRWXG);
+  posix_umask(normal_umask & group_umask);
+
+  if (access(dir, F_OK) != 0)
+    if (posix_mkdir(dir, dir_mode) != 0)
+      Error(ERR_WARN, "cannot create %s directory '%s'", text, dir);
+
+  posix_umask(normal_umask);           /* reset normal umask */
+}
+
+void InitUserDataDirectory()
+{
+  createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE);
+}
+
+void SetFilePermissions(char *filename, int permission_class)
+{
+  chmod(filename, (permission_class == PERMS_PRIVATE ?
+                  FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC));
+}
+
+int getFileVersionFromCookieString(const char *cookie)
+{
+  const char *ptr_cookie1, *ptr_cookie2;
+  const char *pattern1 = "_FILE_VERSION_";
+  const char *pattern2 = "?.?";
+  const int len_cookie = strlen(cookie);
+  const int len_pattern1 = strlen(pattern1);
+  const int len_pattern2 = strlen(pattern2);
+  const int len_pattern = len_pattern1 + len_pattern2;
+  int version_major, version_minor;
+
+  if (len_cookie <= len_pattern)
+    return -1;
+
+  ptr_cookie1 = &cookie[len_cookie - len_pattern];
+  ptr_cookie2 = &cookie[len_cookie - len_pattern2];
+
+  if (strncmp(ptr_cookie1, pattern1, len_pattern1) != 0)
+    return -1;
+
+  if (ptr_cookie2[0] < '0' || ptr_cookie2[0] > '9' ||
+      ptr_cookie2[1] != '.' ||
+      ptr_cookie2[2] < '0' || ptr_cookie2[2] > '9')
+    return -1;
+
+  version_major = ptr_cookie2[0] - '0';
+  version_minor = ptr_cookie2[2] - '0';
+
+  return VERSION_IDENT(version_major, version_minor, 0);
+}
+
+boolean checkCookieString(const char *cookie, const char *template)
+{
+  const char *pattern = "_FILE_VERSION_?.?";
+  const int len_cookie = strlen(cookie);
+  const int len_template = strlen(template);
+  const int len_pattern = strlen(pattern);
+
+  if (len_cookie != len_template)
+    return FALSE;
+
+  if (strncmp(cookie, template, len_cookie - len_pattern) != 0)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* ------------------------------------------------------------------------- */
+/* setup file list handling functions                                        */
+/* ------------------------------------------------------------------------- */
+
+int get_string_integer_value(char *s)
+{
+  static char *number_text[][3] =
+  {
+    { "0", "zero", "null", },
+    { "1", "one", "first" },
+    { "2", "two", "second" },
+    { "3", "three", "third" },
+    { "4", "four", "fourth" },
+    { "5", "five", "fifth" },
+    { "6", "six", "sixth" },
+    { "7", "seven", "seventh" },
+    { "8", "eight", "eighth" },
+    { "9", "nine", "ninth" },
+    { "10", "ten", "tenth" },
+    { "11", "eleven", "eleventh" },
+    { "12", "twelve", "twelfth" },
+  };
+
+  int i, j;
+  char *s_lower = getStringToLower(s);
+  int result = -1;
+
+  for (i=0; i<13; i++)
+    for (j=0; j<3; j++)
+      if (strcmp(s_lower, number_text[i][j]) == 0)
+       result = i;
+
+  if (result == -1)
+    result = atoi(s);
+
+  free(s_lower);
+
+  return result;
+}
+
+boolean get_string_boolean_value(char *s)
+{
+  char *s_lower = getStringToLower(s);
+  boolean result = FALSE;
+
+  if (strcmp(s_lower, "true") == 0 ||
+      strcmp(s_lower, "yes") == 0 ||
+      strcmp(s_lower, "on") == 0 ||
+      get_string_integer_value(s) == 1)
+    result = TRUE;
+
+  free(s_lower);
+
+  return result;
+}
+
+char *getFormattedSetupEntry(char *token, char *value)
+{
+  int i;
+  static char entry[MAX_LINE_LEN];
+
+  sprintf(entry, "%s:", token);
+  for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
+    entry[i] = ' ';
+  entry[i] = '\0';
+
+  strcat(entry, value);
+
+  return entry;
+}
+
+void freeSetupFileList(struct SetupFileList *setup_file_list)
+{
+  if (!setup_file_list)
+    return;
+
+  if (setup_file_list->token)
+    free(setup_file_list->token);
+  if (setup_file_list->value)
+    free(setup_file_list->value);
+  if (setup_file_list->next)
+    freeSetupFileList(setup_file_list->next);
+  free(setup_file_list);
+}
+
+static struct SetupFileList *newSetupFileList(char *token, char *value)
+{
+  struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList));
+
+  new->token = checked_malloc(strlen(token) + 1);
+  strcpy(new->token, token);
+
+  new->value = checked_malloc(strlen(value) + 1);
+  strcpy(new->value, value);
+
+  new->next = NULL;
+
+  return new;
+}
+
+char *getTokenValue(struct SetupFileList *setup_file_list, char *token)
+{
+  if (!setup_file_list)
+    return NULL;
+
+  if (strcmp(setup_file_list->token, token) == 0)
+    return setup_file_list->value;
+  else
+    return getTokenValue(setup_file_list->next, token);
+}
+
+static void setTokenValue(struct SetupFileList *setup_file_list,
+                         char *token, char *value)
+{
+  if (!setup_file_list)
+    return;
+
+  if (strcmp(setup_file_list->token, token) == 0)
+  {
+    free(setup_file_list->value);
+    setup_file_list->value = checked_malloc(strlen(value) + 1);
+    strcpy(setup_file_list->value, value);
+  }
+  else if (setup_file_list->next == NULL)
+    setup_file_list->next = newSetupFileList(token, value);
+  else
+    setTokenValue(setup_file_list->next, token, value);
+}
+
+#ifdef DEBUG
+static void printSetupFileList(struct SetupFileList *setup_file_list)
+{
+  if (!setup_file_list)
+    return;
+
+  printf("token: '%s'\n", setup_file_list->token);
+  printf("value: '%s'\n", setup_file_list->value);
+
+  printSetupFileList(setup_file_list->next);
+}
+#endif
+
+struct SetupFileList *loadSetupFileList(char *filename)
+{
+  int line_len;
+  char line[MAX_LINE_LEN];
+  char *token, *value, *line_ptr;
+  struct SetupFileList *setup_file_list = newSetupFileList("", "");
+  struct SetupFileList *first_valid_list_entry;
+
+  FILE *file;
+
+  if (!(file = fopen(filename, MODE_READ)))
+  {
+    Error(ERR_WARN, "cannot open configuration file '%s'", filename);
+    return NULL;
+  }
+
+  while(!feof(file))
+  {
+    /* read next line of input file */
+    if (!fgets(line, MAX_LINE_LEN, file))
+      break;
+
+    /* cut trailing comment or whitespace from input line */
+    for (line_ptr = line; *line_ptr; line_ptr++)
+    {
+      if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r')
+      {
+       *line_ptr = '\0';
+       break;
+      }
+    }
+
+    /* cut trailing whitespaces from input line */
+    for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--)
+      if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0')
+       *line_ptr = '\0';
+
+    /* ignore empty lines */
+    if (*line == '\0')
+      continue;
+
+    line_len = strlen(line);
+
+    /* cut leading whitespaces from token */
+    for (token = line; *token; token++)
+      if (*token != ' ' && *token != '\t')
+       break;
+
+    /* find end of token */
+    for (line_ptr = token; *line_ptr; line_ptr++)
+    {
+      if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':')
+      {
+       *line_ptr = '\0';
+       break;
+      }
+    }
+
+    if (line_ptr < line + line_len)
+      value = line_ptr + 1;
+    else
+      value = "\0";
+
+    /* cut leading whitespaces from value */
+    for (; *value; value++)
+      if (*value != ' ' && *value != '\t')
+       break;
+
+    if (*token && *value)
+      setTokenValue(setup_file_list, token, value);
+  }
+
+  fclose(file);
+
+  first_valid_list_entry = setup_file_list->next;
+
+  /* free empty list header */
+  setup_file_list->next = NULL;
+  freeSetupFileList(setup_file_list);
+
+  if (first_valid_list_entry == NULL)
+    Error(ERR_WARN, "configuration file '%s' is empty", filename);
+
+  return first_valid_list_entry;
+}
+
+void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list,
+                                 char *identifier)
+{
+  if (!setup_file_list)
+    return;
+
+  if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0)
+  {
+    if (strcmp(setup_file_list->value, identifier) != 0)
+    {
+      Error(ERR_WARN, "configuration file has wrong version");
+      return;
+    }
+    else
+      return;
+  }
+
+  if (setup_file_list->next)
+    checkSetupFileListIdentifier(setup_file_list->next, identifier);
+  else
+  {
+    Error(ERR_WARN, "configuration file has no version information");
+    return;
+  }
+}
+
+
+/* ========================================================================= */
+/* setup file stuff                                                          */
+/* ========================================================================= */
+
+#define TOKEN_STR_LAST_LEVEL_SERIES    "last_level_series"
+#define TOKEN_STR_LAST_PLAYED_LEVEL    "last_played_level"
+#define TOKEN_STR_HANDICAP_LEVEL       "handicap_level"
+#define TOKEN_STR_PLAYER_PREFIX                "player_"
+
+/* global setup */
+#define SETUP_TOKEN_PLAYER_NAME                0
+#define SETUP_TOKEN_SOUND              1
+#define SETUP_TOKEN_SOUND_LOOPS                2
+#define SETUP_TOKEN_SOUND_MUSIC                3
+#define SETUP_TOKEN_SOUND_SIMPLE       4
+#define SETUP_TOKEN_SCROLL_DELAY       5
+#define SETUP_TOKEN_SOFT_SCROLLING     6
+#define SETUP_TOKEN_FADING             7
+#define SETUP_TOKEN_AUTORECORD         8
+#define SETUP_TOKEN_QUICK_DOORS                9
+#define SETUP_TOKEN_TEAM_MODE          10
+#define SETUP_TOKEN_HANDICAP           11
+#define SETUP_TOKEN_TIME_LIMIT         12
+#define SETUP_TOKEN_FULLSCREEN         13
+
+/* player setup */
+#define SETUP_TOKEN_USE_JOYSTICK       0
+#define SETUP_TOKEN_JOY_DEVICE_NAME    1
+#define SETUP_TOKEN_JOY_XLEFT          2
+#define SETUP_TOKEN_JOY_XMIDDLE                3
+#define SETUP_TOKEN_JOY_XRIGHT         4
+#define SETUP_TOKEN_JOY_YUPPER         5
+#define SETUP_TOKEN_JOY_YMIDDLE                6
+#define SETUP_TOKEN_JOY_YLOWER         7
+#define SETUP_TOKEN_JOY_SNAP           8
+#define SETUP_TOKEN_JOY_BOMB           9
+#define SETUP_TOKEN_KEY_LEFT           10
+#define SETUP_TOKEN_KEY_RIGHT          11
+#define SETUP_TOKEN_KEY_UP             12
+#define SETUP_TOKEN_KEY_DOWN           13
+#define SETUP_TOKEN_KEY_SNAP           14
+#define SETUP_TOKEN_KEY_BOMB           15
+
+/* level directory info */
+#define LEVELINFO_TOKEN_NAME           0
+#define LEVELINFO_TOKEN_NAME_SHORT     1
+#define LEVELINFO_TOKEN_NAME_SORTING   2
+#define LEVELINFO_TOKEN_AUTHOR         3
+#define LEVELINFO_TOKEN_IMPORTED_FROM  4
+#define LEVELINFO_TOKEN_LEVELS         5
+#define LEVELINFO_TOKEN_FIRST_LEVEL    6
+#define LEVELINFO_TOKEN_SORT_PRIORITY  7
+#define LEVELINFO_TOKEN_LEVEL_GROUP    8
+#define LEVELINFO_TOKEN_READONLY       9
+
+#define FIRST_GLOBAL_SETUP_TOKEN       SETUP_TOKEN_PLAYER_NAME
+#define LAST_GLOBAL_SETUP_TOKEN                SETUP_TOKEN_FULLSCREEN
+
+#define FIRST_PLAYER_SETUP_TOKEN       SETUP_TOKEN_USE_JOYSTICK
+#define LAST_PLAYER_SETUP_TOKEN                SETUP_TOKEN_KEY_BOMB
+
+#define FIRST_LEVELINFO_TOKEN          LEVELINFO_TOKEN_NAME
+#define LAST_LEVELINFO_TOKEN           LEVELINFO_TOKEN_READONLY
+
+static struct SetupInfo si;
+static struct SetupInputInfo sii;
+static struct LevelDirInfo ldi;
+static struct TokenInfo global_setup_tokens[] =
+{
+  /* global setup */
+  { TYPE_STRING,  &si.player_name,     "player_name"                   },
+  { TYPE_SWITCH,  &si.sound,           "sound"                         },
+  { TYPE_SWITCH,  &si.sound_loops,     "repeating_sound_loops"         },
+  { TYPE_SWITCH,  &si.sound_music,     "background_music"              },
+  { TYPE_SWITCH,  &si.sound_simple,    "simple_sound_effects"          },
+  { TYPE_SWITCH,  &si.scroll_delay,    "scroll_delay"                  },
+  { TYPE_SWITCH,  &si.soft_scrolling,  "soft_scrolling"                },
+  { TYPE_SWITCH,  &si.fading,          "screen_fading"                 },
+  { TYPE_SWITCH,  &si.autorecord,      "automatic_tape_recording"      },
+  { TYPE_SWITCH,  &si.quick_doors,     "quick_doors"                   },
+  { TYPE_SWITCH,  &si.team_mode,       "team_mode"                     },
+  { TYPE_SWITCH,  &si.handicap,                "handicap"                      },
+  { TYPE_SWITCH,  &si.time_limit,      "time_limit"                    },
+  { TYPE_SWITCH,  &si.fullscreen,      "fullscreen"                    }
+};
+
+static struct TokenInfo player_setup_tokens[] =
+{
+  /* player setup */
+  { TYPE_BOOLEAN, &sii.use_joystick,   ".use_joystick"                 },
+  { TYPE_STRING,  &sii.joy.device_name,        ".joy.device_name"              },
+  { TYPE_INTEGER, &sii.joy.xleft,      ".joy.xleft"                    },
+  { TYPE_INTEGER, &sii.joy.xmiddle,    ".joy.xmiddle"                  },
+  { TYPE_INTEGER, &sii.joy.xright,     ".joy.xright"                   },
+  { TYPE_INTEGER, &sii.joy.yupper,     ".joy.yupper"                   },
+  { TYPE_INTEGER, &sii.joy.ymiddle,    ".joy.ymiddle"                  },
+  { TYPE_INTEGER, &sii.joy.ylower,     ".joy.ylower"                   },
+  { TYPE_INTEGER, &sii.joy.snap,       ".joy.snap_field"               },
+  { TYPE_INTEGER, &sii.joy.bomb,       ".joy.place_bomb"               },
+  { TYPE_KEY,     &sii.key.left,       ".key.move_left"                },
+  { TYPE_KEY,     &sii.key.right,      ".key.move_right"               },
+  { TYPE_KEY,     &sii.key.up,         ".key.move_up"                  },
+  { TYPE_KEY,     &sii.key.down,       ".key.move_down"                },
+  { TYPE_KEY,     &sii.key.snap,       ".key.snap_field"               },
+  { TYPE_KEY,     &sii.key.bomb,       ".key.place_bomb"               }
+};
+
+static struct TokenInfo levelinfo_tokens[] =
+{
+  /* level directory info */
+  { TYPE_STRING,  &ldi.name,           "name"                          },
+  { TYPE_STRING,  &ldi.name_short,     "name_short"                    },
+  { TYPE_STRING,  &ldi.name_sorting,   "name_sorting"                  },
+  { TYPE_STRING,  &ldi.author,         "author"                        },
+  { TYPE_STRING,  &ldi.imported_from,  "imported_from"                 },
+  { TYPE_INTEGER, &ldi.levels,         "levels"                        },
+  { TYPE_INTEGER, &ldi.first_level,    "first_level"                   },
+  { TYPE_INTEGER, &ldi.sort_priority,  "sort_priority"                 },
+  { TYPE_BOOLEAN, &ldi.level_group,    "level_group"                   },
+  { TYPE_BOOLEAN, &ldi.readonly,       "readonly"                      }
+};
+
+static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi)
+{
+  ldi->filename = NULL;
+  ldi->fullpath = NULL;
+  ldi->basepath = NULL;
+  ldi->name = getStringCopy(ANONYMOUS_NAME);
+  ldi->name_short = NULL;
+  ldi->name_sorting = NULL;
+  ldi->author = getStringCopy(ANONYMOUS_NAME);
+  ldi->imported_from = NULL;
+  ldi->levels = 0;
+  ldi->first_level = 0;
+  ldi->last_level = 0;
+  ldi->sort_priority = LEVELCLASS_UNDEFINED;   /* default: least priority */
+  ldi->level_group = FALSE;
+  ldi->parent_link = FALSE;
+  ldi->user_defined = FALSE;
+  ldi->readonly = TRUE;
+  ldi->color = 0;
+  ldi->class_desc = NULL;
+  ldi->handicap_level = 0;
+  ldi->cl_first = -1;
+  ldi->cl_cursor = -1;
+
+  ldi->node_parent = NULL;
+  ldi->node_group = NULL;
+  ldi->next = NULL;
+}
+
+static void setLevelDirInfoToDefaultsFromParent(struct LevelDirInfo *ldi,
+                                               struct LevelDirInfo *parent)
+{
+  if (parent == NULL)
+  {
+    setLevelDirInfoToDefaults(ldi);
+    return;
+  }
+
+  /* first copy all values from the parent structure ... */
+  *ldi = *parent;
+
+  /* ... then set all fields to default that cannot be inherited from parent.
+     This is especially important for all those fields that can be set from
+     the 'levelinfo.conf' config file, because the function 'setSetupInfo()'
+     calls 'free()' for all already set token values which requires that no
+     other structure's pointer may point to them!
+  */
+
+  ldi->filename = NULL;
+  ldi->fullpath = NULL;
+  ldi->basepath = NULL;
+  ldi->name = getStringCopy(ANONYMOUS_NAME);
+  ldi->name_short = NULL;
+  ldi->name_sorting = NULL;
+  ldi->author = getStringCopy(parent->author);
+  ldi->imported_from = getStringCopy(parent->imported_from);
+
+  ldi->level_group = FALSE;
+  ldi->parent_link = FALSE;
+
+  ldi->node_parent = parent;
+  ldi->node_group = NULL;
+  ldi->next = NULL;
+}
+
+static void setSetupInfoToDefaults(struct SetupInfo *si)
+{
+  int i;
+
+  si->player_name = getStringCopy(getLoginName());
+
+  si->sound = TRUE;
+  si->sound_loops = TRUE;
+  si->sound_music = TRUE;
+  si->sound_simple = TRUE;
+  si->toons = TRUE;
+  si->double_buffering = TRUE;
+  si->direct_draw = !si->double_buffering;
+  si->scroll_delay = TRUE;
+  si->soft_scrolling = TRUE;
+  si->fading = FALSE;
+  si->autorecord = TRUE;
+  si->quick_doors = FALSE;
+  si->team_mode = FALSE;
+  si->handicap = TRUE;
+  si->time_limit = TRUE;
+  si->fullscreen = FALSE;
+
+  for (i=0; i<MAX_PLAYERS; i++)
+  {
+    si->input[i].use_joystick = FALSE;
+    si->input[i].joy.device_name=getStringCopy(getDeviceNameFromJoystickNr(i));
+    si->input[i].joy.xleft   = JOYSTICK_XLEFT;
+    si->input[i].joy.xmiddle = JOYSTICK_XMIDDLE;
+    si->input[i].joy.xright  = JOYSTICK_XRIGHT;
+    si->input[i].joy.yupper  = JOYSTICK_YUPPER;
+    si->input[i].joy.ymiddle = JOYSTICK_YMIDDLE;
+    si->input[i].joy.ylower  = JOYSTICK_YLOWER;
+    si->input[i].joy.snap  = (i == 0 ? JOY_BUTTON_1 : 0);
+    si->input[i].joy.bomb  = (i == 0 ? JOY_BUTTON_2 : 0);
+    si->input[i].key.left  = (i == 0 ? DEFAULT_KEY_LEFT  : KSYM_UNDEFINED);
+    si->input[i].key.right = (i == 0 ? DEFAULT_KEY_RIGHT : KSYM_UNDEFINED);
+    si->input[i].key.up    = (i == 0 ? DEFAULT_KEY_UP    : KSYM_UNDEFINED);
+    si->input[i].key.down  = (i == 0 ? DEFAULT_KEY_DOWN  : KSYM_UNDEFINED);
+    si->input[i].key.snap  = (i == 0 ? DEFAULT_KEY_SNAP  : KSYM_UNDEFINED);
+    si->input[i].key.bomb  = (i == 0 ? DEFAULT_KEY_BOMB  : KSYM_UNDEFINED);
+  }
+}
+
+static void setSetupInfo(struct TokenInfo *token_info,
+                        int token_nr, char *token_value)
+{
+  int token_type = token_info[token_nr].type;
+  void *setup_value = token_info[token_nr].value;
+
+  if (token_value == NULL)
+    return;
+
+  /* set setup field to corresponding token value */
+  switch (token_type)
+  {
+    case TYPE_BOOLEAN:
+    case TYPE_SWITCH:
+      *(boolean *)setup_value = get_string_boolean_value(token_value);
+      break;
+
+    case TYPE_KEY:
+      *(Key *)setup_value = getKeyFromX11KeyName(token_value);
+      break;
+
+    case TYPE_INTEGER:
+      *(int *)setup_value = get_string_integer_value(token_value);
+      break;
+
+    case TYPE_STRING:
+      if (*(char **)setup_value != NULL)
+       free(*(char **)setup_value);
+      *(char **)setup_value = getStringCopy(token_value);
+      break;
+
+    default:
+      break;
+  }
+}
+
+static void decodeSetupFileList(struct SetupFileList *setup_file_list)
+{
+  int i, pnr;
+
+  if (!setup_file_list)
+    return;
+
+  /* handle global setup values */
+  si = setup;
+  for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
+    setSetupInfo(global_setup_tokens, i,
+                getTokenValue(setup_file_list, global_setup_tokens[i].text));
+  setup = si;
+
+  /* handle player specific setup values */
+  for (pnr=0; pnr<MAX_PLAYERS; pnr++)
+  {
+    char prefix[30];
+
+    sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
+
+    sii = setup.input[pnr];
+    for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
+    {
+      char full_token[100];
+
+      sprintf(full_token, "%s%s", prefix, player_setup_tokens[i].text);
+      setSetupInfo(player_setup_tokens, i,
+                  getTokenValue(setup_file_list, full_token));
+    }
+    setup.input[pnr] = sii;
+  }
+}
+
+static int compareLevelDirInfoEntries(const void *object1, const void *object2)
+{
+  const struct LevelDirInfo *entry1 = *((struct LevelDirInfo **)object1);
+  const struct LevelDirInfo *entry2 = *((struct LevelDirInfo **)object2);
+  int compare_result;
+
+  if (entry1->parent_link || entry2->parent_link)
+    compare_result = (entry1->parent_link ? -1 : +1);
+  else if (entry1->sort_priority == entry2->sort_priority)
+  {
+    char *name1 = getStringToLower(entry1->name_sorting);
+    char *name2 = getStringToLower(entry2->name_sorting);
+
+    compare_result = strcmp(name1, name2);
+
+    free(name1);
+    free(name2);
+  }
+  else if (LEVELSORTING(entry1) == LEVELSORTING(entry2))
+    compare_result = entry1->sort_priority - entry2->sort_priority;
+  else
+    compare_result = LEVELSORTING(entry1) - LEVELSORTING(entry2);
+
+  return compare_result;
+}
+
+static void createParentLevelDirNode(struct LevelDirInfo *node_parent)
+{
+  struct LevelDirInfo *leveldir_new = newLevelDirInfo();
+
+  setLevelDirInfoToDefaults(leveldir_new);
+
+  leveldir_new->node_parent = node_parent;
+  leveldir_new->parent_link = TRUE;
+
+  leveldir_new->name = ".. (parent directory)";
+  leveldir_new->name_short = getStringCopy(leveldir_new->name);
+  leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
+
+  leveldir_new->filename = "..";
+  leveldir_new->fullpath = getStringCopy(node_parent->fullpath);
+
+  leveldir_new->sort_priority = node_parent->sort_priority;
+  leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
+
+  pushLevelDirInfo(&node_parent->node_group, leveldir_new);
+}
+
+static void LoadLevelInfoFromLevelDir(struct LevelDirInfo **node_first,
+                                     struct LevelDirInfo *node_parent,
+                                     char *level_directory)
+{
+  DIR *dir;
+  struct dirent *dir_entry;
+  boolean valid_entry_found = FALSE;
+
+  if ((dir = opendir(level_directory)) == NULL)
+  {
+    Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
+    return;
+  }
+
+  while ((dir_entry = readdir(dir)) != NULL)   /* loop until last dir entry */
+  {
+    struct SetupFileList *setup_file_list = NULL;
+    struct stat file_status;
+    char *directory_name = dir_entry->d_name;
+    char *directory_path = getPath2(level_directory, directory_name);
+    char *filename = NULL;
+
+    /* skip entries for current and parent directory */
+    if (strcmp(directory_name, ".")  == 0 ||
+       strcmp(directory_name, "..") == 0)
+    {
+      free(directory_path);
+      continue;
+    }
+
+    /* find out if directory entry is itself a directory */
+    if (stat(directory_path, &file_status) != 0 ||     /* cannot stat file */
+       (file_status.st_mode & S_IFMT) != S_IFDIR)      /* not a directory */
+    {
+      free(directory_path);
+      continue;
+    }
+
+    filename = getPath2(directory_path, LEVELINFO_FILENAME);
+    setup_file_list = loadSetupFileList(filename);
+
+    if (setup_file_list)
+    {
+      struct LevelDirInfo *leveldir_new = newLevelDirInfo();
+      int i;
+
+      checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE);
+      setLevelDirInfoToDefaultsFromParent(leveldir_new, node_parent);
+
+      /* set all structure fields according to the token/value pairs */
+      ldi = *leveldir_new;
+      for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
+       setSetupInfo(levelinfo_tokens, i,
+                    getTokenValue(setup_file_list, levelinfo_tokens[i].text));
+      *leveldir_new = ldi;
+
+      DrawInitText(leveldir_new->name, 150, FC_YELLOW);
+
+      if (leveldir_new->name_short == NULL)
+       leveldir_new->name_short = getStringCopy(leveldir_new->name);
+
+      if (leveldir_new->name_sorting == NULL)
+       leveldir_new->name_sorting = getStringCopy(leveldir_new->name);
+
+      leveldir_new->filename = getStringCopy(directory_name);
+
+      if (node_parent == NULL)         /* top level group */
+      {
+       leveldir_new->basepath = level_directory;
+       leveldir_new->fullpath = leveldir_new->filename;
+      }
+      else                             /* sub level group */
+      {
+       leveldir_new->basepath = node_parent->basepath;
+       leveldir_new->fullpath = getPath2(node_parent->fullpath,
+                                         directory_name);
+      }
+
+      if (leveldir_new->levels < 1)
+       leveldir_new->levels = 1;
+
+      leveldir_new->last_level =
+       leveldir_new->first_level + leveldir_new->levels - 1;
+
+      leveldir_new->user_defined =
+       (leveldir_new->basepath == options.level_directory ? FALSE : TRUE);
+
+      leveldir_new->color = LEVELCOLOR(leveldir_new);
+      leveldir_new->class_desc = getLevelClassDescription(leveldir_new);
+
+      leveldir_new->handicap_level =   /* set handicap to default value */
+       (leveldir_new->user_defined ?
+        leveldir_new->last_level :
+        leveldir_new->first_level);
+
+      pushLevelDirInfo(node_first, leveldir_new);
+
+      freeSetupFileList(setup_file_list);
+      valid_entry_found = TRUE;
+
+      if (leveldir_new->level_group)
+      {
+       /* create node to link back to current level directory */
+       createParentLevelDirNode(leveldir_new);
+
+       /* step into sub-directory and look for more level series */
+       LoadLevelInfoFromLevelDir(&leveldir_new->node_group,
+                                 leveldir_new, directory_path);
+      }
+    }
+    else
+      Error(ERR_WARN, "ignoring level directory '%s'", directory_path);
+
+    free(directory_path);
+    free(filename);
+  }
+
+  closedir(dir);
+
+  if (!valid_entry_found)
+    Error(ERR_WARN, "cannot find any valid level series in directory '%s'",
+         level_directory);
+}
+
+void LoadLevelInfo()
+{
+  InitUserLevelDirectory(getLoginName());
+
+  DrawInitText("Loading level series:", 120, FC_GREEN);
+
+  LoadLevelInfoFromLevelDir(&leveldir_first, NULL, options.level_directory);
+  LoadLevelInfoFromLevelDir(&leveldir_first, NULL, getUserLevelDir(""));
+
+  leveldir_current = getFirstValidLevelSeries(leveldir_first);
+
+  if (leveldir_first == NULL)
+    Error(ERR_EXIT, "cannot find any valid level series in any directory");
+
+  sortLevelDirInfo(&leveldir_first, compareLevelDirInfoEntries);
+
+#if 0
+  dumpLevelDirInfo(leveldir_first, 0);
+#endif
+}
+
+static void SaveUserLevelInfo()
+{
+  char *filename;
+  FILE *file;
+  int i;
+
+  filename = getPath2(getUserLevelDir(getLoginName()), LEVELINFO_FILENAME);
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Error(ERR_WARN, "cannot write level info file '%s'", filename);
+    free(filename);
+    return;
+  }
+
+  /* always start with reliable default values */
+  setLevelDirInfoToDefaults(&ldi);
+
+  ldi.name = getLoginName();
+  ldi.author = getRealName();
+  ldi.levels = 100;
+  ldi.first_level = 1;
+  ldi.sort_priority = LEVELCLASS_USER_START;
+  ldi.readonly = FALSE;
+
+  fprintf(file, "%s\n\n",
+         getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE));
+
+  for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
+    if (i != LEVELINFO_TOKEN_NAME_SHORT &&
+       i != LEVELINFO_TOKEN_NAME_SORTING &&
+       i != LEVELINFO_TOKEN_IMPORTED_FROM)
+      fprintf(file, "%s\n", getSetupLine(levelinfo_tokens, "", i));
+
+  fclose(file);
+  free(filename);
+
+  SetFilePermissions(filename, PERMS_PRIVATE);
+}
+
+void LoadSetup()
+{
+  char *filename;
+  struct SetupFileList *setup_file_list = NULL;
+
+  /* always start with reliable default values */
+  setSetupInfoToDefaults(&setup);
+
+  filename = getPath2(getSetupDir(), SETUP_FILENAME);
+
+  setup_file_list = loadSetupFileList(filename);
+
+  if (setup_file_list)
+  {
+    checkSetupFileListIdentifier(setup_file_list, SETUP_COOKIE);
+    decodeSetupFileList(setup_file_list);
+
+    setup.direct_draw = !setup.double_buffering;
+
+    freeSetupFileList(setup_file_list);
+
+    /* needed to work around problems with fixed length strings */
+    if (strlen(setup.player_name) > MAX_PLAYER_NAME_LEN)
+      setup.player_name[MAX_PLAYER_NAME_LEN] = '\0';
+    else if (strlen(setup.player_name) < MAX_PLAYER_NAME_LEN)
+    {
+      char *new_name = checked_malloc(MAX_PLAYER_NAME_LEN + 1);
+
+      strcpy(new_name, setup.player_name);
+      free(setup.player_name);
+      setup.player_name = new_name;
+    }
+  }
+  else
+    Error(ERR_WARN, "using default setup values");
+
+  free(filename);
+}
+
+static char *getSetupLine(struct TokenInfo *token_info,
+                         char *prefix, int token_nr)
+{
+  int i;
+  static char entry[MAX_LINE_LEN];
+  int token_type = token_info[token_nr].type;
+  void *setup_value = token_info[token_nr].value;
+  char *token_text = token_info[token_nr].text;
+
+  /* start with the prefix, token and some spaces to format output line */
+  sprintf(entry, "%s%s:", prefix, token_text);
+  for (i=strlen(entry); i<TOKEN_VALUE_POSITION; i++)
+    strcat(entry, " ");
+
+  /* continue with the token's value (which can have different types) */
+  switch (token_type)
+  {
+    case TYPE_BOOLEAN:
+      strcat(entry, (*(boolean *)setup_value ? "true" : "false"));
+      break;
+
+    case TYPE_SWITCH:
+      strcat(entry, (*(boolean *)setup_value ? "on" : "off"));
+      break;
+
+    case TYPE_KEY:
+      {
+       Key key = *(Key *)setup_value;
+       char *keyname = getKeyNameFromKey(key);
+
+       strcat(entry, getX11KeyNameFromKey(key));
+       for (i=strlen(entry); i<50; i++)
+         strcat(entry, " ");
+
+       /* add comment, if useful */
+       if (strcmp(keyname, "(undefined)") != 0 &&
+           strcmp(keyname, "(unknown)") != 0)
+       {
+         strcat(entry, "# ");
+         strcat(entry, keyname);
+       }
+      }
+      break;
+
+    case TYPE_INTEGER:
+      {
+       char buffer[MAX_LINE_LEN];
+
+       sprintf(buffer, "%d", *(int *)setup_value);
+       strcat(entry, buffer);
+      }
+      break;
+
+    case TYPE_STRING:
+      strcat(entry, *(char **)setup_value);
+      break;
+
+    default:
+      break;
+  }
+
+  return entry;
+}
+
+void SaveSetup()
+{
+  int i, pnr;
+  char *filename;
+  FILE *file;
+
+  InitUserDataDirectory();
+
+  filename = getPath2(getSetupDir(), SETUP_FILENAME);
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Error(ERR_WARN, "cannot write setup file '%s'", filename);
+    free(filename);
+    return;
+  }
+
+  fprintf(file, "%s\n",
+         getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, SETUP_COOKIE));
+  fprintf(file, "\n");
+
+  /* handle global setup values */
+  si = setup;
+  for (i=FIRST_GLOBAL_SETUP_TOKEN; i<=LAST_GLOBAL_SETUP_TOKEN; i++)
+  {
+    fprintf(file, "%s\n", getSetupLine(global_setup_tokens, "", i));
+
+    /* just to make things nicer :) */
+    if (i == SETUP_TOKEN_PLAYER_NAME)
+      fprintf(file, "\n");
+  }
+
+  /* handle player specific setup values */
+  for (pnr=0; pnr<MAX_PLAYERS; pnr++)
+  {
+    char prefix[30];
+
+    sprintf(prefix, "%s%d", TOKEN_STR_PLAYER_PREFIX, pnr + 1);
+    fprintf(file, "\n");
+
+    sii = setup.input[pnr];
+    for (i=FIRST_PLAYER_SETUP_TOKEN; i<=LAST_PLAYER_SETUP_TOKEN; i++)
+      fprintf(file, "%s\n", getSetupLine(player_setup_tokens, prefix, i));
+  }
+
+  fclose(file);
+  free(filename);
+
+  SetFilePermissions(filename, PERMS_PRIVATE);
+}
+
+void LoadLevelSetup_LastSeries()
+{
+  char *filename;
+  struct SetupFileList *level_setup_list = NULL;
+
+  /* always start with reliable default values */
+  leveldir_current = getFirstValidLevelSeries(leveldir_first);
+
+  /* ----------------------------------------------------------------------- */
+  /* ~/.rocksndiamonds/levelsetup.conf                                       */
+  /* ----------------------------------------------------------------------- */
+
+  filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+
+  if ((level_setup_list = loadSetupFileList(filename)))
+  {
+    char *last_level_series =
+      getTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES);
+
+    leveldir_current = getLevelDirInfoFromFilename(last_level_series);
+    if (leveldir_current == NULL)
+      leveldir_current = leveldir_first;
+
+    checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
+
+    freeSetupFileList(level_setup_list);
+  }
+  else
+    Error(ERR_WARN, "using default setup values");
+
+  free(filename);
+}
+
+void SaveLevelSetup_LastSeries()
+{
+  char *filename;
+  char *level_subdir = leveldir_current->filename;
+  FILE *file;
+
+  /* ----------------------------------------------------------------------- */
+  /* ~/.rocksndiamonds/levelsetup.conf                                       */
+  /* ----------------------------------------------------------------------- */
+
+  InitUserDataDirectory();
+
+  filename = getPath2(getSetupDir(), LEVELSETUP_FILENAME);
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Error(ERR_WARN, "cannot write setup file '%s'", filename);
+    free(filename);
+    return;
+  }
+
+  fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
+                                                LEVELSETUP_COOKIE));
+  fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_LEVEL_SERIES,
+                                              level_subdir));
+
+  fclose(file);
+  free(filename);
+
+  SetFilePermissions(filename, PERMS_PRIVATE);
+}
+
+static void checkSeriesInfo()
+{
+  static char *level_directory = NULL;
+  DIR *dir;
+  struct dirent *dir_entry;
+
+  /* check for more levels besides the 'levels' field of 'levelinfo.conf' */
+
+  level_directory = getPath2((leveldir_current->user_defined ?
+                             getUserLevelDir("") :
+                             options.level_directory),
+                            leveldir_current->fullpath);
+
+  if ((dir = opendir(level_directory)) == NULL)
+  {
+    Error(ERR_WARN, "cannot read level directory '%s'", level_directory);
+    return;
+  }
+
+  while ((dir_entry = readdir(dir)) != NULL)   /* last directory entry */
+  {
+    if (strlen(dir_entry->d_name) > 4 &&
+       dir_entry->d_name[3] == '.' &&
+       strcmp(&dir_entry->d_name[4], LEVELFILE_EXTENSION) == 0)
+    {
+      char levelnum_str[4];
+      int levelnum_value;
+
+      strncpy(levelnum_str, dir_entry->d_name, 3);
+      levelnum_str[3] = '\0';
+
+      levelnum_value = atoi(levelnum_str);
+
+      if (levelnum_value < leveldir_current->first_level)
+      {
+       Error(ERR_WARN, "additional level %d found", levelnum_value);
+       leveldir_current->first_level = levelnum_value;
+      }
+      else if (levelnum_value > leveldir_current->last_level)
+      {
+       Error(ERR_WARN, "additional level %d found", levelnum_value);
+       leveldir_current->last_level = levelnum_value;
+      }
+    }
+  }
+
+  closedir(dir);
+}
+
+void LoadLevelSetup_SeriesInfo()
+{
+  char *filename;
+  struct SetupFileList *level_setup_list = NULL;
+  char *level_subdir = leveldir_current->filename;
+
+  /* always start with reliable default values */
+  level_nr = leveldir_current->first_level;
+
+  checkSeriesInfo(leveldir_current);
+
+  /* ----------------------------------------------------------------------- */
+  /* ~/.rocksndiamonds/levelsetup/<level series>/levelsetup.conf             */
+  /* ----------------------------------------------------------------------- */
+
+  level_subdir = leveldir_current->filename;
+
+  filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME);
+
+  if ((level_setup_list = loadSetupFileList(filename)))
+  {
+    char *token_value;
+
+    token_value = getTokenValue(level_setup_list, TOKEN_STR_LAST_PLAYED_LEVEL);
+
+    if (token_value)
+    {
+      level_nr = atoi(token_value);
+
+      if (level_nr < leveldir_current->first_level)
+       level_nr = leveldir_current->first_level;
+      if (level_nr > leveldir_current->last_level)
+       level_nr = leveldir_current->last_level;
+    }
+
+    token_value = getTokenValue(level_setup_list, TOKEN_STR_HANDICAP_LEVEL);
+
+    if (token_value)
+    {
+      int level_nr = atoi(token_value);
+
+      if (level_nr < leveldir_current->first_level)
+       level_nr = leveldir_current->first_level;
+      if (level_nr > leveldir_current->last_level + 1)
+       level_nr = leveldir_current->last_level;
+
+      if (leveldir_current->user_defined)
+       level_nr = leveldir_current->last_level;
+
+      leveldir_current->handicap_level = level_nr;
+    }
+
+    checkSetupFileListIdentifier(level_setup_list, LEVELSETUP_COOKIE);
+
+    freeSetupFileList(level_setup_list);
+  }
+  else
+    Error(ERR_WARN, "using default setup values");
+
+  free(filename);
+}
+
+void SaveLevelSetup_SeriesInfo()
+{
+  char *filename;
+  char *level_subdir = leveldir_current->filename;
+  char *level_nr_str = int2str(level_nr, 0);
+  char *handicap_level_str = int2str(leveldir_current->handicap_level, 0);
+  FILE *file;
+
+  /* ----------------------------------------------------------------------- */
+  /* ~/.rocksndiamonds/levelsetup/<level series>/levelsetup.conf             */
+  /* ----------------------------------------------------------------------- */
+
+  InitLevelSetupDirectory(level_subdir);
+
+  filename = getPath2(getLevelSetupDir(level_subdir), LEVELSETUP_FILENAME);
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Error(ERR_WARN, "cannot write setup file '%s'", filename);
+    free(filename);
+    return;
+  }
+
+  fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER,
+                                                LEVELSETUP_COOKIE));
+  fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_LAST_PLAYED_LEVEL,
+                                              level_nr_str));
+  fprintf(file, "%s\n", getFormattedSetupEntry(TOKEN_STR_HANDICAP_LEVEL,
+                                              handicap_level_str));
+
+  fclose(file);
+  free(filename);
+
+  SetFilePermissions(filename, PERMS_PRIVATE);
+}
diff --git a/src/libgame/setup.h b/src/libgame/setup.h
new file mode 100644 (file)
index 0000000..edec4d0
--- /dev/null
@@ -0,0 +1,126 @@
+/***********************************************************
+* Artsoft Retro-Game Library                               *
+*----------------------------------------------------------*
+* (c) 1994-2002 Artsoft Entertainment                      *
+*               Holger Schemel                             *
+*               Detmolder Strasse 189                      *
+*               33604 Bielefeld                            *
+*               Germany                                    *
+*               e-mail: info@artsoft.org                   *
+*----------------------------------------------------------*
+* setup.h                                                  *
+***********************************************************/
+
+#ifndef SETUP_H
+#define SETUP_H
+
+#include "system.h"
+
+
+/* sort priorities of level series (also used as level series classes) */
+#define LEVELCLASS_TUTORIAL_START      10
+#define LEVELCLASS_TUTORIAL_END                99
+#define LEVELCLASS_CLASSICS_START      100
+#define LEVELCLASS_CLASSICS_END                199
+#define LEVELCLASS_CONTRIBUTION_START  200
+#define LEVELCLASS_CONTRIBUTION_END    299
+#define LEVELCLASS_USER_START          300
+#define LEVELCLASS_USER_END            399
+#define LEVELCLASS_BD_START            400
+#define LEVELCLASS_BD_END              499
+#define LEVELCLASS_EM_START            500
+#define LEVELCLASS_EM_END              599
+#define LEVELCLASS_SP_START            600
+#define LEVELCLASS_SP_END              699
+#define LEVELCLASS_DX_START            700
+#define LEVELCLASS_DX_END              799
+
+#define LEVELCLASS_TUTORIAL            LEVELCLASS_TUTORIAL_START
+#define LEVELCLASS_CLASSICS            LEVELCLASS_CLASSICS_START
+#define LEVELCLASS_CONTRIBUTION                LEVELCLASS_CONTRIBUTION_START
+#define LEVELCLASS_USER                        LEVELCLASS_USER_START
+#define LEVELCLASS_BD                  LEVELCLASS_BD_START
+#define LEVELCLASS_EM                  LEVELCLASS_EM_START
+#define LEVELCLASS_SP                  LEVELCLASS_SP_START
+#define LEVELCLASS_DX                  LEVELCLASS_DX_START
+
+#define LEVELCLASS_UNDEFINED           999
+
+#define IS_LEVELCLASS_TUTORIAL(p) \
+       ((p)->sort_priority >= LEVELCLASS_TUTORIAL_START && \
+        (p)->sort_priority <= LEVELCLASS_TUTORIAL_END)
+#define IS_LEVELCLASS_CLASSICS(p) \
+       ((p)->sort_priority >= LEVELCLASS_CLASSICS_START && \
+        (p)->sort_priority <= LEVELCLASS_CLASSICS_END)
+#define IS_LEVELCLASS_CONTRIBUTION(p) \
+       ((p)->sort_priority >= LEVELCLASS_CONTRIBUTION_START && \
+        (p)->sort_priority <= LEVELCLASS_CONTRIBUTION_END)
+#define IS_LEVELCLASS_USER(p) \
+       ((p)->sort_priority >= LEVELCLASS_USER_START && \
+        (p)->sort_priority <= LEVELCLASS_USER_END)
+#define IS_LEVELCLASS_BD(p) \
+       ((p)->sort_priority >= LEVELCLASS_BD_START && \
+        (p)->sort_priority <= LEVELCLASS_BD_END)
+#define IS_LEVELCLASS_EM(p) \
+       ((p)->sort_priority >= LEVELCLASS_EM_START && \
+        (p)->sort_priority <= LEVELCLASS_EM_END)
+#define IS_LEVELCLASS_SP(p) \
+       ((p)->sort_priority >= LEVELCLASS_SP_START && \
+        (p)->sort_priority <= LEVELCLASS_SP_END)
+#define IS_LEVELCLASS_DX(p) \
+       ((p)->sort_priority >= LEVELCLASS_DX_START && \
+        (p)->sort_priority <= LEVELCLASS_DX_END)
+
+#define LEVELCLASS(n)  (IS_LEVELCLASS_TUTORIAL(n) ? LEVELCLASS_TUTORIAL : \
+                        IS_LEVELCLASS_CLASSICS(n) ? LEVELCLASS_CLASSICS : \
+                        IS_LEVELCLASS_CONTRIBUTION(n) ? LEVELCLASS_CONTRIBUTION : \
+                        IS_LEVELCLASS_USER(n) ? LEVELCLASS_USER : \
+                        IS_LEVELCLASS_BD(n) ? LEVELCLASS_BD : \
+                        IS_LEVELCLASS_EM(n) ? LEVELCLASS_EM : \
+                        IS_LEVELCLASS_SP(n) ? LEVELCLASS_SP : \
+                        IS_LEVELCLASS_DX(n) ? LEVELCLASS_DX : \
+                        LEVELCLASS_UNDEFINED)
+
+
+char *getLevelFilename(int);
+char *getTapeFilename(int);
+char *getScoreFilename(int);
+void InitTapeDirectory(char *);
+void InitScoreDirectory(char *);
+void InitUserLevelDirectory(char *);
+void InitLevelSetupDirectory(char *);
+
+void ReadChunk_VERS(FILE *, int *, int *);
+void WriteChunk_VERS(FILE *, int, int);
+
+struct LevelDirInfo *newLevelDirInfo();
+void pushLevelDirInfo(struct LevelDirInfo **, struct LevelDirInfo *);
+int numLevelDirInfo(struct LevelDirInfo *);
+boolean validLevelSeries(struct LevelDirInfo *);
+struct LevelDirInfo *getFirstValidLevelSeries(struct LevelDirInfo *);
+struct LevelDirInfo *getLevelDirInfoFirstGroupEntry(struct LevelDirInfo *);
+int numLevelDirInfoInGroup(struct LevelDirInfo *);
+int posLevelDirInfo(struct LevelDirInfo *);
+struct LevelDirInfo *getLevelDirInfoFromPos(struct LevelDirInfo *, int);
+struct LevelDirInfo *getLevelDirInfoFromFilename(char *);
+void dumpLevelDirInfo(struct LevelDirInfo *, int);
+void sortLevelDirInfo(struct LevelDirInfo **,
+                     int (*compare_function)(const void *, const void *));
+
+char *getUserDataDir(void);
+char *getSetupDir(void);
+void createDirectory(char *, char *, int);
+void InitUserDataDirectory(void);
+void SetFilePermissions(char *, int);
+int getFileVersionFromCookieString(const char *);
+boolean checkCookieString(const char *, const char *);
+
+void LoadLevelInfo(void);
+void LoadSetup(void);
+void SaveSetup(void);
+void LoadLevelSetup_LastSeries(void);
+void SaveLevelSetup_LastSeries(void);
+void LoadLevelSetup_SeriesInfo(void);
+void SaveLevelSetup_SeriesInfo(void);
+
+#endif /* MISC_H */
index 3d00d8e890d4ec419a0907220c76c3adaab1f229..5604ad21d818440f5860122d1ac65ced0d307b75 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "system.h"
 #include "sound.h"
+#include "setup.h"
 #include "misc.h"
 
 
@@ -34,26 +35,29 @@ struct OptionInfo   options;
 struct VideoSystemInfo video;
 struct AudioSystemInfo audio;
 struct GfxInfo         gfx;
+struct JoystickInfo    joystick;
+struct SetupInfo       setup;
 
 struct LevelDirInfo    *leveldir_first = NULL;
 struct LevelDirInfo    *leveldir_current = NULL;
+int                    level_nr;
 
-Display        *display = NULL;
-Visual        *visual = NULL;
-int            screen = 0;
-Colormap       cmap = None;
+Display                       *display = NULL;
+Visual                *visual = NULL;
+int                    screen = 0;
+Colormap               cmap = None;
 
-DrawWindow     *window = NULL;
-DrawBuffer     *backbuffer = NULL;
-DrawBuffer     *drawto = NULL;
+DrawWindow            *window = NULL;
+DrawBuffer            *backbuffer = NULL;
+DrawBuffer            *drawto = NULL;
 
-int            button_status = MB_NOT_PRESSED;
-boolean                motion_status = FALSE;
+int                    button_status = MB_NOT_PRESSED;
+boolean                        motion_status = FALSE;
 
-int            redraw_mask = REDRAW_NONE;
-int            redraw_tiles = 0;
+int                    redraw_mask = REDRAW_NONE;
+int                    redraw_tiles = 0;
 
-int            FrameCounter = 0;
+int                    FrameCounter = 0;
 
 
 /* ========================================================================= */
index bf0f58b1497448f3d3ef1c8924dedddbf3bd9c4a..0cf978df10d41cf7f983fa049d288338cbb6dd9a 100644 (file)
 #define FULLSCREEN_NOT_AVAILABLE FALSE
 #define FULLSCREEN_AVAILABLE    TRUE
 
-/* values for button_status */
+/* default input keys */
+#define DEFAULT_KEY_LEFT       KSYM_Left
+#define DEFAULT_KEY_RIGHT      KSYM_Right
+#define DEFAULT_KEY_UP         KSYM_Up
+#define DEFAULT_KEY_DOWN       KSYM_Down
+#define DEFAULT_KEY_SNAP       KSYM_Shift_L
+#define DEFAULT_KEY_BOMB       KSYM_Shift_R
+#define DEFAULT_KEY_OKAY       KSYM_Return
+#define DEFAULT_KEY_CANCEL     KSYM_Escape
+
+/* values for move directions */
+#define MV_NO_MOVING           0
+#define MV_LEFT                        (1 << 0)
+#define MV_RIGHT               (1 << 1)
+#define MV_UP                  (1 << 2)
+#define MV_DOWN                        (1 << 3)
+
+/* values for button status */
 #define MB_NOT_PRESSED         FALSE
 #define MB_NOT_RELEASED                TRUE
 #define MB_RELEASED            FALSE
 #define REDRAW_FPS             (1 << 11)
 #define REDRAWTILES_THRESHOLD  (SCR_FIELDX * SCR_FIELDY / 2)
 
+/* maximum number of parallel players supported by libgame functions */
+#define MAX_PLAYERS            4
+
+/* maximum allowed length of player name */
+#define MAX_PLAYER_NAME_LEN    10
 
 /* default name for empty highscore entry */
 #define EMPTY_PLAYER_NAME      "no name"
@@ -206,6 +228,63 @@ struct GfxInfo
   int vxsize, vysize;
 };
 
+struct JoystickInfo
+{
+  int status;
+  int fd[MAX_PLAYERS];         /* file descriptor of player's joystick */
+};
+
+struct SetupJoystickInfo
+{
+  char *device_name;           /* device name of player's joystick */
+
+  int xleft, xmiddle, xright;
+  int yupper, ymiddle, ylower;
+  int snap;
+  int bomb;
+};
+
+struct SetupKeyboardInfo
+{
+  Key left;
+  Key right;
+  Key up;
+  Key down;
+  Key snap;
+  Key bomb;
+};
+
+struct SetupInputInfo
+{
+  boolean use_joystick;
+  struct SetupJoystickInfo joy;
+  struct SetupKeyboardInfo key;
+};
+
+struct SetupInfo
+{
+  char *player_name;
+
+  boolean sound;
+  boolean sound_loops;
+  boolean sound_music;
+  boolean sound_simple;
+  boolean toons;
+  boolean double_buffering;
+  boolean direct_draw;         /* !double_buffering (redundant!) */
+  boolean scroll_delay;
+  boolean soft_scrolling;
+  boolean fading;
+  boolean autorecord;
+  boolean quick_doors;
+  boolean team_mode;
+  boolean handicap;
+  boolean time_limit;
+  boolean fullscreen;
+
+  struct SetupInputInfo input[MAX_PLAYERS];
+};
+
 struct LevelDirInfo
 {
   char *filename;      /* level series single directory name */
@@ -245,26 +324,29 @@ extern struct OptionInfo  options;
 extern struct VideoSystemInfo  video;
 extern struct AudioSystemInfo  audio;
 extern struct GfxInfo          gfx;
+extern struct JoystickInfo     joystick;
+extern struct SetupInfo                setup;
 
 extern struct LevelDirInfo     *leveldir_first;
 extern struct LevelDirInfo     *leveldir_current;
+extern int                     level_nr;
 
-extern Display        *display;
-extern Visual         *visual;
-extern int             screen;
-extern Colormap                cmap;
+extern Display                *display;
+extern Visual                 *visual;
+extern int                     screen;
+extern Colormap                        cmap;
 
-extern DrawWindow      *window;
-extern DrawBuffer      *backbuffer;
-extern DrawBuffer      *drawto;
+extern DrawWindow             *window;
+extern DrawBuffer             *backbuffer;
+extern DrawBuffer             *drawto;
 
-extern int             button_status;
-extern boolean         motion_status;
+extern int                     button_status;
+extern boolean                 motion_status;
 
-extern int             redraw_mask;
-extern int             redraw_tiles;
+extern int                     redraw_mask;
+extern int                     redraw_tiles;
 
-extern int             FrameCounter;
+extern int                     FrameCounter;
 
 
 /* function definitions */
index 56a6d0070e913f6217023af60eb37f8a24a213e7..34bc8e4aa48d1305c43d4cb5d084560eb636f2ab 100644 (file)
 #ifndef TYPES_H
 #define TYPES_H
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
 typedef unsigned char boolean;
 typedef unsigned char byte;
 
index de38f3f093b91eafe334534cd3c19ff8e10eaa86..528741b98b8050c61242fadcbac5be4829f595c6 100644 (file)
@@ -17,7 +17,6 @@
 #include "init.h"
 #include "game.h"
 #include "events.h"
-#include "joystick.h"
 
 GC             tile_clip_gc;
 Bitmap        *pix[NUM_BITMAPS];
@@ -25,22 +24,12 @@ Pixmap              tile_clipmask[NUM_TILES];
 DrawBuffer     *fieldbuffer;
 DrawBuffer     *drawto_field;
 
-int            joystick_device = 0;
-char          *joystick_device_name[MAX_PLAYERS] =
-{
-  DEV_JOYSTICK_0,
-  DEV_JOYSTICK_1,
-  DEV_JOYSTICK_2,
-  DEV_JOYSTICK_3
-};
-
 int            game_status = MAINMENU;
 boolean                level_editor_test_game = FALSE;
 boolean                network_playing = FALSE;
 
 int            key_joystick_mapping = 0;
 int            global_joystick_status = JOYSTICK_STATUS;
-int            joystick_status = JOYSTICK_STATUS;
 
 boolean                redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
 int            redraw_x1 = 0, redraw_y1 = 0;
@@ -62,7 +51,6 @@ short         ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 unsigned long  Elementeigenschaften1[MAX_ELEMENTS];
 unsigned long  Elementeigenschaften2[MAX_ELEMENTS];
 
-int            level_nr;
 int            lev_fieldx,lev_fieldy, scroll_x,scroll_y;
 
 int            FX = SX, FY = SY, ScrollStepSize;
index 86377ccf152a4df2741a069c899cc16518f20584..0768ed90f69f70d787589b323a6bcbf38f1c53ca 100644 (file)
@@ -49,8 +49,6 @@
 #define MAX_LEV_FIELDX 128
 #define MAX_LEV_FIELDY 128
 
-#define MAX_PLAYERS    4
-
 #define SCREENX(a)     ((a) - scroll_x)
 #define SCREENY(a)     ((a) - scroll_y)
 #define LEVELX(a)      ((a) + scroll_x)
 #define NUM_BITMAPS            12
 
 /* boundaries of arrays etc. */
-#define MAX_PLAYER_NAME_LEN    10
 #define MAX_LEVEL_NAME_LEN     32
 #define MAX_LEVEL_AUTHOR_LEN   32
 #define MAX_TAPELEN            (1000 * 50)     /* max. time * framerate */
@@ -213,56 +210,6 @@ struct HiScore
   int Score;
 };
 
-struct SetupJoystickInfo
-{
-  char *device_name;
-  int xleft, xmiddle, xright;
-  int yupper, ymiddle, ylower;
-  int snap;
-  int bomb;
-};
-
-struct SetupKeyboardInfo
-{
-  Key left;
-  Key right;
-  Key up;
-  Key down;
-  Key snap;
-  Key bomb;
-};
-
-struct SetupInputInfo
-{
-  boolean use_joystick;
-  struct SetupJoystickInfo joy;
-  struct SetupKeyboardInfo key;
-};
-
-struct SetupInfo
-{
-  char *player_name;
-
-  boolean sound;
-  boolean sound_loops;
-  boolean sound_music;
-  boolean sound_simple;
-  boolean toons;
-  boolean double_buffering;
-  boolean direct_draw;         /* !double_buffering (redundant!) */
-  boolean scroll_delay;
-  boolean soft_scrolling;
-  boolean fading;
-  boolean autorecord;
-  boolean quick_doors;
-  boolean team_mode;
-  boolean handicap;
-  boolean time_limit;
-  boolean fullscreen;
-
-  struct SetupInputInfo input[MAX_PLAYERS];
-};
-
 struct PlayerInfo
 {
   boolean present;             /* player present in level playfield */
@@ -278,8 +225,6 @@ struct PlayerInfo
   byte programmed_action;      /* action forced by game itself (like moving
                                   through doors); overrides other actions */
 
-  int joystick_fd;             /* file descriptor of player's joystick */
-
   int jx,jy, last_jx,last_jy;
   int MovDir, MovPos, GfxPos;
   int Frame;
@@ -404,7 +349,7 @@ extern boolean              level_editor_test_game;
 extern boolean         network_playing;
 
 extern int             key_joystick_mapping;
-extern int             global_joystick_status, joystick_status;
+extern int             global_joystick_status;
 
 extern boolean         redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
 extern int             redraw_x1, redraw_y1;
@@ -426,7 +371,6 @@ extern short                ExplodeField[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern unsigned long   Elementeigenschaften1[MAX_ELEMENTS];
 extern unsigned long   Elementeigenschaften2[MAX_ELEMENTS];
 
-extern int             level_nr;
 extern int             lev_fieldx,lev_fieldy, scroll_x,scroll_y;
 
 extern int             FX,FY, ScrollStepSize;
@@ -450,8 +394,6 @@ extern struct LevelInfo             level;
 extern struct PlayerInfo       stored_player[], *local_player;
 extern struct HiScore          highscore[];
 extern struct TapeInfo         tape;
-extern struct JoystickInfo     joystick[];
-extern struct SetupInfo                setup;
 extern struct GameInfo         game;
 extern struct GlobalInfo       global;
 
@@ -1498,23 +1440,6 @@ extern int               num_element_info;
 
 #define NUM_SOUNDS             55
 
-/* default input keys */
-#define DEFAULT_KEY_LEFT       KSYM_Left
-#define DEFAULT_KEY_RIGHT      KSYM_Right
-#define DEFAULT_KEY_UP         KSYM_Up
-#define DEFAULT_KEY_DOWN       KSYM_Down
-#define DEFAULT_KEY_SNAP       KSYM_Shift_L
-#define DEFAULT_KEY_BOMB       KSYM_Shift_R
-#define DEFAULT_KEY_OKAY       KSYM_Return
-#define DEFAULT_KEY_CANCEL     KSYM_Escape
-
-/* directions for moving */
-#define MV_NO_MOVING           0
-#define MV_LEFT                        (1 << 0)
-#define MV_RIGHT               (1 << 1)
-#define MV_UP                  (1 << 2)
-#define MV_DOWN                        (1 << 3)
-
 /* values for game_status */
 #define EXITGAME               0
 #define MAINMENU               1
index 8a6a486d2e270fd675a56601979cc41df605ef4d..5c317af059ce93235d035ca5b9ca007e46dd2e85 100644 (file)
@@ -20,7 +20,6 @@
 #include "editor.h"
 #include "files.h"
 #include "tape.h"
-#include "joystick.h"
 #include "cartoons.h"
 #include "network.h"
 #include "init.h"
@@ -94,6 +93,7 @@ void DrawMainMenu()
   UnmapAllGadgets();
   FadeSounds();
   KeyboardAutoRepeatOn();
+  ActivateJoystickIfAvailable();
 
   /* needed if last screen was the playing screen, invoked from level editor */
   if (level_editor_test_game)
@@ -1635,6 +1635,7 @@ void DrawSetupInputScreen()
   DrawText(SX+32, SY+3*32, "Device:", FS_BIG, FC_GREEN);
   DrawText(SX+32, SY+15*32, "Exit", FS_BIG, FC_GREEN);
 
+  DeactivateJoystickForCalibration();
   DrawTextFCentered(SYSIZE - 20, FC_BLUE,
                    "Joysticks deactivated on this screen");
 
@@ -1660,7 +1661,8 @@ static void setJoystickDeviceToNr(char *device_name, int device_nr)
       device_name[strlen(device_name) - 1] = '0' + (char)(device_nr % 10);
   }
   else
-    strncpy(device_name, joystick_device_name[device_nr], strlen(device_name));
+    strncpy(device_name, getDeviceNameFromJoystickNr(device_nr),
+           strlen(device_name));
 }
 
 static void drawPlayerSetupInputInfo(int player_nr)
@@ -2052,14 +2054,14 @@ void CalibrateJoystick(int player_nr)
   int calibration_step = 1;
 #endif
 
-  int joystick_fd = stored_player[player_nr].joystick_fd;
+  int joystick_fd = joystick.fd[player_nr];
   int x, y, last_x, last_y, xpos = 8, ypos = 3;
   boolean check[3][3];
   int check_remaining;
   int joy_value;
   int result = -1;
 
-  if (joystick_status == JOYSTICK_OFF ||
+  if (joystick.status == JOYSTICK_NOT_AVAILABLE ||
       joystick_fd < 0 ||
       !setup.input[player_nr].use_joystick)
     goto error_out;
@@ -2153,7 +2155,7 @@ void CalibrateJoystick(int player_nr)
 #else
     if (read(joystick_fd, &joy_ctrl, sizeof(joy_ctrl)) != sizeof(joy_ctrl))
     {
-      joystick_status = JOYSTICK_OFF;
+      joystick.status = JOYSTICK_NOT_AVAILABLE;
       goto error_out;
     }
 #endif
@@ -2192,7 +2194,7 @@ void CalibrateJoystick(int player_nr)
       }
       else if (calibrate_joystick(joystick_fd) != 0)
       {
-       joystick_status = JOYSTICK_OFF;
+       joystick.status = JOYSTICK_NOT_AVAILABLE;
        goto error_out;
       }
 
index ca2bbd5d2651d6217abdd5e46fc30f5afc9a007d..8a5f48e0e0f4197b78718a5130ff5b03fe34132a 100644 (file)
 * tools.c                                                  *
 ***********************************************************/
 
+#if 0
 #include <stdarg.h>
 
 #if defined(PLATFORM_FREEBSD)
 #include <machine/joystick.h>
 #endif
+#endif
 
 #include "libgame/libgame.h"
 
 #include "tools.h"
 #include "game.h"
 #include "events.h"
-#include "joystick.h"
 #include "cartoons.h"
 #include "network.h"
 #include "tape.h"