added Android project files
[rocksndiamonds.git] / src / game.c
index d517cdc06587c182cfb5f522b6beddb064dc4af1..57771d75b866c7f4995fefb43eea95ad94830fd5 100644 (file)
@@ -1016,14 +1016,16 @@ static struct GamePanelControlInfo game_panel_controls[] =
 #define GAME_CTRL_ID_PANEL_STOP                8
 #define GAME_CTRL_ID_PANEL_PAUSE       9
 #define GAME_CTRL_ID_PANEL_PLAY                10
-#define SOUND_CTRL_ID_MUSIC            11
-#define SOUND_CTRL_ID_LOOPS            12
-#define SOUND_CTRL_ID_SIMPLE           13
-#define SOUND_CTRL_ID_PANEL_MUSIC      14
-#define SOUND_CTRL_ID_PANEL_LOOPS      15
-#define SOUND_CTRL_ID_PANEL_SIMPLE     16
+#define GAME_CTRL_ID_TOUCH_STOP                11
+#define GAME_CTRL_ID_TOUCH_PAUSE       12
+#define SOUND_CTRL_ID_MUSIC            13
+#define SOUND_CTRL_ID_LOOPS            14
+#define SOUND_CTRL_ID_SIMPLE           15
+#define SOUND_CTRL_ID_PANEL_MUSIC      16
+#define SOUND_CTRL_ID_PANEL_LOOPS      17
+#define SOUND_CTRL_ID_PANEL_SIMPLE     18
 
-#define NUM_GAME_BUTTONS               17
+#define NUM_GAME_BUTTONS               19
 
 
 // forward declaration for internal use
@@ -3354,7 +3356,7 @@ void InitGame(void)
   SetGameStatus(GAME_MODE_PLAYING);
 
   if (level_editor_test_game)
-    FadeSkipNextFadeIn();
+    FadeSkipNextFadeOut();
   else
     FadeSetEnterScreen();
 
@@ -3367,6 +3369,9 @@ void InitGame(void)
 
   FadeOut(fade_mask);
 
+  if (level_editor_test_game)
+    FadeSkipNextFadeIn();
+
   // needed if different viewport properties defined for playing
   ChangeViewportPropertiesIfNeeded();
 
@@ -3401,6 +3406,7 @@ void InitGame(void)
     player->action = 0;
     player->effective_action = 0;
     player->programmed_action = 0;
+    player->snap_action = 0;
 
     player->mouse_action.lx = 0;
     player->mouse_action.ly = 0;
@@ -3737,6 +3743,19 @@ void InitGame(void)
       game.belt_dir_nr[i] = 3;         // not moving, next moving left
 
 #if USE_NEW_PLAYER_ASSIGNMENTS
+  // use preferred player also in local single-player mode
+  if (!network.enabled && !game.team_mode)
+  {
+    int old_index_nr = local_player->index_nr;
+    int new_index_nr = setup.network_player_nr;
+
+    if (new_index_nr >= 0 && new_index_nr < MAX_PLAYERS)
+    {
+      stored_player[old_index_nr].connected_locally = FALSE;
+      stored_player[new_index_nr].connected_locally = TRUE;
+    }
+  }
+
   for (i = 0; i < MAX_PLAYERS; i++)
   {
     stored_player[i].connected = FALSE;
@@ -4503,7 +4522,7 @@ void GameWon(void)
     int i;
 
     // do not start end game actions before the player stops moving (to exit)
-    if (local_player->MovPos)
+    if (local_player->active && local_player->MovPos)
       return;
 
     game.LevelSolved_GameWon = TRUE;
@@ -5258,11 +5277,8 @@ static void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir,
 
   while (scroll_x != new_scroll_x || scroll_y != new_scroll_y)
   {
-    int dx = 0, dy = 0;
-    int fx = FX, fy = FY;
-
-    dx = (new_scroll_x < scroll_x ? +1 : new_scroll_x > scroll_x ? -1 : 0);
-    dy = (new_scroll_y < scroll_y ? +1 : new_scroll_y > scroll_y ? -1 : 0);
+    int dx = (new_scroll_x < scroll_x ? +1 : new_scroll_x > scroll_x ? -1 : 0);
+    int dy = (new_scroll_y < scroll_y ? +1 : new_scroll_y > scroll_y ? -1 : 0);
 
     if (dx == 0 && dy == 0)            // no scrolling needed at all
       break;
@@ -5270,14 +5286,19 @@ static void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir,
     scroll_x -= dx;
     scroll_y -= dy;
 
-    fx += dx * TILEX / 2;
-    fy += dy * TILEY / 2;
+    // set values for horizontal/vertical screen scrolling (half tile size)
+    int dir_x = (dx != 0 ? MV_HORIZONTAL : 0);
+    int dir_y = (dy != 0 ? MV_VERTICAL   : 0);
+    int pos_x = dx * TILEX / 2;
+    int pos_y = dy * TILEY / 2;
+    int fx = getFieldbufferOffsetX_RND(dir_x, pos_x);
+    int fy = getFieldbufferOffsetY_RND(dir_y, pos_y);
 
     ScrollLevel(dx, dy);
     DrawAllPlayers();
 
     // scroll in two steps of half tile size to make things smoother
-    BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+    BlitScreenToBitmapExt_RND(window, fx, fy);
 
     // scroll second step to align at full tile size
     BlitScreenToBitmap(window);
@@ -11044,10 +11065,7 @@ static void CheckSingleStepMode(struct PlayerInfo *player)
     if (!player->is_moving &&
        !player->is_pushing &&
        !player->is_dropping_pressed)
-    {
       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
-      SnapField(player, 0, 0);                 // stop snapping
-    }
   }
 
   CheckSaveEngineSnapshot(player);
@@ -11451,13 +11469,14 @@ static void GameActionsExt(void)
     stored_player[map_player_action[local_player->index_nr]].effective_action =
       summarized_player_action;
 
+  // summarize all actions at centered player in local team mode
   if (tape.recording &&
-      setup.team_mode &&
+      setup.team_mode && !network.enabled &&
       setup.input_on_focus &&
       game.centered_player_nr != -1)
   {
     for (i = 0; i < MAX_PLAYERS; i++)
-      stored_player[i].effective_action =
+      stored_player[map_player_action[i]].effective_action =
        (i == game.centered_player_nr ? summarized_player_action : 0);
   }
 
@@ -11982,7 +12001,8 @@ void GameActions_RND(void)
           element == EL_DC_MAGIC_WALL_FULL ||
           element == EL_DC_MAGIC_WALL_ACTIVE ||
           element == EL_DC_MAGIC_WALL_EMPTYING) &&
-         ABS(x-jx) + ABS(y-jy) < ABS(magic_wall_x-jx) + ABS(magic_wall_y-jy))
+         ABS(x - jx) + ABS(y - jy) <
+         ABS(magic_wall_x - jx) + ABS(magic_wall_y - jy))
       {
        magic_wall_x = x;
        magic_wall_y = y;
@@ -12164,11 +12184,17 @@ void GameActions_RND(void)
   DrawAllPlayers();
   PlayAllPlayersSound();
 
-  if (local_player->show_envelope != 0 && local_player->MovPos == 0)
+  for (i = 0; i < MAX_PLAYERS; i++)
   {
-    ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1);
+    struct PlayerInfo *player = &stored_player[i];
+
+    if (player->show_envelope != 0 && (!player->active ||
+                                      player->MovPos == 0))
+    {
+      ShowEnvelope(player->show_envelope - EL_ENVELOPE_1);
 
-    local_player->show_envelope = 0;
+      player->show_envelope = 0;
+    }
   }
 
   // use random number generator in every frame to make it less predictable
@@ -12499,7 +12525,6 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
        game.centered_player_nr == -1))
   {
     int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
-    int offset = game.scroll_delay_value;
 
     if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
     {
@@ -12511,15 +12536,20 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
     }
     else
     {
+      int offset_raw = game.scroll_delay_value;
+
       if (jx != old_jx)                // player has moved horizontally
       {
-       if ((player->MovDir == MV_LEFT  && scroll_x > jx - MIDPOSX + offset) ||
-           (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
-         scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
+       int offset = MIN(offset_raw, (SCR_FIELDX - 2) / 2);
+       int offset_x = offset * (player->MovDir == MV_LEFT ? +1 : -1);
+       int new_scroll_x = jx - MIDPOSX + offset_x;
+
+       if ((player->MovDir == MV_LEFT  && scroll_x > new_scroll_x) ||
+           (player->MovDir == MV_RIGHT && scroll_x < new_scroll_x))
+         scroll_x = new_scroll_x;
 
        // don't scroll over playfield boundaries
-       if (scroll_x < SBX_Left || scroll_x > SBX_Right)
-         scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
+       scroll_x = MIN(MAX(SBX_Left, scroll_x), SBX_Right);
 
        // don't scroll more than one field at a time
        scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
@@ -12531,13 +12561,16 @@ boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
       }
       else                     // player has moved vertically
       {
-       if ((player->MovDir == MV_UP   && scroll_y > jy - MIDPOSY + offset) ||
-           (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
-         scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
+       int offset = MIN(offset_raw, (SCR_FIELDY - 2) / 2);
+       int offset_y = offset * (player->MovDir == MV_UP ? +1 : -1);
+       int new_scroll_y = jy - MIDPOSY + offset_y;
+
+       if ((player->MovDir == MV_UP   && scroll_y > new_scroll_y) ||
+           (player->MovDir == MV_DOWN && scroll_y < new_scroll_y))
+         scroll_y = new_scroll_y;
 
        // don't scroll over playfield boundaries
-       if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
-         scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
+       scroll_y = MIN(MAX(SBY_Upper, scroll_y), SBY_Lower);
 
        // don't scroll more than one field at a time
        scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
@@ -13451,6 +13484,9 @@ void RemovePlayer(struct PlayerInfo *player)
   player->present = FALSE;
   player->active = FALSE;
 
+  // required for some CE actions (even if the player is not active anymore)
+  player->MovPos = 0;
+
   if (!ExplodeField[jx][jy])
     StorePlayer[jx][jy] = 0;
 
@@ -15442,93 +15478,104 @@ static struct
   int gadget_id;
   boolean *setup_value;
   boolean allowed_on_tape;
+  boolean is_touch_button;
   char *infotext;
 } gamebutton_info[NUM_GAME_BUTTONS] =
 {
   {
     IMG_GFX_GAME_BUTTON_STOP,                  &game.button.stop,
     GAME_CTRL_ID_STOP,                         NULL,
-    TRUE,                                      "stop game"
+    TRUE, FALSE,                               "stop game"
   },
   {
     IMG_GFX_GAME_BUTTON_PAUSE,                 &game.button.pause,
     GAME_CTRL_ID_PAUSE,                                NULL,
-    TRUE,                                      "pause game"
+    TRUE, FALSE,                               "pause game"
   },
   {
     IMG_GFX_GAME_BUTTON_PLAY,                  &game.button.play,
     GAME_CTRL_ID_PLAY,                         NULL,
-    TRUE,                                      "play game"
+    TRUE, FALSE,                               "play game"
   },
   {
     IMG_GFX_GAME_BUTTON_UNDO,                  &game.button.undo,
     GAME_CTRL_ID_UNDO,                         NULL,
-    TRUE,                                      "undo step"
+    TRUE, FALSE,                               "undo step"
   },
   {
     IMG_GFX_GAME_BUTTON_REDO,                  &game.button.redo,
     GAME_CTRL_ID_REDO,                         NULL,
-    TRUE,                                      "redo step"
+    TRUE, FALSE,                               "redo step"
   },
   {
     IMG_GFX_GAME_BUTTON_SAVE,                  &game.button.save,
     GAME_CTRL_ID_SAVE,                         NULL,
-    TRUE,                                      "save game"
+    TRUE, FALSE,                               "save game"
   },
   {
     IMG_GFX_GAME_BUTTON_PAUSE2,                        &game.button.pause2,
     GAME_CTRL_ID_PAUSE2,                       NULL,
-    TRUE,                                      "pause game"
+    TRUE, FALSE,                               "pause game"
   },
   {
     IMG_GFX_GAME_BUTTON_LOAD,                  &game.button.load,
     GAME_CTRL_ID_LOAD,                         NULL,
-    TRUE,                                      "load game"
+    TRUE, FALSE,                               "load game"
   },
   {
     IMG_GFX_GAME_BUTTON_PANEL_STOP,            &game.button.panel_stop,
     GAME_CTRL_ID_PANEL_STOP,                   NULL,
-    FALSE,                                     "stop game"
+    FALSE, FALSE,                              "stop game"
   },
   {
     IMG_GFX_GAME_BUTTON_PANEL_PAUSE,           &game.button.panel_pause,
     GAME_CTRL_ID_PANEL_PAUSE,                  NULL,
-    FALSE,                                     "pause game"
+    FALSE, FALSE,                              "pause game"
   },
   {
     IMG_GFX_GAME_BUTTON_PANEL_PLAY,            &game.button.panel_play,
     GAME_CTRL_ID_PANEL_PLAY,                   NULL,
-    FALSE,                                     "play game"
+    FALSE, FALSE,                              "play game"
+  },
+  {
+    IMG_GFX_GAME_BUTTON_TOUCH_STOP,            &game.button.touch_stop,
+    GAME_CTRL_ID_TOUCH_STOP,                   NULL,
+    FALSE, TRUE,                               "stop game"
+  },
+  {
+    IMG_GFX_GAME_BUTTON_TOUCH_PAUSE,           &game.button.touch_pause,
+    GAME_CTRL_ID_TOUCH_PAUSE,                  NULL,
+    FALSE, TRUE,                               "pause game"
   },
   {
     IMG_GFX_GAME_BUTTON_SOUND_MUSIC,           &game.button.sound_music,
     SOUND_CTRL_ID_MUSIC,                       &setup.sound_music,
-    TRUE,                                      "background music on/off"
+    TRUE, FALSE,                               "background music on/off"
   },
   {
     IMG_GFX_GAME_BUTTON_SOUND_LOOPS,           &game.button.sound_loops,
     SOUND_CTRL_ID_LOOPS,                       &setup.sound_loops,
-    TRUE,                                      "sound loops on/off"
+    TRUE, FALSE,                               "sound loops on/off"
   },
   {
     IMG_GFX_GAME_BUTTON_SOUND_SIMPLE,          &game.button.sound_simple,
     SOUND_CTRL_ID_SIMPLE,                      &setup.sound_simple,
-    TRUE,                                      "normal sounds on/off"
+    TRUE, FALSE,                               "normal sounds on/off"
   },
   {
     IMG_GFX_GAME_BUTTON_PANEL_SOUND_MUSIC,     &game.button.panel_sound_music,
     SOUND_CTRL_ID_PANEL_MUSIC,                 &setup.sound_music,
-    FALSE,                                     "background music on/off"
+    FALSE, FALSE,                              "background music on/off"
   },
   {
     IMG_GFX_GAME_BUTTON_PANEL_SOUND_LOOPS,     &game.button.panel_sound_loops,
     SOUND_CTRL_ID_PANEL_LOOPS,                 &setup.sound_loops,
-    FALSE,                                     "sound loops on/off"
+    FALSE, FALSE,                              "sound loops on/off"
   },
   {
     IMG_GFX_GAME_BUTTON_PANEL_SOUND_SIMPLE,    &game.button.panel_sound_simple,
     SOUND_CTRL_ID_PANEL_SIMPLE,                        &setup.sound_simple,
-    FALSE,                                     "normal sounds on/off"
+    FALSE, FALSE,                              "normal sounds on/off"
   }
 };
 
@@ -15545,10 +15592,11 @@ void CreateGameButtons(void)
     int button_type;
     boolean checked;
     unsigned int event_mask;
+    boolean is_touch_button = gamebutton_info[i].is_touch_button;
     boolean allowed_on_tape = gamebutton_info[i].allowed_on_tape;
     boolean on_tape = (tape.show_game_buttons && allowed_on_tape);
-    int base_x = (on_tape ? VX : DX);
-    int base_y = (on_tape ? VY : DY);
+    int base_x = (is_touch_button ? 0 : on_tape ? VX : DX);
+    int base_y = (is_touch_button ? 0 : on_tape ? VY : DY);
     int gd_x   = gfx->src_x;
     int gd_y   = gfx->src_y;
     int gd_xp  = gfx->src_x + gfx->pressed_xoffset;
@@ -15557,6 +15605,8 @@ void CreateGameButtons(void)
     int gd_ya  = gfx->src_y + gfx->active_yoffset;
     int gd_xap = gfx->src_x + gfx->active_xoffset + gfx->pressed_xoffset;
     int gd_yap = gfx->src_y + gfx->active_yoffset + gfx->pressed_yoffset;
+    int x = (is_touch_button ? pos->x : GDI_ACTIVE_POS(pos->x));
+    int y = (is_touch_button ? pos->y : GDI_ACTIVE_POS(pos->y));
     int id = i;
 
     if (gfx->bitmap == NULL)
@@ -15568,6 +15618,7 @@ void CreateGameButtons(void)
 
     if (id == GAME_CTRL_ID_STOP ||
        id == GAME_CTRL_ID_PANEL_STOP ||
+       id == GAME_CTRL_ID_TOUCH_STOP ||
        id == GAME_CTRL_ID_PLAY ||
        id == GAME_CTRL_ID_PANEL_PLAY ||
        id == GAME_CTRL_ID_SAVE ||
@@ -15595,8 +15646,8 @@ void CreateGameButtons(void)
     gi = CreateGadget(GDI_CUSTOM_ID, id,
                      GDI_IMAGE_ID, graphic,
                      GDI_INFO_TEXT, gamebutton_info[i].infotext,
-                     GDI_X, base_x + GDI_ACTIVE_POS(pos->x),
-                     GDI_Y, base_y + GDI_ACTIVE_POS(pos->y),
+                     GDI_X, base_x + x,
+                     GDI_Y, base_y + y,
                      GDI_WIDTH, gfx->width,
                      GDI_HEIGHT, gfx->height,
                      GDI_TYPE, button_type,
@@ -15607,6 +15658,7 @@ void CreateGameButtons(void)
                      GDI_ALT_DESIGN_UNPRESSED, gfx->bitmap, gd_xa, gd_ya,
                      GDI_ALT_DESIGN_PRESSED, gfx->bitmap, gd_xap, gd_yap,
                      GDI_DIRECT_DRAW, FALSE,
+                     GDI_OVERLAY_TOUCH_BUTTON, is_touch_button,
                      GDI_EVENT_MASK, event_mask,
                      GDI_CALLBACK_ACTION, HandleGameButtons,
                      GDI_END);
@@ -15677,8 +15729,6 @@ void MapUndoRedoButtons(void)
 
   MapGadget(game_gadget[GAME_CTRL_ID_UNDO]);
   MapGadget(game_gadget[GAME_CTRL_ID_REDO]);
-
-  ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, TRUE, GDI_END);
 }
 
 void UnmapUndoRedoButtons(void)
@@ -15688,8 +15738,22 @@ void UnmapUndoRedoButtons(void)
 
   MapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO);
   MapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO);
+}
+
+void ModifyPauseButtons(void)
+{
+  static int ids[] =
+  {
+    GAME_CTRL_ID_PAUSE,
+    GAME_CTRL_ID_PAUSE2,
+    GAME_CTRL_ID_PANEL_PAUSE,
+    GAME_CTRL_ID_TOUCH_PAUSE,
+    -1
+  };
+  int i;
 
-  ModifyGadget(game_gadget[GAME_CTRL_ID_PAUSE2], GDI_CHECKED, FALSE, GDI_END);
+  for (i = 0; ids[i] > -1; i++)
+    ModifyGadget(game_gadget[ids[i]], GDI_CHECKED, tape.pausing, GDI_END);
 }
 
 static void MapGameButtonsExt(boolean on_tape)
@@ -15723,9 +15787,6 @@ static void RedrawGameButtonsExt(boolean on_tape)
   for (i = 0; i < NUM_GAME_BUTTONS; i++)
     if (!on_tape || gamebutton_info[i].allowed_on_tape)
       RedrawGadget(game_gadget[i]);
-
-  // RedrawGadget() may have set REDRAW_ALL if buttons are defined off-area
-  redraw_mask &= ~REDRAW_ALL;
 }
 
 static void SetGadgetState(struct GadgetInfo *gi, boolean state)
@@ -15832,6 +15893,7 @@ static void HandleGameButtonsExt(int id, int button)
   {
     case GAME_CTRL_ID_STOP:
     case GAME_CTRL_ID_PANEL_STOP:
+    case GAME_CTRL_ID_TOUCH_STOP:
       if (game_status == GAME_MODE_MAIN)
        break;
 
@@ -15845,6 +15907,7 @@ static void HandleGameButtonsExt(int id, int button)
     case GAME_CTRL_ID_PAUSE:
     case GAME_CTRL_ID_PAUSE2:
     case GAME_CTRL_ID_PANEL_PAUSE:
+    case GAME_CTRL_ID_TOUCH_PAUSE:
       if (network.enabled && game_status == GAME_MODE_PLAYING)
       {
        if (tape.pausing)