rnd-20050525-1-src
[rocksndiamonds.git] / src / screens.c
index 015cbd48aa4d4804936fa0b6b8f288728bc13760..7d783a9b21a3f672e3f5c13ce5574d63db856b8a 100644 (file)
@@ -97,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] :       \
@@ -201,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()
@@ -238,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();
@@ -276,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);
@@ -306,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);
@@ -330,7 +329,7 @@ void DrawMainMenu()
   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();
@@ -348,6 +347,7 @@ void DrawMainMenu()
   OpenDoor(DOOR_CLOSE_1 | DOOR_OPEN_2);
 }
 
+#if 0
 static void gotoTopLevelDir()
 {
   /* move upwards to top level directory */
@@ -376,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;
@@ -404,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;
@@ -417,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;
 
@@ -429,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);
@@ -468,7 +483,9 @@ void HandleMainMenu(int mx, int my, int dx, int dy, int button)
          SaveLevelSetup_LastSeries();
          SaveLevelSetup_SeriesInfo();
 
+#if 0
          gotoTopLevelDir();
+#endif
 
          DrawChooseLevel();
        }
@@ -497,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
@@ -526,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();
   }
 }
@@ -789,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;
@@ -798,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++;
     }
 
@@ -961,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;
 
@@ -994,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;
@@ -1007,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;
 
-    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);
+      if (sound_info[sound].loop)
+       PlaySoundLoop(sound);
+      else
+       PlaySound(sound);
 
-    DrawTextSCentered(ybottom, FONT_TEXT_4,
-                     "Press any key or button for next page");
+      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);
 
-    PlayMusic(list->music);
+      DrawTextFCentered(ystart + y++ * dy, FONT_TEXT_3, "\"%s\"", list->title);
+    }
 
-    list = list->next;
+    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 DrawInfoScreen_Credits()
@@ -1431,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;
@@ -1462,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,
@@ -1584,7 +1654,8 @@ static void HandleChooseTree(int mx, int my, int dx, int dy, int button,
     return;
   }
 
-  if (IN_VIS_FIELD(x, y) &&
+  if (!anyScrollbarGadgetActive() &&
+      IN_VIS_FIELD(x, y) &&
       mx < screen_gadget[SCREEN_CTRL_ID_SCROLL_VERTICAL]->x &&
       y >= 0 && y < num_page_entries)
   {
@@ -1819,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;
@@ -1892,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,                   ""                      },
@@ -1902,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:"     },
@@ -2158,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);
 
@@ -2337,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] =
   {
@@ -2351,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
@@ -2382,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++)
   {
@@ -2528,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 */
@@ -2884,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.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);
 
-  if (tape.auto_play && !tape.playing)
-    AutoPlayTape();    /* continue automatically playing next tape */
+       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 -------------------------------------- */