added animation events triggered by clicking other global animations
[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 //                  http://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
18
19 /* values for global toon animation definition */
20 #define NUM_GLOBAL_TOON_ANIMS           1
21 #define NUM_GLOBAL_TOON_PARTS           MAX_NUM_TOONS
22
23 /* values for global animation definition (including toons) */
24 #define NUM_GLOBAL_ANIMS_AND_TOONS      (NUM_GLOBAL_ANIMS +             \
25                                          NUM_GLOBAL_TOON_ANIMS)
26 #define NUM_GLOBAL_ANIM_PARTS_AND_TOONS MAX(NUM_GLOBAL_ANIM_PARTS_ALL,  \
27                                             NUM_GLOBAL_TOON_PARTS)
28
29 #define ANIM_CLASS_BIT_TITLE_INITIAL    0
30 #define ANIM_CLASS_BIT_TITLE            1
31 #define ANIM_CLASS_BIT_MAIN             2
32 #define ANIM_CLASS_BIT_SUBMENU          3
33 #define ANIM_CLASS_BIT_MENU             4
34 #define ANIM_CLASS_BIT_TOONS            5
35
36 #define NUM_ANIM_CLASSES                6
37
38 #define ANIM_CLASS_NONE                 0
39 #define ANIM_CLASS_TITLE_INITIAL        (1 << ANIM_CLASS_BIT_TITLE_INITIAL)
40 #define ANIM_CLASS_TITLE                (1 << ANIM_CLASS_BIT_TITLE)
41 #define ANIM_CLASS_MAIN                 (1 << ANIM_CLASS_BIT_MAIN)
42 #define ANIM_CLASS_SUBMENU              (1 << ANIM_CLASS_BIT_SUBMENU)
43 #define ANIM_CLASS_MENU                 (1 << ANIM_CLASS_BIT_MENU)
44 #define ANIM_CLASS_TOONS                (1 << ANIM_CLASS_BIT_TOONS)
45
46 #define ANIM_CLASS_TOONS_MENU_MAIN      (ANIM_CLASS_TOONS |     \
47                                          ANIM_CLASS_MENU  |     \
48                                          ANIM_CLASS_MAIN)
49
50 #define ANIM_CLASS_TOONS_MENU_SUBMENU   (ANIM_CLASS_TOONS |     \
51                                          ANIM_CLASS_MENU  |     \
52                                          ANIM_CLASS_SUBMENU)
53
54 /* values for global animation states */
55 #define ANIM_STATE_INACTIVE             0
56 #define ANIM_STATE_RESTART              (1 << 0)
57 #define ANIM_STATE_WAITING              (1 << 1)
58 #define ANIM_STATE_RUNNING              (1 << 2)
59
60 /* values for global animation control */
61 #define ANIM_NO_ACTION                  0
62 #define ANIM_START                      1
63 #define ANIM_CONTINUE                   2
64 #define ANIM_STOP                       3
65
66
67 struct GlobalAnimPartControlInfo
68 {
69   int old_nr;           // position before mapping animation parts linearly
70   int old_anim_nr;      // position before mapping animations linearly
71
72   int nr;
73   int anim_nr;
74   int mode_nr;
75
76   boolean is_base;      // animation part is base/main/default animation part
77
78   int sound;
79   int music;
80   int graphic;
81
82   struct GraphicInfo graphic_info;
83   struct GraphicInfo control_info;
84
85   int viewport_x;
86   int viewport_y;
87   int viewport_width;
88   int viewport_height;
89
90   int x, y;
91   int step_xoffset, step_yoffset;
92
93   unsigned int initial_anim_sync_frame;
94   unsigned int step_delay, step_delay_value;
95
96   int init_delay_counter;
97   int anim_delay_counter;
98   int post_delay_counter;
99
100   boolean init_event_state;
101   boolean anim_event_state;
102
103   boolean clickable;
104   boolean clicked;
105
106   int drawing_stage;
107
108   int state;
109   int last_anim_status;
110 };
111
112 struct GlobalAnimMainControlInfo
113 {
114   struct GlobalAnimPartControlInfo base;
115   struct GlobalAnimPartControlInfo part[NUM_GLOBAL_ANIM_PARTS_AND_TOONS];
116
117   int nr;
118   int mode_nr;
119
120   struct GraphicInfo control_info;
121
122   int num_parts;        // number of animation parts, but without base part
123   int num_parts_all;    // number of animation parts, including base part
124   int part_counter;
125   int active_part_nr;
126
127   boolean has_base;     // animation has base/main/default animation part
128
129   int init_delay_counter;
130
131   int state;
132
133   int last_state, last_active_part_nr;
134 };
135
136 struct GlobalAnimControlInfo
137 {
138   struct GlobalAnimMainControlInfo anim[NUM_GLOBAL_ANIMS_AND_TOONS];
139
140   int nr;
141   int num_anims;
142 };
143
144 struct GameModeAnimClass
145 {
146   int game_mode;
147   int class;
148 } game_mode_anim_classes_list[] =
149 {
150   { GAME_MODE_TITLE_INITIAL_1,          ANIM_CLASS_TITLE_INITIAL        },
151   { GAME_MODE_TITLE_INITIAL_2,          ANIM_CLASS_TITLE_INITIAL        },
152   { GAME_MODE_TITLE_INITIAL_3,          ANIM_CLASS_TITLE_INITIAL        },
153   { GAME_MODE_TITLE_INITIAL_4,          ANIM_CLASS_TITLE_INITIAL        },
154   { GAME_MODE_TITLE_INITIAL_5,          ANIM_CLASS_TITLE_INITIAL        },
155   { GAME_MODE_TITLE_1,                  ANIM_CLASS_TITLE                },
156   { GAME_MODE_TITLE_2,                  ANIM_CLASS_TITLE                },
157   { GAME_MODE_TITLE_3,                  ANIM_CLASS_TITLE                },
158   { GAME_MODE_TITLE_4,                  ANIM_CLASS_TITLE                },
159   { GAME_MODE_TITLE_5,                  ANIM_CLASS_TITLE                },
160   { GAME_MODE_LEVELS,                   ANIM_CLASS_TOONS_MENU_SUBMENU   },
161   { GAME_MODE_LEVELNR,                  ANIM_CLASS_TOONS_MENU_SUBMENU   },
162   { GAME_MODE_INFO,                     ANIM_CLASS_TOONS_MENU_SUBMENU   },
163   { GAME_MODE_SETUP,                    ANIM_CLASS_TOONS_MENU_SUBMENU   },
164   { GAME_MODE_PSEUDO_MAINONLY,          ANIM_CLASS_TOONS_MENU_MAIN      },
165   { GAME_MODE_PSEUDO_TYPENAME,          ANIM_CLASS_TOONS_MENU_MAIN      },
166   { GAME_MODE_SCORES,                   ANIM_CLASS_TOONS                },
167
168   { -1,                                 -1                              }
169 };
170
171 struct AnimClassGameMode
172 {
173   int class_bit;
174   int game_mode;
175 } anim_class_game_modes_list[] =
176 {
177   { ANIM_CLASS_BIT_TITLE_INITIAL,       GAME_MODE_TITLE_INITIAL         },
178   { ANIM_CLASS_BIT_TITLE,               GAME_MODE_TITLE                 },
179   { ANIM_CLASS_BIT_MAIN,                GAME_MODE_MAIN                  },
180   { ANIM_CLASS_BIT_SUBMENU,             GAME_MODE_PSEUDO_SUBMENU        },
181   { ANIM_CLASS_BIT_MENU,                GAME_MODE_PSEUDO_MENU           },
182   { ANIM_CLASS_BIT_TOONS,               GAME_MODE_PSEUDO_TOONS          },
183
184   { -1,                                 -1                              }
185 };
186
187 /* forward declaration for internal use */
188 static void HandleGlobalAnim(int, int);
189 static void DoAnimationExt(void);
190 static void ResetGlobalAnim_Clickable();
191 static void ResetGlobalAnim_Clicked();
192
193 static struct GlobalAnimControlInfo global_anim_ctrl[NUM_GAME_MODES];
194
195 static unsigned int anim_sync_frame = 0;
196
197 static int game_mode_anim_classes[NUM_GAME_MODES];
198 static int anim_class_game_modes[NUM_ANIM_CLASSES];
199
200 static int anim_status_last = GAME_MODE_DEFAULT;
201 static int anim_classes_last = ANIM_CLASS_NONE;
202
203 static boolean drawing_to_fading_buffer = FALSE;
204
205
206 /* ========================================================================= */
207 /* generic animation frame calculation                                       */
208 /* ========================================================================= */
209
210 int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
211                       int sync_frame)
212 {
213   int frame = 0;
214
215   sync_frame += start_frame * delay;
216
217   if (mode & ANIM_LOOP)                 /* looping animation */
218   {
219     frame = (sync_frame % (delay * num_frames)) / delay;
220   }
221   else if (mode & ANIM_LINEAR)          /* linear (non-looping) animation */
222   {
223     frame = sync_frame / delay;
224
225     if (frame > num_frames - 1)
226       frame = num_frames - 1;
227   }
228   else if (mode & ANIM_PINGPONG)        /* oscillate (border frames once) */
229   {
230     int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1);
231
232     frame = (sync_frame % (delay * max_anim_frames)) / delay;
233     frame = (frame < num_frames ? frame : max_anim_frames - frame);
234   }
235   else if (mode & ANIM_PINGPONG2)       /* oscillate (border frames twice) */
236   {
237     int max_anim_frames = 2 * num_frames;
238
239     frame = (sync_frame % (delay * max_anim_frames)) / delay;
240     frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
241   }
242   else if (mode & ANIM_RANDOM)          /* play frames in random order */
243   {
244     /* note: expect different frames for the same delay cycle! */
245
246     if (gfx.anim_random_frame < 0)
247       frame = GetSimpleRandom(num_frames);
248     else
249       frame = gfx.anim_random_frame % num_frames;
250   }
251   else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY))
252   {
253     frame = sync_frame % num_frames;
254   }
255
256   if (mode & ANIM_REVERSE)              /* use reverse animation direction */
257     frame = num_frames - frame - 1;
258
259   return frame;
260 }
261
262
263 /* ========================================================================= */
264 /* global animation functions                                                */
265 /* ========================================================================= */
266
267 static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim)
268 {
269   struct GraphicInfo *c = &anim->control_info;
270   int last_anim_random_frame = gfx.anim_random_frame;
271   int part_nr;
272
273   gfx.anim_random_frame = -1;   // (use simple, ad-hoc random numbers)
274
275   part_nr = getAnimationFrame(anim->num_parts, 1,
276                               c->anim_mode, c->anim_start_frame,
277                               anim->part_counter);
278
279   gfx.anim_random_frame = last_anim_random_frame;
280
281   return part_nr;
282 }
283
284 static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2)
285 {
286   const struct GlobalAnimPartControlInfo *o1 =
287     (struct GlobalAnimPartControlInfo *)obj1;
288   const struct GlobalAnimPartControlInfo *o2 =
289     (struct GlobalAnimPartControlInfo *)obj2;
290   int compare_result;
291
292   if (o1->control_info.draw_order != o2->control_info.draw_order)
293     compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
294   else
295     compare_result = o1->nr - o2->nr;
296
297   return compare_result;
298 }
299
300 static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2)
301 {
302   const struct GlobalAnimMainControlInfo *o1 =
303     (struct GlobalAnimMainControlInfo *)obj1;
304   const struct GlobalAnimMainControlInfo *o2 =
305     (struct GlobalAnimMainControlInfo *)obj2;
306   int compare_result;
307
308   if (o1->control_info.draw_order != o2->control_info.draw_order)
309     compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
310   else
311     compare_result = o1->nr - o2->nr;
312
313   return compare_result;
314 }
315
316 static void InitToonControls()
317 {
318   int mode_nr_toons = GAME_MODE_PSEUDO_TOONS;
319   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr_toons];
320   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[ctrl->num_anims];
321   int mode_nr, anim_nr, part_nr;
322   int control = IMG_INTERNAL_GLOBAL_TOON_DEFAULT;
323   int num_toons = MAX_NUM_TOONS;
324   int i;
325
326   if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
327     num_toons = global.num_toons;
328
329   mode_nr = mode_nr_toons;
330   anim_nr = ctrl->num_anims;
331
332   anim->nr = anim_nr;
333   anim->mode_nr = mode_nr;
334   anim->control_info = graphic_info[control];
335
336   anim->num_parts = 0;
337   anim->num_parts_all = 0;
338   anim->part_counter = 0;
339   anim->active_part_nr = 0;
340
341   anim->has_base = FALSE;
342
343   anim->init_delay_counter = 0;
344
345   anim->state = ANIM_STATE_INACTIVE;
346
347   part_nr = 0;
348
349   for (i = 0; i < num_toons; i++)
350   {
351     struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
352     int sound = SND_UNDEFINED;
353     int music = MUS_UNDEFINED;
354     int graphic = IMG_TOON_1 + i;
355     int control = graphic;
356
357     part->nr = part_nr;
358     part->anim_nr = anim_nr;
359     part->mode_nr = mode_nr;
360
361     part->is_base = FALSE;
362
363     part->sound = sound;
364     part->music = music;
365     part->graphic = graphic;
366
367     part->graphic_info = graphic_info[graphic];
368     part->control_info = graphic_info[control];
369
370     part->graphic_info.anim_delay *= part->graphic_info.step_delay;
371
372     part->control_info.init_delay_fixed = 0;
373     part->control_info.init_delay_random = 150;
374
375     part->control_info.x = ARG_UNDEFINED_VALUE;
376     part->control_info.y = ARG_UNDEFINED_VALUE;
377
378     part->initial_anim_sync_frame = 0;
379
380     part->step_delay = 0;
381     part->step_delay_value = graphic_info[control].step_delay;
382
383     part->state = ANIM_STATE_INACTIVE;
384     part->last_anim_status = -1;
385
386     anim->num_parts++;
387     anim->num_parts_all++;
388
389     part_nr++;
390   }
391
392   ctrl->num_anims++;
393 }
394
395 void InitGlobalAnimControls()
396 {
397   int i, m, a, p;
398   int mode_nr, anim_nr, part_nr;
399   int sound, music, graphic, control;
400
401   anim_sync_frame = 0;
402
403   for (m = 0; m < NUM_GAME_MODES; m++)
404   {
405     mode_nr = m;
406
407     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
408
409     ctrl->nr = mode_nr;
410     ctrl->num_anims = 0;
411
412     anim_nr = 0;
413
414     for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
415     {
416       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
417       int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
418
419       control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
420
421       // if no base animation parameters defined, use default values
422       if (control == IMG_UNDEFINED)
423         control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
424
425       anim->nr = anim_nr;
426       anim->mode_nr = mode_nr;
427       anim->control_info = graphic_info[control];
428
429       anim->num_parts = 0;
430       anim->num_parts_all = 0;
431       anim->part_counter = 0;
432       anim->active_part_nr = 0;
433
434       anim->has_base = FALSE;
435
436       anim->init_delay_counter = 0;
437
438       anim->state = ANIM_STATE_INACTIVE;
439
440       part_nr = 0;
441
442       for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
443       {
444         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
445
446         sound   = global_anim_info[a].sound[p][m];
447         music   = global_anim_info[a].music[p][m];
448         graphic = global_anim_info[a].graphic[p][m];
449         control = global_anim_info[ctrl_id].graphic[p][m];
450
451         if (graphic == IMG_UNDEFINED || graphic_info[graphic].bitmap == NULL ||
452             control == IMG_UNDEFINED)
453           continue;
454
455 #if 0
456         printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n",
457                m, a, p, mode_nr, anim_nr, part_nr, control);
458 #endif
459
460 #if 0
461         printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n",
462                m, a, p, mode_nr, anim_nr, part_nr, sound);
463 #endif
464
465         part->old_nr = p;
466         part->old_anim_nr = a;
467
468         part->nr = part_nr;
469         part->anim_nr = anim_nr;
470         part->mode_nr = mode_nr;
471
472         part->sound = sound;
473         part->music = music;
474         part->graphic = graphic;
475
476         part->graphic_info = graphic_info[graphic];
477         part->control_info = graphic_info[control];
478
479         part->initial_anim_sync_frame = 0;
480
481         part->step_delay = 0;
482         part->step_delay_value = graphic_info[control].step_delay;
483
484         part->state = ANIM_STATE_INACTIVE;
485         part->last_anim_status = -1;
486
487         anim->num_parts_all++;
488
489         if (p < GLOBAL_ANIM_ID_PART_BASE)
490         {
491           part->is_base = FALSE;
492
493           anim->num_parts++;
494           part_nr++;
495         }
496         else
497         {
498           part->is_base = TRUE;
499
500           anim->base = *part;
501           anim->has_base = TRUE;
502         }
503       }
504
505       if (anim->num_parts > 0 || anim->has_base)
506       {
507         ctrl->num_anims++;
508         anim_nr++;
509       }
510     }
511   }
512
513   InitToonControls();
514
515   /* sort all animations according to draw_order and animation number */
516   for (m = 0; m < NUM_GAME_MODES; m++)
517   {
518     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[m];
519
520     /* sort all main animations for this game mode */
521     qsort(ctrl->anim, ctrl->num_anims,
522           sizeof(struct GlobalAnimMainControlInfo),
523           compareGlobalAnimMainControlInfo);
524
525     for (a = 0; a < ctrl->num_anims; a++)
526     {
527       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a];
528
529       /* sort all animation parts for this main animation */
530       qsort(anim->part, anim->num_parts,
531             sizeof(struct GlobalAnimPartControlInfo),
532             compareGlobalAnimPartControlInfo);
533     }
534   }
535
536   for (i = 0; i < NUM_GAME_MODES; i++)
537     game_mode_anim_classes[i] = ANIM_CLASS_NONE;
538   for (i = 0; game_mode_anim_classes_list[i].game_mode != -1; i++)
539     game_mode_anim_classes[game_mode_anim_classes_list[i].game_mode] =
540       game_mode_anim_classes_list[i].class;
541
542   for (i = 0; i < NUM_ANIM_CLASSES; i++)
543     anim_class_game_modes[i] = GAME_MODE_DEFAULT;
544   for (i = 0; anim_class_game_modes_list[i].game_mode != -1; i++)
545     anim_class_game_modes[anim_class_game_modes_list[i].class_bit] =
546       anim_class_game_modes_list[i].game_mode;
547
548   anim_status_last = GAME_MODE_LOADING;
549   anim_classes_last = ANIM_CLASS_NONE;
550 }
551
552 void InitGlobalAnimations()
553 {
554   InitGlobalAnimControls();
555 }
556
557 void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage)
558 {
559   Bitmap *fade_bitmap =
560     (drawing_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
561      drawing_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
562   int game_mode_anim_action[NUM_GAME_MODES];
563   int mode_nr;
564
565   if (!setup.toons)
566     return;
567
568   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1 &&
569       drawing_target == DRAW_TO_SCREEN)
570     DoAnimationExt();
571
572   // always start with reliable default values (no animation actions)
573   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
574     game_mode_anim_action[mode_nr] = ANIM_NO_ACTION;
575
576   if (global.anim_status != anim_status_last)
577   {
578     boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING);
579     boolean after_fading  = (anim_status_last   == GAME_MODE_PSEUDO_FADING);
580     int anim_classes_next = game_mode_anim_classes[global.anim_status_next];
581     int i;
582
583     if (drawing_target == DRAW_TO_FADE_TARGET)
584       after_fading = TRUE;
585
586     // ---------- part 1 ------------------------------------------------------
587     // start or stop global animations by change of game mode
588     // (special handling of animations for "current screen" and "all screens")
589
590     // stop animations for last screen
591     game_mode_anim_action[anim_status_last] = ANIM_STOP;
592
593     // start animations for current screen
594     game_mode_anim_action[global.anim_status] = ANIM_START;
595
596     // start animations for all screens after loading new artwork set
597     if (anim_status_last == GAME_MODE_LOADING)
598       game_mode_anim_action[GAME_MODE_DEFAULT] = ANIM_START;
599
600     // ---------- part 2 ------------------------------------------------------
601     // start or stop global animations by change of animation class
602     // (generic handling of animations for "class of screens")
603
604     for (i = 0; i < NUM_ANIM_CLASSES; i++)
605     {
606       int anim_class_check = (1 << i);
607       int anim_class_game_mode = anim_class_game_modes[i];
608       int anim_class_last = anim_classes_last & anim_class_check;
609       int anim_class_next = anim_classes_next & anim_class_check;
610
611       // stop animations for changed screen class before fading to new screen
612       if (before_fading && anim_class_last && !anim_class_next)
613         game_mode_anim_action[anim_class_game_mode] = ANIM_STOP;
614
615       // start animations for changed screen class after fading to new screen
616       if (after_fading && !anim_class_last && anim_class_next)
617         game_mode_anim_action[anim_class_game_mode] = ANIM_START;
618     }
619
620     if (drawing_target == DRAW_TO_SCREEN)
621     {
622       if (after_fading)
623         anim_classes_last = anim_classes_next;
624
625       anim_status_last = global.anim_status;
626
627       // start or stop animations determined to be started or stopped above
628       for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
629         if (game_mode_anim_action[mode_nr] != ANIM_NO_ACTION)
630           HandleGlobalAnim(game_mode_anim_action[mode_nr], mode_nr);
631     }
632     else if (drawing_target == DRAW_TO_FADE_TARGET)
633     {
634       drawing_to_fading_buffer = TRUE;
635
636       // start animations determined to be (temporary) started above
637       for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
638         if (game_mode_anim_action[mode_nr] == ANIM_START)
639           HandleGlobalAnim(ANIM_START, mode_nr);
640     }
641   }
642
643   if (global.anim_status == GAME_MODE_LOADING)
644     return;
645
646   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
647   {
648     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
649     int anim_nr;
650
651     // when preparing source fading buffer, only draw animations to be stopped
652     if (drawing_target == DRAW_TO_FADE_SOURCE &&
653         game_mode_anim_action[mode_nr] != ANIM_STOP)
654       continue;
655
656     // when preparing target fading buffer, only draw animations to be started
657     if (drawing_target == DRAW_TO_FADE_TARGET &&
658         game_mode_anim_action[mode_nr] != ANIM_START)
659       continue;
660
661 #if 0
662     if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
663         mode_nr != game_status)
664       continue;
665 #endif
666
667     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
668     {
669       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
670       struct GraphicInfo *c = &anim->control_info;
671       int part_first, part_last;
672       int part_nr;
673
674       if (!(anim->state & ANIM_STATE_RUNNING))
675         continue;
676
677       part_first = part_last = anim->active_part_nr;
678
679       if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
680       {
681         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
682
683         part_first = 0;
684         part_last = num_parts - 1;
685       }
686
687       for (part_nr = part_first; part_nr <= part_last; part_nr++)
688       {
689         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
690         struct GraphicInfo *g = &part->graphic_info;
691         Bitmap *src_bitmap;
692         int src_x, src_y;
693         int width  = g->width;
694         int height = g->height;
695         int dst_x = part->x;
696         int dst_y = part->y;
697         int cut_x = 0;
698         int cut_y = 0;
699         int sync_frame;
700         int frame;
701
702         if (!(part->state & ANIM_STATE_RUNNING))
703           continue;
704
705         if (part->drawing_stage != drawing_stage)
706           continue;
707
708         if (part->x < 0)
709         {
710           dst_x = 0;
711           width += part->x;
712           cut_x = -part->x;
713         }
714         else if (part->x > part->viewport_width - g->width)
715           width -= (part->x - (part->viewport_width - g->width));
716
717         if (part->y < 0)
718         {
719           dst_y = 0;
720           height += part->y;
721           cut_y = -part->y;
722         }
723         else if (part->y > part->viewport_height - g->height)
724           height -= (part->y - (part->viewport_height - g->height));
725
726         if (width <= 0 || height <= 0)
727           continue;
728
729         dst_x += part->viewport_x;
730         dst_y += part->viewport_y;
731
732         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
733         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
734                                   g->anim_mode, g->anim_start_frame,
735                                   sync_frame);
736
737         getFixedGraphicSource(part->graphic, frame, &src_bitmap,
738                               &src_x, &src_y);
739
740         src_x += cut_x;
741         src_y += cut_y;
742
743         if (drawing_target == DRAW_TO_SCREEN)
744           BlitToScreenMasked(src_bitmap, src_x, src_y, width, height,
745                              dst_x, dst_y);
746         else
747           BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height,
748                            dst_x, dst_y);
749       }
750     }
751   }
752
753   if (drawing_target == DRAW_TO_FADE_TARGET)
754   {
755     // stop animations determined to be (temporary) started above
756     for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
757       if (game_mode_anim_action[mode_nr] == ANIM_START)
758         HandleGlobalAnim(ANIM_STOP, mode_nr);
759
760     drawing_to_fading_buffer = FALSE;
761   }
762 }
763
764 void DrawGlobalAnimations(int drawing_target, int drawing_stage)
765 {
766   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
767     ResetGlobalAnim_Clickable();
768
769   DrawGlobalAnimationsExt(drawing_target, drawing_stage);
770
771   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_2)
772     ResetGlobalAnim_Clicked();
773 }
774
775 boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
776 {
777   int viewport_x;
778   int viewport_y;
779   int viewport_width;
780   int viewport_height;
781   boolean changed = FALSE;
782
783   if (part->last_anim_status == global.anim_status)
784     return FALSE;
785
786   part->last_anim_status = global.anim_status;
787
788   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
789
790   if (part->control_info.class == get_hash_from_key("window") ||
791       part->control_info.class == get_hash_from_key("border"))
792   {
793     viewport_x = 0;
794     viewport_y = 0;
795     viewport_width  = WIN_XSIZE;
796     viewport_height = WIN_YSIZE;
797
798     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
799   }
800   else if (part->control_info.class == get_hash_from_key("door_1"))
801   {
802     viewport_x = DX;
803     viewport_y = DY;
804     viewport_width  = DXSIZE;
805     viewport_height = DYSIZE;
806   }
807   else if (part->control_info.class == get_hash_from_key("door_2"))
808   {
809     viewport_x = VX;
810     viewport_y = VY;
811     viewport_width  = VXSIZE;
812     viewport_height = VYSIZE;
813   }
814   else          // default: "playfield"
815   {
816     viewport_x = REAL_SX;
817     viewport_y = REAL_SY;
818     viewport_width  = FULL_SXSIZE;
819     viewport_height = FULL_SYSIZE;
820   }
821
822   if (viewport_x != part->viewport_x ||
823       viewport_y != part->viewport_y ||
824       viewport_width  != part->viewport_width ||
825       viewport_height != part->viewport_height)
826   {
827     part->viewport_x = viewport_x;
828     part->viewport_y = viewport_y;
829     part->viewport_width  = viewport_width;
830     part->viewport_height = viewport_height;
831
832     changed = TRUE;
833   }
834
835   return changed;
836 }
837
838 static void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
839 {
840   int sound = part->sound;
841
842   if (sound == SND_UNDEFINED)
843     return;
844
845   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
846       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
847     return;
848
849   // !!! TODO: ADD STEREO POSITION FOR MOVING ANIMATIONS !!!
850   if (IS_LOOP_SOUND(sound))
851     PlaySoundLoop(sound);
852   else
853     PlaySound(sound);
854
855 #if 0
856   printf("::: PLAY SOUND %d.%d.%d: %d\n",
857          part->anim_nr, part->nr, part->mode_nr, sound);
858 #endif
859 }
860
861 static void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
862 {
863   int sound = part->sound;
864
865   if (sound == SND_UNDEFINED)
866     return;
867
868   StopSound(sound);
869
870 #if 0
871   printf("::: STOP SOUND %d.%d.%d: %d\n",
872          part->anim_nr, part->nr, part->mode_nr, sound);
873 #endif
874 }
875
876 static void PlayGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
877 {
878   int music = part->music;
879
880   if (music == MUS_UNDEFINED)
881     return;
882
883   if (!setup.sound_music)
884     return;
885
886   PlayMusic(music);
887
888 #if 0
889   printf("::: PLAY MUSIC %d.%d.%d: %d\n",
890          part->anim_nr, part->nr, part->mode_nr, music);
891 #endif
892 }
893
894 static void StopGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
895 {
896   int music = part->music;
897
898   if (music == MUS_UNDEFINED)
899     return;
900
901   StopMusic();
902
903 #if 0
904   printf("::: STOP MUSIC %d.%d.%d: %d\n",
905          part->anim_nr, part->nr, part->mode_nr, music);
906 #endif
907 }
908
909 static void PlayGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
910 {
911   // when drawing animations to fading buffer, do not play sounds or music
912   if (drawing_to_fading_buffer)
913     return;
914
915   PlayGlobalAnimSound(part);
916   PlayGlobalAnimMusic(part);
917 }
918
919 static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
920 {
921   StopGlobalAnimSound(part);
922   StopGlobalAnimMusic(part);
923 }
924
925 static boolean matchesAnimEventMask(int bits, int mask)
926 {
927   return (bits & (mask & ANIM_EVENT_CLICK_ANIM_ALL) &&
928           bits & (mask & ANIM_EVENT_CLICK_PART_ALL));
929 }
930
931 static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask)
932 {
933   struct GraphicInfo *c = &part->control_info;
934
935   boolean clickable_self = FALSE;
936   boolean clickable_triggered = FALSE;
937
938   if (mask & ANIM_EVENT_CLICK_SELF)
939     clickable_self = (c->init_event & ANIM_EVENT_CLICK_SELF ||
940                       c->anim_event & ANIM_EVENT_CLICK_SELF);
941
942   clickable_triggered = (matchesAnimEventMask(c->init_event, mask) ||
943                          matchesAnimEventMask(c->anim_event, mask));
944
945   return (clickable_self || clickable_triggered);
946 }
947
948 static boolean isClickedPart(struct GlobalAnimPartControlInfo *part,
949                              int mx, int my, boolean clicked)
950 {
951   struct GraphicInfo *g = &part->graphic_info;
952   int part_x = part->viewport_x + part->x;
953   int part_y = part->viewport_y + part->y;
954   int part_width  = g->width;
955   int part_height = g->height;
956
957   // check if mouse click was detected at all
958   if (!clicked)
959     return FALSE;
960
961   // check if mouse click is inside the animation part's viewport
962   if (mx <  part->viewport_x ||
963       mx >= part->viewport_x + part->viewport_width ||
964       my <  part->viewport_y ||
965       my >= part->viewport_y + part->viewport_height)
966     return FALSE;
967
968   // check if mouse click is inside the animation part's graphic
969   if (mx <  part_x ||
970       mx >= part_x + part_width ||
971       my <  part_y ||
972       my >= part_y + part_height)
973     return FALSE;
974
975   return TRUE;
976 }
977
978 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
979 {
980   struct GraphicInfo *g = &part->graphic_info;
981   struct GraphicInfo *c = &part->control_info;
982   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
983
984   if (viewport_changed)
985     state |= ANIM_STATE_RESTART;
986
987   if (state & ANIM_STATE_RESTART)
988   {
989     // when drawing animations to fading buffer, only start fixed animations
990     if (drawing_to_fading_buffer && (c->x == ARG_UNDEFINED_VALUE ||
991                                      c->y == ARG_UNDEFINED_VALUE))
992       return ANIM_STATE_INACTIVE;
993
994     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
995
996     part->init_delay_counter =
997       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
998
999     part->anim_delay_counter =
1000       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
1001
1002     part->init_event_state = c->init_event;
1003     part->anim_event_state = c->anim_event;
1004
1005     part->initial_anim_sync_frame =
1006       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
1007
1008     if (c->direction & MV_HORIZONTAL)
1009     {
1010       int pos_bottom = part->viewport_height - g->height;
1011
1012       if (c->position == POS_TOP)
1013         part->y = 0;
1014       else if (c->position == POS_UPPER)
1015         part->y = GetSimpleRandom(pos_bottom / 2);
1016       else if (c->position == POS_MIDDLE)
1017         part->y = pos_bottom / 2;
1018       else if (c->position == POS_LOWER)
1019         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
1020       else if (c->position == POS_BOTTOM)
1021         part->y = pos_bottom;
1022       else
1023         part->y = GetSimpleRandom(pos_bottom);
1024
1025       if (c->direction == MV_RIGHT)
1026       {
1027         part->step_xoffset = c->step_offset;
1028         part->x = -g->width + part->step_xoffset;
1029       }
1030       else
1031       {
1032         part->step_xoffset = -c->step_offset;
1033         part->x = part->viewport_width + part->step_xoffset;
1034       }
1035
1036       part->step_yoffset = 0;
1037     }
1038     else if (c->direction & MV_VERTICAL)
1039     {
1040       int pos_right = part->viewport_width - g->width;
1041
1042       if (c->position == POS_LEFT)
1043         part->x = 0;
1044       else if (c->position == POS_RIGHT)
1045         part->x = pos_right;
1046       else
1047         part->x = GetSimpleRandom(pos_right);
1048
1049       if (c->direction == MV_DOWN)
1050       {
1051         part->step_yoffset = c->step_offset;
1052         part->y = -g->height + part->step_yoffset;
1053       }
1054       else
1055       {
1056         part->step_yoffset = -c->step_offset;
1057         part->y = part->viewport_height + part->step_yoffset;
1058       }
1059
1060       part->step_xoffset = 0;
1061     }
1062     else
1063     {
1064       part->x = 0;
1065       part->y = 0;
1066
1067       part->step_xoffset = 0;
1068       part->step_yoffset = 0;
1069     }
1070
1071     if (c->x != ARG_UNDEFINED_VALUE)
1072       part->x = c->x;
1073     if (c->y != ARG_UNDEFINED_VALUE)
1074       part->y = c->y;
1075
1076     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
1077       part->step_xoffset = c->step_xoffset;
1078     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
1079       part->step_yoffset = c->step_yoffset;
1080
1081     if (part->init_delay_counter == 0 &&
1082         part->init_event_state == ANIM_EVENT_NONE)
1083       PlayGlobalAnimSoundAndMusic(part);
1084   }
1085
1086   if (part->clicked &&
1087       part->init_event_state != ANIM_EVENT_NONE)
1088   {
1089     if (part->initial_anim_sync_frame > 0)
1090       part->initial_anim_sync_frame -= part->init_delay_counter - 1;
1091
1092     part->init_delay_counter = 1;
1093     part->init_event_state = ANIM_EVENT_NONE;
1094
1095     part->clicked = FALSE;
1096   }
1097
1098   if (part->clicked &&
1099       part->anim_event_state != ANIM_EVENT_NONE)
1100   {
1101     part->anim_delay_counter = 1;
1102     part->anim_event_state = ANIM_EVENT_NONE;
1103
1104     part->clicked = FALSE;
1105   }
1106
1107   if (part->init_delay_counter > 0)
1108   {
1109     part->init_delay_counter--;
1110
1111     if (part->init_delay_counter == 0)
1112     {
1113       part->init_event_state = ANIM_EVENT_NONE;
1114
1115       PlayGlobalAnimSoundAndMusic(part);
1116     }
1117
1118     return ANIM_STATE_WAITING;
1119   }
1120
1121   if (part->init_event_state != ANIM_EVENT_NONE)
1122     return ANIM_STATE_WAITING;
1123
1124   // animation part is now running/visible and therefore clickable
1125   part->clickable = TRUE;
1126
1127   // check if moving animation has left the visible screen area
1128   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
1129       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
1130       (part->y <= -g->height             && part->step_yoffset <= 0) ||
1131       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
1132   {
1133     // do not wait for "anim" events for off-screen animations
1134     part->anim_event_state = ANIM_EVENT_NONE;
1135
1136     // do not stop animation before "anim" or "post" counter are finished
1137     if (part->anim_delay_counter == 0 &&
1138         part->post_delay_counter == 0)
1139     {
1140       StopGlobalAnimSoundAndMusic(part);
1141
1142       part->post_delay_counter =
1143         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1144
1145       if (part->post_delay_counter > 0)
1146         return ANIM_STATE_RUNNING;
1147
1148       // drawing last frame not needed here -- animation not visible anymore
1149       return ANIM_STATE_RESTART;
1150     }
1151   }
1152
1153   if (part->anim_delay_counter > 0)
1154   {
1155     part->anim_delay_counter--;
1156
1157     if (part->anim_delay_counter == 0)
1158     {
1159       part->anim_event_state = ANIM_EVENT_NONE;
1160
1161       StopGlobalAnimSoundAndMusic(part);
1162
1163       part->post_delay_counter =
1164         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1165
1166       if (part->post_delay_counter > 0)
1167         return ANIM_STATE_RUNNING;
1168
1169       // additional state "RUNNING" required to not skip drawing last frame
1170       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
1171     }
1172   }
1173
1174   if (part->post_delay_counter > 0)
1175   {
1176     part->post_delay_counter--;
1177
1178     if (part->post_delay_counter == 0)
1179       return ANIM_STATE_RESTART;
1180
1181     return ANIM_STATE_WAITING;
1182   }
1183
1184   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
1185                        anim_sync_frame))
1186     return ANIM_STATE_RUNNING;
1187
1188 #if 0
1189   {
1190     static unsigned int last_counter = -1;
1191     unsigned int counter = Counter();
1192
1193     printf("::: NEXT ANIM PART [%d, %d]\n",
1194            anim_sync_frame, counter - last_counter);
1195
1196     last_counter = counter;
1197   }
1198 #endif
1199
1200   part->x += part->step_xoffset;
1201   part->y += part->step_yoffset;
1202
1203   return ANIM_STATE_RUNNING;
1204 }
1205
1206 void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
1207 {
1208   struct GlobalAnimPartControlInfo *part;
1209   struct GraphicInfo *c = &anim->control_info;
1210   int state, active_part_nr;
1211
1212 #if 0
1213   printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1214          anim->mode_nr, anim->nr, anim->num_parts);
1215   printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
1216 #endif
1217
1218 #if 0
1219   printf("::: %s(%d): %d, %d, %d [%d]\n",
1220          (action == ANIM_START ? "ANIM_START" :
1221           action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
1222           action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
1223          anim->nr,
1224          anim->state & ANIM_STATE_RESTART,
1225          anim->state & ANIM_STATE_WAITING,
1226          anim->state & ANIM_STATE_RUNNING,
1227          anim->num_parts);
1228 #endif
1229
1230   switch (action)
1231   {
1232     case ANIM_START:
1233       anim->state = anim->last_state = ANIM_STATE_RESTART;
1234       anim->active_part_nr = anim->last_active_part_nr = 0;
1235       anim->part_counter = 0;
1236
1237       break;
1238
1239     case ANIM_CONTINUE:
1240       if (anim->state == ANIM_STATE_INACTIVE)
1241         return;
1242
1243       anim->state = anim->last_state;
1244       anim->active_part_nr = anim->last_active_part_nr;
1245
1246       break;
1247
1248     case ANIM_STOP:
1249       anim->state = ANIM_STATE_INACTIVE;
1250
1251       {
1252         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1253         int i;
1254
1255         for (i = 0; i < num_parts; i++)
1256           StopGlobalAnimSoundAndMusic(&anim->part[i]);
1257       }
1258
1259       return;
1260
1261     default:
1262       break;
1263   }
1264
1265   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
1266   {
1267     int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1268     int i;
1269
1270 #if 0
1271     printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1272            anim->mode_nr, anim->nr, num_parts);
1273 #endif
1274
1275     for (i = 0; i < num_parts; i++)
1276     {
1277       part = &anim->part[i];
1278
1279       switch (action)
1280       {
1281         case ANIM_START:
1282           anim->state = ANIM_STATE_RUNNING;
1283           part->state = ANIM_STATE_RESTART;
1284
1285           break;
1286
1287         case ANIM_CONTINUE:
1288           if (part->state == ANIM_STATE_INACTIVE)
1289             continue;
1290
1291           break;
1292
1293         case ANIM_STOP:
1294           part->state = ANIM_STATE_INACTIVE;
1295
1296           continue;
1297
1298         default:
1299           break;
1300       }
1301
1302       part->state = HandleGlobalAnim_Part(part, part->state);
1303
1304       // when animation mode is "once", stop after animation was played once
1305       if (c->anim_mode & ANIM_ONCE &&
1306           part->state & ANIM_STATE_RESTART)
1307         part->state = ANIM_STATE_INACTIVE;
1308     }
1309
1310     anim->last_state = anim->state;
1311     anim->last_active_part_nr = anim->active_part_nr;
1312
1313     return;
1314   }
1315
1316   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
1317     anim->active_part_nr = getGlobalAnimationPart(anim);
1318
1319   part = &anim->part[anim->active_part_nr];
1320
1321   part->state = ANIM_STATE_RUNNING;
1322
1323   anim->state = HandleGlobalAnim_Part(part, anim->state);
1324
1325   if (anim->state & ANIM_STATE_RESTART)
1326     anim->part_counter++;
1327
1328   // when animation mode is "once", stop after all animations were played once
1329   if (c->anim_mode & ANIM_ONCE &&
1330       anim->part_counter == anim->num_parts)
1331     anim->state = ANIM_STATE_INACTIVE;
1332
1333   state = anim->state;
1334   active_part_nr = anim->active_part_nr;
1335
1336   // while the animation parts are pausing (waiting or inactive), play the base
1337   // (main) animation; this corresponds to the "boring player animation" logic
1338   // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!)
1339   if (anim->has_base)
1340   {
1341     if (anim->state == ANIM_STATE_WAITING ||
1342         anim->state == ANIM_STATE_INACTIVE)
1343     {
1344       anim->active_part_nr = anim->num_parts;   // part nr of base animation
1345       part = &anim->part[anim->active_part_nr];
1346
1347       if (anim->state != anim->last_state)
1348         part->state = ANIM_STATE_RESTART;
1349
1350       anim->state = ANIM_STATE_RUNNING;
1351       part->state = HandleGlobalAnim_Part(part, part->state);
1352     }
1353   }
1354
1355   anim->last_state = state;
1356   anim->last_active_part_nr = active_part_nr;
1357 }
1358
1359 void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
1360 {
1361   int i;
1362
1363 #if 0
1364   printf("::: HandleGlobalAnim_Mode: %d => %d\n",
1365          ctrl->nr, ctrl->num_anims);
1366 #endif
1367
1368   for (i = 0; i < ctrl->num_anims; i++)
1369     HandleGlobalAnim_Main(&ctrl->anim[i], action);
1370 }
1371
1372 static void HandleGlobalAnim(int action, int game_mode)
1373 {
1374 #if 0
1375   printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
1376 #endif
1377
1378   HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
1379 }
1380
1381 static void DoAnimationExt()
1382 {
1383   int i;
1384
1385 #if 0
1386   printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
1387 #endif
1388
1389   // global animations now synchronized with frame delay of screen update
1390   anim_sync_frame++;
1391
1392   for (i = 0; i < NUM_GAME_MODES; i++)
1393     HandleGlobalAnim(ANIM_CONTINUE, i);
1394
1395 #if 0
1396   // force screen redraw in next frame to continue drawing global animations
1397   redraw_mask = REDRAW_ALL;
1398 #endif
1399 }
1400
1401 static void InitGlobalAnim_Clickable()
1402 {
1403   int mode_nr;
1404
1405   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
1406   {
1407     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
1408     int anim_nr;
1409
1410     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
1411     {
1412       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
1413       int part_nr;
1414
1415       for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++)
1416       {
1417         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
1418
1419         part->clickable = FALSE;
1420       }
1421     }
1422   }
1423 }
1424
1425 static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked)
1426 {
1427   boolean any_part_clicked = FALSE;
1428   int mode_nr;
1429
1430   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
1431   {
1432     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
1433     int anim_nr;
1434
1435     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
1436     {
1437       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
1438       int part_nr;
1439
1440       for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++)
1441       {
1442         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
1443
1444         if (!clicked)
1445         {
1446           part->clicked = FALSE;
1447
1448           continue;
1449         }
1450
1451         if (part->clickable &&
1452             isClickedPart(part, mx, my, clicked))
1453         {
1454 #if 0
1455           printf("::: %d.%d CLICKED\n", anim_nr, part_nr);
1456 #endif
1457
1458           if (isClickablePart(part, ANIM_EVENT_CLICK_SELF))
1459             any_part_clicked = part->clicked = TRUE;
1460
1461           // check if this click is defined to trigger other animations
1462           int old_anim_nr = part->old_anim_nr;
1463           int old_part_nr = part->old_nr;
1464           int mask = ANIM_EVENT_CLICK_ANIM_1 << old_anim_nr;
1465
1466           if (part->is_base)
1467             mask |= ANIM_EVENT_CLICK_PART_ALL;
1468           else
1469             mask |= ANIM_EVENT_CLICK_PART_1 << old_part_nr;
1470
1471           int anim2_nr;
1472
1473           for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++)
1474           {
1475             struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr];
1476             int part2_nr;
1477
1478             for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++)
1479             {
1480               struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr];
1481
1482               if (isClickablePart(part2, mask))
1483                 any_part_clicked = part2->clicked = TRUE;
1484
1485 #if 0
1486               struct GraphicInfo *c = &part2->control_info;
1487
1488               printf("::: - %d.%d: 0x%08x, 0x%08x [0x%08x]",
1489                      anim2_nr, part2_nr, c->init_event, c->anim_event, mask);
1490
1491               if (isClickablePart(part2, mask))
1492                 printf(" <--- TRIGGERED BY %d.%d",
1493                        anim_nr, part_nr);
1494
1495               printf("\n");
1496 #endif
1497             }
1498           }
1499         }
1500       }
1501     }
1502   }
1503
1504   return any_part_clicked;
1505 }
1506
1507 static void ResetGlobalAnim_Clickable()
1508 {
1509   InitGlobalAnim_Clickable();
1510 }
1511
1512 static void ResetGlobalAnim_Clicked()
1513 {
1514   InitGlobalAnim_Clicked(-1, -1, FALSE);
1515 }
1516
1517 boolean HandleGlobalAnimClicks(int mx, int my, int button)
1518 {
1519   static boolean click_consumed = FALSE;
1520   static int last_button = 0;
1521   boolean press_event;
1522   boolean release_event;
1523   boolean click_consumed_current = click_consumed;
1524
1525   /* check if button state has changed since last invocation */
1526   press_event   = (button != 0 && last_button == 0);
1527   release_event = (button == 0 && last_button != 0);
1528   last_button = button;
1529
1530   if (press_event)
1531   {
1532     click_consumed = InitGlobalAnim_Clicked(mx, my, TRUE);
1533     click_consumed_current = click_consumed;
1534   }
1535
1536   if (release_event)
1537     click_consumed = FALSE;
1538
1539   return click_consumed_current;
1540 }