rnd-19990610-1-src
authorHolger Schemel <info@artsoft.org>
Wed, 9 Jun 1999 23:46:32 +0000 (01:46 +0200)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:34:04 +0000 (10:34 +0200)
src/files.c
src/main.c
src/main.h
src/screens.c
src/tools.c

index 7e1ad30bc6dafa99c5a9478dc6929c6a34b41678..80c766cd94bb8b97f8a6e385266d9f4f9738e4fb 100644 (file)
 #define MAX_LINE_LEN           1000    /* maximal input line length */
 #define CHUNK_ID_LEN           4       /* IFF style chunk id length */
 #define LEVEL_HEADER_SIZE      80      /* size of level file header */
-#define LEVEL_HEADER_UNUSED    16      /* unused level header bytes */
+#define LEVEL_HEADER_UNUSED    15      /* unused level header bytes */
 #define TAPE_HEADER_SIZE       20      /* size of tape file header */
 #define TAPE_HEADER_UNUSED     7       /* unused tape header bytes */
-#define FILE_VERSION_1_0       10      /* old 1.0 file version */
-#define FILE_VERSION_1_2       12      /* actual file version */
+#define FILE_VERSION_1_0       10      /* 1.0 file version (old) */
+#define FILE_VERSION_1_2       12      /* 1.2 file version (still in use) */
+#define FILE_VERSION_1_4       14      /* 1.4 file version (new) */
 
 /* file identifier strings */
-#define LEVEL_COOKIE           "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.2"
+#define LEVEL_COOKIE           "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.4"
 #define SCORE_COOKIE           "ROCKSNDIAMONDS_SCORE_FILE_VERSION_1.2"
 #define TAPE_COOKIE            "ROCKSNDIAMONDS_TAPE_FILE_VERSION_1.2"
 #define SETUP_COOKIE           "ROCKSNDIAMONDS_SETUP_FILE_VERSION_1.2"
@@ -41,6 +42,7 @@
 #define LEVELINFO_COOKIE       "ROCKSNDIAMONDS_LEVELINFO_FILE_VERSION_1.2"
 /* old file identifiers for backward compatibility */
 #define LEVEL_COOKIE_10                "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.0"
+#define LEVEL_COOKIE_12                "ROCKSNDIAMONDS_LEVEL_FILE_VERSION_1.2"
 #define TAPE_COOKIE_10         "ROCKSNDIAMONDS_LEVELREC_FILE_VERSION_1.0"
 
 /* file names and filename extensions */
 #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(n) \
-       (leveldir[n].sort_priority >= LEVELCLASS_TUTORIAL_START && \
-        leveldir[n].sort_priority <= LEVELCLASS_TUTORIAL_END)
-#define IS_LEVELCLASS_CLASSICS(n) \
-       (leveldir[n].sort_priority >= LEVELCLASS_CLASSICS_START && \
-        leveldir[n].sort_priority <= LEVELCLASS_CLASSICS_END)
-#define IS_LEVELCLASS_CONTRIBUTION(n) \
-       (leveldir[n].sort_priority >= LEVELCLASS_CONTRIBUTION_START && \
-        leveldir[n].sort_priority <= LEVELCLASS_CONTRIBUTION_END)
-#define IS_LEVELCLASS_USER(n) \
-       (leveldir[n].sort_priority >= LEVELCLASS_USER_START && \
-        leveldir[n].sort_priority <= LEVELCLASS_USER_END)
+#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_YELLOW : \
-                        IS_LEVELCLASS_CONTRIBUTION(n) ? FC_GREEN : \
-                        IS_LEVELCLASS_USER(n) ? FC_RED : FC_BLUE)
+#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()' */
@@ -321,7 +390,7 @@ static void setLevelInfoToDefaults()
   }
   else
   {
-    switch (LEVELCLASS(leveldir_nr))
+    switch (LEVELCLASS(&leveldir[leveldir_nr]))
     {
       case LEVELCLASS_TUTORIAL:
        strcpy(level.author, PROGRAM_AUTHOR_STRING);
@@ -350,7 +419,8 @@ void LoadLevel(int level_nr)
   char *filename = getLevelFilename(level_nr);
   char cookie[MAX_LINE_LEN];
   char chunk[CHUNK_ID_LEN + 1];
-  int file_version = FILE_VERSION_1_2; /* last version of level files */
+  boolean encoding_16bit = FALSE;      /* default: maximal 256 elements */
+  int file_version = FILE_VERSION_1_4; /* last version of level files */
   int chunk_length;
   FILE *file;
 
@@ -370,6 +440,8 @@ void LoadLevel(int level_nr)
 
   if (strcmp(cookie, LEVEL_COOKIE_10) == 0)    /* old 1.0 level format */
     file_version = FILE_VERSION_1_0;
+  else if (strcmp(cookie, LEVEL_COOKIE_12) == 0)/* 1.2 (8 bit) level format */
+    file_version = FILE_VERSION_1_2;
   else if (strcmp(cookie, LEVEL_COOKIE) != 0)  /* unknown level format */
   {
     Error(ERR_WARN, "wrong file identifier of level file '%s'", filename);
@@ -424,10 +496,11 @@ void LoadLevel(int level_nr)
   level.double_speed   = (fgetc(file) == 1 ? TRUE : FALSE);
   level.gravity                = (fgetc(file) == 1 ? TRUE : FALSE);
 
+  encoding_16bit       = (fgetc(file) == 1 ? TRUE : FALSE);
+
   for(i=0; i<LEVEL_HEADER_UNUSED; i++) /* skip unused header bytes */
     fgetc(file);
 
-  /* read chunk "BODY" */
   if (file_version >= FILE_VERSION_1_2)
   {
     getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN);
@@ -454,7 +527,10 @@ void LoadLevel(int level_nr)
       for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
        for(y=0; y<3; y++)
          for(x=0; x<3; x++)
-           level.yam_content[i][x][y] = fgetc(file);
+           level.yam_content[i][x][y] =
+             (encoding_16bit ?
+              getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) :
+              fgetc(file));
 
       getFileChunk(file, chunk, &chunk_length, BYTE_ORDER_BIG_ENDIAN);
     }
@@ -476,13 +552,16 @@ void LoadLevel(int level_nr)
   /* now read in the valid level fields from level file */
   for(y=0; y<lev_fieldy; y++)
     for(x=0; x<lev_fieldx; x++)
-      Feld[x][y] = Ur[x][y] = fgetc(file);
+      Feld[x][y] = Ur[x][y] =
+       (encoding_16bit ?
+        getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) :
+        fgetc(file));
 
   fclose(file);
 
   /* player was faster than monsters in pre-1.0 levels */
   if (file_version == FILE_VERSION_1_0 &&
-      IS_LEVELCLASS_CONTRIBUTION(leveldir_nr))
+      IS_LEVELCLASS_CONTRIBUTION(&leveldir[leveldir_nr]))
   {
     Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
     Error(ERR_WARN, "using high speed movement for player");
@@ -497,6 +576,8 @@ void SaveLevel(int level_nr)
 {
   int i, x, y;
   char *filename = getLevelFilename(level_nr);
+  boolean encoding_16bit = FALSE;      /* default: maximal 256 elements */
+  char *oldest_possible_cookie;
   FILE *file;
 
   if (!(file = fopen(filename, "w")))
@@ -505,7 +586,22 @@ void SaveLevel(int level_nr)
     return;
   }
 
-  fputs(LEVEL_COOKIE, file);           /* file identifier */
+  /* check yam content for 16-bit elements */
+  for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
+    for(y=0; y<3; y++)
+      for(x=0; x<3; x++)
+       if (level.yam_content[i][x][y] > 255)
+         encoding_16bit = TRUE;
+
+  /* check level field for 16-bit elements */
+  for(y=0; y<lev_fieldy; y++) 
+    for(x=0; x<lev_fieldx; x++) 
+      if (Ur[x][y] > 255)
+       encoding_16bit = TRUE;
+
+  oldest_possible_cookie = (encoding_16bit ? LEVEL_COOKIE : LEVEL_COOKIE_12);
+
+  fputs(oldest_possible_cookie, file);         /* file identifier */
   fputc('\n', file);
 
   putFileChunk(file, "HEAD", LEVEL_HEADER_SIZE, BYTE_ORDER_BIG_ENDIAN);
@@ -523,7 +619,7 @@ void SaveLevel(int level_nr)
   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       fputc(level.yam_content[i][x][y], file);
+       fputc(encoding_16bit ? EL_LEERRAUM : level.yam_content[i][x][y], file);
   fputc(level.amoeba_speed, file);
   fputc(level.time_magic_wall, file);
   fputc(level.time_wheel, file);
@@ -531,6 +627,8 @@ void SaveLevel(int level_nr)
   fputc((level.double_speed ? 1 : 0), file);
   fputc((level.gravity ? 1 : 0), file);
 
+  fputc((encoding_16bit ? 1 : 0), file);
+
   for(i=0; i<LEVEL_HEADER_UNUSED; i++) /* set unused header bytes to zero */
     fputc(0, file);
 
@@ -550,13 +648,20 @@ void SaveLevel(int level_nr)
   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       fputc(level.yam_content[i][x][y], file);
+       if (encoding_16bit)
+         putFile16BitInteger(file, level.yam_content[i][x][y],
+                             BYTE_ORDER_BIG_ENDIAN);
+       else
+         fputc(level.yam_content[i][x][y], file);
 
   putFileChunk(file, "BODY", lev_fieldx * lev_fieldy, BYTE_ORDER_BIG_ENDIAN);
 
   for(y=0; y<lev_fieldy; y++) 
     for(x=0; x<lev_fieldx; x++) 
-      fputc(Ur[x][y], file);
+      if (encoding_16bit)
+       putFile16BitInteger(file, Ur[x][y], BYTE_ORDER_BIG_ENDIAN);
+      else
+       fputc(Ur[x][y], file);
 
   fclose(file);
 
@@ -909,11 +1014,13 @@ void SaveScore(int level_nr)
 
 /* level directory info */
 #define LEVELINFO_TOKEN_NAME           29
-#define LEVELINFO_TOKEN_AUTHOR         30
-#define LEVELINFO_TOKEN_LEVELS         31
-#define LEVELINFO_TOKEN_FIRST_LEVEL    32
-#define LEVELINFO_TOKEN_SORT_PRIORITY  33
-#define LEVELINFO_TOKEN_READONLY       34
+#define LEVELINFO_TOKEN_NAME_SHORT     30
+#define LEVELINFO_TOKEN_AUTHOR         31
+#define LEVELINFO_TOKEN_IMPORTED_FROM  32
+#define LEVELINFO_TOKEN_LEVELS         33
+#define LEVELINFO_TOKEN_FIRST_LEVEL    34
+#define LEVELINFO_TOKEN_SORT_PRIORITY  35
+#define LEVELINFO_TOKEN_READONLY       36
 
 #define FIRST_GLOBAL_SETUP_TOKEN       SETUP_TOKEN_PLAYER_NAME
 #define LAST_GLOBAL_SETUP_TOKEN                SETUP_TOKEN_TEAM_MODE
@@ -977,6 +1084,7 @@ static struct
   { TYPE_STRING,  &ldi.name,           "name"                          },
   { TYPE_STRING,  &ldi.name_short,     "name_short"                    },
   { 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"                 },
@@ -1243,6 +1351,7 @@ static void setLevelDirInfoToDefaults(struct LevelDirInfo *ldi)
   ldi->name = getStringCopy(ANONYMOUS_NAME);
   ldi->name_short = NULL;
   ldi->author = getStringCopy(ANONYMOUS_NAME);
+  ldi->imported_from = NULL;
   ldi->levels = 0;
   ldi->first_level = 0;
   ldi->sort_priority = LEVELCLASS_UNDEFINED;   /* default: least priority */
@@ -1400,18 +1509,20 @@ static int compareLevelDirInfoEntries(const void *object1, const void *object2)
   const struct LevelDirInfo *entry2 = object2;
   int compare_result;
 
-  if (entry1->sort_priority != entry2->sort_priority)
-    compare_result = entry1->sort_priority - entry2->sort_priority;
-  else
+  if (entry1->sort_priority == entry2->sort_priority)
   {
-    char *name1 = getStringToLower(entry1->name);
-    char *name2 = getStringToLower(entry2->name);
+    char *name1 = getStringToLower(entry1->name_short);
+    char *name2 = getStringToLower(entry2->name_short);
 
     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;
 }
@@ -1474,7 +1585,9 @@ static int LoadLevelInfoFromLevelDir(char *level_directory, int start_entry)
        leveldir[current_entry].levels - 1;
       leveldir[current_entry].user_defined =
        (level_directory == options.level_directory ? FALSE : TRUE);
-      leveldir[current_entry].color = LEVELCOLOR(current_entry);
+      leveldir[current_entry].color = LEVELCOLOR(&leveldir[current_entry]);
+      leveldir[current_entry].class_desc =
+       getLevelClassDescription(&leveldir[current_entry]);
 
       freeSetupFileList(setup_file_list);
       current_entry++;
@@ -1538,7 +1651,6 @@ static void SaveUserLevelInfo()
   setLevelDirInfoToDefaults(&ldi);
 
   ldi.name = getLoginName();
-  ldi.name_short = getLoginName();
   ldi.author = getRealName();
   ldi.levels = 100;
   ldi.first_level = 1;
@@ -1549,7 +1661,8 @@ static void SaveUserLevelInfo()
          getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE));
 
   for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++)
-    fprintf(file, "%s\n", getSetupLine("", i));
+    if (i != LEVELINFO_TOKEN_NAME_SHORT && i != LEVELINFO_TOKEN_IMPORTED_FROM)
+      fprintf(file, "%s\n", getSetupLine("", i));
 
   fclose(file);
   free(filename);
index e18599dfd383ca4f1e93fdaa11a761704b3456fb..14756c5ec57383f5f1c9f2462d661e608a4a5c48 100644 (file)
@@ -236,10 +236,10 @@ char *element_info[] =
   "yellow door",
   "green door",
   "blue door",
-  "grey door (opened by red key)",
-  "grey door (opened by yellow key)",
-  "grey door (opened by green key)",
-  "grey door (opened by blue key)",
+  "gray door (opened by red key)",
+  "gray door (opened by yellow key)",
+  "gray door (opened by green key)",
+  "gray door (opened by blue key)",
   "dynamite",
   "pac man",
   "invisible normal wall",
@@ -451,7 +451,71 @@ char *element_info[] =
   "unknown",
   "unknown",
   "unknown",
-  "unknown"
+  "unknown",
+
+  /* 256 */
+
+  "pearl",
+  "crystal",
+  "wall with pearl",
+  "wall with crystal",
+  "white door",
+  "gray door (opened by white key)",
+  "white key",
+  "force field",
+  "extra time",
+  "switch gate (open)",
+  "switch gate (closed)",
+  "switch for switch gate",
+  "time gate",
+  "time gate with magic wheel",
+  "green conveyor belt (left)",
+  "green conveyor belt (middle)",
+  "green conveyor belt (right)",
+  "switch for green conveyor belt",
+  "red conveyor belt (left)",
+  "red conveyor belt (middle)",
+  "red conveyor belt (right)",
+  "switch for red conveyor belt",
+  "blue conveyor belt (left)",
+  "blue conveyor belt (middle)",
+  "blue conveyor belt (right)",
+  "switch for blue conveyor belt",
+  "land mine",
+  "mail envelope",
+  "light switch",
+  "sign (exclamation)",
+  "sign (radio activity)",
+  "sign (stop)",
+  "sign (wheel chair)",
+  "sign (parking)",
+  "sign (one way)",
+  "sign (heart)",
+  "sign (triangle)",
+  "sign (round)",
+  "sign (exit)",
+  "sign (yin yang)",
+  "sign (other)",
+  "mole (starts moving left)",
+  "mole (starts moving right)",
+  "mole (starts moving up)",
+  "mole (starts moving down)",
+  "steel (?)",
+  "invisible sand",
+  "-",
+  "-",
+  "-",
+  "-",
+  "-",
+  "-",
+  "-",
+  "-",
+  "-",
+  "-"
+
+  /*
+  "-------------------------------",
+  */
 };
 
 int main(int argc, char *argv[])
index d0aed23d74ed2a3e4c1470f15f51a938d27d5f44..0550a996fbb53d6aa12b2ff75b3ea467b94dbde0 100644 (file)
@@ -366,17 +366,19 @@ struct LevelInfo
 
 struct LevelDirInfo
 {
-  char *filename;
-  char *name;
+  char *filename;      /* level series sub-directory inside level directory */
+  char *name;          /* level series name, as displayed on main screen */
   char *name_short;    /* optional short name for level selection screen */
-  char *author;
-  int levels;
-  int first_level;
-  int last_level;
-  int sort_priority;
-  boolean user_defined;
-  boolean readonly;
-  int color;
+  char *author;                /* level series author name levels without author */
+  char *imported_from; /* optional comment for imported level series */
+  int levels;          /* number of levels in level series */
+  int first_level;     /* first level number (to allow start with 0 or 1) */
+  int last_level;      /* last level number (automatically calculated) */
+  int sort_priority;   /* sort levels by 'sort_priority' and then by name */
+  boolean user_defined;        /* user defined levels are stored in home directory */
+  boolean readonly;    /* readonly levels can not be changed with editor */
+  int color;           /* color to use on selection screen for this level */
+  char *class_desc;    /* description of level series class */
 };
 
 struct TapeInfo
@@ -815,35 +817,83 @@ extern char               *element_info[];
 #define EL_UNUSED_254          254
 #define EL_UNUSED_255          255
 
+#define EL_PEARL               256
+#define EL_CRYSTAL             257
+#define EL_WALL_PEARL          258
+#define EL_WALL_CRYSTAL                259
+#define EL_DOOR_WHITE          260
+#define EL_DOOR_WHITE_GRAY     261
+#define EL_KEY_WHITE           262
+#define EL_FORCE_FIELD         263
+#define EL_EXTRA_TIME          264
+#define EL_SWITCH_GATE_OPEN    265
+#define EL_SWITCH_GATE_CLOSED  266
+#define EL_SWITCH_GATE_SWITCH  267
+#define EL_TIME_GATE           268
+#define EL_TIME_GATE_WHEEL     269
+#define EL_BELT_GREEN_LEFT     270
+#define EL_BELT_GREEN_MIDDLE   271
+#define EL_BELT_GREEN_RIGHT    272
+#define EL_BELT_GREEN_SWITCH   273
+#define EL_BELT_RED_LEFT       274
+#define EL_BELT_RED_MIDDLE     275
+#define EL_BELT_RED_RIGHT      276
+#define EL_BELT_RED_SWITCH     277
+#define EL_BELT_BLUE_LEFT      278
+#define EL_BELT_BLUE_MIDDLE    279
+#define EL_BELT_BLUE_RIGHT     280
+#define EL_BELT_BLUE_SWITCH    281
+#define EL_LANDMINE            282
+#define EL_ENVELOPE            283
+#define EL_LIGHT_SWITCH                284
+#define EL_SIGN_EXCLAMATION    285
+#define EL_SIGN_RADIOACTIVITY  286
+#define EL_SIGN_STOP           287
+#define EL_SIGN_WHEELCHAIR     288
+#define EL_SIGN_PARKING                289
+#define EL_SIGN_ONEWAY         290
+#define EL_SIGN_HEART          291
+#define EL_SIGN_TRIANGLE       292
+#define EL_SIGN_ROUND          293
+#define EL_SIGN_EXIT           294
+#define EL_SIGN_YINYANG                295
+#define EL_SIGN_OTHER          296
+#define EL_MOLE_LEFT           297
+#define EL_MOLE_RIGHT          298
+#define EL_MOLE_UP             299
+#define EL_MOLE_DOWN           300
+#define EL_STEEL_SLANTED       301
+#define EL_SAND_INVISIBLE      302
+
 /* "real" (and therefore drawable) runtime elements */
-#define EL_SIEB_LEER           300
-#define EL_SIEB2_LEER          301
-#define EL_SIEB_VOLL           302
-#define EL_SIEB2_VOLL          303
-#define EL_SIEB_TOT            304
-#define EL_SIEB2_TOT           305
-#define EL_AUSGANG_ACT         306
-#define EL_SP_TERMINAL_ACTIVE  307
-#define EL_SP_BUG_ACTIVE       308
-#define EL_EM_KEY_1            309
-#define EL_EM_KEY_2            310
-#define EL_EM_KEY_3            311
-#define EL_EM_KEY_4            312
-#define EL_DYNABOMB_ACTIVE_1   313
-#define EL_DYNABOMB_ACTIVE_2   314
-#define EL_DYNABOMB_ACTIVE_3   315
-#define EL_DYNABOMB_ACTIVE_4   316
+#define EL_SIEB_LEER           1000
+#define EL_SIEB2_LEER          1001
+#define EL_SIEB_VOLL           1002
+#define EL_SIEB2_VOLL          1003
+#define EL_SIEB_TOT            1004
+#define EL_SIEB2_TOT           1005
+#define EL_AUSGANG_ACT         1006
+#define EL_SP_TERMINAL_ACTIVE  1007
+#define EL_SP_BUG_ACTIVE       1008
+#define EL_EM_KEY_1            1009
+#define EL_EM_KEY_2            1010
+#define EL_EM_KEY_3            1011
+#define EL_EM_KEY_4            1012
+#define EL_DYNABOMB_ACTIVE_1   1013
+#define EL_DYNABOMB_ACTIVE_2   1014
+#define EL_DYNABOMB_ACTIVE_3   1015
+#define EL_DYNABOMB_ACTIVE_4   1016
 
 /* "unreal" (and therefore not drawable) runtime elements */
-#define EL_BLOCKED             400
-#define EL_EXPLODING           401
-#define EL_CRACKINGNUT         402
-#define EL_BLURB_LEFT          403
-#define EL_BLURB_RIGHT         404
-#define EL_AMOEBING            405
-#define EL_MAUERND             406
-#define EL_BURNING             407
-#define EL_PLAYER_IS_LEAVING   408
+#define EL_BLOCKED             2000
+#define EL_EXPLODING           2001
+#define EL_CRACKINGNUT         2002
+#define EL_BLURB_LEFT          2003
+#define EL_BLURB_RIGHT         2004
+#define EL_AMOEBING            2005
+#define EL_MAUERND             2006
+#define EL_BURNING             2007
+#define EL_PLAYER_IS_LEAVING   2008
 
 /* game graphics:
 **       0 -  255: graphics from "RocksScreen"
@@ -1213,6 +1263,55 @@ extern char              *element_info[];
 #define GFX_CHAR_COPY          (GFX_CHAR_ASCII0 + 94)
 #define GFX_CHAR_END           (GFX_CHAR_START + 79)
 
+/* new elements which still have no graphic */
+#define GFX_PEARL              GFX_CHAR_FRAGE
+#define GFX_CRYSTAL            GFX_CHAR_FRAGE
+#define GFX_WALL_PEARL         GFX_CHAR_FRAGE
+#define GFX_WALL_CRYSTAL       GFX_CHAR_FRAGE
+#define GFX_DOOR_WHITE         GFX_CHAR_FRAGE
+#define GFX_DOOR_WHITE_GRAY    GFX_CHAR_FRAGE
+#define GFX_KEY_WHITE          GFX_CHAR_FRAGE
+#define GFX_FORCE_FIELD                GFX_CHAR_FRAGE
+#define GFX_EXTRA_TIME         GFX_CHAR_FRAGE
+#define GFX_SWITCH_GATE_OPEN   GFX_CHAR_FRAGE
+#define GFX_SWITCH_GATE_CLOSED GFX_CHAR_FRAGE
+#define GFX_SWITCH_GATE_SWITCH GFX_CHAR_FRAGE
+#define GFX_TIME_GATE          GFX_CHAR_FRAGE
+#define GFX_TIME_GATE_WHEEL    GFX_CHAR_FRAGE
+#define GFX_BELT_GREEN_LEFT    GFX_CHAR_FRAGE
+#define GFX_BELT_GREEN_MIDDLE  GFX_CHAR_FRAGE
+#define GFX_BELT_GREEN_RIGHT   GFX_CHAR_FRAGE
+#define GFX_BELT_GREEN_SWITCH  GFX_CHAR_FRAGE
+#define GFX_BELT_RED_LEFT      GFX_CHAR_FRAGE
+#define GFX_BELT_RED_MIDDLE    GFX_CHAR_FRAGE
+#define GFX_BELT_RED_RIGHT     GFX_CHAR_FRAGE
+#define GFX_BELT_RED_SWITCH    GFX_CHAR_FRAGE
+#define GFX_BELT_BLUE_LEFT     GFX_CHAR_FRAGE
+#define GFX_BELT_BLUE_MIDDLE   GFX_CHAR_FRAGE
+#define GFX_BELT_BLUE_RIGHT    GFX_CHAR_FRAGE
+#define GFX_BELT_BLUE_SWITCH   GFX_CHAR_FRAGE
+#define GFX_LANDMINE           GFX_CHAR_FRAGE
+#define GFX_ENVELOPE           GFX_CHAR_FRAGE
+#define GFX_LIGHT_SWITCH       GFX_CHAR_FRAGE
+#define GFX_SIGN_EXCLAMATION   GFX_CHAR_FRAGE
+#define GFX_SIGN_RADIOACTIVITY GFX_CHAR_FRAGE
+#define GFX_SIGN_STOP          GFX_CHAR_FRAGE
+#define GFX_SIGN_WHEELCHAIR    GFX_CHAR_FRAGE
+#define GFX_SIGN_PARKING       GFX_CHAR_FRAGE
+#define GFX_SIGN_ONEWAY                GFX_CHAR_FRAGE
+#define GFX_SIGN_HEART         GFX_CHAR_FRAGE
+#define GFX_SIGN_TRIANGLE      GFX_CHAR_FRAGE
+#define GFX_SIGN_ROUND         GFX_CHAR_FRAGE
+#define GFX_SIGN_EXIT          GFX_CHAR_FRAGE
+#define GFX_SIGN_YINYANG       GFX_CHAR_FRAGE
+#define GFX_SIGN_OTHER         GFX_CHAR_FRAGE
+#define GFX_MOLE_LEFT          GFX_CHAR_FRAGE
+#define GFX_MOLE_RIGHT         GFX_CHAR_FRAGE
+#define GFX_MOLE_UP            GFX_CHAR_FRAGE
+#define GFX_MOLE_DOWN          GFX_CHAR_FRAGE
+#define GFX_STEEL_SLANTED      GFX_CHAR_FRAGE
+#define GFX_SAND_INVISIBLE     GFX_CHAR_FRAGE
+
 /* the names of the sounds */
 #define SND_ALCHEMY            0
 #define SND_AMOEBE             1
index 8afe55356e3719947e6a7dbd4b1a5f169d9cae4d..bd1a65f1002f60a94aeb7578c3d542e8f5e9767f 100644 (file)
@@ -839,9 +839,16 @@ static void drawChooseLevelInfo(int leveldir_nr)
   int x, last_redraw_mask = redraw_mask;
 
   XFillRectangle(display, drawto, gc, SX + 32, SY + 32, SXSIZE - 32, 32);
+
+#if 0
   DrawTextFCentered(40, FC_RED, "%3d levels (%s)",
                    leveldir[leveldir_nr].levels,
                    leveldir[leveldir_nr].readonly ? "readonly" : "writable");
+#else
+  DrawTextFCentered(40, FC_RED, "%3d levels (%s)",
+                   leveldir[leveldir_nr].levels,
+                   leveldir[leveldir_nr].class_desc);
+#endif
 
   /* let BackToFront() redraw only what is needed */
   redraw_mask = last_redraw_mask | REDRAW_TILES;
@@ -915,7 +922,7 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
        first_entry = 0;
 
       drawChooseLevelList(first_entry, num_page_entries);
-      drawChooseLevelInfo(first_entry);
+      drawChooseLevelInfo(first_entry + choice - 3);
       DrawGraphic(0, choice - 1, GFX_KUGEL_ROT);
       return;
     }
@@ -930,7 +937,7 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
        first_entry = MAX(0, num_leveldirs - num_page_entries);
 
       drawChooseLevelList(first_entry, num_page_entries);
-      drawChooseLevelInfo(first_entry + num_page_entries - 1);
+      drawChooseLevelInfo(first_entry + choice - 3);
       DrawGraphic(0, choice - 1, GFX_KUGEL_ROT);
       return;
     }
index a5224ae11bfabbbe570dd1f12c898c2a79aebf31..4159ba7e59218f7a3718aa005e0e7c1d243a891e 100644 (file)
@@ -1532,26 +1532,35 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
   redraw_mask |= REDRAW_MICROLEVEL;
 }
 
+#define MICROLABEL_EMPTY               0
+#define MICROLABEL_LEVEL_NAME          1
+#define MICROLABEL_CREATED_BY          2
+#define MICROLABEL_LEVEL_AUTHOR                3
+#define MICROLABEL_IMPORTED_FROM       4
+#define MICROLABEL_LEVEL_IMPORT_INFO   5
+
+#define MAX_MICROLABEL_SIZE            (SXSIZE / FONT4_XSIZE)
+
 static void DrawMicroLevelLabelExt(int mode)
 {
-  char label_text[100];
+  char label_text[MAX_MICROLABEL_SIZE + 1];
 
   XFillRectangle(display, drawto,gc,
                 SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
 
-  strcpy(label_text, (mode == 1 ? level.name :
-                     mode == 2 ? "created by" :
-                     mode == 3 ? level.author : ""));
+  strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
+                      mode == MICROLABEL_CREATED_BY ? "created by" :
+                      mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
+                      mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
+                      mode == MICROLABEL_LEVEL_IMPORT_INFO ?
+                      leveldir[leveldir_nr].imported_from : ""),
+         MAX_MICROLABEL_SIZE);
+  label_text[MAX_MICROLABEL_SIZE] = '\0';
 
   if (strlen(label_text) > 0)
   {
-    int size, lxpos, lypos;
-
-    label_text[SXSIZE / FONT4_XSIZE] = '\0';
-
-    size = strlen(label_text);
-    lxpos = SX + (SXSIZE - size * FONT4_XSIZE) / 2;
-    lypos = MICROLABEL_YPOS;
+    int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
+    int lypos = MICROLABEL_YPOS;
 
     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
   }
@@ -1630,10 +1639,22 @@ void DrawMicroLevel(int xpos, int ypos, boolean restart)
       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
   {
-    label_counter = (label_counter + 1) % 23;
-    label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
-                  label_counter >= 9 && label_counter <= 12 ? 2 :
-                  label_counter >= 14 && label_counter <= 21 ? 3 : 0);
+    int max_label_counter = 23;
+
+    if (leveldir[leveldir_nr].imported_from != NULL)
+      max_label_counter += 14;
+
+    label_counter = (label_counter + 1) % max_label_counter;
+    label_state = (label_counter >= 0 && label_counter <= 7 ?
+                  MICROLABEL_LEVEL_NAME :
+                  label_counter >= 9 && label_counter <= 12 ?
+                  MICROLABEL_CREATED_BY :
+                  label_counter >= 14 && label_counter <= 21 ?
+                  MICROLABEL_LEVEL_AUTHOR :
+                  label_counter >= 23 && label_counter <= 26 ?
+                  MICROLABEL_IMPORTED_FROM :
+                  label_counter >= 28 && label_counter <= 35 ?
+                  MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
     DrawMicroLevelLabelExt(label_state);
   }
 }
@@ -2425,6 +2446,53 @@ int el2gfx(int element)
     case EL_EM_KEY_2:          return GFX_EM_KEY_2;
     case EL_EM_KEY_3:          return GFX_EM_KEY_3;
     case EL_EM_KEY_4:          return GFX_EM_KEY_4;
+    case EL_PEARL:             return GFX_PEARL;
+    case EL_CRYSTAL:           return GFX_CRYSTAL;
+    case EL_WALL_PEARL:                return GFX_WALL_PEARL;
+    case EL_WALL_CRYSTAL:      return GFX_WALL_CRYSTAL;
+    case EL_DOOR_WHITE:                return GFX_DOOR_WHITE;
+    case EL_DOOR_WHITE_GRAY:   return GFX_DOOR_WHITE_GRAY;
+    case EL_KEY_WHITE:         return GFX_KEY_WHITE;
+    case EL_FORCE_FIELD:       return GFX_FORCE_FIELD;
+    case EL_EXTRA_TIME:                return GFX_EXTRA_TIME;
+    case EL_SWITCH_GATE_OPEN:  return GFX_SWITCH_GATE_OPEN;
+    case EL_SWITCH_GATE_CLOSED:        return GFX_SWITCH_GATE_CLOSED;
+    case EL_SWITCH_GATE_SWITCH:        return GFX_SWITCH_GATE_SWITCH;
+    case EL_TIME_GATE:         return GFX_TIME_GATE;
+    case EL_TIME_GATE_WHEEL:   return GFX_TIME_GATE_WHEEL;
+    case EL_BELT_GREEN_LEFT:   return GFX_BELT_GREEN_LEFT;
+    case EL_BELT_GREEN_MIDDLE: return GFX_BELT_GREEN_MIDDLE;
+    case EL_BELT_GREEN_RIGHT:  return GFX_BELT_GREEN_RIGHT;
+    case EL_BELT_GREEN_SWITCH: return GFX_BELT_GREEN_SWITCH;
+    case EL_BELT_RED_LEFT:     return GFX_BELT_RED_LEFT;
+    case EL_BELT_RED_MIDDLE:   return GFX_BELT_RED_MIDDLE;
+    case EL_BELT_RED_RIGHT:    return GFX_BELT_RED_RIGHT;
+    case EL_BELT_RED_SWITCH:   return GFX_BELT_RED_SWITCH;
+    case EL_BELT_BLUE_LEFT:    return GFX_BELT_BLUE_LEFT;
+    case EL_BELT_BLUE_MIDDLE:  return GFX_BELT_BLUE_MIDDLE;
+    case EL_BELT_BLUE_RIGHT:   return GFX_BELT_BLUE_RIGHT;
+    case EL_BELT_BLUE_SWITCH:  return GFX_BELT_BLUE_SWITCH;
+    case EL_LANDMINE:          return GFX_LANDMINE;
+    case EL_ENVELOPE:          return GFX_ENVELOPE;
+    case EL_LIGHT_SWITCH:      return GFX_LIGHT_SWITCH;
+    case EL_SIGN_EXCLAMATION:  return GFX_SIGN_EXCLAMATION;
+    case EL_SIGN_RADIOACTIVITY:        return GFX_SIGN_RADIOACTIVITY;
+    case EL_SIGN_STOP:         return GFX_SIGN_STOP;
+    case EL_SIGN_WHEELCHAIR:   return GFX_SIGN_WHEELCHAIR;
+    case EL_SIGN_PARKING:      return GFX_SIGN_PARKING;
+    case EL_SIGN_ONEWAY:       return GFX_SIGN_ONEWAY;
+    case EL_SIGN_HEART:                return GFX_SIGN_HEART;
+    case EL_SIGN_TRIANGLE:     return GFX_SIGN_TRIANGLE;
+    case EL_SIGN_ROUND:                return GFX_SIGN_ROUND;
+    case EL_SIGN_EXIT:         return GFX_SIGN_EXIT;
+    case EL_SIGN_YINYANG:      return GFX_SIGN_YINYANG;
+    case EL_SIGN_OTHER:                return GFX_SIGN_OTHER;
+    case EL_MOLE_LEFT:         return GFX_MOLE_LEFT;
+    case EL_MOLE_RIGHT:                return GFX_MOLE_RIGHT;
+    case EL_MOLE_UP:           return GFX_MOLE_UP;
+    case EL_MOLE_DOWN:         return GFX_MOLE_DOWN;
+    case EL_STEEL_SLANTED:     return GFX_STEEL_SLANTED;
+    case EL_SAND_INVISIBLE:    return GFX_SAND_INVISIBLE;
 
     default:
     {