rnd-20050525-1-src
[rocksndiamonds.git] / src / screens.c
index 23bfc0c44b7d4027c5e94b361466338dd6d5bede..7d783a9b21a3f672e3f5c13ce5574d63db856b8a 100644 (file)
@@ -51,8 +51,9 @@
 #define INFO_MODE_MUSIC                        2
 #define INFO_MODE_CREDITS              3
 #define INFO_MODE_PROGRAM              4
+#define INFO_MODE_LEVELSET             5
 
-#define MAX_INFO_MODES                 5
+#define MAX_INFO_MODES                 6
 
 /* for various menu stuff  */
 #define MAX_INFO_ELEMENTS_ON_SCREEN    10
@@ -96,12 +97,13 @@ static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
 static int setup_mode = SETUP_MODE_MAIN;
 static int info_mode = INFO_MODE_MAIN;
 
-#define mSX (SX + (game_status >= GAME_MODE_MAIN &&    \
-                  game_status <= GAME_MODE_SETUP ?     \
-                  menu.draw_xoffset[game_status] : menu.draw_xoffset_default))
-#define mSY (SY + (game_status >= GAME_MODE_MAIN &&    \
-                  game_status <= GAME_MODE_SETUP ?     \
-                  menu.draw_yoffset[game_status] : menu.draw_yoffset_default))
+#define DRAW_OFFSET_MODE(x)    (x >= GAME_MODE_MAIN &&                 \
+                                x <= GAME_MODE_SETUP ? x :             \
+                                x == GAME_MODE_PSEUDO_TYPENAME ?       \
+                                GAME_MODE_MAIN : GAME_MODE_DEFAULT)
+
+#define mSX (SX + menu.draw_xoffset[DRAW_OFFSET_MODE(game_status)])
+#define mSY (SY + menu.draw_yoffset[DRAW_OFFSET_MODE(game_status)])
 
 #define NUM_MENU_ENTRIES_ON_SCREEN (menu.list_size[game_status] > 2 ?  \
                                    menu.list_size[game_status] :       \
@@ -200,13 +202,8 @@ static void PlayMenuMusic()
 
 void DrawHeadline()
 {
-  int text1_width = getTextWidth(PROGRAM_TITLE_STRING,     FONT_TITLE_1);
-  int text2_width = getTextWidth(PROGRAM_COPYRIGHT_STRING, FONT_TITLE_2);
-  int x1 = SX + (SXSIZE - text1_width) / 2;
-  int x2 = SX + (SXSIZE - text2_width) / 2;
-
-  DrawText(x1, SY + 8,  PROGRAM_TITLE_STRING,     FONT_TITLE_1);
-  DrawText(x2, SY + 46, PROGRAM_COPYRIGHT_STRING, FONT_TITLE_2);
+  DrawTextSCentered(8,  FONT_TITLE_1, PROGRAM_TITLE_STRING);
+  DrawTextSCentered(46, FONT_TITLE_2, PROGRAM_COPYRIGHT_STRING);
 }
 
 static void ToggleFullscreenIfNeeded()
@@ -237,8 +234,7 @@ void DrawMainMenu()
 {
   static LevelDirTree *leveldir_last_valid = NULL;
   char *name_text = (!options.network && setup.team_mode ? "Team:" : "Name:");
-  int name_width  = getTextWidth("Name:",  FONT_MENU_1);
-  int level_width = getTextWidth("Level:", FONT_MENU_1);
+  int name_width, level_width;
   int i;
 
   UnmapAllGadgets();
@@ -275,7 +271,7 @@ void DrawMainMenu()
   leveldir_last_valid = leveldir_current;
 
   /* needed if last screen (level choice) changed graphics, sounds or music */
-  ReloadCustomArtwork();
+  ReloadCustomArtwork(0);
 
 #ifdef TARGET_SDL
   SetDrawtoField(DRAW_BACKBUFFER);
@@ -305,11 +301,15 @@ void DrawMainMenu()
   DrawText(mSX + 32, mSY + 8*32, "Setup", FONT_MENU_1);
   DrawText(mSX + 32, mSY + 9*32, "Quit", FONT_MENU_1);
 
+  /* calculated after (possible) reload of custom artwork */
+  name_width = getTextWidth(name_text, FONT_MENU_1);
+  level_width = getTextWidth("Level:", FONT_MENU_1);
+
   DrawText(mSX + 32 + name_width, mSY + 2*32, setup.player_name, FONT_INPUT_1);
   DrawText(mSX + level_width + 5 * 32, mSY + 3*32, int2str(level_nr,3),
           FONT_VALUE_1);
 
-  DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, TRUE);
+  DrawMicroLevel(MICROLEVEL_XPOS, MICROLEVEL_YPOS, TRUE);
 
   DrawTextF(mSX + 32 + level_width - 2, mSY + 3*32 + 1, FONT_TEXT_3, "%d-%d",
            leveldir_current->first_level, leveldir_current->last_level);
@@ -323,12 +323,13 @@ void DrawMainMenu()
   }
 
   for (i = 0; i < 8; i++)
-    initCursor(i, (i == 1 || i == 6 ? IMG_MENU_BUTTON_RIGHT :IMG_MENU_BUTTON));
+    initCursor(i, (i == 1 || i == 4 || i == 6 ? IMG_MENU_BUTTON_RIGHT :
+                  IMG_MENU_BUTTON));
 
   drawCursorXY(level_width/32 + 4, 1, IMG_MENU_BUTTON_LEFT);
   drawCursorXY(level_width/32 + 8, 1, IMG_MENU_BUTTON_RIGHT);
 
-  DrawText(SX + 56, SY + 326, "A Game by Artsoft Entertainment", FONT_TITLE_2);
+  DrawTextSCentered(326, FONT_TITLE_2, "A Game by Artsoft Entertainment");
 
   FadeToFront();
   InitAnimation();
@@ -346,6 +347,7 @@ void DrawMainMenu()
   OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
 }
 
+#if 0
 static void gotoTopLevelDir()
 {
   /* move upwards to top level directory */
@@ -374,9 +376,11 @@ static void gotoTopLevelDir()
     leveldir_current = leveldir_current->node_parent;
   }
 }
+#endif
 
 void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 {
+  static unsigned long level_delay = 0;
   static int choice = 5;
   int x = 0;
   int y = choice;
@@ -402,9 +406,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
   if (y == 1 && ((x == 10 && level_nr > leveldir_current->first_level) ||
                 (x == 14 && level_nr < leveldir_current->last_level)) &&
-      button)
+      button && DelayReached(&level_delay, GADGET_FRAME_DELAY))
   {
-    static unsigned long level_delay = 0;
     int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
     int old_level_nr = level_nr;
     int new_level_nr;
@@ -415,11 +418,25 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
     if (new_level_nr > leveldir_current->last_level)
       new_level_nr = leveldir_current->last_level;
 
+#if 1
     if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
+    {
+      /* skipping levels is only allowed when trying to skip single level */
+      if (setup.skip_levels && step == 1 &&
+         Request("Level still unsolved ! Skip despite handicap ?", REQ_ASK))
+      {
+       leveldir_current->handicap_level++;
+       SaveLevelSetup_SeriesInfo();
+      }
+
       new_level_nr = leveldir_current->handicap_level;
+    }
+#else
+    if (setup.handicap && new_level_nr > leveldir_current->handicap_level)
+      new_level_nr = leveldir_current->handicap_level;
+#endif
 
-    if (new_level_nr != old_level_nr &&
-       DelayReached(&level_delay, GADGET_FRAME_DELAY))
+    if (new_level_nr != old_level_nr)
     {
       level_nr = new_level_nr;
 
@@ -427,7 +444,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
               FONT_VALUE_1);
 
       LoadLevel(level_nr);
-      DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, TRUE);
+      DrawMicroLevel(MICROLEVEL_XPOS, MICROLEVEL_YPOS, TRUE);
 
       TapeErase();
       LoadTape(level_nr);
@@ -439,7 +456,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
       DelayReached(&level_delay, 0);   /* reset delay counter */
     }
   }
-  else if (IN_GFX_SCREEN(mx, my) &&
+  else if (IN_VIS_FIELD(x, y) &&
           y >= 0 && y <= 7 && (y != 1 || x < 10))
   {
     if (button)
@@ -466,7 +483,9 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
          SaveLevelSetup_LastSeries();
          SaveLevelSetup_SeriesInfo();
 
+#if 0
          gotoTopLevelDir();
+#endif
 
          DrawChooseLevel();
        }
@@ -495,7 +514,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
        if (setup.autorecord)
          TapeStartRecording();
 
-#if defined(PLATFORM_UNIX)
+#if defined(NETWORK_AVALIABLE)
        if (options.network)
          SendToServer_StartPlaying();
        else
@@ -524,7 +543,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
 
   if (game_status == GAME_MODE_MAIN)
   {
-    DrawMicroLevel(MICROLEV_XPOS, MICROLEV_YPOS, FALSE);
+    DrawMicroLevel(MICROLEVEL_XPOS, MICROLEVEL_YPOS, FALSE);
     DoAnimation();
   }
 }
@@ -561,6 +580,12 @@ static void execInfoProgram()
   DrawInfoScreen();
 }
 
+static void execInfoLevelSet()
+{
+  info_mode = INFO_MODE_LEVELSET;
+  DrawInfoScreen();
+}
+
 static void execExitInfo()
 {
   game_status = GAME_MODE_MAIN;
@@ -573,6 +598,7 @@ static struct TokenInfo info_info_main[] =
   { TYPE_ENTER_SCREEN, execInfoMusic,          "Music Info"            },
   { TYPE_ENTER_SCREEN, execInfoCredits,        "Credits"               },
   { TYPE_ENTER_SCREEN, execInfoProgram,        "Program Info"          },
+  { TYPE_ENTER_SCREEN, execInfoLevelSet,       "Level Set Info"        },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execExitInfo,           "Exit"                  },
 
@@ -678,7 +704,7 @@ void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
       y += dy;
   }
 
-  if (IN_GFX_SCREEN(mx, my) &&
+  if (IN_VIS_FIELD(x, y) &&
       y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY)
   {
     if (button)
@@ -724,7 +750,7 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
     ClearWindow();
     DrawHeadline();
 
-    DrawTextSCentered(100, FONT_TEXT_1, "The game elements:");
+    DrawTextSCentered(100, FONT_TEXT_1, "The Game Elements:");
 
     DrawTextSCentered(SYSIZE - 20, FONT_TEXT_4,
                      "Press any key or button for next page");
@@ -780,7 +806,7 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
       infoscreen_frame[i - start]--;
     }
 
-    if (helpanim_info[j].element == -1)
+    if (helpanim_info[j].element == HELPANIM_LIST_NEXT)
     {
       if (!infoscreen_frame[i - start])
        infoscreen_step[i - start] = 0;
@@ -789,7 +815,7 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
     {
       if (!infoscreen_frame[i - start])
        infoscreen_step[i - start]++;
-      while (helpanim_info[j].element != -1)
+      while (helpanim_info[j].element != HELPANIM_LIST_NEXT)
        j++;
     }
 
@@ -811,8 +837,6 @@ void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
   FrameCounter++;
 }
 
-#if 1
-
 static char *getHelpText(int element, int action, int direction)
 {
   char token[MAX_LINE_LEN];
@@ -830,12 +854,18 @@ static char *getHelpText(int element, int action, int direction)
 
 void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
 {
+#if 0
   int font_nr = FONT_TEXT_2;
-  int max_chars_per_line = 34;
-  int max_lines_per_text = 2;    
-  int sx = mSX + 56;
+#else
+  int font_nr = FONT_LEVEL_NUMBER;
+#endif
+  int font_width = getFontWidth(font_nr);
+  int sx = mSX + MINI_TILEX + TILEX + MINI_TILEX;
   int sy = mSY + 65 + 2 * 32 + 1;
   int ystep = TILEY + 4;
+  int pad_x = sx - SX;
+  int max_chars_per_line = (SXSIZE - pad_x - MINI_TILEX) / font_width;
+  int max_lines_per_text = 2;    
   char *text = NULL;
 
   if (action != -1 && direction != -1)         /* element.action.direction */
@@ -860,48 +890,6 @@ void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
                  max_chars_per_line, max_lines_per_text);
 }
 
-#else
-
-void DrawInfoScreen_HelpText(int element, int action, int direction, int ypos)
-{
-  int font_nr = FONT_TEXT_2;
-  int max_chars_per_line = 34;
-  int max_lines_per_text = 2;    
-  int sx = mSX + 56;
-  int sy = mSY + 65 + 2 * 32 + 1;
-  int ystep = TILEY + 4;
-  char *text;
-
-  /* 1st try: get text for base element */
-  text = getHashEntry(helptext_info, element_info[element].token_name);
-
-  if (text == NULL)
-  {
-    /* 2nd try: get text for element/action/direction */
-    char token[MAX_LINE_LEN];
-
-    strcpy(token, element_info[element].token_name);
-
-    if (action != -1)
-      strcat(token, element_action_info[action].suffix);
-
-    if (direction != -1)
-      strcat(token, element_direction_info[MV_DIR_BIT(direction)].suffix);
-
-    text = getHashEntry(helptext_info, token);
-
-    if (text == NULL)
-      text = "No description available";
-  }
-
-  if (strlen(text) <= max_chars_per_line)      /* only one line of text */
-    sy += getFontHeight(font_nr) / 2;
-
-  DrawTextWrapped(sx, sy + ypos * ystep, text, font_nr,
-                 max_chars_per_line, max_lines_per_text);
-}
-#endif
-
 void DrawInfoScreen_Elements()
 {
   LoadHelpAnimInfo();
@@ -990,7 +978,7 @@ void DrawInfoScreen_Music()
 void HandleInfoScreen_Music(int button)
 {
   static struct MusicFileInfo *list = NULL;
-  int ystart = 150, ystep = 30;
+  int ystart = 150, dy = 30;
   int ybottom = SYSIZE - 20;
   int button_released = !button;
 
@@ -1023,6 +1011,12 @@ void HandleInfoScreen_Music(int button)
 
   if (button_released || button == MB_MENU_INITIALIZE)
   {
+    int y = 0;
+
+    if (button != MB_MENU_INITIALIZE)
+      if (list != NULL)
+       list = list->next;
+
     if (list == NULL)
     {
       info_mode = INFO_MODE_MAIN;
@@ -1036,22 +1030,68 @@ void HandleInfoScreen_Music(int button)
     ClearWindow();
     DrawHeadline();
 
-    DrawTextSCentered(100, FONT_TEXT_1, "The game background music:");
+    if (list->is_sound)
+    {
+      int sound = list->music;
+
+      if (sound_info[sound].loop)
+       PlaySoundLoop(sound);
+      else
+       PlaySound(sound);
 
-    DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2, "Excerpt from");
-    DrawTextFCentered(ystart + 1 * ystep, FONT_TEXT_3, "\"%s\"", list->title);
-    DrawTextSCentered(ystart + 2 * ystep, FONT_TEXT_2, "by");
-    DrawTextFCentered(ystart + 3 * ystep, FONT_TEXT_3, "%s", list->artist);
-    DrawTextSCentered(ystart + 4 * ystep, FONT_TEXT_2, "from the album");
-    DrawTextFCentered(ystart + 5 * ystep, FONT_TEXT_3, "\"%s\"", list->album);
+      DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Sounds:");
+    }
+    else
+    {
+      PlayMusic(list->music);
 
-    DrawTextSCentered(ybottom, FONT_TEXT_4,
-                     "Press any key or button for next page");
+      DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Music:");
+    }
+
+    if (strcmp(list->title, UNKNOWN_NAME) != 0)
+    {
+      if (strcmp(list->title_header, UNKNOWN_NAME) != 0)
+       DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->title_header);
+
+      DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title);
+    }
 
-    PlayMusic(list->music);
+    if (strcmp(list->artist, UNKNOWN_NAME) != 0)
+    {
+      if (strcmp(list->artist_header, UNKNOWN_NAME) != 0)
+       DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->artist_header);
+      else
+       DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "by");
+
+      DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->artist);
+    }
+
+    if (strcmp(list->album, UNKNOWN_NAME) != 0)
+    {
+      if (strcmp(list->album_header, UNKNOWN_NAME) != 0)
+       DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->album_header);
+      else
+       DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the album");
+
+      DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->album);
+    }
+
+    if (strcmp(list->year, UNKNOWN_NAME) != 0)
+    {
+      if (strcmp(list->year_header, UNKNOWN_NAME) != 0)
+       DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, list->year_header);
+      else
+       DrawTextSCentered(ystart + y++ * dy, FONT_TEXT_2, "from the year");
 
-    list = list->next;
+      DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "%s", list->year);
+    }
+
+    DrawTextSCentered(ybottom, FONT_TEXT_4,
+                     "Press any key or button for next page");
   }
+
+  if (list != NULL && list->is_sound && sound_info[list->music].loop)
+    PlaySoundLoop(list->music);
 }
 
 void DrawInfoScreen_Credits()
@@ -1110,7 +1150,7 @@ void DrawInfoScreen_Program()
   ClearWindow();
   DrawHeadline();
 
-  DrawTextSCentered(100, FONT_TEXT_1, "Program information:");
+  DrawTextSCentered(100, FONT_TEXT_1, "Program Information:");
 
   DrawTextSCentered(ystart + 0 * ystep, FONT_TEXT_2,
                    "This game is Freeware!");
@@ -1165,6 +1205,66 @@ void HandleInfoScreen_Program(int button)
   }
 }
 
+void DrawInfoScreen_LevelSet()
+{
+  int ystart = 150;
+  int ybottom = SYSIZE - 20;
+  char *filename = getLevelSetInfoFilename();
+#if 0
+  int font_nr = FONT_TEXT_2;
+#else
+  int font_nr = FONT_LEVEL_NUMBER;
+#endif
+  int font_width = getFontWidth(font_nr);
+  int font_height = getFontHeight(font_nr);
+  int pad_x = 32;
+  int pad_y = ystart;
+  int sx = SX + pad_x;
+  int sy = SY + pad_y;
+  int max_chars_per_line = (SXSIZE - 2 * pad_x) / font_width;
+  int max_lines_per_screen = (SYSIZE - pad_y) / font_height - 1;
+
+  ClearWindow();
+  DrawHeadline();
+
+  DrawTextSCentered(100, FONT_TEXT_1, "Level Set Information:");
+
+  DrawTextSCentered(ybottom, FONT_TEXT_4,
+                   "Press any key or button for info menu");
+
+  if (filename != NULL)
+    DrawTextFromFile(sx, sy, filename, font_nr, max_chars_per_line,
+                    max_lines_per_screen);
+  else
+    DrawTextSCentered(ystart, FONT_TEXT_2,
+                     "No information for this level set.");
+}
+
+void HandleInfoScreen_LevelSet(int button)
+{
+  int button_released = !button;
+
+  if (button == MB_MENU_LEAVE)
+  {
+    info_mode = INFO_MODE_MAIN;
+    DrawInfoScreen();
+
+    return;
+  }
+
+  if (button_released)
+  {
+    FadeSoundsAndMusic();
+
+    info_mode = INFO_MODE_MAIN;
+    DrawInfoScreen();
+  }
+  else
+  {
+    PlayMenuSoundIfLoop();
+  }
+}
+
 void DrawInfoScreen()
 {
   SetMainBackgroundImage(IMG_BACKGROUND_INFO);
@@ -1177,6 +1277,8 @@ void DrawInfoScreen()
     DrawInfoScreen_Credits();
   else if (info_mode == INFO_MODE_PROGRAM)
     DrawInfoScreen_Program();
+  else if (info_mode == INFO_MODE_LEVELSET)
+    DrawInfoScreen_LevelSet();
   else
     DrawInfoScreen_Main();
 
@@ -1197,6 +1299,8 @@ void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
     HandleInfoScreen_Credits(button);
   else if (info_mode == INFO_MODE_PROGRAM)
     HandleInfoScreen_Program(button);
+  else if (info_mode == INFO_MODE_LEVELSET)
+    HandleInfoScreen_LevelSet(button);
   else
     HandleInfoScreen_Main(mx, my, dx, dy, button);
 
@@ -1396,6 +1500,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
   int num_entries = numTreeInfoInGroup(ti);
   int num_page_entries;
   int last_game_status = game_status;  /* save current game status */
+  boolean position_set_by_scrollbar = (dx == 999);
 
   /* force LEVELS draw offset on choose level and artwork setup screen */
   game_status = GAME_MODE_LEVELS;
@@ -1427,7 +1532,7 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
       ti->cl_cursor = entry_pos - ti->cl_first;
     }
 
-    if (dx == 999)     /* first entry is set by scrollbar position */
+    if (position_set_by_scrollbar)
       ti->cl_first = dy;
     else
       AdjustChooseTreeScrollbar(SCREEN_CTRL_ID_SCROLL_VERTICAL,
@@ -1549,7 +1654,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     return;
   }
 
-  if (IN_GFX_SCREEN(mx, my) &&
+  if (!anyScrollbarGadgetActive() &&
+      IN_VIS_FIELD(x, y) &&
       mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
       y >= 0 && y < num_page_entries)
   {
@@ -1784,7 +1890,7 @@ static void execSetupArtwork()
   setup.music_set = artwork.mus_current->identifier;
 
   /* needed if last screen (setup choice) changed graphics, sounds or music */
-  ReloadCustomArtwork();
+  ReloadCustomArtwork(0);
 
   /* needed for displaying artwork name instead of artwork identifier */
   graphics_set_name = artwork.gfx_current->name;
@@ -1857,6 +1963,7 @@ static struct TokenInfo setup_info_game[] =
 {
   { TYPE_SWITCH,       &setup.team_mode,       "Team-Mode:"            },
   { TYPE_SWITCH,       &setup.handicap,        "Handicap:"             },
+  { TYPE_SWITCH,       &setup.skip_levels,     "Skip Levels:"          },
   { TYPE_SWITCH,       &setup.time_limit,      "Timelimit:"            },
   { TYPE_SWITCH,       &setup.autorecord,      "Auto-Record:"          },
   { TYPE_EMPTY,                NULL,                   ""                      },
@@ -1867,9 +1974,12 @@ static struct TokenInfo setup_info_game[] =
 
 static struct TokenInfo setup_info_editor[] =
 {
+#if 0
   { TYPE_STRING,       NULL,                   "Offer Special Elements:"},
+#endif
   { TYPE_SWITCH,       &setup.editor.el_boulderdash,   "BoulderDash:"  },
   { TYPE_SWITCH,       &setup.editor.el_emerald_mine,  "Emerald Mine:" },
+  { TYPE_SWITCH,       &setup.editor.el_emerald_mine_club,"E.M. Club:" },
   { TYPE_SWITCH,       &setup.editor.el_more,          "More:"         },
   { TYPE_SWITCH,       &setup.editor.el_sokoban,       "Sokoban:"      },
   { TYPE_SWITCH,       &setup.editor.el_supaplex,      "Supaplex:"     },
@@ -2123,8 +2233,14 @@ static void DrawSetupScreen_Generic()
        (value_ptr == &setup.fullscreen   && !video.fullscreen_available))
       setup_info[i].type |= TYPE_GHOSTED;
 
+#if 0
+    if (setup_info[i].type & TYPE_STRING ||
+       (setup_info[i].type & TYPE_SWITCH && setup_mode == SETUP_MODE_EDITOR))
+      font_nr = FONT_MENU_2;
+#else
     if (setup_info[i].type & TYPE_STRING)
       font_nr = FONT_MENU_2;
+#endif
 
     DrawText(mSX + 32, mSY + ypos * 32, setup_info[i].text, font_nr);
 
@@ -2204,7 +2320,7 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
       y += dy;
   }
 
-  if (IN_GFX_SCREEN(mx, my) &&
+  if (IN_VIS_FIELD(x, y) &&
       y >= 0 && y < num_setup_info && setup_info[y].type & ~TYPE_SKIP_ENTRY)
   {
     if (button)
@@ -2302,7 +2418,7 @@ static void drawPlayerSetupInputInfo(int player_nr)
     { &custom_key.up,    "Joystick Up"    },
     { &custom_key.down,  "Joystick Down"  },
     { &custom_key.snap,  "Button 1"       },
-    { &custom_key.bomb,  "Button 2"       }
+    { &custom_key.drop,  "Button 2"       }
   };
   static char *joystick_name[MAX_PLAYERS] =
   {
@@ -2316,6 +2432,8 @@ static void drawPlayerSetupInputInfo(int player_nr)
 
   DrawText(mSX+11*32, mSY+2*32, int2str(player_nr +1, 1), FONT_INPUT_1_ACTIVE);
 #if 1
+  ClearRectangleOnBackground(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
+                            TILEX, TILEY);
   DrawGraphicThruMaskExt(drawto, mSX + 8 * TILEX, mSY + 2 * TILEY,
                         PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0);
 #else
@@ -2347,7 +2465,7 @@ static void drawPlayerSetupInputInfo(int player_nr)
   DrawText(mSX+2*32, mSY+8*32, ":", FONT_VALUE_OLD);
   DrawText(mSX+2*32, mSY+9*32, ":", FONT_VALUE_OLD);
   DrawText(mSX+32, mSY+10*32, "Snap Field:", FONT_VALUE_OLD);
-  DrawText(mSX+32, mSY+12*32, "Place Bomb:", FONT_VALUE_OLD);
+  DrawText(mSX+32, mSY+12*32, "Drop Element:", FONT_VALUE_OLD);
 
   for (i = 0; i < 6; i++)
   {
@@ -2409,7 +2527,7 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
       y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
   }
 
-  if (IN_GFX_SCREEN(mx, my) &&
+  if (IN_VIS_FIELD(x, y) &&
       y == 0 && ((x < 10 && !button) || ((x == 10 || x == 12) && button)))
   {
     static unsigned long delay = 0;
@@ -2421,7 +2539,7 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
 
     drawPlayerSetupInputInfo(player_nr);
   }
-  else if (IN_GFX_SCREEN(mx, my) &&
+  else if (IN_VIS_FIELD(x, y) &&
           y >= pos_start && y <= pos_end &&
           !(y >= pos_empty1 && y <= pos_empty2))
   {
@@ -2493,12 +2611,12 @@ void CustomizeKeyboard(int player_nr)
     char *text;
   } customize_step[] =
   {
-    { &custom_key.left,  "Move Left"  },
-    { &custom_key.right, "Move Right" },
-    { &custom_key.up,    "Move Up"    },
-    { &custom_key.down,  "Move Down"  },
-    { &custom_key.snap,  "Snap Field" },
-    { &custom_key.bomb,  "Place Bomb" }
+    { &custom_key.left,  "Move Left"   },
+    { &custom_key.right, "Move Right"  },
+    { &custom_key.up,    "Move Up"     },
+    { &custom_key.down,  "Move Down"   },
+    { &custom_key.snap,  "Snap Field"  },
+    { &custom_key.drop,  "Drop Element"        }
   };
 
   /* read existing key bindings from player setup */
@@ -2849,17 +2967,133 @@ void HandleGameActions()
   if (game_status != GAME_MODE_PLAYING)
     return;
 
-  if (local_player->LevelSolved)
-    GameWon();
+  /* !!! FIX THIS (START) !!! */
+  if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+  {
+    byte *recorded_player_action;
+    byte summarized_player_action = 0;
+    byte tape_action[MAX_PLAYERS];
+    int i;
+
+    if (level.native_em_level->lev->home == 0) /* all players at home */
+    {
+      GameWon();
 
-  if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
-    TapeStop();
+      if (!TAPE_IS_STOPPED(tape))
+       TapeStop();
 
-  GameActions();
-  BackToFront();
+      if (game_status != GAME_MODE_PLAYING)
+       return;
+    }
+
+    if (level.native_em_level->ply1->alive == 0 &&
+       level.native_em_level->ply2->alive == 0)        /* all dead */
+      AllPlayersGone = TRUE;
+
+    if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
+      TapeStop();
+
+    /* --- game actions --- */
 
-  if (tape.auto_play && !tape.playing)
-    AutoPlayTape();    /* continue automatically playing next tape */
+    if (tape.pausing)
+    {
+      /* don't use 100% CPU while in pause mode -- this should better be solved
+        like in the R'n'D game engine! */
+
+      Delay(10);
+
+      return;
+    }
+
+    recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
+
+#if 1
+    /* !!! CHECK THIS (tape.pausing is always FALSE here!) !!! */
+    if (recorded_player_action == NULL && tape.pausing)
+      return;
+#endif
+
+    for (i = 0; i < MAX_PLAYERS; i++)
+    {
+      summarized_player_action |= stored_player[i].action;
+
+      if (!network_playing)
+       stored_player[i].effective_action = stored_player[i].action;
+    }
+
+    if (!options.network && !setup.team_mode)
+      local_player->effective_action = summarized_player_action;
+
+    if (recorded_player_action != NULL)
+      for (i = 0; i < MAX_PLAYERS; i++)
+       stored_player[i].effective_action = recorded_player_action[i];
+
+    for (i = 0; i < MAX_PLAYERS; i++)
+    {
+      tape_action[i] = stored_player[i].effective_action;
+
+      /* !!! (this does not happen in the EM engine) !!! */
+      if (tape.recording && tape_action[i] && !tape.player_participates[i])
+       tape.player_participates[i] = TRUE;  /* player just appeared from CE */
+    }
+
+    /* only save actions from input devices, but not programmed actions */
+    if (tape.recording)
+      TapeRecordAction(tape_action);
+
+    GameActions_EM(local_player->effective_action);
+
+    if (TimeFrames >= FRAMES_PER_SECOND)
+    {
+      TimeFrames = 0;
+      TapeTime++;
+
+      if (!level.use_step_counter)
+      {
+       TimePlayed++;
+
+       if (TimeLeft > 0)
+       {
+         TimeLeft--;
+
+         if (TimeLeft <= 10 && setup.time_limit)
+           PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
+
+         DrawGameValue_Time(TimeLeft);
+
+         if (!TimeLeft && setup.time_limit)
+           level.native_em_level->lev->killed_out_of_time = TRUE;
+       }
+       else if (level.time == 0 && level.native_em_level->lev->home > 0)
+         DrawGameValue_Time(TimePlayed);
+
+       level.native_em_level->lev->time =
+         (level.time == 0 ? TimePlayed : TimeLeft);
+      }
+
+      if (tape.recording || tape.playing)
+       DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
+    }
+
+    FrameCounter++;
+    TimeFrames++;
+
+    BackToFront();
+  }
+  else
+  {
+    if (local_player->LevelSolved)
+      GameWon();
+
+    if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
+      TapeStop();
+
+    GameActions();
+    BackToFront();
+
+    if (tape.auto_play && !tape.playing)
+      AutoPlayTape();  /* continue automatically playing next tape */
+  }
 }
 
 /* ---------- new screen button stuff -------------------------------------- */