rnd-20050525-1-src
[rocksndiamonds.git] / src / screens.c
index 346bb9276d04f99b1466d85d8fc96284a2249234..7d783a9b21a3f672e3f5c13ce5574d63db856b8a 100644 (file)
 #define SETUPINPUT_SCREEN_POS_EMPTY2   (SETUPINPUT_SCREEN_POS_END - 1)
 
 /* screens on the info screen */
-#define INFO_MODE_ELEMENTS             0
-#define INFO_MODE_MUSIC                        1
-#define INFO_MODE_CREDITS              2
-#define INFO_MODE_PROGRAM              3
+#define INFO_MODE_MAIN                 0
+#define INFO_MODE_ELEMENTS             1
+#define INFO_MODE_MUSIC                        2
+#define INFO_MODE_CREDITS              3
+#define INFO_MODE_PROGRAM              4
+#define INFO_MODE_LEVELSET             5
 
-#define MAX_INFO_MODES                 4
+#define MAX_INFO_MODES                 6
 
 /* for various menu stuff  */
 #define MAX_INFO_ELEMENTS_ON_SCREEN    10
@@ -77,28 +79,31 @@ static void CalibrateJoystick(int);
 static void execSetupArtwork(void);
 static void HandleChooseTree(int, int, int, int, int, TreeInfo **);
 
-static void DrawInfoScreenDemoAnim(int, boolean);
-static void DrawInfoScreenDemoText(int, int, int, int);
-static void DrawInfoScreenMusicText(int);
-static void DrawInfoScreenCreditsText(void);
+static void DrawChooseLevel(void);
 static void DrawInfoScreen(void);
+static void DrawSetupScreen(void);
+
+static void DrawInfoScreen_HelpAnim(int, int, boolean);
+static void DrawInfoScreen_HelpText(int, int, int, int);
+static void HandleInfoScreen_Main(int, int, int, int, int);
+static void HandleInfoScreen_Elements(int);
+static void HandleInfoScreen_Music(int);
+static void HandleInfoScreen_Credits(int);
+static void HandleInfoScreen_Program(int);
+
+static void MapChooseTreeGadgets(TreeInfo *);
 
 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
 static int setup_mode = SETUP_MODE_MAIN;
+static int info_mode = INFO_MODE_MAIN;
 
-static long infoscreen_state;
-static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
-static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
-static int num_infoscreen_elements;
-static int num_infoscreen_music;
-static int infoscreen_musicpos;
+#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 + (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 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] :       \
@@ -197,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()
@@ -234,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();
@@ -272,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);
@@ -302,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);
@@ -320,16 +323,18 @@ 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();
-  HandleMainMenu(0,0, 0,0, MB_MENU_INITIALIZE);
+
+  HandleMainMenu(0, 0, 0, 0, MB_MENU_INITIALIZE);
 
   TapeStop();
   if (TAPE_IS_EMPTY(tape))
@@ -340,12 +345,9 @@ void DrawMainMenu()
   PlayMenuMusic();
 
   OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
-
-#if 0
-  ClearEventQueue();
-#endif
 }
 
+#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,8 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
       DelayReached(&level_delay, 0);   /* reset delay counter */
     }
   }
-  else if (x == 0 && y >= 0 && y <= 7)
+  else if (IN_VIS_FIELD(x, y) &&
+          y >= 0 && y <= 7 && (y != 1 || x < 10))
   {
     if (button)
     {
@@ -465,7 +483,9 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
          SaveLevelSetup_LastSeries();
          SaveLevelSetup_SeriesInfo();
 
+#if 0
          gotoTopLevelDir();
+#endif
 
          DrawChooseLevel();
        }
@@ -486,6 +506,7 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
       else if (y == 4)
       {
        game_status = GAME_MODE_INFO;
+       info_mode = INFO_MODE_MAIN;
        DrawInfoScreen();
       }
       else if (y == 5)
@@ -493,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
@@ -522,16 +543,195 @@ 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();
   }
+}
 
-  BackToFront();
+
+/* ========================================================================= */
+/* info screen functions                                                     */
+/* ========================================================================= */
+
+static struct TokenInfo *info_info;
+static int num_info_info;
+
+static void execInfoElements()
+{
+  info_mode = INFO_MODE_ELEMENTS;
+  DrawInfoScreen();
+}
+
+static void execInfoMusic()
+{
+  info_mode = INFO_MODE_MUSIC;
+  DrawInfoScreen();
+}
+
+static void execInfoCredits()
+{
+  info_mode = INFO_MODE_CREDITS;
+  DrawInfoScreen();
+}
+
+static void execInfoProgram()
+{
+  info_mode = INFO_MODE_PROGRAM;
+  DrawInfoScreen();
+}
+
+static void execInfoLevelSet()
+{
+  info_mode = INFO_MODE_LEVELSET;
+  DrawInfoScreen();
+}
+
+static void execExitInfo()
+{
+  game_status = GAME_MODE_MAIN;
+  DrawMainMenu();
+}
+
+static struct TokenInfo info_info_main[] =
+{
+  { TYPE_ENTER_SCREEN, execInfoElements,       "Elements Info"         },
+  { 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"                  },
+
+  { 0,                 NULL,                   NULL                    }
+};
+
+static void DrawInfoScreen_Main()
+{
+  int i;
+
+  UnmapAllGadgets();
+  CloseDoor(DOOR_CLOSE_2);
+
+  ClearWindow();
+
+  DrawText(mSX + 16, mSY + 16, "Info Screen", FONT_TITLE_1);
+
+  info_info = info_info_main;
+  num_info_info = 0;
+
+  for (i = 0; info_info[i].type != 0 && i < NUM_MENU_ENTRIES_ON_SCREEN; i++)
+  {
+    int ypos = MENU_SCREEN_START_YPOS + i;
+    int font_nr = FONT_MENU_1;
+
+    DrawText(mSX + 32, mSY + ypos * 32, info_info[i].text, font_nr);
+
+    if (info_info[i].type & TYPE_ENTER_MENU)
+      initCursor(i, IMG_MENU_BUTTON_RIGHT);
+    else if (info_info[i].type & TYPE_LEAVE_MENU)
+      initCursor(i, IMG_MENU_BUTTON_LEFT);
+    else if (info_info[i].type & ~TYPE_SKIP_ENTRY)
+      initCursor(i, IMG_MENU_BUTTON);
+
+    num_info_info++;
+  }
+
+  FadeToFront();
+  InitAnimation();
+
+  PlayMenuSound();
+  PlayMenuMusic();
+
+  HandleInfoScreen_Main(0, 0, 0, 0, MB_MENU_INITIALIZE);
 }
 
-void DrawInfoScreenDemoAnim(int start, boolean init)
+void HandleInfoScreen_Main(int mx, int my, int dx, int dy, int button)
 {
-  int i = 0, j = 0;
+  static int choice_store[MAX_INFO_MODES];
+  int choice = choice_store[info_mode];                /* always starts with 0 */
+  int x = 0;
+  int y = choice;
+
+  if (button == MB_MENU_INITIALIZE)
+  {
+    /* advance to first valid menu entry */
+    while (choice < num_info_info &&
+          info_info[choice].type & TYPE_SKIP_ENTRY)
+      choice++;
+    choice_store[info_mode] = choice;
+
+    drawCursor(choice, FC_RED);
+    return;
+  }
+  else if (button == MB_MENU_LEAVE)
+  {
+    for (y = 0; y < num_info_info; y++)
+    {
+      if (info_info[y].type & TYPE_LEAVE_MENU)
+      {
+       void (*menu_callback_function)(void) = info_info[y].value;
+
+       menu_callback_function();
+       break;  /* absolutely needed because function changes 'info_info'! */
+      }
+    }
+
+    return;
+  }
+
+  if (mx || my)                /* mouse input */
+  {
+    x = (mx - mSX) / 32;
+    y = (my - mSY) / 32 - MENU_SCREEN_START_YPOS;
+  }
+  else if (dx || dy)   /* keyboard input */
+  {
+    if (dx)
+    {
+      int menu_navigation_type = (dx < 0 ? TYPE_LEAVE_MENU : TYPE_ENTER_MENU);
+
+      if (info_info[choice].type & menu_navigation_type ||
+         info_info[choice].type & TYPE_ENTER_SCREEN ||
+         info_info[choice].type & TYPE_BOOLEAN_STYLE)
+       button = MB_MENU_CHOICE;
+    }
+    else if (dy)
+      y = choice + dy;
+
+    /* jump to next non-empty menu entry (up or down) */
+    while (y > 0 && y < num_info_info - 1 &&
+          info_info[y].type & TYPE_SKIP_ENTRY)
+      y += dy;
+  }
+
+  if (IN_VIS_FIELD(x, y) &&
+      y >= 0 && y < num_info_info && info_info[y].type & ~TYPE_SKIP_ENTRY)
+  {
+    if (button)
+    {
+      if (y != choice)
+      {
+       drawCursor(y, FC_RED);
+       drawCursor(choice, FC_BLUE);
+       choice = choice_store[info_mode] = y;
+      }
+    }
+    else if (!(info_info[y].type & TYPE_GHOSTED))
+    {
+      if (info_info[y].type & TYPE_ENTER_OR_LEAVE_MENU)
+      {
+       void (*menu_callback_function)(void) = info_info[choice].value;
+
+       menu_callback_function();
+      }
+    }
+  }
+}
+
+void DrawInfoScreen_HelpAnim(int start, int max_anims, boolean init)
+{
+  static int infoscreen_step[MAX_INFO_ELEMENTS_ON_SCREEN];
+  static int infoscreen_frame[MAX_INFO_ELEMENTS_ON_SCREEN];
   int xstart = mSX + 16;
   int ystart = mSY + 64 + 2 * 32;
   int ystep = TILEY + 4;
@@ -539,23 +739,30 @@ void DrawInfoScreenDemoAnim(int start, boolean init)
   int graphic;
   int delay;
   int sync_frame;
+  int i, j;
 
   if (init)
   {
+    for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
+      infoscreen_step[i] = infoscreen_frame[i] = 0;
+
     SetMainBackgroundImage(IMG_BACKGROUND_INFO);
     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");
+
+    FrameCounter = 0;
   }
 
+  i = j = 0;
   while (helpanim_info[j].element != HELPANIM_LIST_END)
   {
     if (i >= start + MAX_INFO_ELEMENTS_ON_SCREEN ||
-       i >= num_infoscreen_elements)
+       i >= max_anims)
       break;
     else if (i < start)
     {
@@ -599,7 +806,7 @@ void DrawInfoScreenDemoAnim(int start, 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;
@@ -608,7 +815,7 @@ void DrawInfoScreenDemoAnim(int start, 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++;
     }
 
@@ -620,7 +827,7 @@ void DrawInfoScreenDemoAnim(int start, boolean init)
                            graphic, sync_frame, USE_MASKING);
 
     if (init)
-      DrawInfoScreenDemoText(element, action, direction, i - start);
+      DrawInfoScreen_HelpText(element, action, direction, i - start);
 
     i++;
   }
@@ -630,81 +837,270 @@ void DrawInfoScreenDemoAnim(int start, boolean init)
   FrameCounter++;
 }
 
-void DrawInfoScreenDemoText(int element, int action, int direction, int ypos)
+static char *getHelpText(int element, int action, int 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);
+
+  return getHashEntry(helptext_info, token);
+}
+
+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;
-  char *text;
-
-  text = getHashEntry(helptext_info, element_info[element].token_name);
-
-  if (text == NULL)
-  {
-    char token[MAX_LINE_LEN];
+  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;
 
-    strcpy(token, element_info[element].token_name);
+  if (action != -1 && direction != -1)         /* element.action.direction */
+    text = getHelpText(element, action, direction);
 
-    if (action != -1)
-      strcat(token, element_action_info[action].suffix);
+  if (text == NULL && action != -1)            /* element.action */
+    text = getHelpText(element, action, -1);
 
-    if (direction != -1)
-      strcat(token, element_direction_info[MV_DIR_BIT(direction)].suffix);
+  if (text == NULL && direction != -1)         /* element.direction */
+    text = getHelpText(element, -1, direction);
 
-    text = getHashEntry(helptext_info, token);
+  if (text == NULL)                            /* base element */
+    text = getHelpText(element, -1, -1);
 
-    if (text == NULL)
-      text = "No description available";
-  }
+  if (text == NULL)                            /* not found */
+    text = "No description available";
 
-  if (strlen(text) <= max_chars_per_line)
+  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);
 }
 
-void DrawInfoScreenMusicText(int num)
+void DrawInfoScreen_Elements()
 {
-  struct MusicFileInfo *list = music_file_info;
-  int ystart = 150, ystep = 30;
-  int ybottom = SYSIZE - 20;
+  LoadHelpAnimInfo();
+  LoadHelpTextInfo();
+
+  HandleInfoScreen_Elements(MB_MENU_INITIALIZE);
+
+  FadeToFront();
+  InitAnimation();
+}
+
+void HandleInfoScreen_Elements(int button)
+{
+  static unsigned long info_delay = 0;
+  static int num_anims;
+  static int num_pages;
+  static int page;
+  int anims_per_page = MAX_INFO_ELEMENTS_ON_SCREEN;
+  int button_released = !button;
   int i;
 
-  for (i=0; i < num && list; i++)
-    list = list->next;
+  if (button == MB_MENU_INITIALIZE)
+  {
+    boolean new_element = TRUE;
 
-  FadeSoundsAndMusic();
+    num_anims = 0;
+    for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
+    {
+      if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
+       new_element = TRUE;
+      else if (new_element)
+      {
+       num_anims++;
+       new_element = FALSE;
+      }
+    }
+
+    num_pages = (num_anims + anims_per_page - 1) / anims_per_page;
+    page = 0;
+  }
+  else if (button == MB_MENU_LEAVE)
+  {
+    info_mode = INFO_MODE_MAIN;
+    DrawInfoScreen();
+
+    return;
+  }
+
+  if (button_released || button == MB_MENU_INITIALIZE)
+  {
+    if (button != MB_MENU_INITIALIZE)
+      page++;
+
+    if (page >= num_pages)
+    {
+      FadeSoundsAndMusic();
+
+      info_mode = INFO_MODE_MAIN;
+      DrawInfoScreen();
+
+      return;
+    }
+
+    DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, TRUE);
+  }
+  else
+  {
+    if (DelayReached(&info_delay, GAME_FRAME_DELAY))
+      if (page < num_pages)
+       DrawInfoScreen_HelpAnim(page * anims_per_page, num_anims, FALSE);
+
+    PlayMenuSoundIfLoop();
+  }
+}
+
+void DrawInfoScreen_Music()
+{
   ClearWindow();
   DrawHeadline();
 
-  DrawTextSCentered(100, FONT_TEXT_1, "The game background music loops:");
+  LoadMusicInfo();
 
-  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);
+  HandleInfoScreen_Music(MB_MENU_INITIALIZE);
+}
 
-  DrawTextSCentered(ybottom, FONT_TEXT_4,
-                   "Press any key or button for next page");
+void HandleInfoScreen_Music(int button)
+{
+  static struct MusicFileInfo *list = NULL;
+  int ystart = 150, dy = 30;
+  int ybottom = SYSIZE - 20;
+  int button_released = !button;
 
-  /* !!! add playing music !!! */
-#if 0
-  PlaySoundLoop(background_loop[num]);
-#endif
+  if (button == MB_MENU_INITIALIZE)
+  {
+    list = music_file_info;
+
+    if (list == NULL)
+    {
+      FadeSoundsAndMusic();
+
+      ClearWindow();
+      DrawHeadline();
+
+      DrawTextSCentered(100, FONT_TEXT_1, "No music info for this level set.");
+
+      DrawTextSCentered(ybottom, FONT_TEXT_4,
+                       "Press any key or button for info menu");
+
+      return;
+    }
+  }
+  else if (button == MB_MENU_LEAVE)
+  {
+    info_mode = INFO_MODE_MAIN;
+    DrawInfoScreen();
+
+    return;
+  }
+
+  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;
+      DrawInfoScreen();
+
+      return;
+    }
+
+    FadeSoundsAndMusic();
+
+    ClearWindow();
+    DrawHeadline();
+
+    if (list->is_sound)
+    {
+      int sound = list->music;
+
+      if (sound_info[sound].loop)
+       PlaySoundLoop(sound);
+      else
+       PlaySound(sound);
+
+      DrawTextSCentered(100, FONT_TEXT_1, "The Game Background Sounds:");
+    }
+    else
+    {
+      PlayMusic(list->music);
+
+      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);
+    }
+
+    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");
+
+      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 DrawInfoScreenCreditsText()
+void DrawInfoScreen_Credits()
 {
   int ystart = 150, ystep = 30;
   int ybottom = SYSIZE - 20;
 
   FadeSoundsAndMusic();
+
   ClearWindow();
   DrawHeadline();
 
@@ -718,10 +1114,35 @@ void DrawInfoScreenCreditsText()
   DrawTextSCentered(ystart + 6 * ystep, FONT_TEXT_2, "of new levels!");
 
   DrawTextSCentered(ybottom, FONT_TEXT_4,
-                   "Press any key or button for next page");
+                   "Press any key or button for info menu");
 }
 
-void DrawInfoScreenContactText()
+void HandleInfoScreen_Credits(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_Program()
 {
   int ystart = 150, ystep = 30;
   int ybottom = SYSIZE - 20;
@@ -729,7 +1150,7 @@ void DrawInfoScreenContactText()
   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!");
@@ -756,155 +1177,141 @@ void DrawInfoScreenContactText()
                    ":-)");
 
   DrawTextSCentered(ybottom, FONT_TEXT_4,
-                   "Press any key or button for main menu");
+                   "Press any key or button for info menu");
 }
 
-#if 1
-void DrawInfoScreen()
+void HandleInfoScreen_Program(int button)
 {
-  struct MusicFileInfo *list;
-  int i;
-
-  UnmapAllGadgets();
-  CloseDoor(DOOR_CLOSE_2);
-
-  for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
-    infoscreen_step[i] = infoscreen_frame[i] = 0;
-  infoscreen_musicpos = 0;
-  infoscreen_state = 0;
-
-  LoadHelpAnimInfo();
-  LoadHelpTextInfo();
-  LoadMusicInfo();
-
-  num_infoscreen_elements = 0;
-  for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
-    if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
-      num_infoscreen_elements++;
+  int button_released = !button;
 
-  num_infoscreen_music = 0;
-  for (list = music_file_info; list != NULL; list = list->next)
-    num_infoscreen_music++;
+  if (button == MB_MENU_LEAVE)
+  {
+    info_mode = INFO_MODE_MAIN;
+    DrawInfoScreen();
 
-  DrawInfoScreenDemoAnim(0, TRUE);
-#if 0
-  DrawInfoScreenDemoText(0);
-#endif
+    return;
+  }
 
-  FadeToFront();
-  InitAnimation();
+  if (button_released)
+  {
+    FadeSoundsAndMusic();
 
-  PlayMenuSound();
-  PlayMenuMusic();
+    info_mode = INFO_MODE_MAIN;
+    DrawInfoScreen();
+  }
+  else
+  {
+    PlayMenuSoundIfLoop();
+  }
 }
 
-#else
-
-void DrawInfoScreen()
+void DrawInfoScreen_LevelSet()
 {
-  struct MusicFileInfo *list;
-  int i;
-
-  UnmapAllGadgets();
-  CloseDoor(DOOR_CLOSE_2);
-
-  for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
-    infoscreen_step[i] = infoscreen_frame[i] = 0;
-  infoscreen_musicpos = 0;
-  infoscreen_state = 0;
-
-  LoadHelpAnimInfo();
-  LoadHelpTextInfo();
-  LoadMusicInfo();
-
-  num_infoscreen_elements = 0;
-  for (i = 0; helpanim_info[i].element != HELPANIM_LIST_END; i++)
-    if (helpanim_info[i].element == HELPANIM_LIST_NEXT)
-      num_infoscreen_elements++;
-
-  num_infoscreen_music = 0;
-  for (list = music_file_info; list != NULL; list = list->next)
-    num_infoscreen_music++;
-
-  DrawInfoScreenDemoAnim(0, TRUE);
+  int ystart = 150;
+  int ybottom = SYSIZE - 20;
+  char *filename = getLevelSetInfoFilename();
 #if 0
-  DrawInfoScreenDemoText(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;
 
-  FadeToFront();
-  InitAnimation();
+  ClearWindow();
+  DrawHeadline();
 
-  PlayMenuSound();
-  PlayMenuMusic();
+  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.");
 }
-#endif
 
-void HandleInfoScreen(int button)
+void HandleInfoScreen_LevelSet(int button)
 {
-  static unsigned long hs_delay = 0;
-  int num_infoscreen_element_pages =
-    (num_infoscreen_elements + MAX_INFO_ELEMENTS_ON_SCREEN - 1)
-    / MAX_INFO_ELEMENTS_ON_SCREEN;
   int button_released = !button;
-  int i;
 
-  if (button_released)
+  if (button == MB_MENU_LEAVE)
   {
-    if (infoscreen_state < num_infoscreen_element_pages - 1)
-    {
-      for (i = 0; i < MAX_INFO_ELEMENTS_ON_SCREEN; i++)
-       infoscreen_step[i] = infoscreen_frame[i] = 0;
-      infoscreen_state++;
+    info_mode = INFO_MODE_MAIN;
+    DrawInfoScreen();
 
-      FrameCounter = 0;
-      DrawInfoScreenDemoAnim(infoscreen_state * MAX_INFO_ELEMENTS_ON_SCREEN,
-                            TRUE);
-#if 0
-      DrawInfoScreenDemoText(infoscreen_state * MAX_INFO_ELEMENTS_ON_SCREEN);
-#endif
-    }
-    else if (infoscreen_state <
-            num_infoscreen_element_pages + num_infoscreen_music - 1)
-    {
-      infoscreen_state++;
-      DrawInfoScreenMusicText(infoscreen_state - num_infoscreen_element_pages);
-    }
-    else if (infoscreen_state ==
-            num_infoscreen_element_pages + num_infoscreen_music - 1)
-    {
-      infoscreen_state++;
-      DrawInfoScreenCreditsText();
-    }
-    else if (infoscreen_state ==
-            num_infoscreen_element_pages + num_infoscreen_music)
-    {
-      infoscreen_state++;
-      DrawInfoScreenContactText();
-    }
-    else
-    {
-      FadeSoundsAndMusic();
+    return;
+  }
 
-      game_status = GAME_MODE_MAIN;
-      DrawMainMenu();
-    }
+  if (button_released)
+  {
+    FadeSoundsAndMusic();
+
+    info_mode = INFO_MODE_MAIN;
+    DrawInfoScreen();
   }
   else
   {
-    if (DelayReached(&hs_delay, GAME_FRAME_DELAY))
-    {
-      if (infoscreen_state < num_infoscreen_element_pages)
-       DrawInfoScreenDemoAnim(infoscreen_state * MAX_INFO_ELEMENTS_ON_SCREEN,
-                              FALSE);
-    }
-
     PlayMenuSoundIfLoop();
   }
+}
+
+void DrawInfoScreen()
+{
+  SetMainBackgroundImage(IMG_BACKGROUND_INFO);
+
+  if (info_mode == INFO_MODE_ELEMENTS)
+    DrawInfoScreen_Elements();
+  else if (info_mode == INFO_MODE_MUSIC)
+    DrawInfoScreen_Music();
+  else if (info_mode == INFO_MODE_CREDITS)
+    DrawInfoScreen_Credits();
+  else if (info_mode == INFO_MODE_PROGRAM)
+    DrawInfoScreen_Program();
+  else if (info_mode == INFO_MODE_LEVELSET)
+    DrawInfoScreen_LevelSet();
+  else
+    DrawInfoScreen_Main();
+
+  if (info_mode != INFO_MODE_MUSIC)
+  {
+    PlayMenuSound();
+    PlayMenuMusic();
+  }
+}
+
+void HandleInfoScreen(int mx, int my, int dx, int dy, int button)
+{
+  if (info_mode == INFO_MODE_ELEMENTS)
+    HandleInfoScreen_Elements(button);
+  else if (info_mode == INFO_MODE_MUSIC)
+    HandleInfoScreen_Music(button);
+  else if (info_mode == INFO_MODE_CREDITS)
+    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);
 
   DoAnimation();
-  BackToFront();
 }
 
+
+/* ========================================================================= */
+/* type name functions                                                       */
+/* ========================================================================= */
+
 void HandleTypeName(int newxpos, Key key)
 {
   static int xpos = 0, ypos = 2;
@@ -956,10 +1363,13 @@ void HandleTypeName(int newxpos, Key key)
     SaveSetup();
     game_status = GAME_MODE_MAIN;
   }
-
-  BackToFront();
 }
 
+
+/* ========================================================================= */
+/* tree menu functions                                                       */
+/* ========================================================================= */
+
 static void DrawChooseTree(TreeInfo **ti_ptr)
 {
   UnmapAllGadgets();
@@ -971,7 +1381,7 @@ static void DrawChooseTree(TreeInfo **ti_ptr)
 
   ClearWindow();
 
-  HandleChooseTree(0,0, 0,0, MB_MENU_INITIALIZE, ti_ptr);
+  HandleChooseTree(0, 0, 0, 0, MB_MENU_INITIALIZE, ti_ptr);
   MapChooseTreeGadgets(*ti_ptr);
 
   FadeToFront();
@@ -1090,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;
@@ -1121,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,
@@ -1243,7 +1654,10 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     return;
   }
 
-  if (x == 0 && y >= 0 && y < num_page_entries)
+  if (!anyScrollbarGadgetActive() &&
+      IN_VIS_FIELD(x, y) &&
+      mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
+      y >= 0 && y < num_page_entries)
   {
     if (button)
     {
@@ -1302,13 +1716,6 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
       }
     }
   }
-
-#if 0
-  if (game_status == GAME_MODE_LEVELS || game_status == GAME_MODE_SETUP)
-    DoAnimation();
-
-  BackToFront();
-#endif
 }
 
 void DrawChooseLevel()
@@ -1326,7 +1733,6 @@ void HandleChooseLevel(int mx, int my, int dx, int dy, int button)
   HandleChooseTree(mx, my, dx, dy, button, &leveldir_current);
 
   DoAnimation();
-  BackToFront();
 }
 
 void DrawHallOfFame(int highlight_position)
@@ -1341,10 +1747,10 @@ void DrawHallOfFame(int highlight_position)
   FadeToFront();
   InitAnimation();
 
-  HandleHallOfFame(highlight_position,0, 0,0, MB_MENU_INITIALIZE);
-
   PlayMenuSound();
   PlayMenuMusic();
+
+  HandleHallOfFame(highlight_position, 0, 0, 0, MB_MENU_INITIALIZE);
 }
 
 static void drawHallOfFameList(int first_entry, int highlight_position)
@@ -1433,7 +1839,6 @@ void HandleHallOfFame(int mx, int my, int dx, int dy, int button)
     PlayMenuSoundIfLoop();
 
   DoAnimation();
-  BackToFront();
 }
 
 
@@ -1485,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;
@@ -1550,6 +1955,7 @@ static struct TokenInfo setup_info_main[] =
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execExitSetup,          "Exit"                  },
   { TYPE_LEAVE_MENU,   execSaveAndExitSetup,   "Save and Exit"         },
+
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1557,18 +1963,23 @@ 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,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+
   { 0,                 NULL,                   NULL                    }
 };
 
 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:"     },
@@ -1581,6 +1992,7 @@ static struct TokenInfo setup_info_editor[] =
   { TYPE_SWITCH,       &setup.editor.el_user_defined,  "User defined:" },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1597,6 +2009,7 @@ static struct TokenInfo setup_info_graphics[] =
   { TYPE_SWITCH,       &setup.toons,           "Toons:"                },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1607,6 +2020,7 @@ static struct TokenInfo setup_info_sound[] =
   { TYPE_SWITCH,       &setup.sound_music,     "Game Music:"           },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1625,6 +2039,7 @@ static struct TokenInfo setup_info_artwork[] =
   { TYPE_YES_NO,       &setup.override_level_music,    "Music:"        },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1640,6 +2055,7 @@ static struct TokenInfo setup_info_shortcut[] =
   { TYPE_YES_NO,       &setup.ask_on_escape,   "Ask on Esc:"           },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_LEAVE_MENU,   execSetupMain,          "Back"                  },
+
   { 0,                 NULL,                   NULL                    }
 };
 
@@ -1817,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);
 
@@ -1837,7 +2259,7 @@ static void DrawSetupScreen_Generic()
 
   FadeToFront();
   InitAnimation();
-  HandleSetupScreen_Generic(0,0,0,0,MB_MENU_INITIALIZE);
+  HandleSetupScreen_Generic(0, 0, 0, 0, MB_MENU_INITIALIZE);
 }
 
 void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
@@ -1851,7 +2273,7 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
   {
     /* advance to first valid menu entry */
     while (choice < num_setup_info &&
-          (setup_info[choice].type & TYPE_SKIP_ENTRY))
+          setup_info[choice].type & TYPE_SKIP_ENTRY)
       choice++;
     choice_store[setup_mode] = choice;
 
@@ -1885,8 +2307,8 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
     {
       int menu_navigation_type = (dx < 0 ? TYPE_LEAVE_MENU : TYPE_ENTER_MENU);
 
-      if ((setup_info[choice].type & menu_navigation_type) ||
-         (setup_info[choice].type & TYPE_BOOLEAN_STYLE))
+      if (setup_info[choice].type & menu_navigation_type ||
+         setup_info[choice].type & TYPE_BOOLEAN_STYLE)
        button = MB_MENU_CHOICE;
     }
     else if (dy)
@@ -1894,12 +2316,12 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
 
     /* jump to next non-empty menu entry (up or down) */
     while (y > 0 && y < num_setup_info - 1 &&
-          (setup_info[y].type & TYPE_SKIP_ENTRY))
+          setup_info[y].type & TYPE_SKIP_ENTRY)
       y += dy;
   }
 
-  if (x == 0 && y >= 0 && y < num_setup_info &&
-      (setup_info[y].type & ~TYPE_SKIP_ENTRY))
+  if (IN_VIS_FIELD(x, y) &&
+      y >= 0 && y < num_setup_info && setup_info[y].type & ~TYPE_SKIP_ENTRY)
   {
     if (button)
     {
@@ -1920,8 +2342,8 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
       }
       else
       {
-       if ((setup_info[y].type & TYPE_KEYTEXT) &&
-           (setup_info[y + 1].type & TYPE_KEY))
+       if (setup_info[y].type & TYPE_KEYTEXT &&
+           setup_info[y + 1].type & TYPE_KEY)
          y++;
 
        if (setup_info[y].type & TYPE_VALUE)
@@ -1929,13 +2351,6 @@ void HandleSetupScreen_Generic(int mx, int my, int dx, int dy, int button)
       }
     }
   }
-
-#if 0
-  BackToFront();
-
-  if (game_status == GAME_MODE_SETUP)
-    DoAnimation();
-#endif
 }
 
 void DrawSetupScreen_Input()
@@ -1962,7 +2377,7 @@ void DrawSetupScreen_Input()
                    "Joysticks deactivated on this screen");
 #endif
 
-  HandleSetupScreen_Input(0,0, 0,0, MB_MENU_INITIALIZE);
+  HandleSetupScreen_Input(0, 0, 0, 0, MB_MENU_INITIALIZE);
   FadeToFront();
   InitAnimation();
 }
@@ -2003,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] =
   {
@@ -2017,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
@@ -2048,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++)
   {
@@ -2078,6 +2495,7 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
   {
     drawPlayerSetupInputInfo(player_nr);
     drawCursor(choice, FC_RED);
+
     return;
   }
   else if (button == MB_MENU_LEAVE)
@@ -2085,6 +2503,8 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
     setup_mode = SETUP_MODE_MAIN;
     DrawSetupScreen();
     InitJoysticks();
+
+    return;
   }
 
   if (mx || my)                /* mouse input */
@@ -2107,7 +2527,8 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
       y = (dy > 0 ? pos_empty2 + 1 : pos_empty1 - 1);
   }
 
-  if (y == 0 && ((x == 0 && !button) || ((x == 10 || x == 12) && button)))
+  if (IN_VIS_FIELD(x, y) &&
+      y == 0 && ((x < 10 && !button) || ((x == 10 || x == 12) && button)))
   {
     static unsigned long delay = 0;
 
@@ -2118,7 +2539,8 @@ void HandleSetupScreen_Input(int mx, int my, int dx, int dy, int button)
 
     drawPlayerSetupInputInfo(player_nr);
   }
-  else if (x == 0 && y >= pos_start && y <= pos_end &&
+  else if (IN_VIS_FIELD(x, y) &&
+          y >= pos_start && y <= pos_end &&
           !(y >= pos_empty1 && y <= pos_empty2))
   {
     if (button)
@@ -2189,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 */
@@ -2538,7 +2960,6 @@ void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
     HandleSetupScreen_Generic(mx, my, dx, dy, button);
 
   DoAnimation();
-  BackToFront();
 }
 
 void HandleGameActions()
@@ -2546,20 +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 (!TAPE_IS_STOPPED(tape))
+       TapeStop();
 
-  if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
-    TapeStop();
+      if (game_status != GAME_MODE_PLAYING)
+       return;
+    }
 
-  GameActions();
+    if (level.native_em_level->ply1->alive == 0 &&
+       level.native_em_level->ply2->alive == 0)        /* all dead */
+      AllPlayersGone = TRUE;
 
-  BackToFront();
+    if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
+      TapeStop();
+
+    /* --- game actions --- */
+
+    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
-  if (tape.auto_play && !tape.playing)
-    AutoPlayTape();    /* continue automatically playing next tape */
+    /* !!! 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 -------------------------------------- */
@@ -2831,6 +3365,7 @@ void MapChooseTreeGadgets(TreeInfo *ti)
     MapGadget(screen_gadget[i]);
 }
 
+#if 0
 void UnmapChooseTreeGadgets()
 {
   int i;
@@ -2838,6 +3373,7 @@ void UnmapChooseTreeGadgets()
   for (i = 0; i < NUM_SCREEN_GADGETS; i++)
     UnmapGadget(screen_gadget[i]);
 }
+#endif
 
 static void HandleScreenGadgets(struct GadgetInfo *gi)
 {