added setup option to enable network multi-player games
[rocksndiamonds.git] / src / screens.c
index c44fb2b0cdf9f9250f95561c1b0d17dc76d8490d..1346c21886fef76e0ca866324d03f14b77affd2f 100644 (file)
 #define SCREEN_CTRL_ID_NEXT_LEVEL      1
 #define SCREEN_CTRL_ID_PREV_PLAYER     2
 #define SCREEN_CTRL_ID_NEXT_PLAYER     3
-#define SCREEN_CTRL_ID_SCROLL_UP       4
-#define SCREEN_CTRL_ID_SCROLL_DOWN     5
-#define SCREEN_CTRL_ID_SCROLL_VERTICAL 6
+#define SCREEN_CTRL_ID_INSERT_SOLUTION 4
+#define SCREEN_CTRL_ID_PLAY_SOLUTION   5
+#define SCREEN_CTRL_ID_SCROLL_UP       6
+#define SCREEN_CTRL_ID_SCROLL_DOWN     7
+#define SCREEN_CTRL_ID_SCROLL_VERTICAL 8
 
-#define NUM_SCREEN_GADGETS             7
+#define NUM_SCREEN_GADGETS             9
 
-#define NUM_SCREEN_MENUBUTTONS         4
+#define NUM_SCREEN_MENUBUTTONS         6
 #define NUM_SCREEN_SCROLLBUTTONS       2
 #define NUM_SCREEN_SCROLLBARS          1
 
 #define SCREEN_MASK_MAIN               (1 << 0)
-#define SCREEN_MASK_INPUT              (1 << 1)
+#define SCREEN_MASK_MAIN_HAS_SOLUTION  (1 << 1)
+#define SCREEN_MASK_INPUT              (1 << 2)
 
 /* graphic position and size values for buttons and scrollbars */
 #define SC_MENUBUTTON_XSIZE            TILEX
@@ -246,6 +249,8 @@ static void MapScreenMenuGadgets(int);
 static void MapScreenGadgets(int);
 static void MapScreenTreeGadgets(TreeInfo *);
 
+static void UpdateScreenMenuGadgets(int, boolean);
+
 static struct GadgetInfo *screen_gadget[NUM_SCREEN_GADGETS];
 
 static int info_mode = INFO_MODE_MAIN;
@@ -749,19 +754,19 @@ static struct MainControlInfo main_controls[] =
 #endif
   {
     MAIN_CONTROL_FIRST_LEVEL,
-    NULL,                              -1,
+    &menu.main.button.first_level,     IMG_MENU_BUTTON_FIRST_LEVEL,
     &menu.main.text.first_level,       &main_text_first_level,
     NULL,                              NULL,
   },
   {
     MAIN_CONTROL_LAST_LEVEL,
-    NULL,                              -1,
+    &menu.main.button.last_level,      IMG_MENU_BUTTON_LAST_LEVEL,
     &menu.main.text.last_level,                &main_text_last_level,
     NULL,                              NULL,
   },
   {
     MAIN_CONTROL_LEVEL_NUMBER,
-    NULL,                              -1,
+    &menu.main.button.level_number,    IMG_MENU_BUTTON_LEVEL_NUMBER,
     &menu.main.text.level_number,      &main_text_level_number,
     NULL,                              NULL,
   },
@@ -1148,8 +1153,8 @@ static void InitializeMainControls()
 
     if (pos_text != NULL)              /* (x/y may be -1/-1 here) */
     {
-      /* calculate size for non-clickable text -- needed for text alignment */
-      boolean calculate_text_size = (pos_button == NULL && text != NULL);
+      /* calculate text size -- needed for text alignment */
+      boolean calculate_text_size = (text != NULL);
 
       if (pos_text->width == -1 || calculate_text_size)
        pos_text->width = text_width;
@@ -1651,9 +1656,14 @@ void DrawMainMenu()
   FreeScreenGadgets();
   CreateScreenGadgets();
 
+  /* may be required if audio buttons shown on tape and changed in setup menu */
+  FreeGameButtons();
+  CreateGameButtons();
+
   /* map gadgets for main menu screen */
   MapTapeButtons();
   MapScreenMenuGadgets(SCREEN_MASK_MAIN);
+  UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape());
 
   /* copy actual game door content to door double buffer for OpenDoor() */
   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
@@ -1925,6 +1935,8 @@ void HandleMainMenu_SelectLevel(int step, int direction, int selected_level_nr)
 
     SaveLevelSetup_SeriesInfo();
 
+    UpdateScreenMenuGadgets(SCREEN_MASK_MAIN_HAS_SOLUTION, hasSolutionTape());
+
     /* needed because DrawPreviewLevelInitial() takes some time */
     BackToFront();
     /* SyncDisplay(); */
@@ -5867,6 +5879,7 @@ static struct TokenInfo setup_info_main[] =
 static struct TokenInfo setup_info_game[] =
 {
   { TYPE_SWITCH,       &setup.team_mode,       "Team-Mode (Multi-Player):" },
+  { TYPE_SWITCH,       &setup.network_mode,    "Network Multi-Player Mode:" },
   { TYPE_YES_NO,       &setup.input_on_focus,  "Only Move Focussed Player:" },
   { TYPE_SWITCH,       &setup.time_limit,      "Time Limit:"           },
   { TYPE_SWITCH,       &setup.handicap,        "Handicap:"             },
@@ -6029,6 +6042,7 @@ static struct TokenInfo setup_info_touch_virtual_buttons_0[] =
   { TYPE_ENTER_LIST,   execSetupChooseTransparency, "Button Transparency:" },
   { TYPE_STRING,       &transparency_text,     ""                      },
   { TYPE_SWITCH,       &setup.touch.draw_outlined, "Draw Buttons Outlined:" },
+  { TYPE_SWITCH,       &setup.touch.draw_pressed, "Highlight Pressed Buttons:" },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_ENTER_LIST,   execSetupConfigureVirtualButtons, "Configure Virtual Buttons" },
   { TYPE_EMPTY,                NULL,                   ""                      },
@@ -6049,6 +6063,7 @@ static struct TokenInfo setup_info_touch_virtual_buttons_1[] =
   { TYPE_ENTER_LIST,   execSetupChooseTransparency, "Button Transparency:" },
   { TYPE_STRING,       &transparency_text,     ""                      },
   { TYPE_SWITCH,       &setup.touch.draw_outlined, "Draw Buttons Outlined:" },
+  { TYPE_SWITCH,       &setup.touch.draw_pressed, "Highlight Pressed Buttons:" },
   { TYPE_EMPTY,                NULL,                   ""                      },
   { TYPE_ENTER_LIST,   execSetupConfigureVirtualButtons, "Configure Virtual Buttons" },
   { TYPE_EMPTY,                NULL,                   ""                      },
@@ -6397,6 +6412,11 @@ static void changeSetupValue(int screen_pos, int setup_info_pos_raw, int dx)
   // fullscreen state may have changed at this point
   if (si->value == &setup.fullscreen)
     ToggleFullscreenOrChangeWindowScalingIfNeeded();
+
+  if (si->value == &setup.network_mode &&
+      setup.network_mode &&
+      !options.network)
+    Request("Please restart game to enable network games!", REQ_CONFIRM);
 }
 
 static struct TokenInfo *getSetupInfoFinal(struct TokenInfo *setup_info_orig)
@@ -7556,13 +7576,19 @@ boolean ConfigureVirtualButtonsMain()
 
            /* press 'Enter' to keep the existing key binding */
            if (key == KSYM_Return ||
+#if defined(TARGET_SDL2)
                key == KSYM_Menu ||
+#endif
                key == KSYM_space)
            {
              step_nr++;
            }
-           else if (key == KSYM_BackSpace ||
-                    key == KSYM_Back)
+           else if (key == KSYM_BackSpace
+#if defined(TARGET_SDL2)
+                    ||
+                    key == KSYM_Back
+#endif
+                    )
            {
              if (step_nr == 0)
              {
@@ -7902,6 +7928,16 @@ static void getScreenMenuButtonPos(int *x, int *y, int gadget_id)
       *y = mSY + TILEY * MENU_SCREEN_START_YPOS;
       break;
 
+    case SCREEN_CTRL_ID_INSERT_SOLUTION:
+      *x = mSX + GDI_ACTIVE_POS(menu.main.button.insert_solution.x);
+      *y = mSY + GDI_ACTIVE_POS(menu.main.button.insert_solution.y);
+      break;
+
+    case SCREEN_CTRL_ID_PLAY_SOLUTION:
+      *x = mSX + GDI_ACTIVE_POS(menu.main.button.play_solution.x);
+      *y = mSY + GDI_ACTIVE_POS(menu.main.button.play_solution.y);
+      break;
+
     default:
       Error(ERR_EXIT, "unknown gadget ID %d", gadget_id);
   }
@@ -7944,6 +7980,20 @@ static struct
     SCREEN_MASK_INPUT,
     "next player"
   },
+  {
+    IMG_MENU_BUTTON_INSERT_SOLUTION, IMG_MENU_BUTTON_INSERT_SOLUTION_ACTIVE,
+    getScreenMenuButtonPos,
+    SCREEN_CTRL_ID_INSERT_SOLUTION,
+    SCREEN_MASK_MAIN_HAS_SOLUTION,
+    "insert solution tape"
+  },
+  {
+    IMG_MENU_BUTTON_PLAY_SOLUTION, IMG_MENU_BUTTON_PLAY_SOLUTION_ACTIVE,
+    getScreenMenuButtonPos,
+    SCREEN_CTRL_ID_PLAY_SOLUTION,
+    SCREEN_MASK_MAIN_HAS_SOLUTION,
+    "play solution tape"
+  },
 };
 
 static struct
@@ -8002,12 +8052,23 @@ static void CreateScreenMenubuttons()
     int gd_x1, gd_x2, gd_y1, gd_y2;
     int id = menubutton_info[i].gadget_id;
 
-    event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+    if (menubutton_info[i].screen_mask == SCREEN_MASK_MAIN_HAS_SOLUTION)
+      event_mask = GD_EVENT_RELEASED;
+    else
+      event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
 
     menubutton_info[i].get_gadget_position(&x, &y, id);
 
-    width = SC_MENUBUTTON_XSIZE;
-    height = SC_MENUBUTTON_YSIZE;
+    if (menubutton_info[i].screen_mask == SCREEN_MASK_MAIN_HAS_SOLUTION)
+    {
+      width  = graphic_info[menubutton_info[i].gfx_pressed].width;
+      height = graphic_info[menubutton_info[i].gfx_pressed].height;
+    }
+    else
+    {
+      width = SC_MENUBUTTON_XSIZE;
+      height = SC_MENUBUTTON_YSIZE;
+    }
 
     gfx_unpressed = menubutton_info[i].gfx_unpressed;
     gfx_pressed   = menubutton_info[i].gfx_pressed;
@@ -8020,6 +8081,7 @@ static void CreateScreenMenubuttons()
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
+                     GDI_IMAGE_ID, gfx_unpressed,
                      GDI_INFO_TEXT, menubutton_info[i].infotext,
                      GDI_X, x,
                      GDI_Y, y,
@@ -8087,6 +8149,7 @@ static void CreateScreenScrollbuttons()
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
+                     GDI_IMAGE_ID, gfx_unpressed,
                      GDI_INFO_TEXT, scrollbutton_info[i].infotext,
                      GDI_X, x,
                      GDI_Y, y,
@@ -8159,6 +8222,7 @@ static void CreateScreenScrollbars()
 
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_CUSTOM_TYPE_ID, i,
+                     GDI_IMAGE_ID, gfx_unpressed,
                      GDI_INFO_TEXT, scrollbar_info[i].infotext,
                      GDI_X, x,
                      GDI_Y, y,
@@ -8213,6 +8277,33 @@ void MapScreenMenuGadgets(int screen_mask)
       MapGadget(screen_gadget[menubutton_info[i].gadget_id]);
 }
 
+void UnmapScreenMenuGadgets(int screen_mask)
+{
+  int i;
+
+  for (i = 0; i < NUM_SCREEN_MENUBUTTONS; i++)
+  {
+    if (screen_mask & menubutton_info[i].screen_mask)
+    {
+      UnmapGadget(screen_gadget[menubutton_info[i].gadget_id]);
+
+      if (screen_mask & SCREEN_MASK_MAIN_HAS_SOLUTION)
+       DrawBackground(screen_gadget[menubutton_info[i].gadget_id]->x,
+                      screen_gadget[menubutton_info[i].gadget_id]->y,
+                      screen_gadget[menubutton_info[i].gadget_id]->width,
+                      screen_gadget[menubutton_info[i].gadget_id]->height);
+    }
+  }
+}
+
+void UpdateScreenMenuGadgets(int screen_mask, boolean map_gadgets)
+{
+  if (map_gadgets)
+    MapScreenMenuGadgets(screen_mask);
+  else
+    UnmapScreenMenuGadgets(screen_mask);
+}
+
 void MapScreenGadgets(int num_entries)
 {
   int i;
@@ -8236,7 +8327,9 @@ static void HandleScreenGadgets(struct GadgetInfo *gi)
 {
   int id = gi->custom_id;
   int button = gi->event.button;
-  int step = (button == 1 ? 1 : button == 2 ? 5 : 10);
+  int step = (button == MB_LEFTBUTTON   ? 1 :
+             button == MB_MIDDLEBUTTON ? 5 :
+             button == MB_RIGHTBUTTON  ? 10 : 1);
 
   switch (id)
   {
@@ -8256,6 +8349,14 @@ static void HandleScreenGadgets(struct GadgetInfo *gi)
       HandleSetupScreen_Input_Player(step, +1);
       break;
 
+    case SCREEN_CTRL_ID_INSERT_SOLUTION:
+      InsertSolutionTape();
+      break;
+
+    case SCREEN_CTRL_ID_PLAY_SOLUTION:
+      PlaySolutionTape();
+      break;
+
     case SCREEN_CTRL_ID_SCROLL_UP:
       if (game_status == GAME_MODE_LEVELS)
        HandleChooseLevelSet(0,0, 0, -1 * SCROLL_LINE, MB_MENU_MARK);
@@ -8293,3 +8394,50 @@ static void HandleScreenGadgets(struct GadgetInfo *gi)
       break;
   }
 }
+
+void DumpScreenIdentifiers()
+{
+  int i;
+
+  Print("Active screen elements on current screen:\n");
+
+  for (i = 0; main_controls[i].nr != -1; i++)
+  {
+    struct MainControlInfo *mci = &main_controls[i];
+
+    if (mci->button_graphic != -1)
+    {
+      char *token = getTokenFromImageID(mci->button_graphic);
+
+      Print("- '%s'\n", token);
+    }
+  }
+
+  Print("Done.\n");
+}
+
+boolean DoScreenAction(int image_id)
+{
+  int i;
+
+  if (game_status != GAME_MODE_MAIN)
+    return FALSE;
+
+  for (i = 0; main_controls[i].nr != -1; i++)
+  {
+    struct MainControlInfo *mci = &main_controls[i];
+    struct MenuPosInfo *pos = mci->pos_button;
+
+    if (mci->button_graphic == image_id)
+    {
+      int x = mSX + pos->x;
+      int y = mSY + pos->y;
+
+      HandleMainMenu(x, y, 0, 0, MB_MENU_CHOICE);
+
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}