added asking for restart after game was lost (MM game engine only)
[rocksndiamonds.git] / src / game_mm / mm_game.c
index 19439a8427458bed53b19d0bb1660c514f0b9f38..0a9d2da6fe061ecab630719923aba7ca3cf565ce 100644 (file)
@@ -9,6 +9,8 @@
 // mm_game.c
 // ============================================================================
 
+#include <math.h>
+
 #include "main_mm.h"
 
 #include "mm_main.h"
@@ -742,6 +744,9 @@ void InitGameActions_MM()
 
   if (game_mm.kettles_still_needed == 0)
     CheckExitMM();
+
+  SetTileCursorXY(laser.start_edge.x, laser.start_edge.y);
+  SetTileCursorActive(TRUE);
 }
 
 void AddLaserEdge(int lx, int ly)
@@ -1536,6 +1541,8 @@ boolean HitElement(int element, int hit_mask)
       if (game_mm.kettles_still_needed > 0)
        game_mm.kettles_still_needed--;
 
+      game.snapshot.collected_item = TRUE;
+
       if (game_mm.kettles_still_needed == 0)
       {
        CheckExitMM();
@@ -1963,8 +1970,12 @@ boolean HitLaserDestination(int element, int hit_mask)
   AddDamagedField(ELX, ELY);
 
   if (game_mm.lights_still_needed == 0)
+  {
     game_mm.level_solved = TRUE;
 
+    SetTileCursorActive(FALSE);
+  }
+
   return TRUE;
 }
 
@@ -2472,11 +2483,15 @@ static void Explode_MM(int x, int y, int phase, int mode)
       game_mm.game_over = TRUE;
       game_mm.game_over_cause = GAME_OVER_BOMB;
 
+      SetTileCursorActive(FALSE);
+
       laser.overloaded = FALSE;
     }
     else if (IS_MCDUFFIN(Store[x][y]))
     {
       Store[x][y] = EL_EMPTY;
+
+      game.restart_game_message = "Bomb killed Mc Duffin ! Play it again ?";
     }
 
     Feld[x][y] = Store[x][y];
@@ -2720,11 +2735,12 @@ static void ContinueMoving_MM(int x, int y)
   laser.redraw = TRUE;
 }
 
-void ClickElement(int x, int y, int button)
+boolean ClickElement(int x, int y, int button)
 {
   static unsigned int click_delay = 0;
   static int click_delay_value = CLICK_DELAY;
   static boolean new_button = TRUE;
+  boolean element_clicked = FALSE;
   int element;
 
   if (button == -1)
@@ -2734,12 +2750,12 @@ void ClickElement(int x, int y, int button)
     click_delay_value = CLICK_DELAY;
     new_button = TRUE;
 
-    return;
+    return FALSE;
   }
 
   /* do not rotate objects hit by the laser after the game was solved */
   if (game_mm.level_solved && Hit[x][y])
-    return;
+    return FALSE;
 
   if (button == MB_RELEASED)
   {
@@ -2749,20 +2765,20 @@ void ClickElement(int x, int y, int button)
     /* release eventually hold auto-rotating mirror */
     RotateMirror(x, y, MB_RELEASED);
 
-    return;
+    return FALSE;
   }
 
   if (!FrameReached(&click_delay, click_delay_value) && !new_button)
-    return;
+    return FALSE;
 
   if (button == MB_MIDDLEBUTTON)       /* middle button has no function */
-    return;
+    return FALSE;
 
   if (!IN_LEV_FIELD(x, y))
-    return;
+    return FALSE;
 
   if (Feld[x][y] == EL_EMPTY)
-    return;
+    return FALSE;
 
   element = Feld[x][y];
 
@@ -2774,6 +2790,8 @@ void ClickElement(int x, int y, int button)
       IS_DF_MIRROR_AUTO(element))
   {
     RotateMirror(x, y, button);
+
+    element_clicked = TRUE;
   }
   else if (IS_MCDUFFIN(element))
   {
@@ -2800,17 +2818,21 @@ void ClickElement(int x, int y, int button)
 
     if (!laser.fuse_off)
       ScanLaser();
+
+    element_clicked = TRUE;
   }
   else if (element == EL_FUSE_ON && laser.fuse_off)
   {
     if (x != laser.fuse_x || y != laser.fuse_y)
-      return;
+      return FALSE;
 
     laser.fuse_off = FALSE;
     laser.fuse_x = laser.fuse_y = -1;
 
     DrawGraphic_MM(x, y, IMG_MM_FUSE_ACTIVE);
     ScanLaser();
+
+    element_clicked = TRUE;
   }
   else if (element == EL_FUSE_ON && !laser.fuse_off && new_button)
   {
@@ -2821,16 +2843,22 @@ void ClickElement(int x, int y, int button)
 
     DrawLaser(0, DL_LASER_DISABLED);
     DrawGraphic_MM(x, y, IMG_MM_FUSE);
+
+    element_clicked = TRUE;
   }
   else if (element == EL_LIGHTBALL)
   {
     Bang_MM(x, y);
     RaiseScoreElement_MM(element);
     DrawLaser(0, DL_LASER_ENABLED);
+
+    element_clicked = TRUE;
   }
 
   click_delay_value = (new_button ? CLICK_DELAY_FIRST : CLICK_DELAY);
   new_button = FALSE;
+
+  return element_clicked;
 }
 
 void RotateMirror(int x, int y, int button)
@@ -3153,6 +3181,10 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
       game_mm.game_over = TRUE;
       game_mm.game_over_cause = GAME_OVER_NO_ENERGY;
 
+      SetTileCursorActive(FALSE);
+
+      game.restart_game_message = "Out of magic energy ! Play it again ?";
+
 #if 0
       if (Request("Out of magic energy ! Play it again ?",
                  REQ_ASK | REQ_STAY_CLOSED))
@@ -3283,6 +3315,10 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
       game_mm.game_over = TRUE;
       game_mm.game_over_cause = GAME_OVER_OVERLOADED;
 
+      SetTileCursorActive(FALSE);
+
+      game.restart_game_message = "Magic spell hit Mc Duffin ! Play it again ?";
+
 #if 0
       if (Request("Magic spell hit Mc Duffin ! Play it again ?",
                  REQ_ASK | REQ_STAY_CLOSED))
@@ -3729,9 +3765,12 @@ static void GameActions_MM_Ext(struct MouseActionInfo action, boolean warp_mode)
 
 void GameActions_MM(struct MouseActionInfo action, boolean warp_mode)
 {
-  ClickElement(action.lx, action.ly, action.button);
+  boolean element_clicked = ClickElement(action.lx, action.ly, action.button);
+  boolean button_released = (action.button == MB_RELEASED);
 
   GameActions_MM_Ext(action, warp_mode);
+
+  CheckSingleStepMode_MM(element_clicked, button_released);
 }
 
 void MovePacMen()
@@ -4283,3 +4322,88 @@ void LoadEngineSnapshotValues_MM()
 
   RedrawPlayfield_MM(TRUE);
 }
+
+static int getAngleFromTouchDelta(int dx, int dy,  int base)
+{
+  double pi = 3.141592653;
+  double rad = atan2((double)-dy, (double)dx);
+  double rad2 = (rad < 0 ? rad + 2 * pi : rad);
+  double deg = rad2 * 180.0 / pi;
+
+  return (int)(deg * base / 360.0 + 0.5) % base;
+}
+
+int getButtonFromTouchPosition(int x, int y, int dst_mx, int dst_my)
+{
+  // calculate start (source) position to be at the middle of the tile
+  int src_mx = SX + x * TILESIZE_VAR + TILESIZE_VAR / 2;
+  int src_my = SY + y * TILESIZE_VAR + TILESIZE_VAR / 2;
+  int dx = dst_mx - src_mx;
+  int dy = dst_my - src_my;
+  int element;
+  int base = 16;
+  int phases = 16;
+  int angle_old = -1;
+  int angle_new = -1;
+  int button = 0;
+  int i;
+
+  if (!IN_LEV_FIELD(x, y))
+    return 0;
+
+  element = Feld[x][y];
+
+  if (!IS_MCDUFFIN(element) &&
+      !IS_MIRROR(element) &&
+      !IS_BEAMER(element) &&
+      !IS_POLAR(element) &&
+      !IS_POLAR_CROSS(element) &&
+      !IS_DF_MIRROR(element))
+    return 0;
+
+  angle_old = get_element_angle(element);
+
+  if (IS_MCDUFFIN(element))
+  {
+    angle_new = (dx > 0 && ABS(dy) < ABS(dx) ? ANG_RAY_RIGHT :
+                dy < 0 && ABS(dx) < ABS(dy) ? ANG_RAY_UP :
+                dx < 0 && ABS(dy) < ABS(dx) ? ANG_RAY_LEFT :
+                dy > 0 && ABS(dx) < ABS(dy) ? ANG_RAY_DOWN :
+                -1);
+  }
+  else if (IS_MIRROR(element) ||
+          IS_DF_MIRROR(element))
+  {
+    for (i = 0; i < laser.num_damages; i++)
+    {
+      if (laser.damage[i].x == x &&
+         laser.damage[i].y == y &&
+         ObjHit(x, y, HIT_POS_CENTER))
+      {
+       angle_old = get_mirrored_angle(laser.damage[i].angle, angle_old);
+       angle_new = getAngleFromTouchDelta(dx, dy, base) % phases;
+
+       break;
+      }
+    }
+  }
+
+  if (angle_new == -1)
+  {
+    if (IS_MIRROR(element) ||
+       IS_DF_MIRROR(element) ||
+       IS_POLAR(element))
+      base = 32;
+
+    if (IS_POLAR_CROSS(element))
+      phases = 4;
+
+    angle_new = getAngleFromTouchDelta(dx, dy, base) % phases;
+  }
+
+  button = (angle_new == angle_old ? 0 :
+           (angle_new - angle_old + phases) % phases < (phases / 2) ?
+           MB_LEFTBUTTON : MB_RIGHTBUTTON);
+
+  return button;
+}