added step-based engine snapshots to undo/redo game steps (continued)
[rocksndiamonds.git] / src / tools.c
index d5dc6909490e514acd3bed4cf2d814ac2926420d..7c0634294d1e78ebb2ea70822f2249858f29a0f5 100644 (file)
@@ -2028,6 +2028,14 @@ void DrawLevelField(int x, int y)
   }
 }
 
+void DrawSizedElement(int x, int y, int element, int tilesize)
+{
+  int graphic;
+
+  graphic = el2edimg(element);
+  DrawSizedGraphic(x, y, graphic, 0, tilesize);
+}
+
 void DrawMiniElement(int x, int y, int element)
 {
   int graphic;
@@ -2036,6 +2044,19 @@ void DrawMiniElement(int x, int y, int element)
   DrawMiniGraphic(x, y, graphic);
 }
 
+void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
+                           int tilesize)
+{
+  int x = sx + scroll_x, y = sy + scroll_y;
+
+  if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
+    DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
+  else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
+    DrawSizedElement(sx, sy, Feld[x][y], tilesize);
+  else
+    DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
+}
+
 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
 {
   int x = sx + scroll_x, y = sy + scroll_y;
@@ -2501,6 +2522,18 @@ void DrawLevel(int draw_background_mask)
   redraw_mask |= REDRAW_FIELD;
 }
 
+void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
+                   int tilesize)
+{
+  int x,y;
+
+  for (x = 0; x < size_x; x++)
+    for (y = 0; y < size_y; y++)
+      DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
+
+  redraw_mask |= REDRAW_FIELD;
+}
+
 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
 {
   int x,y;
@@ -3356,109 +3389,110 @@ static int RequestHandleEvents(unsigned int req_state)
     {
       Event event;
 
-      NextEvent(&event);
-
-      switch (event.type)
+      while (NextValidEvent(&event))
       {
-       case EVENT_BUTTONPRESS:
-       case EVENT_BUTTONRELEASE:
-       case EVENT_MOTIONNOTIFY:
+       switch (event.type)
        {
-         if (event.type == EVENT_MOTIONNOTIFY)
-         {
-           if (!PointerInWindow(window))
-             continue; /* window and pointer are on different screens */
-
-           if (!button_status)
-             continue;
-
-           motion_status = TRUE;
-           mx = ((MotionEvent *) &event)->x;
-           my = ((MotionEvent *) &event)->y;
-         }
-         else
+         case EVENT_BUTTONPRESS:
+         case EVENT_BUTTONRELEASE:
+         case EVENT_MOTIONNOTIFY:
          {
-           motion_status = FALSE;
-           mx = ((ButtonEvent *) &event)->x;
-           my = ((ButtonEvent *) &event)->y;
-           if (event.type == EVENT_BUTTONPRESS)
-             button_status = ((ButtonEvent *) &event)->button;
+           if (event.type == EVENT_MOTIONNOTIFY)
+           {
+             if (!PointerInWindow(window))
+               continue;       /* window and pointer on different screens */
+
+             if (!button_status)
+               continue;
+
+             motion_status = TRUE;
+             mx = ((MotionEvent *) &event)->x;
+             my = ((MotionEvent *) &event)->y;
+           }
            else
-             button_status = MB_RELEASED;
-         }
-
-         /* this sets 'request_gadget_id' */
-         HandleGadgets(mx, my, button_status);
-
-         switch (request_gadget_id)
-         {
-           case TOOL_CTRL_ID_YES:
-             result = TRUE;
-             break;
-           case TOOL_CTRL_ID_NO:
-             result = FALSE;
-             break;
-           case TOOL_CTRL_ID_CONFIRM:
-             result = TRUE | FALSE;
-             break;
-
-           case TOOL_CTRL_ID_PLAYER_1:
-             result = 1;
-             break;
-           case TOOL_CTRL_ID_PLAYER_2:
-             result = 2;
-             break;
-           case TOOL_CTRL_ID_PLAYER_3:
-             result = 3;
-             break;
-           case TOOL_CTRL_ID_PLAYER_4:
-             result = 4;
-             break;
-
-           default:
-             break;
+           {
+             motion_status = FALSE;
+             mx = ((ButtonEvent *) &event)->x;
+             my = ((ButtonEvent *) &event)->y;
+             if (event.type == EVENT_BUTTONPRESS)
+               button_status = ((ButtonEvent *) &event)->button;
+             else
+               button_status = MB_RELEASED;
+           }
+
+           /* this sets 'request_gadget_id' */
+           HandleGadgets(mx, my, button_status);
+
+           switch (request_gadget_id)
+           {
+             case TOOL_CTRL_ID_YES:
+               result = TRUE;
+               break;
+             case TOOL_CTRL_ID_NO:
+               result = FALSE;
+               break;
+             case TOOL_CTRL_ID_CONFIRM:
+               result = TRUE | FALSE;
+               break;
+
+             case TOOL_CTRL_ID_PLAYER_1:
+               result = 1;
+               break;
+             case TOOL_CTRL_ID_PLAYER_2:
+               result = 2;
+               break;
+             case TOOL_CTRL_ID_PLAYER_3:
+               result = 3;
+               break;
+             case TOOL_CTRL_ID_PLAYER_4:
+               result = 4;
+               break;
+
+             default:
+               break;
+           }
+
+           break;
          }
 
-         break;
-       }
+         case EVENT_KEYPRESS:
+           switch (GetEventKey((KeyEvent *)&event, TRUE))
+           {
+             case KSYM_space:
+               if (req_state & REQ_CONFIRM)
+                 result = 1;
+               break;
 
-       case EVENT_KEYPRESS:
-         switch (GetEventKey((KeyEvent *)&event, TRUE))
-         {
-           case KSYM_space:
-             if (req_state & REQ_CONFIRM)
-               result = 1;
-             break;
-
-           case KSYM_Return:
+             case KSYM_Return:
 #if defined(TARGET_SDL2)
-           case KSYM_Menu:
+             case KSYM_Menu:
 #endif
-             result = 1;
-             break;
+               result = 1;
+               break;
 
-           case KSYM_Escape:
+             case KSYM_Escape:
 #if defined(TARGET_SDL2)
-           case KSYM_Back:
+             case KSYM_Back:
 #endif
-             result = 0;
-             break;
+               result = 0;
+               break;
 
-           default:
-             break;
-         }
+             default:
+               break;
+           }
 
-         if (req_state & REQ_PLAYER)
-           result = 0;
-         break;
+           if (req_state & REQ_PLAYER)
+             result = 0;
+           break;
 
-       case EVENT_KEYRELEASE:
-         ClearPlayerAction();
-         break;
+         case EVENT_KEYRELEASE:
+           ClearPlayerAction();
+           break;
 
-       default:
-         HandleOtherEvents(&event);
-         break;
+         default:
+           HandleOtherEvents(&event);
+           break;
+       }
       }
     }
     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
@@ -4151,6 +4185,8 @@ unsigned int MoveDoor(unsigned int door_state)
       }
     }
 
+    max_step_delay = MAX(1, max_step_delay);   // prevent division by zero
+
     num_move_steps = max_move_delay / max_step_delay;
     num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
 
@@ -7758,13 +7794,59 @@ void InitGraphicInfo_EM(void)
 #endif
 }
 
+void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
+                               boolean any_player_moving,
+                               boolean any_player_snapping,
+                               boolean any_player_dropping)
+{
+  static boolean player_was_waiting = TRUE;
+
+  if (frame == 0 && !any_player_dropping)
+  {
+    if (!player_was_waiting)
+    {
+      SaveEngineSnapshotToList();
+
+      player_was_waiting = TRUE;
+    }
+  }
+  else if (any_player_moving || any_player_snapping || any_player_dropping)
+  {
+    player_was_waiting = FALSE;
+  }
+}
+
+void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
+                               boolean murphy_is_dropping)
+{
+  static boolean player_was_waiting = FALSE;
+
+  if (murphy_is_waiting)
+  {
+    if (!player_was_waiting)
+    {
+      SaveEngineSnapshotToList();
+
+      player_was_waiting = TRUE;
+    }
+  }
+  else
+  {
+    player_was_waiting = FALSE;
+  }
+}
+
 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
                            boolean any_player_moving,
-                           boolean player_is_dropping)
+                           boolean any_player_snapping,
+                           boolean any_player_dropping)
 {
   if (tape.single_step && tape.recording && !tape.pausing)
-    if (frame == 0 && !player_is_dropping)
+    if (frame == 0 && !any_player_dropping)
       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+
+  CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
+                            any_player_snapping, any_player_dropping);
 }
 
 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
@@ -7773,6 +7855,8 @@ void CheckSingleStepMode_SP(boolean murphy_is_waiting,
   if (tape.single_step && tape.recording && !tape.pausing)
     if (murphy_is_waiting)
       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+
+  CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
 }
 
 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
@@ -8044,7 +8128,7 @@ void ChangeViewportPropertiesIfNeeded()
       // printf("::: new_tilesize_var != TILESIZE_VAR\n");
 
       // changing tile size invalidates scroll values of engine snapshots
-      FreeEngineSnapshot();
+      FreeEngineSnapshotSingle();
 
       // changing tile size requires update of graphic mapping for EM engine
       init_em_graphics = TRUE;