+
+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 event_action = (part->init_event_state ?
+ part->control_info.init_event_action :
+ part->control_info.anim_event_action);
+
+ if (event_action == ANIM_EVENT_ACTION_NONE)
+ return FALSE;
+
+ if (event_action < MAX_IMAGE_FILES)
+ PushUserEvent(USEREVENT_ANIM_EVENT_ACTION, event_action, 0);
+ else
+ OpenURLFromHash(anim_url_hash, event_action);
+
+ // check if further actions are allowed to be executed
+ if (part->control_info.style & STYLE_MULTIPLE_ACTIONS)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void InitGlobalAnim_Clickable(void)
+{
+ int i;
+
+ for (i = 0; i < num_global_anim_list; i++)
+ {
+ struct GlobalAnimPartControlInfo *part = global_anim_list[i];
+
+ if (part->triggered)
+ part->clicked = TRUE;
+
+ part->triggered = FALSE;
+ part->clickable = FALSE;
+ }
+}
+
+#define ANIM_CLICKED_RESET 0
+#define ANIM_CLICKED_PRESSED 1
+#define ANIM_CLICKED_RELEASED 2
+
+static boolean InitGlobalAnim_Clicked(int mx, int my, int clicked_event)
+{
+ boolean click_consumed = FALSE;
+ boolean anything_clicked = FALSE;
+ boolean any_part_clicked = FALSE;
+ boolean any_event_action = FALSE;
+ int i;
+
+ // check animation parts in reverse draw order (to stop when clicked)
+ for (i = num_global_anim_list - 1; i >= 0; i--)
+ {
+ struct GlobalAnimPartControlInfo *part = global_anim_list[i];
+
+ // if request dialog is active, only handle pointer-style animations
+ if (game.request_active &&
+ part->control_info.class != get_hash_from_string("pointer"))
+ continue;
+
+ if (clicked_event == ANIM_CLICKED_RESET)
+ {
+ part->clicked = FALSE;
+
+ continue;
+ }
+
+ if (!part->clickable)
+ continue;
+
+ if (!(part->state & ANIM_STATE_RUNNING))
+ continue;
+
+ // always handle "any" click events (clicking anywhere on screen) ...
+ if (clicked_event == ANIM_CLICKED_PRESSED &&
+ isClickablePart(part, ANIM_EVENT_ANY))
+ {
+#if DEBUG_ANIM_EVENTS
+ Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY ANY",
+ part->old_anim_nr + 1, part->old_nr + 1);
+#endif
+
+ anything_clicked = part->clicked = TRUE;
+ click_consumed |= clickConsumed(part);
+ }
+
+ // always handle "unclick:any" events (releasing anywhere on screen) ...
+ if (clicked_event == ANIM_CLICKED_RELEASED &&
+ isClickablePart(part, ANIM_EVENT_UNCLICK_ANY))
+ {
+#if DEBUG_ANIM_EVENTS
+ Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY UNCLICK:ANY",
+ part->old_anim_nr + 1, part->old_nr + 1);
+#endif
+
+ anything_clicked = part->clicked = TRUE;
+ click_consumed |= clickConsumed(part);
+ }
+
+ // ... but only handle the first (topmost) clickable animation
+ if (any_part_clicked)
+ continue;
+
+ if (clicked_event == ANIM_CLICKED_PRESSED &&
+ isClickedPart(part, mx, my, TRUE))
+ {
+#if 0
+ Debug("anim:InitGlobalAnim_Clicked", "%d.%d CLICKED [%d]",
+ anim_nr, part_nr, part->control_info.anim_event_action);
+#endif
+
+ // after executing event action, ignore any further actions
+ if (!any_event_action && DoGlobalAnim_EventAction(part))
+ any_event_action = TRUE;
+
+ // determine if mouse clicks should be blocked from other animations
+ any_part_clicked |= clickConsumed(part);
+
+ if (isClickablePart(part, ANIM_EVENT_SELF))
+ {
+#if DEBUG_ANIM_EVENTS
+ Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY SELF",
+ part->old_anim_nr + 1, part->old_nr + 1);
+#endif
+
+ anything_clicked = part->clicked = TRUE;
+ click_consumed |= clickConsumed(part);
+ }
+
+ // determine if mouse clicks should be blocked by this animation
+ click_consumed |= clickBlocked(part);
+
+ // check if this click is defined to trigger other animations
+ InitGlobalAnim_Triggered(part, &click_consumed, &any_event_action,
+ ANIM_EVENT_CLICK, "CLICK");
+ }
+ }
+
+ if (anything_clicked)
+ {
+ handle_click = TRUE;
+
+ for (i = 0; i < NUM_GAME_MODES; i++)
+ HandleGlobalAnim(ANIM_CONTINUE, i);
+
+ handle_click = FALSE;
+
+ // prevent ignoring release event if processed within same game frame
+ StopProcessingEvents();
+ }
+
+ return (click_consumed || any_event_action);
+}
+
+static void ResetGlobalAnim_Clickable(void)
+{
+ InitGlobalAnim_Clickable();
+}
+
+static void ResetGlobalAnim_Clicked(void)
+{
+ InitGlobalAnim_Clicked(-1, -1, ANIM_CLICKED_RESET);
+}
+
+void RestartGlobalAnimsByStatus(int status)
+{
+ int anim_status_last = global.anim_status;
+
+ global.anim_status = status;
+
+ // force restarting global animations by changed global animation status
+ DrawGlobalAnimationsExt(DRAW_TO_SCREEN, DRAW_GLOBAL_ANIM_STAGE_RESTART);
+
+ global.anim_status = anim_status_last;
+}
+
+void SetAnimStatusBeforeFading(int status)
+{
+ anim_status_last_before_fading = status;
+}
+
+boolean HandleGlobalAnimClicks(int mx, int my, int button, boolean force_click)
+{
+ static boolean click_consumed = FALSE;
+ static int last_button = 0;
+ boolean press_event;
+ 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);
+ last_button = button;
+
+ if (press_event)
+ {
+ click_consumed = InitGlobalAnim_Clicked(mx, my, ANIM_CLICKED_PRESSED);
+ click_consumed_current = click_consumed;
+ }
+
+ if (release_event)
+ {
+ InitGlobalAnim_Clicked(mx, my, ANIM_CLICKED_RELEASED);
+ click_consumed = FALSE;
+ }
+
+ return click_consumed_current;
+}
+
+int getGlobalAnimSyncFrame(void)
+{
+ return anim_sync_frame;
+}
+
+void HandleGlobalAnimEventByElementChange(int element, int page, int x, int y,
+ int trigger_x, int trigger_y)
+{
+ if (!IS_CUSTOM_ELEMENT(element))
+ return;
+
+ // custom element stored as 0 to 255, change page stored as 1 to 32
+ InitGlobalAnim_Triggered_ByCustomElement(element - EL_CUSTOM_START, page + 1,
+ x, y, trigger_x, trigger_y);
+}