added centering levels that are smaller than the playfield (MM engine)
[rocksndiamonds.git] / src / tools.c
index b87d7201018950e61db340d14f24b0838e83a7fb..695a536223c87d07372d8d55be2a62f7b8dd888a 100644 (file)
@@ -360,30 +360,26 @@ static int getLevelFromScreenY_SP(int sy)
 
 static int getLevelFromScreenX_MM(int sx)
 {
-#if 0
   int level_xsize = level.native_mm_level->fieldx;
   int full_xsize = level_xsize * TILESIZE_VAR;
 
   sx -= (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
-#endif
 
   int px = sx - SX;
-  int lx = px / TILESIZE_VAR;
+  int lx = (px + TILESIZE_VAR) / TILESIZE_VAR - 1;
 
   return lx;
 }
 
 static int getLevelFromScreenY_MM(int sy)
 {
-#if 0
   int level_ysize = level.native_mm_level->fieldy;
   int full_ysize = level_ysize * TILESIZE_VAR;
 
   sy -= (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
-#endif
 
   int py = sy - SY;
-  int ly = py / TILESIZE_VAR;
+  int ly = (py + TILESIZE_VAR) / TILESIZE_VAR - 1;
 
   return ly;
 }
@@ -635,6 +631,64 @@ void DrawMaskedBorderToTarget(int draw_target)
   }
 }
 
+void DrawTileCursor(int draw_target)
+{
+  Bitmap *fade_bitmap;
+  Bitmap *src_bitmap;
+  int src_x, src_y;
+  int dst_x, dst_y;
+  int graphic = IMG_GLOBAL_TILE_CURSOR;
+  int frame = 0;
+  int tilesize = TILESIZE_VAR;
+  int width = tilesize;
+  int height = tilesize;
+
+  if (game_status != GAME_MODE_PLAYING)
+    return;
+
+  if (!tile_cursor.enabled ||
+      !tile_cursor.active)
+    return;
+
+  if (tile_cursor.moving)
+  {
+    int step = TILESIZE_VAR / 4;
+    int dx = tile_cursor.target_x - tile_cursor.x;
+    int dy = tile_cursor.target_y - tile_cursor.y;
+
+    if (ABS(dx) < step)
+      tile_cursor.x = tile_cursor.target_x;
+    else
+      tile_cursor.x += SIGN(dx) * step;
+
+    if (ABS(dy) < step)
+      tile_cursor.y = tile_cursor.target_y;
+    else
+      tile_cursor.y += SIGN(dy) * step;
+
+    if (tile_cursor.x == tile_cursor.target_x &&
+       tile_cursor.y == tile_cursor.target_y)
+      tile_cursor.moving = FALSE;
+  }
+
+  dst_x = tile_cursor.x;
+  dst_y = tile_cursor.y;
+
+  frame = getGraphicAnimationFrame(graphic, -1);
+
+  getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
+
+  fade_bitmap =
+    (draw_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
+     draw_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
+
+  if (draw_target == DRAW_TO_SCREEN)
+    BlitToScreenMasked(src_bitmap, src_x, src_y, width, height, dst_x, dst_y);
+  else
+    BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height,
+                    dst_x, dst_y);
+}
+
 void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
 {
   int fx = getFieldbufferOffsetX_RND();
@@ -1005,6 +1059,7 @@ void FadeOut(int fade_mask)
 
   SetScreenStates_BeforeFadingOut();
 
+  SetTileCursorActive(FALSE);
   SetOverlayActive(FALSE);
 
 #if 0
@@ -4770,7 +4825,7 @@ unsigned int MoveDoor(unsigned int door_state)
     door_state &= ~DOOR_CLOSE_ALL;
   }
 
-  if (game_status == GAME_MODE_EDITOR)
+  if (game_status == GAME_MODE_EDITOR && !(door_state & DOOR_FORCE_ANIM))
     door_state |= DOOR_NO_DELAY;
 
   if (door_state & DOOR_ACTION)
@@ -8688,6 +8743,23 @@ void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
   }
 }
 
+void CheckSaveEngineSnapshot_MM(boolean element_clicked,
+                               boolean button_released)
+{
+  if (button_released)
+  {
+    if (game.snapshot.mode == SNAPSHOT_MODE_EVERY_MOVE)
+      CheckSaveEngineSnapshotToList();
+  }
+  else if (element_clicked)
+  {
+    if (game.snapshot.mode != SNAPSHOT_MODE_EVERY_MOVE)
+      CheckSaveEngineSnapshotToList();
+
+    game.snapshot.changed_action = TRUE;
+  }
+}
+
 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
                            boolean any_player_moving,
                            boolean any_player_snapping,
@@ -8718,6 +8790,16 @@ void CheckSingleStepMode_SP(boolean murphy_is_waiting,
   CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
 }
 
+void CheckSingleStepMode_MM(boolean element_clicked,
+                           boolean button_released)
+{
+  if (tape.single_step && tape.recording && !tape.pausing)
+    if (button_released)
+      TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+
+  CheckSaveEngineSnapshot_MM(element_clicked, button_released);
+}
+
 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
                         int graphic, int sync_frame, int x, int y)
 {
@@ -8973,6 +9055,31 @@ void ResetFontStatus()
   SetFontStatus(-1);
 }
 
+boolean CheckIfPlayfieldViewportHasChanged()
+{
+  // if game status has not changed, playfield viewport has not changed either
+  if (game_status == game_status_last)
+    return FALSE;
+
+  // check if playfield viewport has changed with current game status
+  struct RectWithBorder *vp_playfield = &viewport.playfield[game_status];
+  int new_real_sx      = vp_playfield->x;
+  int new_real_sy      = vp_playfield->y;
+  int new_full_sxsize  = vp_playfield->width;
+  int new_full_sysize  = vp_playfield->height;
+
+  return (new_real_sx != REAL_SX ||
+         new_real_sy != REAL_SY ||
+         new_full_sxsize != FULL_SXSIZE ||
+         new_full_sysize != FULL_SYSIZE);
+}
+
+boolean CheckIfGlobalBorderOrPlayfieldViewportHasChanged()
+{
+  return (CheckIfGlobalBorderHasChanged() ||
+         CheckIfPlayfieldViewportHasChanged());
+}
+
 void ChangeViewportPropertiesIfNeeded()
 {
   boolean use_mini_tilesize = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?