added support for opening URLs for global animation event actions
[rocksndiamonds.git] / src / anim.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  https://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // anim.c
10 // ============================================================================
11
12 #include "libgame/libgame.h"
13
14 #include "anim.h"
15 #include "main.h"
16 #include "tools.h"
17 #include "files.h"
18 #include "events.h"
19 #include "screens.h"
20
21
22 #define DEBUG_ANIM_DELAY                0
23 #define DEBUG_ANIM_EVENTS               0
24
25
26 // values for global toon animation definition
27 #define NUM_GLOBAL_TOON_ANIMS           1
28 #define NUM_GLOBAL_TOON_PARTS           MAX_NUM_TOONS
29
30 // values for global animation definition (including toons)
31 #define NUM_GLOBAL_ANIMS_AND_TOONS      (NUM_GLOBAL_ANIMS +             \
32                                          NUM_GLOBAL_TOON_ANIMS)
33 #define NUM_GLOBAL_ANIM_PARTS_AND_TOONS MAX(NUM_GLOBAL_ANIM_PARTS_ALL,  \
34                                             NUM_GLOBAL_TOON_PARTS)
35
36 #define ANIM_CLASS_BIT_TITLE_INITIAL    0
37 #define ANIM_CLASS_BIT_TITLE            1
38 #define ANIM_CLASS_BIT_MAIN             2
39 #define ANIM_CLASS_BIT_SCORES           3
40 #define ANIM_CLASS_BIT_SCORESONLY       4
41 #define ANIM_CLASS_BIT_SUBMENU          5
42 #define ANIM_CLASS_BIT_MENU             6
43 #define ANIM_CLASS_BIT_TOONS            7
44 #define ANIM_CLASS_BIT_NO_TITLE         8
45
46 #define NUM_ANIM_CLASSES                9
47
48 #define ANIM_CLASS_NONE                 0
49 #define ANIM_CLASS_TITLE_INITIAL        (1 << ANIM_CLASS_BIT_TITLE_INITIAL)
50 #define ANIM_CLASS_TITLE                (1 << ANIM_CLASS_BIT_TITLE)
51 #define ANIM_CLASS_MAIN                 (1 << ANIM_CLASS_BIT_MAIN)
52 #define ANIM_CLASS_SCORES               (1 << ANIM_CLASS_BIT_SCORES)
53 #define ANIM_CLASS_SCORESONLY           (1 << ANIM_CLASS_BIT_SCORESONLY)
54 #define ANIM_CLASS_SUBMENU              (1 << ANIM_CLASS_BIT_SUBMENU)
55 #define ANIM_CLASS_MENU                 (1 << ANIM_CLASS_BIT_MENU)
56 #define ANIM_CLASS_TOONS                (1 << ANIM_CLASS_BIT_TOONS)
57 #define ANIM_CLASS_NO_TITLE             (1 << ANIM_CLASS_BIT_NO_TITLE)
58
59 #define ANIM_CLASS_TOONS_SCORES         (ANIM_CLASS_TOONS       |       \
60                                          ANIM_CLASS_SCORES      |       \
61                                          ANIM_CLASS_NO_TITLE)
62
63 #define ANIM_CLASS_TOONS_SCORESONLY     (ANIM_CLASS_TOONS       |       \
64                                          ANIM_CLASS_SCORES      |       \
65                                          ANIM_CLASS_SCORESONLY  |       \
66                                          ANIM_CLASS_NO_TITLE)
67
68 #define ANIM_CLASS_TOONS_MENU_MAIN      (ANIM_CLASS_TOONS       |       \
69                                          ANIM_CLASS_MENU        |       \
70                                          ANIM_CLASS_MAIN        |       \
71                                          ANIM_CLASS_NO_TITLE)
72
73 #define ANIM_CLASS_TOONS_MENU_SUBMENU   (ANIM_CLASS_TOONS       |       \
74                                          ANIM_CLASS_MENU        |       \
75                                          ANIM_CLASS_SUBMENU     |       \
76                                          ANIM_CLASS_NO_TITLE)
77
78 // values for global animation states
79 #define ANIM_STATE_INACTIVE             0
80 #define ANIM_STATE_RESTART              (1 << 0)
81 #define ANIM_STATE_WAITING              (1 << 1)
82 #define ANIM_STATE_RUNNING              (1 << 2)
83
84 // values for global animation control
85 #define ANIM_NO_ACTION                  0
86 #define ANIM_START                      1
87 #define ANIM_CONTINUE                   2
88 #define ANIM_STOP                       3
89
90
91 struct GlobalAnimPartControlInfo
92 {
93   int old_nr;           // position before mapping animation parts linearly
94   int old_anim_nr;      // position before mapping animations linearly
95
96   int nr;
97   int anim_nr;
98   int mode_nr;
99
100   boolean is_base;      // animation part is base/main/default animation part
101
102   int sound;
103   int music;
104   int graphic;
105
106   struct GraphicInfo graphic_info;
107   struct GraphicInfo control_info;
108
109   int viewport_x;
110   int viewport_y;
111   int viewport_width;
112   int viewport_height;
113
114   int x, y;
115   int step_xoffset, step_yoffset;
116
117   unsigned int initial_anim_sync_frame;
118   unsigned int anim_random_frame;
119   unsigned int step_delay, step_delay_value;
120
121   int init_delay_counter;
122   int anim_delay_counter;
123   int post_delay_counter;
124
125   boolean init_event_state;
126   boolean anim_event_state;
127
128   boolean triggered;
129   boolean clickable;
130   boolean clicked;
131
132   int drawing_stage;
133
134   int state;
135   int last_anim_status;
136 };
137
138 struct GlobalAnimMainControlInfo
139 {
140   struct GlobalAnimPartControlInfo base;
141   struct GlobalAnimPartControlInfo part[NUM_GLOBAL_ANIM_PARTS_AND_TOONS];
142
143   int nr;
144   int mode_nr;
145
146   struct GraphicInfo control_info;
147
148   int num_parts;        // number of animation parts, but without base part
149   int num_parts_all;    // number of animation parts, including base part
150   int part_counter;
151   int active_part_nr;
152
153   boolean has_base;     // animation has base/main/default animation part
154
155   int last_x, last_y;
156
157   int init_delay_counter;
158
159   int state;
160
161   int last_state, last_active_part_nr;
162 };
163
164 struct GlobalAnimControlInfo
165 {
166   struct GlobalAnimMainControlInfo anim[NUM_GLOBAL_ANIMS_AND_TOONS];
167
168   int nr;
169   int num_anims;
170 };
171
172 struct GameModeAnimClass
173 {
174   int game_mode;
175   int class;
176 } game_mode_anim_classes_list[] =
177 {
178   { GAME_MODE_TITLE_INITIAL_1,          ANIM_CLASS_TITLE_INITIAL        },
179   { GAME_MODE_TITLE_INITIAL_2,          ANIM_CLASS_TITLE_INITIAL        },
180   { GAME_MODE_TITLE_INITIAL_3,          ANIM_CLASS_TITLE_INITIAL        },
181   { GAME_MODE_TITLE_INITIAL_4,          ANIM_CLASS_TITLE_INITIAL        },
182   { GAME_MODE_TITLE_INITIAL_5,          ANIM_CLASS_TITLE_INITIAL        },
183   { GAME_MODE_TITLE_1,                  ANIM_CLASS_TITLE                },
184   { GAME_MODE_TITLE_2,                  ANIM_CLASS_TITLE                },
185   { GAME_MODE_TITLE_3,                  ANIM_CLASS_TITLE                },
186   { GAME_MODE_TITLE_4,                  ANIM_CLASS_TITLE                },
187   { GAME_MODE_TITLE_5,                  ANIM_CLASS_TITLE                },
188   { GAME_MODE_NAMES,                    ANIM_CLASS_TOONS_MENU_SUBMENU   },
189   { GAME_MODE_LEVELS,                   ANIM_CLASS_TOONS_MENU_SUBMENU   },
190   { GAME_MODE_LEVELNR,                  ANIM_CLASS_TOONS_MENU_SUBMENU   },
191   { GAME_MODE_INFO,                     ANIM_CLASS_TOONS_MENU_SUBMENU   },
192   { GAME_MODE_SETUP,                    ANIM_CLASS_TOONS_MENU_SUBMENU   },
193   { GAME_MODE_PSEUDO_NAMESONLY,         ANIM_CLASS_TOONS_MENU_SUBMENU   },
194   { GAME_MODE_PSEUDO_TYPENAMES,         ANIM_CLASS_TOONS_MENU_SUBMENU   },
195   { GAME_MODE_PSEUDO_MAINONLY,          ANIM_CLASS_TOONS_MENU_MAIN      },
196   { GAME_MODE_PSEUDO_TYPENAME,          ANIM_CLASS_TOONS_MENU_MAIN      },
197   { GAME_MODE_PSEUDO_SCORESOLD,         ANIM_CLASS_TOONS_SCORESONLY     },
198   { GAME_MODE_PSEUDO_SCORESNEW,         ANIM_CLASS_TOONS_SCORESONLY     },
199   { GAME_MODE_SCOREINFO,                ANIM_CLASS_TOONS_SCORES         },
200   { GAME_MODE_EDITOR,                   ANIM_CLASS_NO_TITLE             },
201   { GAME_MODE_PLAYING,                  ANIM_CLASS_NO_TITLE             },
202
203   { -1,                                 -1                              }
204 };
205
206 struct AnimClassGameMode
207 {
208   int class_bit;
209   int game_mode;
210 } anim_class_game_modes_list[] =
211 {
212   { ANIM_CLASS_BIT_TITLE_INITIAL,       GAME_MODE_TITLE_INITIAL         },
213   { ANIM_CLASS_BIT_TITLE,               GAME_MODE_TITLE                 },
214   { ANIM_CLASS_BIT_MAIN,                GAME_MODE_MAIN                  },
215   { ANIM_CLASS_BIT_SCORES,              GAME_MODE_SCORES                },
216   { ANIM_CLASS_BIT_SCORESONLY,          GAME_MODE_PSEUDO_SCORESONLY     },
217   { ANIM_CLASS_BIT_SUBMENU,             GAME_MODE_PSEUDO_SUBMENU        },
218   { ANIM_CLASS_BIT_MENU,                GAME_MODE_PSEUDO_MENU           },
219   { ANIM_CLASS_BIT_TOONS,               GAME_MODE_PSEUDO_TOONS          },
220   { ANIM_CLASS_BIT_NO_TITLE,            GAME_MODE_PSEUDO_NO_TITLE       },
221
222   { -1,                                 -1                              }
223 };
224
225 // forward declaration for internal use
226 static void DoGlobalAnim_DelayAction(struct GlobalAnimPartControlInfo *, int);
227 static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *);
228 static void HandleGlobalAnim(int, int);
229 static void DoAnimationExt(void);
230 static void ResetGlobalAnim_Clickable(void);
231 static void ResetGlobalAnim_Clicked(void);
232
233 static struct GlobalAnimControlInfo global_anim_ctrl[NUM_GAME_MODES];
234
235 static unsigned int anim_sync_frame = 0;
236
237 static int game_mode_anim_classes[NUM_GAME_MODES];
238 static int anim_class_game_modes[NUM_ANIM_CLASSES];
239
240 static int anim_status_last_before_fading = GAME_MODE_DEFAULT;
241 static int anim_status_last = GAME_MODE_DEFAULT;
242 static int anim_classes_last = ANIM_CLASS_NONE;
243
244 static boolean drawing_to_fading_buffer = FALSE;
245
246 static boolean handle_click = FALSE;
247
248
249 // ============================================================================
250 // generic animation frame calculation
251 // ============================================================================
252
253 int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
254                       int sync_frame)
255 {
256   int frame = 0;
257
258   if (delay < 1)                        // delay must be at least 1
259     delay = 1;
260
261   sync_frame += start_frame * delay;
262
263   if (mode & ANIM_LOOP)                 // looping animation
264   {
265     frame = (sync_frame % (delay * num_frames)) / delay;
266   }
267   else if (mode & ANIM_LINEAR)          // linear (non-looping) animation
268   {
269     frame = sync_frame / delay;
270
271     if (frame > num_frames - 1)
272       frame = num_frames - 1;
273   }
274   else if (mode & ANIM_PINGPONG)        // oscillate (border frames once)
275   {
276     int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1);
277
278     frame = (sync_frame % (delay * max_anim_frames)) / delay;
279     frame = (frame < num_frames ? frame : max_anim_frames - frame);
280   }
281   else if (mode & ANIM_PINGPONG2)       // oscillate (border frames twice)
282   {
283     int max_anim_frames = 2 * num_frames;
284
285     frame = (sync_frame % (delay * max_anim_frames)) / delay;
286     frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
287   }
288   else if (mode & ANIM_RANDOM)          // play frames in random order
289   {
290     // note: expect different frames for the same delay cycle!
291
292     if (gfx.anim_random_frame < 0)
293       frame = GetSimpleRandom(num_frames);
294     else
295       frame = gfx.anim_random_frame % num_frames;
296   }
297   else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY))
298   {
299     frame = sync_frame % num_frames;
300   }
301
302   if (mode & ANIM_REVERSE)              // use reverse animation direction
303     frame = num_frames - frame - 1;
304
305   return frame;
306 }
307
308
309 // ============================================================================
310 // global animation functions
311 // ============================================================================
312
313 static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim)
314 {
315   struct GraphicInfo *c = &anim->control_info;
316   int last_anim_random_frame = gfx.anim_random_frame;
317   int part_nr;
318
319   gfx.anim_random_frame = -1;   // (use simple, ad-hoc random numbers)
320
321   part_nr = getAnimationFrame(anim->num_parts, 1,
322                               c->anim_mode, c->anim_start_frame,
323                               anim->part_counter);
324
325   gfx.anim_random_frame = last_anim_random_frame;
326
327   return part_nr;
328 }
329
330 static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2)
331 {
332   const struct GlobalAnimPartControlInfo *o1 =
333     (struct GlobalAnimPartControlInfo *)obj1;
334   const struct GlobalAnimPartControlInfo *o2 =
335     (struct GlobalAnimPartControlInfo *)obj2;
336   int compare_result;
337
338   if (o1->control_info.draw_order != o2->control_info.draw_order)
339     compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
340   else
341     compare_result = o1->nr - o2->nr;
342
343   return compare_result;
344 }
345
346 static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2)
347 {
348   const struct GlobalAnimMainControlInfo *o1 =
349     (struct GlobalAnimMainControlInfo *)obj1;
350   const struct GlobalAnimMainControlInfo *o2 =
351     (struct GlobalAnimMainControlInfo *)obj2;
352   int compare_result;
353
354   if (o1->control_info.draw_order != o2->control_info.draw_order)
355     compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
356   else
357     compare_result = o1->nr - o2->nr;
358
359   return compare_result;
360 }
361
362 static void InitToonControls(void)
363 {
364   int mode_nr_toons = GAME_MODE_PSEUDO_TOONS;
365   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr_toons];
366   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[ctrl->num_anims];
367   int mode_nr, anim_nr, part_nr;
368   int control = IMG_INTERNAL_GLOBAL_TOON_DEFAULT;
369   int num_toons = MAX_NUM_TOONS;
370   int i;
371
372   if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
373     num_toons = global.num_toons;
374
375   mode_nr = mode_nr_toons;
376   anim_nr = ctrl->num_anims;
377
378   anim->nr = anim_nr;
379   anim->mode_nr = mode_nr;
380   anim->control_info = graphic_info[control];
381
382   anim->num_parts = 0;
383   anim->num_parts_all = 0;
384   anim->part_counter = 0;
385   anim->active_part_nr = 0;
386
387   anim->has_base = FALSE;
388
389   anim->last_x = POS_OFFSCREEN;
390   anim->last_y = POS_OFFSCREEN;
391
392   anim->init_delay_counter = 0;
393
394   anim->state = ANIM_STATE_INACTIVE;
395
396   part_nr = 0;
397
398   for (i = 0; i < num_toons; i++)
399   {
400     struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
401     int sound = SND_UNDEFINED;
402     int music = MUS_UNDEFINED;
403     int graphic = IMG_TOON_1 + i;
404     int control = graphic;
405
406     part->nr = part_nr;
407     part->anim_nr = anim_nr;
408     part->mode_nr = mode_nr;
409
410     part->is_base = FALSE;
411
412     part->sound = sound;
413     part->music = music;
414     part->graphic = graphic;
415
416     part->graphic_info = graphic_info[graphic];
417     part->control_info = graphic_info[control];
418
419     part->graphic_info.anim_delay *= part->graphic_info.step_delay;
420
421     part->control_info.init_delay_fixed = 0;
422     part->control_info.init_delay_random = 150;
423
424     part->control_info.x = ARG_UNDEFINED_VALUE;
425     part->control_info.y = ARG_UNDEFINED_VALUE;
426
427     part->initial_anim_sync_frame = 0;
428     part->anim_random_frame = -1;
429
430     part->step_delay = 0;
431     part->step_delay_value = graphic_info[control].step_delay;
432
433     part->state = ANIM_STATE_INACTIVE;
434     part->last_anim_status = -1;
435
436     anim->num_parts++;
437     anim->num_parts_all++;
438
439     part_nr++;
440   }
441
442   ctrl->num_anims++;
443 }
444
445 static void InitGlobalAnimControls(void)
446 {
447   int i, m, a, p;
448   int mode_nr, anim_nr, part_nr;
449   int sound, music, graphic, control;
450
451   anim_sync_frame = 0;
452
453   for (m = 0; m < NUM_GAME_MODES; m++)
454   {
455     mode_nr = m;
456
457     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
458
459     ctrl->nr = mode_nr;
460     ctrl->num_anims = 0;
461
462     anim_nr = 0;
463
464     for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
465     {
466       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
467       int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
468
469       control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
470
471       // if no base animation parameters defined, use default values
472       if (control == IMG_UNDEFINED)
473         control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
474
475       anim->nr = anim_nr;
476       anim->mode_nr = mode_nr;
477       anim->control_info = graphic_info[control];
478
479       anim->num_parts = 0;
480       anim->num_parts_all = 0;
481       anim->part_counter = 0;
482       anim->active_part_nr = 0;
483
484       anim->has_base = FALSE;
485
486       anim->last_x = POS_OFFSCREEN;
487       anim->last_y = POS_OFFSCREEN;
488
489       anim->init_delay_counter = 0;
490
491       anim->state = ANIM_STATE_INACTIVE;
492
493       part_nr = 0;
494
495       for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
496       {
497         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
498
499         sound   = global_anim_info[a].sound[p][m];
500         music   = global_anim_info[a].music[p][m];
501         graphic = global_anim_info[a].graphic[p][m];
502         control = global_anim_info[ctrl_id].graphic[p][m];
503
504         if (graphic == IMG_UNDEFINED || graphic_info[graphic].bitmap == NULL ||
505             control == IMG_UNDEFINED)
506           continue;
507
508 #if 0
509         Debug("anim:InitGlobalAnimControls",
510               "mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]",
511               m, a, p, mode_nr, anim_nr, part_nr, control);
512 #endif
513
514 #if 0
515         Debug("anim:InitGlobalAnimControls",
516               "mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]",
517               m, a, p, mode_nr, anim_nr, part_nr, sound);
518 #endif
519
520         part->old_nr = p;
521         part->old_anim_nr = a;
522
523         part->nr = part_nr;
524         part->anim_nr = anim_nr;
525         part->mode_nr = mode_nr;
526
527         part->sound = sound;
528         part->music = music;
529         part->graphic = graphic;
530
531         part->graphic_info = graphic_info[graphic];
532         part->control_info = graphic_info[control];
533
534         part->initial_anim_sync_frame = 0;
535         part->anim_random_frame = -1;
536
537         part->step_delay = 0;
538         part->step_delay_value = graphic_info[control].step_delay;
539
540         part->state = ANIM_STATE_INACTIVE;
541         part->last_anim_status = -1;
542
543         anim->num_parts_all++;
544
545         if (p < GLOBAL_ANIM_ID_PART_BASE)
546         {
547           part->is_base = FALSE;
548
549           anim->num_parts++;
550           part_nr++;
551         }
552         else
553         {
554           part->is_base = TRUE;
555
556           anim->base = *part;
557           anim->has_base = TRUE;
558         }
559
560         // apply special settings for pointer-style animations
561         if (part->control_info.class == get_hash_from_key("pointer"))
562         {
563           // force animation to be on top (must set anim and part control)
564           if (anim->control_info.draw_order == 0)
565             anim->control_info.draw_order = 1000000;
566           if (part->control_info.draw_order == 0)
567             part->control_info.draw_order = 1000000;
568
569           // force animation to pass-through clicks (must set part control)
570           if (part->control_info.style == STYLE_DEFAULT)
571             part->control_info.style |= STYLE_PASSTHROUGH;
572         }
573       }
574
575       if (anim->num_parts > 0 || anim->has_base)
576       {
577         ctrl->num_anims++;
578         anim_nr++;
579       }
580     }
581   }
582
583   InitToonControls();
584
585   // sort all animations according to draw_order and animation number
586   for (m = 0; m < NUM_GAME_MODES; m++)
587   {
588     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[m];
589
590     // sort all main animations for this game mode
591     qsort(ctrl->anim, ctrl->num_anims,
592           sizeof(struct GlobalAnimMainControlInfo),
593           compareGlobalAnimMainControlInfo);
594
595     for (a = 0; a < ctrl->num_anims; a++)
596     {
597       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a];
598
599       // sort all animation parts for this main animation
600       qsort(anim->part, anim->num_parts,
601             sizeof(struct GlobalAnimPartControlInfo),
602             compareGlobalAnimPartControlInfo);
603     }
604   }
605
606   for (i = 0; i < NUM_GAME_MODES; i++)
607     game_mode_anim_classes[i] = ANIM_CLASS_NONE;
608   for (i = 0; game_mode_anim_classes_list[i].game_mode != -1; i++)
609     game_mode_anim_classes[game_mode_anim_classes_list[i].game_mode] =
610       game_mode_anim_classes_list[i].class;
611
612   for (i = 0; i < NUM_ANIM_CLASSES; i++)
613     anim_class_game_modes[i] = GAME_MODE_DEFAULT;
614   for (i = 0; anim_class_game_modes_list[i].game_mode != -1; i++)
615     anim_class_game_modes[anim_class_game_modes_list[i].class_bit] =
616       anim_class_game_modes_list[i].game_mode;
617
618   anim_status_last_before_fading = GAME_MODE_LOADING;
619   anim_status_last = GAME_MODE_LOADING;
620   anim_classes_last = ANIM_CLASS_NONE;
621 }
622
623 void InitGlobalAnimations(void)
624 {
625   InitGlobalAnimControls();
626 }
627
628 static void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage)
629 {
630   Bitmap *fade_bitmap =
631     (drawing_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
632      drawing_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
633   int game_mode_anim_action[NUM_GAME_MODES];
634   int mode_nr;
635
636   if (!setup.toons)
637     return;
638
639   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1 &&
640       drawing_target == DRAW_TO_SCREEN)
641     DoAnimationExt();
642
643   // always start with reliable default values (no animation actions)
644   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
645     game_mode_anim_action[mode_nr] = ANIM_NO_ACTION;
646
647   if (global.anim_status != anim_status_last)
648   {
649     boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING);
650     boolean after_fading  = (anim_status_last   == GAME_MODE_PSEUDO_FADING);
651     int anim_classes_next = game_mode_anim_classes[global.anim_status_next];
652     int i;
653
654     if (drawing_target == DRAW_TO_FADE_TARGET)
655       after_fading = TRUE;
656
657     // special case: changing from/to these screens is done without fading
658     if (global.anim_status == GAME_MODE_PSEUDO_TYPENAME  ||
659         global.anim_status == GAME_MODE_PSEUDO_TYPENAMES ||
660         anim_status_last   == GAME_MODE_PSEUDO_TYPENAME  ||
661         anim_status_last   == GAME_MODE_PSEUDO_TYPENAMES)
662       after_fading = TRUE;
663
664     // ---------- part 1 ------------------------------------------------------
665     // start or stop global animations by change of game mode
666     // (special handling of animations for "current screen" and "all screens")
667
668     if (global.anim_status_next != anim_status_last_before_fading)
669     {
670       // stop animations for last screen before fading to new screen
671       game_mode_anim_action[anim_status_last] = ANIM_STOP;
672
673       // start animations for current screen after fading to new screen
674       game_mode_anim_action[global.anim_status] = ANIM_START;
675     }
676
677     // start animations for all screens after loading new artwork set
678     if (anim_status_last == GAME_MODE_LOADING)
679       game_mode_anim_action[GAME_MODE_DEFAULT] = ANIM_START;
680
681     // ---------- part 2 ------------------------------------------------------
682     // start or stop global animations by change of animation class
683     // (generic handling of animations for "class of screens")
684
685     for (i = 0; i < NUM_ANIM_CLASSES; i++)
686     {
687       int anim_class_check = (1 << i);
688       int anim_class_game_mode = anim_class_game_modes[i];
689       int anim_class_last = anim_classes_last & anim_class_check;
690       int anim_class_next = anim_classes_next & anim_class_check;
691
692       // stop animations for changed screen class before fading to new screen
693       if (before_fading && anim_class_last && !anim_class_next)
694         game_mode_anim_action[anim_class_game_mode] = ANIM_STOP;
695
696       // start animations for changed screen class after fading to new screen
697       if (after_fading && !anim_class_last && anim_class_next)
698         game_mode_anim_action[anim_class_game_mode] = ANIM_START;
699     }
700
701     if (drawing_target == DRAW_TO_SCREEN)
702     {
703       if (after_fading)
704       {
705         anim_classes_last = anim_classes_next;
706         anim_status_last_before_fading = global.anim_status;
707       }
708
709       anim_status_last = global.anim_status;
710
711       // start or stop animations determined to be started or stopped above
712       for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
713         if (game_mode_anim_action[mode_nr] != ANIM_NO_ACTION)
714           HandleGlobalAnim(game_mode_anim_action[mode_nr], mode_nr);
715     }
716     else if (drawing_target == DRAW_TO_FADE_TARGET)
717     {
718       drawing_to_fading_buffer = TRUE;
719
720       // start animations determined to be (temporary) started above
721       for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
722         if (game_mode_anim_action[mode_nr] == ANIM_START)
723           HandleGlobalAnim(ANIM_START, mode_nr);
724     }
725   }
726
727   if (global.anim_status == GAME_MODE_LOADING)
728     return;
729
730   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
731   {
732     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
733     int anim_nr;
734
735     // when preparing source fading buffer, only draw animations to be stopped
736     if (drawing_target == DRAW_TO_FADE_SOURCE &&
737         game_mode_anim_action[mode_nr] != ANIM_STOP)
738       continue;
739
740     // when preparing target fading buffer, only draw animations to be started
741     if (drawing_target == DRAW_TO_FADE_TARGET &&
742         game_mode_anim_action[mode_nr] != ANIM_START)
743       continue;
744
745 #if 0
746     if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
747         mode_nr != game_status)
748       continue;
749 #endif
750
751     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
752     {
753       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
754       struct GraphicInfo *c = &anim->control_info;
755       int part_first, part_last;
756       int part_nr;
757
758       if (!(anim->state & ANIM_STATE_RUNNING))
759         continue;
760
761       part_first = part_last = anim->active_part_nr;
762
763       if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
764       {
765         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
766
767         part_first = 0;
768         part_last = num_parts - 1;
769       }
770
771       for (part_nr = part_first; part_nr <= part_last; part_nr++)
772       {
773         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
774         struct GraphicInfo *g = &part->graphic_info;
775         Bitmap *src_bitmap;
776         int src_x, src_y;
777         int width  = g->width;
778         int height = g->height;
779         int dst_x = part->x;
780         int dst_y = part->y;
781         int cut_x = 0;
782         int cut_y = 0;
783         int sync_frame;
784         int frame;
785         void (*blit_bitmap)(Bitmap *, Bitmap *, int, int, int, int, int, int) =
786           (g->draw_masked ? BlitBitmapMasked : BlitBitmap);
787         void (*blit_screen)(Bitmap *, int, int, int, int, int, int) =
788           (g->draw_masked ? BlitToScreenMasked : BlitToScreen);
789         int last_anim_random_frame = gfx.anim_random_frame;
790
791         if (!(part->state & ANIM_STATE_RUNNING))
792           continue;
793
794         if (part->drawing_stage != drawing_stage)
795           continue;
796
797         if (part->x < 0)
798         {
799           dst_x = 0;
800           width += part->x;
801           cut_x = -part->x;
802         }
803         else if (part->x > part->viewport_width - g->width)
804           width -= (part->x - (part->viewport_width - g->width));
805
806         if (part->y < 0)
807         {
808           dst_y = 0;
809           height += part->y;
810           cut_y = -part->y;
811         }
812         else if (part->y > part->viewport_height - g->height)
813           height -= (part->y - (part->viewport_height - g->height));
814
815         if (width <= 0 || height <= 0)
816           continue;
817
818         dst_x += part->viewport_x;
819         dst_y += part->viewport_y;
820
821         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
822
823         // re-initialize random animation frame after animation delay
824         if (g->anim_mode == ANIM_RANDOM &&
825             sync_frame % g->anim_delay == 0 &&
826             sync_frame > 0)
827           part->anim_random_frame = GetSimpleRandom(g->anim_frames);
828
829         gfx.anim_random_frame = part->anim_random_frame;
830
831         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
832                                   g->anim_mode, g->anim_start_frame,
833                                   sync_frame);
834
835         gfx.anim_random_frame = last_anim_random_frame;
836
837         getGlobalAnimGraphicSource(part->graphic, frame, &src_bitmap,
838                                    &src_x, &src_y);
839
840         src_x += cut_x;
841         src_y += cut_y;
842
843         if (drawing_target == DRAW_TO_SCREEN)
844           blit_screen(src_bitmap, src_x, src_y, width, height,
845                       dst_x, dst_y);
846         else
847           blit_bitmap(src_bitmap, fade_bitmap, src_x, src_y, width, height,
848                       dst_x, dst_y);
849       }
850     }
851   }
852
853   if (drawing_target == DRAW_TO_FADE_TARGET)
854   {
855     // stop animations determined to be (temporary) started above
856     for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
857       if (game_mode_anim_action[mode_nr] == ANIM_START)
858         HandleGlobalAnim(ANIM_STOP, mode_nr);
859
860     drawing_to_fading_buffer = FALSE;
861   }
862 }
863
864 void DrawGlobalAnimations(int drawing_target, int drawing_stage)
865 {
866   int last_cursor_mode_override = gfx.cursor_mode_override;
867
868   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
869   {
870     ResetGlobalAnim_Clickable();
871
872     gfx.cursor_mode_override = CURSOR_UNDEFINED;
873   }
874
875   DrawGlobalAnimationsExt(drawing_target, drawing_stage);
876
877   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_2)
878   {
879     ResetGlobalAnim_Clicked();
880   }
881
882   DrawEnvelopeRequestToScreen(drawing_target, drawing_stage);
883
884   if (gfx.cursor_mode_override != last_cursor_mode_override)
885     SetMouseCursor(gfx.cursor_mode);
886 }
887
888 static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
889 {
890   int viewport_x;
891   int viewport_y;
892   int viewport_width;
893   int viewport_height;
894   boolean changed = FALSE;
895
896   if (part->last_anim_status == global.anim_status &&
897       part->control_info.class != get_hash_from_key("pointer"))
898     return FALSE;
899
900   part->last_anim_status = global.anim_status;
901
902   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
903
904   if (part->control_info.class == get_hash_from_key("window") ||
905       part->control_info.class == get_hash_from_key("border"))
906   {
907     viewport_x = 0;
908     viewport_y = 0;
909     viewport_width  = WIN_XSIZE;
910     viewport_height = WIN_YSIZE;
911
912     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
913   }
914   else if (part->control_info.class == get_hash_from_key("pointer"))
915   {
916     int mx = MIN(MAX(0, gfx.mouse_x), WIN_XSIZE - 1);
917     int my = MIN(MAX(0, gfx.mouse_y), WIN_YSIZE - 1);
918
919     // prevent displaying off-screen custom mouse cursor in upper left corner
920     if (gfx.mouse_x == POS_OFFSCREEN &&
921         gfx.mouse_y == POS_OFFSCREEN)
922       mx = my = POS_OFFSCREEN;
923
924     viewport_x = mx - part->control_info.x;
925     viewport_y = my - part->control_info.y;
926     viewport_width  = part->graphic_info.width;
927     viewport_height = part->graphic_info.height;
928
929     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
930
931     // do not use global animation mouse pointer when reloading artwork
932     if (global.anim_status != GAME_MODE_LOADING)
933       gfx.cursor_mode_override = CURSOR_NONE;
934   }
935   else if (part->control_info.class == get_hash_from_key("door_1"))
936   {
937     viewport_x = DX;
938     viewport_y = DY;
939     viewport_width  = DXSIZE;
940     viewport_height = DYSIZE;
941   }
942   else if (part->control_info.class == get_hash_from_key("door_2"))
943   {
944     if (part->mode_nr == GAME_MODE_EDITOR)
945     {
946       viewport_x = EX;
947       viewport_y = EY;
948       viewport_width  = EXSIZE;
949       viewport_height = EYSIZE;
950     }
951     else
952     {
953       viewport_x = VX;
954       viewport_y = VY;
955       viewport_width  = VXSIZE;
956       viewport_height = VYSIZE;
957     }
958   }
959   else          // default: "playfield"
960   {
961     viewport_x = REAL_SX;
962     viewport_y = REAL_SY;
963     viewport_width  = FULL_SXSIZE;
964     viewport_height = FULL_SYSIZE;
965   }
966
967   if (viewport_x != part->viewport_x ||
968       viewport_y != part->viewport_y ||
969       viewport_width  != part->viewport_width ||
970       viewport_height != part->viewport_height)
971   {
972     part->viewport_x = viewport_x;
973     part->viewport_y = viewport_y;
974     part->viewport_width  = viewport_width;
975     part->viewport_height = viewport_height;
976
977     if (part->control_info.class != get_hash_from_key("pointer"))
978       changed = TRUE;
979   }
980
981   return changed;
982 }
983
984 static void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
985 {
986   int sound = part->sound;
987
988   if (sound == SND_UNDEFINED)
989     return;
990
991   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
992       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
993     return;
994
995   // !!! TODO: ADD STEREO POSITION FOR MOVING ANIMATIONS !!!
996   if (IS_LOOP_SOUND(sound))
997     PlaySoundLoop(sound);
998   else
999     PlaySound(sound);
1000
1001 #if 0
1002   Debug("anim:PlayGlobalAnimSound", "PLAY SOUND %d.%d.%d: %d",
1003          part->anim_nr, part->nr, part->mode_nr, sound);
1004 #endif
1005 }
1006
1007 static void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
1008 {
1009   int sound = part->sound;
1010
1011   if (sound == SND_UNDEFINED)
1012     return;
1013
1014   StopSound(sound);
1015
1016 #if 0
1017   Debug("anim:StopGlobalAnimSound", "STOP SOUND %d.%d.%d: %d",
1018         part->anim_nr, part->nr, part->mode_nr, sound);
1019 #endif
1020 }
1021
1022 static void PlayGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
1023 {
1024   int music = part->music;
1025
1026   if (music == MUS_UNDEFINED)
1027     return;
1028
1029   if (!setup.sound_music)
1030     return;
1031
1032   if (IS_LOOP_MUSIC(music))
1033     PlayMusicLoop(music);
1034   else
1035     PlayMusic(music);
1036
1037 #if 0
1038   Debug("anim:PlayGlobalAnimMusic", "PLAY MUSIC %d.%d.%d: %d",
1039         part->anim_nr, part->nr, part->mode_nr, music);
1040 #endif
1041 }
1042
1043 static void StopGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
1044 {
1045   int music = part->music;
1046
1047   if (music == MUS_UNDEFINED)
1048     return;
1049
1050   StopMusic();
1051
1052 #if 0
1053   Debug("anim:StopGlobalAnimMusic", "STOP MUSIC %d.%d.%d: %d",
1054         part->anim_nr, part->nr, part->mode_nr, music);
1055 #endif
1056 }
1057
1058 static void PlayGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
1059 {
1060   // when drawing animations to fading buffer, do not play sounds or music
1061   if (drawing_to_fading_buffer)
1062     return;
1063
1064   PlayGlobalAnimSound(part);
1065   PlayGlobalAnimMusic(part);
1066 }
1067
1068 static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
1069 {
1070   StopGlobalAnimSound(part);
1071   StopGlobalAnimMusic(part);
1072 }
1073
1074 static void PlayGlobalAnimSoundIfLoop(struct GlobalAnimPartControlInfo *part)
1075 {
1076   // when drawing animations to fading buffer, do not play sounds
1077   if (drawing_to_fading_buffer)
1078     return;
1079
1080   // loop sounds only expire when playing
1081   if (game_status != GAME_MODE_PLAYING)
1082     return;
1083
1084   // check if any sound is defined for this animation part
1085   if (part->sound == SND_UNDEFINED)
1086     return;
1087
1088   // normal (non-loop) sounds do not expire when playing
1089   if (!IS_LOOP_SOUND(part->sound))
1090     return;
1091
1092   // prevent expiring loop sounds when playing
1093   PlayGlobalAnimSound(part);
1094 }
1095
1096 static boolean checkGlobalAnimEvent(int anim_event, int mask)
1097 {
1098   int mask_anim_only = mask & ~ANIM_EVENT_PART_MASK;
1099
1100   if (mask & ANIM_EVENT_ANY)
1101     return (anim_event & ANIM_EVENT_ANY);
1102   else if (mask & ANIM_EVENT_SELF)
1103     return (anim_event & ANIM_EVENT_SELF);
1104   else if (mask & ANIM_EVENT_UNCLICK_ANY)
1105     return (anim_event & ANIM_EVENT_UNCLICK_ANY);
1106   else
1107     return (anim_event == mask ||
1108             anim_event == mask_anim_only);
1109 }
1110
1111 static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask)
1112 {
1113   struct GraphicInfo *c = &part->control_info;
1114   int num_init_events = GetGlobalAnimEventValueCount(c->init_event);
1115   int num_anim_events = GetGlobalAnimEventValueCount(c->anim_event);
1116   int i;
1117
1118   for (i = 0; i < num_init_events; i++)
1119   {
1120     int init_event = GetGlobalAnimEventValue(c->init_event, i);
1121
1122     if (checkGlobalAnimEvent(init_event, mask))
1123       return TRUE;
1124   }
1125
1126   for (i = 0; i < num_anim_events; i++)
1127   {
1128     int anim_event = GetGlobalAnimEventValue(c->anim_event, i);
1129
1130     if (checkGlobalAnimEvent(anim_event, mask))
1131       return TRUE;
1132   }
1133
1134   return FALSE;
1135 }
1136
1137 static boolean isClickedPart(struct GlobalAnimPartControlInfo *part,
1138                              int mx, int my, boolean clicked)
1139 {
1140   struct GraphicInfo *g = &part->graphic_info;
1141   int part_x = part->viewport_x + part->x;
1142   int part_y = part->viewport_y + part->y;
1143   int part_width  = g->width;
1144   int part_height = g->height;
1145
1146   // check if mouse click was detected at all
1147   if (!clicked)
1148     return FALSE;
1149
1150   // check if mouse click is inside the animation part's viewport
1151   if (mx <  part->viewport_x ||
1152       mx >= part->viewport_x + part->viewport_width ||
1153       my <  part->viewport_y ||
1154       my >= part->viewport_y + part->viewport_height)
1155     return FALSE;
1156
1157   // check if mouse click is inside the animation part's graphic
1158   if (mx <  part_x ||
1159       mx >= part_x + part_width ||
1160       my <  part_y ||
1161       my >= part_y + part_height)
1162     return FALSE;
1163
1164   return TRUE;
1165 }
1166
1167 static boolean clickBlocked(struct GlobalAnimPartControlInfo *part)
1168 {
1169   return (part->control_info.style & STYLE_BLOCK ? TRUE : FALSE);
1170 }
1171
1172 static boolean clickConsumed(struct GlobalAnimPartControlInfo *part)
1173 {
1174   return (part->control_info.style & STYLE_PASSTHROUGH ? FALSE : TRUE);
1175 }
1176
1177 static void InitGlobalAnim_Triggered(struct GlobalAnimPartControlInfo *part,
1178                                      boolean *click_consumed,
1179                                      boolean *any_event_action,
1180                                      int event_value, char *info_text)
1181 {
1182   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr];
1183
1184   int gic_anim_nr = part->old_anim_nr + 1;      // X as in "anim_X"
1185   int gic_part_nr = part->old_nr + 1;           // Y as in "part_Y"
1186   int mask = event_value | (gic_anim_nr << ANIM_EVENT_ANIM_BIT);
1187
1188   if (!part->is_base)
1189     mask |= gic_part_nr << ANIM_EVENT_PART_BIT;
1190
1191   int anim2_nr;
1192
1193   for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++)
1194   {
1195     struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr];
1196     int part2_nr;
1197
1198     for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++)
1199     {
1200       struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr];
1201
1202       if (!(part2->state & ANIM_STATE_RUNNING))
1203         continue;
1204
1205       if (isClickablePart(part2, mask))
1206       {
1207         part2->triggered = TRUE;
1208         *click_consumed |= clickConsumed(part);         // click was on "part"!
1209
1210 #if DEBUG_ANIM_EVENTS
1211         Debug("anim:InitGlobalAnim_Triggered",
1212               "%d.%d TRIGGERED BY %s OF %d.%d",
1213               part2->old_anim_nr + 1, part2->old_nr + 1, info_text,
1214               part->old_anim_nr + 1, part->old_nr + 1);
1215 #endif
1216 #if 0
1217         Debug("anim:InitGlobalAnim_Triggered",
1218               "%d.%d TRIGGER CLICKED [%d]", anim2_nr, part2_nr,
1219               part2->control_info.anim_event_action);
1220 #endif
1221
1222         // after executing event action, ignore any further actions
1223         if (!*any_event_action && DoGlobalAnim_EventAction(part2))
1224           *any_event_action = TRUE;
1225       }
1226
1227 #if 0
1228       struct GraphicInfo *c = &part2->control_info;
1229
1230       if (isClickablePart(part2, mask))
1231         Debug("anim:InitGlobalAnim_Triggered",
1232               "%d.%d: 0x%08x, 0x%08x [0x%08x] <--- TRIGGERED BY %d.%d",
1233               anim2_nr, part2_nr, c->init_event, c->anim_event, mask,
1234               anim_nr, part_nr);
1235       else
1236         Debug("anim:InitGlobalAnim_Triggered",
1237               "%d.%d: 0x%08x, 0x%08x [0x%08x]",
1238               anim2_nr, part2_nr, c->init_event, c->anim_event, mask);
1239 #endif
1240     }
1241   }
1242 }
1243
1244 static void HandleGlobalAnimDelay(struct GlobalAnimPartControlInfo *part,
1245                                   int delay_type, char *info_text)
1246 {
1247 #if DEBUG_ANIM_DELAY
1248   Debug("anim:HandleGlobalAnimDelay", "%d.%d %s",
1249         part->old_anim_nr + 1, part->old_nr + 1, info_text);
1250 #endif
1251
1252   DoGlobalAnim_DelayAction(part, delay_type);
1253 }
1254
1255 static void HandleGlobalAnimEvent(struct GlobalAnimPartControlInfo *part,
1256                                   int event_value, char *info_text)
1257 {
1258 #if DEBUG_ANIM_EVENTS
1259   Debug("anim:HandleGlobalAnimEvent", "%d.%d %s",
1260         part->old_anim_nr + 1, part->old_nr + 1, info_text);
1261 #endif
1262
1263   boolean click_consumed = FALSE;
1264   boolean any_event_action = FALSE;
1265
1266   // check if this event is defined to trigger other animations
1267   InitGlobalAnim_Triggered(part, &click_consumed, &any_event_action,
1268                            event_value, info_text);
1269 }
1270
1271 static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
1272                                  int state)
1273 {
1274   if (handle_click && !part->clicked)
1275     return state;
1276
1277   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr];
1278   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[part->anim_nr];
1279   struct GraphicInfo *g = &part->graphic_info;
1280   struct GraphicInfo *c = &part->control_info;
1281   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
1282
1283   if (viewport_changed)
1284     state |= ANIM_STATE_RESTART;
1285
1286   if (state & ANIM_STATE_RESTART)
1287   {
1288     // when drawing animations to fading buffer, only start fixed animations
1289     if (drawing_to_fading_buffer && (c->x == ARG_UNDEFINED_VALUE ||
1290                                      c->y == ARG_UNDEFINED_VALUE))
1291       return ANIM_STATE_INACTIVE;
1292
1293     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
1294
1295     part->init_delay_counter =
1296       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
1297
1298     part->anim_delay_counter =
1299       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
1300
1301     part->post_delay_counter = 0;
1302
1303     part->init_event_state = (c->init_event != ANIM_EVENT_UNDEFINED);
1304     part->anim_event_state = (c->anim_event != ANIM_EVENT_UNDEFINED);
1305
1306     part->initial_anim_sync_frame =
1307       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
1308
1309     // do not re-initialize random animation frame after fade-in
1310     if (part->anim_random_frame == -1)
1311       part->anim_random_frame = GetSimpleRandom(g->anim_frames);
1312
1313     if (c->direction & MV_HORIZONTAL)
1314     {
1315       int pos_bottom = part->viewport_height - g->height;
1316
1317       if (c->position == POS_TOP)
1318         part->y = 0;
1319       else if (c->position == POS_UPPER)
1320         part->y = GetSimpleRandom(pos_bottom / 2);
1321       else if (c->position == POS_MIDDLE)
1322         part->y = pos_bottom / 2;
1323       else if (c->position == POS_LOWER)
1324         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
1325       else if (c->position == POS_BOTTOM)
1326         part->y = pos_bottom;
1327       else
1328         part->y = GetSimpleRandom(pos_bottom);
1329
1330       if (c->direction == MV_RIGHT)
1331       {
1332         part->step_xoffset = c->step_offset;
1333         part->x = -g->width + part->step_xoffset;
1334       }
1335       else
1336       {
1337         part->step_xoffset = -c->step_offset;
1338         part->x = part->viewport_width + part->step_xoffset;
1339       }
1340
1341       part->step_yoffset = 0;
1342     }
1343     else if (c->direction & MV_VERTICAL)
1344     {
1345       int pos_right = part->viewport_width - g->width;
1346
1347       if (c->position == POS_LEFT)
1348         part->x = 0;
1349       else if (c->position == POS_RIGHT)
1350         part->x = pos_right;
1351       else
1352         part->x = GetSimpleRandom(pos_right);
1353
1354       if (c->direction == MV_DOWN)
1355       {
1356         part->step_yoffset = c->step_offset;
1357         part->y = -g->height + part->step_yoffset;
1358       }
1359       else
1360       {
1361         part->step_yoffset = -c->step_offset;
1362         part->y = part->viewport_height + part->step_yoffset;
1363       }
1364
1365       part->step_xoffset = 0;
1366     }
1367     else
1368     {
1369       part->x = 0;
1370       part->y = 0;
1371
1372       part->step_xoffset = 0;
1373       part->step_yoffset = 0;
1374     }
1375
1376     if (part->control_info.class != get_hash_from_key("pointer"))
1377     {
1378       if (c->x != ARG_UNDEFINED_VALUE)
1379         part->x = c->x;
1380       if (c->y != ARG_UNDEFINED_VALUE)
1381         part->y = c->y;
1382     }
1383
1384     if (c->position == POS_LAST &&
1385         anim->last_x > -g->width  && anim->last_x < part->viewport_width &&
1386         anim->last_y > -g->height && anim->last_y < part->viewport_height)
1387     {
1388       part->x = anim->last_x;
1389       part->y = anim->last_y;
1390     }
1391
1392     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
1393       part->step_xoffset = c->step_xoffset;
1394     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
1395       part->step_yoffset = c->step_yoffset;
1396
1397     if (part->init_delay_counter == 0 &&
1398         !part->init_event_state)
1399     {
1400       PlayGlobalAnimSoundAndMusic(part);
1401
1402       HandleGlobalAnimDelay(part, ANIM_DELAY_INIT,  "START [INIT_DELAY]");
1403       HandleGlobalAnimEvent(part, ANIM_EVENT_START, "START [ANIM]");
1404     }
1405     else
1406     {
1407       HandleGlobalAnimEvent(part, ANIM_EVENT_INIT, "START [INIT_DELAY/EVENT]");
1408     }
1409   }
1410
1411   if (part->clicked &&
1412       part->init_event_state)
1413   {
1414     if (part->initial_anim_sync_frame > 0)
1415       part->initial_anim_sync_frame -= part->init_delay_counter - 1;
1416
1417     part->init_delay_counter = 1;
1418     part->init_event_state = FALSE;
1419
1420     part->clicked = FALSE;
1421   }
1422
1423   if (part->clicked &&
1424       part->anim_event_state)
1425   {
1426     part->anim_delay_counter = 1;
1427     part->anim_event_state = FALSE;
1428
1429     part->clicked = FALSE;
1430   }
1431
1432   if (part->init_delay_counter > 0)
1433   {
1434     part->init_delay_counter--;
1435
1436     if (part->init_delay_counter == 0)
1437     {
1438       part->init_event_state = FALSE;
1439
1440       PlayGlobalAnimSoundAndMusic(part);
1441
1442       HandleGlobalAnimDelay(part, ANIM_DELAY_INIT,  "START [INIT_DELAY]");
1443       HandleGlobalAnimEvent(part, ANIM_EVENT_START, "START [ANIM]");
1444     }
1445
1446     return ANIM_STATE_WAITING;
1447   }
1448
1449   if (part->init_event_state)
1450     return ANIM_STATE_WAITING;
1451
1452   // animation part is now running/visible and therefore clickable
1453   part->clickable = TRUE;
1454
1455   // check if moving animation has left the visible screen area
1456   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
1457       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
1458       (part->y <= -g->height             && part->step_yoffset <= 0) ||
1459       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
1460   {
1461     // do not wait for "anim" events for off-screen animations
1462     part->anim_event_state = FALSE;
1463
1464     // do not stop animation before "anim" or "post" counter are finished
1465     if (part->anim_delay_counter == 0 &&
1466         part->post_delay_counter == 0)
1467     {
1468       StopGlobalAnimSoundAndMusic(part);
1469
1470       HandleGlobalAnimEvent(part, ANIM_EVENT_END, "END [ANIM/OFF-SCREEN]");
1471
1472       part->post_delay_counter =
1473         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1474
1475       if (part->post_delay_counter > 0)
1476         return ANIM_STATE_RUNNING;
1477
1478       // drawing last frame not needed here -- animation not visible anymore
1479       return ANIM_STATE_RESTART;
1480     }
1481   }
1482
1483   if (part->anim_delay_counter > 0)
1484   {
1485     part->anim_delay_counter--;
1486
1487     if (part->anim_delay_counter == 0)
1488     {
1489       part->anim_event_state = FALSE;
1490
1491       StopGlobalAnimSoundAndMusic(part);
1492
1493       HandleGlobalAnimDelay(part, ANIM_DELAY_ANIM, "END [ANIM_DELAY]");
1494       HandleGlobalAnimEvent(part, ANIM_EVENT_END,  "END [ANIM_DELAY/EVENT]");
1495
1496       part->post_delay_counter =
1497         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1498
1499       if (part->post_delay_counter > 0)
1500         return ANIM_STATE_RUNNING;
1501
1502       // additional state "RUNNING" required to not skip drawing last frame
1503       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
1504     }
1505   }
1506
1507   if (part->post_delay_counter > 0)
1508   {
1509     part->post_delay_counter--;
1510
1511     if (part->post_delay_counter == 0)
1512     {
1513       HandleGlobalAnimDelay(part, ANIM_DELAY_POST, "END [POST_DELAY]");
1514       HandleGlobalAnimEvent(part, ANIM_EVENT_POST, "END [POST_DELAY]");
1515
1516       return ANIM_STATE_RESTART;
1517     }
1518
1519     return ANIM_STATE_WAITING;
1520   }
1521
1522   // special case to prevent expiring loop sounds when playing
1523   PlayGlobalAnimSoundIfLoop(part);
1524
1525   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
1526                        anim_sync_frame))
1527     return ANIM_STATE_RUNNING;
1528
1529 #if 0
1530   {
1531     static unsigned int last_counter = -1;
1532     unsigned int counter = Counter();
1533
1534     Debug("anim:HandleGlobalAnim_Part", "NEXT ANIM PART [%d, %d]",
1535           anim_sync_frame, counter - last_counter);
1536
1537     last_counter = counter;
1538   }
1539 #endif
1540
1541   part->x += part->step_xoffset;
1542   part->y += part->step_yoffset;
1543
1544   anim->last_x = part->x;
1545   anim->last_y = part->y;
1546
1547   return ANIM_STATE_RUNNING;
1548 }
1549
1550 static void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim,
1551                                   int action)
1552 {
1553   struct GlobalAnimPartControlInfo *part;
1554   struct GraphicInfo *c = &anim->control_info;
1555   int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1556   int state, active_part_nr;
1557   int i;
1558
1559 #if 0
1560   Debug("anim:HandleGlobalAnim_Main", "%d, %d => %d",
1561          anim->mode_nr, anim->nr, anim->num_parts);
1562   Debug("anim:HandleGlobalAnim_Main",
1563         "%d, %d, %d", global.num_toons, setup.toons, num_toons);
1564 #endif
1565
1566 #if 0
1567   Debug("anim:HandleGlobalAnim_Main", "%s(%d): %d, %d, %d [%d]",
1568         (action == ANIM_START ? "ANIM_START" :
1569          action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
1570          action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
1571         anim->nr,
1572         anim->state & ANIM_STATE_RESTART,
1573         anim->state & ANIM_STATE_WAITING,
1574         anim->state & ANIM_STATE_RUNNING,
1575         anim->num_parts);
1576 #endif
1577
1578   switch (action)
1579   {
1580     case ANIM_START:
1581       anim->state = anim->last_state = ANIM_STATE_RESTART;
1582       anim->active_part_nr = anim->last_active_part_nr = 0;
1583       anim->part_counter = 0;
1584
1585       break;
1586
1587     case ANIM_CONTINUE:
1588       if (anim->state == ANIM_STATE_INACTIVE)
1589         return;
1590
1591       anim->state = anim->last_state;
1592       anim->active_part_nr = anim->last_active_part_nr;
1593
1594       break;
1595
1596     case ANIM_STOP:
1597       anim->state = ANIM_STATE_INACTIVE;
1598
1599       for (i = 0; i < num_parts; i++)
1600         StopGlobalAnimSoundAndMusic(&anim->part[i]);
1601
1602       return;
1603
1604     default:
1605       break;
1606   }
1607
1608   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
1609   {
1610 #if 0
1611     Debug("anim:HandleGlobalAnim_Main", "%d, %d => %d",
1612           anim->mode_nr, anim->nr, num_parts);
1613 #endif
1614
1615     for (i = 0; i < num_parts; i++)
1616     {
1617       part = &anim->part[i];
1618
1619       switch (action)
1620       {
1621         case ANIM_START:
1622           anim->state = ANIM_STATE_RUNNING;
1623           part->state = ANIM_STATE_RESTART;
1624
1625           break;
1626
1627         case ANIM_CONTINUE:
1628           if (part->state == ANIM_STATE_INACTIVE)
1629             continue;
1630
1631           break;
1632
1633         case ANIM_STOP:
1634           part->state = ANIM_STATE_INACTIVE;
1635
1636           continue;
1637
1638         default:
1639           break;
1640       }
1641
1642       part->state = HandleGlobalAnim_Part(part, part->state);
1643
1644       // when animation mode is "once", stop after animation was played once
1645       if (c->anim_mode & ANIM_ONCE &&
1646           part->state & ANIM_STATE_RESTART)
1647         part->state = ANIM_STATE_INACTIVE;
1648     }
1649
1650     anim->last_state = anim->state;
1651     anim->last_active_part_nr = anim->active_part_nr;
1652
1653     return;
1654   }
1655
1656   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
1657     anim->active_part_nr = getGlobalAnimationPart(anim);
1658
1659   part = &anim->part[anim->active_part_nr];
1660
1661   // first set all animation parts to "inactive", ...
1662   for (i = 0; i < num_parts; i++)
1663     anim->part[i].state = ANIM_STATE_INACTIVE;
1664
1665   // ... then set current animation parts to "running"
1666   part->state = ANIM_STATE_RUNNING;
1667
1668   anim->state = HandleGlobalAnim_Part(part, anim->state);
1669
1670   if (anim->state & ANIM_STATE_RESTART)
1671     anim->part_counter++;
1672
1673   // when animation mode is "once", stop after all animations were played once
1674   if (c->anim_mode & ANIM_ONCE &&
1675       anim->part_counter == anim->num_parts)
1676     anim->state = ANIM_STATE_INACTIVE;
1677
1678   state = anim->state;
1679   active_part_nr = anim->active_part_nr;
1680
1681   // while the animation parts are pausing (waiting or inactive), play the base
1682   // (main) animation; this corresponds to the "boring player animation" logic
1683   // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!)
1684   if (anim->has_base)
1685   {
1686     if (anim->state == ANIM_STATE_WAITING ||
1687         anim->state == ANIM_STATE_INACTIVE)
1688     {
1689       anim->active_part_nr = anim->num_parts;   // part nr of base animation
1690       part = &anim->part[anim->active_part_nr];
1691
1692       if (anim->state != anim->last_state)
1693         part->state = ANIM_STATE_RESTART;
1694
1695       anim->state = ANIM_STATE_RUNNING;
1696       part->state = HandleGlobalAnim_Part(part, part->state);
1697     }
1698   }
1699
1700   anim->last_state = state;
1701   anim->last_active_part_nr = active_part_nr;
1702 }
1703
1704 static void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
1705 {
1706   int i;
1707
1708 #if 0
1709   Debug("anim:HandleGlobalAnim_Mode", "%d => %d", ctrl->nr, ctrl->num_anims);
1710 #endif
1711
1712   for (i = 0; i < ctrl->num_anims; i++)
1713     HandleGlobalAnim_Main(&ctrl->anim[i], action);
1714 }
1715
1716 static void HandleGlobalAnim(int action, int game_mode)
1717 {
1718 #if 0
1719   Debug("anim:HandleGlobalAnim", "mode == %d", game_status);
1720 #endif
1721
1722   HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
1723 }
1724
1725 static void DoAnimationExt(void)
1726 {
1727   int i;
1728
1729 #if 0
1730   Debug("anim:DoAnimationExt", "%d, %d", anim_sync_frame, Counter());
1731 #endif
1732
1733   // global animations now synchronized with frame delay of screen update
1734   anim_sync_frame++;
1735
1736   for (i = 0; i < NUM_GAME_MODES; i++)
1737     HandleGlobalAnim(ANIM_CONTINUE, i);
1738
1739 #if 0
1740   // force screen redraw in next frame to continue drawing global animations
1741   redraw_mask = REDRAW_ALL;
1742 #endif
1743 }
1744
1745 static void DoGlobalAnim_DelayAction(struct GlobalAnimPartControlInfo *part,
1746                                      int delay_type)
1747 {
1748   int delay_action =
1749     (delay_type == ANIM_DELAY_INIT ? part->control_info.init_delay_action :
1750      delay_type == ANIM_DELAY_ANIM ? part->control_info.anim_delay_action :
1751      delay_type == ANIM_DELAY_POST ? part->control_info.post_delay_action :
1752      ANIM_DELAY_ACTION_NONE);
1753
1754   if (delay_action == ANIM_DELAY_ACTION_NONE)
1755     return;
1756
1757   PushUserEvent(USEREVENT_ANIM_DELAY_ACTION, delay_action, 0);
1758 }
1759
1760 static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *part)
1761 {
1762   int event_action = (part->init_event_state ?
1763                       part->control_info.init_event_action :
1764                       part->control_info.anim_event_action);
1765
1766   if (event_action == ANIM_EVENT_ACTION_NONE)
1767     return FALSE;
1768
1769   if (event_action < MAX_IMAGE_FILES)
1770     PushUserEvent(USEREVENT_ANIM_EVENT_ACTION, event_action, 0);
1771   else
1772     OpenURLFromHash(anim_url_hash, event_action);
1773
1774   // check if further actions are allowed to be executed
1775   if (part->control_info.style & STYLE_MULTIPLE_ACTIONS)
1776     return FALSE;
1777
1778   return TRUE;
1779 }
1780
1781 static void InitGlobalAnim_Clickable(void)
1782 {
1783   int mode_nr;
1784
1785   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
1786   {
1787     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
1788     int anim_nr;
1789
1790     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
1791     {
1792       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
1793       int part_nr;
1794
1795       for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++)
1796       {
1797         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
1798
1799         if (part->triggered)
1800           part->clicked = TRUE;
1801
1802         part->triggered = FALSE;
1803         part->clickable = FALSE;
1804       }
1805     }
1806   }
1807 }
1808
1809 #define ANIM_CLICKED_RESET      0
1810 #define ANIM_CLICKED_PRESSED    1
1811 #define ANIM_CLICKED_RELEASED   2
1812
1813 static boolean InitGlobalAnim_Clicked(int mx, int my, int clicked_event)
1814 {
1815   boolean click_consumed = FALSE;
1816   boolean anything_clicked = FALSE;
1817   boolean any_part_clicked = FALSE;
1818   boolean any_event_action = FALSE;
1819   int mode_nr;
1820   int i;
1821
1822   // check game modes in reverse draw order (to stop when clicked)
1823   for (mode_nr = NUM_GAME_MODES - 1; mode_nr >= 0; mode_nr--)
1824   {
1825     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
1826     int anim_nr;
1827
1828     // check animations in reverse draw order (to stop when clicked)
1829     for (anim_nr = ctrl->num_anims - 1; anim_nr >= 0; anim_nr--)
1830     {
1831       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
1832       int part_nr;
1833
1834       // check animation parts in reverse draw order (to stop when clicked)
1835       for (part_nr = anim->num_parts_all - 1; part_nr >= 0; part_nr--)
1836       {
1837         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
1838
1839         if (clicked_event == ANIM_CLICKED_RESET)
1840         {
1841           part->clicked = FALSE;
1842
1843           continue;
1844         }
1845
1846         if (!part->clickable)
1847           continue;
1848
1849         if (!(part->state & ANIM_STATE_RUNNING))
1850           continue;
1851
1852         // always handle "any" click events (clicking anywhere on screen) ...
1853         if (clicked_event == ANIM_CLICKED_PRESSED &&
1854             isClickablePart(part, ANIM_EVENT_ANY))
1855         {
1856 #if DEBUG_ANIM_EVENTS
1857           Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY ANY",
1858                 part->old_anim_nr + 1, part->old_nr + 1);
1859 #endif
1860
1861           anything_clicked = part->clicked = TRUE;
1862           click_consumed |= clickConsumed(part);
1863         }
1864
1865         // always handle "unclick:any" events (releasing anywhere on screen) ...
1866         if (clicked_event == ANIM_CLICKED_RELEASED &&
1867             isClickablePart(part, ANIM_EVENT_UNCLICK_ANY))
1868         {
1869 #if DEBUG_ANIM_EVENTS
1870           Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY UNCLICK:ANY",
1871                 part->old_anim_nr + 1, part->old_nr + 1);
1872 #endif
1873
1874           anything_clicked = part->clicked = TRUE;
1875           click_consumed |= clickConsumed(part);
1876         }
1877
1878         // ... but only handle the first (topmost) clickable animation
1879         if (any_part_clicked)
1880           continue;
1881
1882         if (clicked_event == ANIM_CLICKED_PRESSED &&
1883             isClickedPart(part, mx, my, TRUE))
1884         {
1885 #if 0
1886           Debug("anim:InitGlobalAnim_Clicked", "%d.%d CLICKED [%d]",
1887                 anim_nr, part_nr, part->control_info.anim_event_action);
1888 #endif
1889
1890           // after executing event action, ignore any further actions
1891           if (!any_event_action && DoGlobalAnim_EventAction(part))
1892             any_event_action = TRUE;
1893
1894           // determine if mouse clicks should be blocked from other animations
1895           any_part_clicked |= clickConsumed(part);
1896
1897           if (isClickablePart(part, ANIM_EVENT_SELF))
1898           {
1899 #if DEBUG_ANIM_EVENTS
1900             Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY SELF",
1901                   part->old_anim_nr + 1, part->old_nr + 1);
1902 #endif
1903
1904             anything_clicked = part->clicked = TRUE;
1905             click_consumed |= clickConsumed(part);
1906           }
1907
1908           // determine if mouse clicks should be blocked by this animation
1909           click_consumed |= clickBlocked(part);
1910
1911           // check if this click is defined to trigger other animations
1912           InitGlobalAnim_Triggered(part, &click_consumed, &any_event_action,
1913                                    ANIM_EVENT_CLICK, "CLICK");
1914         }
1915       }
1916     }
1917   }
1918
1919   if (anything_clicked)
1920   {
1921     handle_click = TRUE;
1922
1923     for (i = 0; i < NUM_GAME_MODES; i++)
1924       HandleGlobalAnim(ANIM_CONTINUE, i);
1925
1926     handle_click = FALSE;
1927
1928     // prevent ignoring release event if processed within same game frame
1929     StopProcessingEvents();
1930   }
1931
1932   return (click_consumed || any_event_action);
1933 }
1934
1935 static void ResetGlobalAnim_Clickable(void)
1936 {
1937   InitGlobalAnim_Clickable();
1938 }
1939
1940 static void ResetGlobalAnim_Clicked(void)
1941 {
1942   InitGlobalAnim_Clicked(-1, -1, ANIM_CLICKED_RESET);
1943 }
1944
1945 boolean HandleGlobalAnimClicks(int mx, int my, int button, boolean force_click)
1946 {
1947   static boolean click_consumed = FALSE;
1948   static int last_button = 0;
1949   boolean press_event;
1950   boolean release_event;
1951   boolean click_consumed_current = click_consumed;
1952
1953   if (button != 0 && force_click)
1954     last_button = 0;
1955
1956   // check if button state has changed since last invocation
1957   press_event   = (button != 0 && last_button == 0);
1958   release_event = (button == 0 && last_button != 0);
1959   last_button = button;
1960
1961   if (press_event)
1962   {
1963     click_consumed = InitGlobalAnim_Clicked(mx, my, ANIM_CLICKED_PRESSED);
1964     click_consumed_current = click_consumed;
1965   }
1966
1967   if (release_event)
1968   {
1969     InitGlobalAnim_Clicked(mx, my, ANIM_CLICKED_RELEASED);
1970     click_consumed = FALSE;
1971   }
1972
1973   return click_consumed_current;
1974 }