added forcing pointer-style global animations to stay inside window area
[rocksndiamonds.git] / src / anim.c
index 2ebf520f79d793a365b5acdedfbdc77a5ea263e5..8256ce7f60f5ec62fda3ebf49adb086a5450cc3b 100644 (file)
@@ -19,6 +19,7 @@
 #include "screens.h"
 
 
+#define DEBUG_ANIM_DELAY               0
 #define DEBUG_ANIM_EVENTS              0
 
 
@@ -209,6 +210,7 @@ struct AnimClassGameMode
 };
 
 // forward declaration for internal use
+static void DoGlobalAnim_DelayAction(struct GlobalAnimPartControlInfo *, int);
 static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *);
 static void HandleGlobalAnim(int, int);
 static void DoAnimationExt(void);
@@ -228,6 +230,8 @@ static int anim_classes_last = ANIM_CLASS_NONE;
 
 static boolean drawing_to_fading_buffer = FALSE;
 
+static boolean handle_click = FALSE;
+
 
 // ============================================================================
 // generic animation frame calculation
@@ -811,13 +815,24 @@ static void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage)
 
 void DrawGlobalAnimations(int drawing_target, int drawing_stage)
 {
+  int last_cursor_mode_override = gfx.cursor_mode_override;
+
   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
+  {
     ResetGlobalAnim_Clickable();
 
+    gfx.cursor_mode_override = CURSOR_UNDEFINED;
+  }
+
   DrawGlobalAnimationsExt(drawing_target, drawing_stage);
 
   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_2)
+  {
     ResetGlobalAnim_Clicked();
+  }
+
+  if (gfx.cursor_mode_override != last_cursor_mode_override)
+    SetMouseCursor(gfx.cursor_mode);
 }
 
 static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
@@ -848,12 +863,17 @@ static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part
   }
   else if (part->control_info.class == get_hash_from_key("pointer"))
   {
-    viewport_x = gfx.mouse_x + part->control_info.x;
-    viewport_y = gfx.mouse_y + part->control_info.y;
+    int mx = MIN(MAX(0, gfx.mouse_x), WIN_XSIZE - 1);
+    int my = MIN(MAX(0, gfx.mouse_y), WIN_YSIZE - 1);
+
+    viewport_x = mx + part->control_info.x;
+    viewport_y = my + part->control_info.y;
     viewport_width  = part->graphic_info.width;
     viewport_height = part->graphic_info.height;
 
     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
+
+    gfx.cursor_mode_override = CURSOR_NONE;
   }
   else if (part->control_info.class == get_hash_from_key("door_1"))
   {
@@ -1155,6 +1175,16 @@ static void InitGlobalAnim_Triggered(struct GlobalAnimPartControlInfo *part,
   }
 }
 
+static void HandleGlobalAnimDelay(struct GlobalAnimPartControlInfo *part,
+                                 int delay_type, char *info_text)
+{
+#if DEBUG_ANIM_DELAY
+  printf("::: %d.%d %s\n", part->old_anim_nr + 1, part->old_nr + 1, info_text);
+#endif
+
+  DoGlobalAnim_DelayAction(part, delay_type);
+}
+
 static void HandleGlobalAnimEvent(struct GlobalAnimPartControlInfo *part,
                                  int event_value, char *info_text)
 {
@@ -1173,6 +1203,9 @@ static void HandleGlobalAnimEvent(struct GlobalAnimPartControlInfo *part,
 static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
                                 int state)
 {
+  if (handle_click && !part->clicked)
+    return state;
+
   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr];
   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[part->anim_nr];
   struct GraphicInfo *g = &part->graphic_info;
@@ -1197,6 +1230,8 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
     part->anim_delay_counter =
       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
 
+    part->post_delay_counter = 0;
+
     part->init_event_state = (c->init_event != ANIM_EVENT_UNDEFINED);
     part->anim_event_state = (c->anim_event != ANIM_EVENT_UNDEFINED);
 
@@ -1292,6 +1327,7 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
     {
       PlayGlobalAnimSoundAndMusic(part);
 
+      HandleGlobalAnimDelay(part, ANIM_DELAY_INIT,  "START [INIT_DELAY]");
       HandleGlobalAnimEvent(part, ANIM_EVENT_START, "START [ANIM]");
     }
     else
@@ -1331,6 +1367,7 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
 
       PlayGlobalAnimSoundAndMusic(part);
 
+      HandleGlobalAnimDelay(part, ANIM_DELAY_INIT,  "START [INIT_DELAY]");
       HandleGlobalAnimEvent(part, ANIM_EVENT_START, "START [ANIM]");
     }
 
@@ -1381,7 +1418,8 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
 
       StopGlobalAnimSoundAndMusic(part);
 
-      HandleGlobalAnimEvent(part, ANIM_EVENT_END, "END [ANIM_DELAY/EVENT]");
+      HandleGlobalAnimDelay(part, ANIM_DELAY_ANIM, "END [ANIM_DELAY]");
+      HandleGlobalAnimEvent(part, ANIM_EVENT_END,  "END [ANIM_DELAY/EVENT]");
 
       part->post_delay_counter =
        (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
@@ -1400,6 +1438,7 @@ static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
 
     if (part->post_delay_counter == 0)
     {
+      HandleGlobalAnimDelay(part, ANIM_DELAY_POST, "END [POST_DELAY]");
       HandleGlobalAnimEvent(part, ANIM_EVENT_POST, "END [POST_DELAY]");
 
       return ANIM_STATE_RESTART;
@@ -1631,22 +1670,37 @@ static void DoAnimationExt(void)
 #endif
 }
 
+static void DoGlobalAnim_DelayAction(struct GlobalAnimPartControlInfo *part,
+                                    int delay_type)
+{
+  int delay_action =
+    (delay_type == ANIM_DELAY_INIT ? part->control_info.init_delay_action :
+     delay_type == ANIM_DELAY_ANIM ? part->control_info.anim_delay_action :
+     delay_type == ANIM_DELAY_POST ? part->control_info.post_delay_action :
+     ANIM_DELAY_ACTION_NONE);
+
+  if (delay_action == ANIM_DELAY_ACTION_NONE)
+    return;
+
+  PushUserEvent(USEREVENT_ANIM_DELAY_ACTION, delay_action, 0);
+}
+
 static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *part)
 {
-  int anim_event_action = part->control_info.anim_event_action;
+  int event_action = (part->init_event_state ?
+                     part->control_info.init_event_action :
+                     part->control_info.anim_event_action);
 
-  if (anim_event_action == -1)
+  if (event_action == ANIM_EVENT_ACTION_NONE)
     return FALSE;
 
-  boolean action_executed = (DoGadgetAction(anim_event_action) ||
-                            DoScreenAction(anim_event_action) ||
-                            DoKeysymAction(anim_event_action));
+  PushUserEvent(USEREVENT_ANIM_EVENT_ACTION, event_action, 0);
 
   // check if further actions are allowed to be executed
   if (part->control_info.style & STYLE_MULTIPLE_ACTIONS)
     return FALSE;
 
-  return action_executed;
+  return TRUE;
 }
 
 static void InitGlobalAnim_Clickable(void)
@@ -1782,6 +1836,15 @@ static boolean InitGlobalAnim_Clicked(int mx, int my, int clicked_event)
     }
   }
 
+  if (anything_clicked)
+  {
+    handle_click = TRUE;
+
+    HandleGlobalAnim(ANIM_CONTINUE, game_status);
+
+    handle_click = FALSE;
+  }
+
   return (anything_clicked || any_event_action);
 }
 
@@ -1795,7 +1858,7 @@ static void ResetGlobalAnim_Clicked(void)
   InitGlobalAnim_Clicked(-1, -1, ANIM_CLICKED_RESET);
 }
 
-boolean HandleGlobalAnimClicks(int mx, int my, int button)
+boolean HandleGlobalAnimClicks(int mx, int my, int button, boolean force_click)
 {
   static boolean click_consumed = FALSE;
   static int last_button = 0;
@@ -1803,6 +1866,9 @@ boolean HandleGlobalAnimClicks(int mx, int my, int button)
   boolean release_event;
   boolean click_consumed_current = click_consumed;
 
+  if (button != 0 && force_click)
+    last_button = 0;
+
   // check if button state has changed since last invocation
   press_event   = (button != 0 && last_button == 0);
   release_event = (button == 0 && last_button != 0);