added using '.draw_masked' for global animation and toon graphics
[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         void (*blit_bitmap)(Bitmap *, Bitmap *, int, int, int, int, int, int) =
702           (g->draw_masked ? BlitBitmapMasked : BlitBitmap);
703         void (*blit_screen)(Bitmap *, int, int, int, int, int, int) =
704           (g->draw_masked ? BlitToScreenMasked : BlitToScreen);
705
706         if (!(part->state & ANIM_STATE_RUNNING))
707           continue;
708
709         if (part->drawing_stage != drawing_stage)
710           continue;
711
712         if (part->x < 0)
713         {
714           dst_x = 0;
715           width += part->x;
716           cut_x = -part->x;
717         }
718         else if (part->x > part->viewport_width - g->width)
719           width -= (part->x - (part->viewport_width - g->width));
720
721         if (part->y < 0)
722         {
723           dst_y = 0;
724           height += part->y;
725           cut_y = -part->y;
726         }
727         else if (part->y > part->viewport_height - g->height)
728           height -= (part->y - (part->viewport_height - g->height));
729
730         if (width <= 0 || height <= 0)
731           continue;
732
733         dst_x += part->viewport_x;
734         dst_y += part->viewport_y;
735
736         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
737         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
738                                   g->anim_mode, g->anim_start_frame,
739                                   sync_frame);
740
741         getFixedGraphicSource(part->graphic, frame, &src_bitmap,
742                               &src_x, &src_y);
743
744         src_x += cut_x;
745         src_y += cut_y;
746
747         if (drawing_target == DRAW_TO_SCREEN)
748           blit_screen(src_bitmap, src_x, src_y, width, height,
749                       dst_x, dst_y);
750         else
751           blit_bitmap(src_bitmap, fade_bitmap, src_x, src_y, width, height,
752                       dst_x, dst_y);
753       }
754     }
755   }
756
757   if (drawing_target == DRAW_TO_FADE_TARGET)
758   {
759     // stop animations determined to be (temporary) started above
760     for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
761       if (game_mode_anim_action[mode_nr] == ANIM_START)
762         HandleGlobalAnim(ANIM_STOP, mode_nr);
763
764     drawing_to_fading_buffer = FALSE;
765   }
766 }
767
768 void DrawGlobalAnimations(int drawing_target, int drawing_stage)
769 {
770   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
771     ResetGlobalAnim_Clickable();
772
773   DrawGlobalAnimationsExt(drawing_target, drawing_stage);
774
775   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_2)
776     ResetGlobalAnim_Clicked();
777 }
778
779 boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
780 {
781   int viewport_x;
782   int viewport_y;
783   int viewport_width;
784   int viewport_height;
785   boolean changed = FALSE;
786
787   if (part->last_anim_status == global.anim_status)
788     return FALSE;
789
790   part->last_anim_status = global.anim_status;
791
792   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
793
794   if (part->control_info.class == get_hash_from_key("window") ||
795       part->control_info.class == get_hash_from_key("border"))
796   {
797     viewport_x = 0;
798     viewport_y = 0;
799     viewport_width  = WIN_XSIZE;
800     viewport_height = WIN_YSIZE;
801
802     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
803   }
804   else if (part->control_info.class == get_hash_from_key("door_1"))
805   {
806     viewport_x = DX;
807     viewport_y = DY;
808     viewport_width  = DXSIZE;
809     viewport_height = DYSIZE;
810   }
811   else if (part->control_info.class == get_hash_from_key("door_2"))
812   {
813     viewport_x = VX;
814     viewport_y = VY;
815     viewport_width  = VXSIZE;
816     viewport_height = VYSIZE;
817   }
818   else          // default: "playfield"
819   {
820     viewport_x = REAL_SX;
821     viewport_y = REAL_SY;
822     viewport_width  = FULL_SXSIZE;
823     viewport_height = FULL_SYSIZE;
824   }
825
826   if (viewport_x != part->viewport_x ||
827       viewport_y != part->viewport_y ||
828       viewport_width  != part->viewport_width ||
829       viewport_height != part->viewport_height)
830   {
831     part->viewport_x = viewport_x;
832     part->viewport_y = viewport_y;
833     part->viewport_width  = viewport_width;
834     part->viewport_height = viewport_height;
835
836     changed = TRUE;
837   }
838
839   return changed;
840 }
841
842 static void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
843 {
844   int sound = part->sound;
845
846   if (sound == SND_UNDEFINED)
847     return;
848
849   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
850       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
851     return;
852
853   // !!! TODO: ADD STEREO POSITION FOR MOVING ANIMATIONS !!!
854   if (IS_LOOP_SOUND(sound))
855     PlaySoundLoop(sound);
856   else
857     PlaySound(sound);
858
859 #if 0
860   printf("::: PLAY SOUND %d.%d.%d: %d\n",
861          part->anim_nr, part->nr, part->mode_nr, sound);
862 #endif
863 }
864
865 static void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
866 {
867   int sound = part->sound;
868
869   if (sound == SND_UNDEFINED)
870     return;
871
872   StopSound(sound);
873
874 #if 0
875   printf("::: STOP SOUND %d.%d.%d: %d\n",
876          part->anim_nr, part->nr, part->mode_nr, sound);
877 #endif
878 }
879
880 static void PlayGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
881 {
882   int music = part->music;
883
884   if (music == MUS_UNDEFINED)
885     return;
886
887   if (!setup.sound_music)
888     return;
889
890   PlayMusic(music);
891
892 #if 0
893   printf("::: PLAY MUSIC %d.%d.%d: %d\n",
894          part->anim_nr, part->nr, part->mode_nr, music);
895 #endif
896 }
897
898 static void StopGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
899 {
900   int music = part->music;
901
902   if (music == MUS_UNDEFINED)
903     return;
904
905   StopMusic();
906
907 #if 0
908   printf("::: STOP MUSIC %d.%d.%d: %d\n",
909          part->anim_nr, part->nr, part->mode_nr, music);
910 #endif
911 }
912
913 static void PlayGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
914 {
915   // when drawing animations to fading buffer, do not play sounds or music
916   if (drawing_to_fading_buffer)
917     return;
918
919   PlayGlobalAnimSound(part);
920   PlayGlobalAnimMusic(part);
921 }
922
923 static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
924 {
925   StopGlobalAnimSound(part);
926   StopGlobalAnimMusic(part);
927 }
928
929 static boolean matchesAnimEventMask(int bits, int mask)
930 {
931   return (bits & (mask & ANIM_EVENT_CLICK_ANIM_ALL) &&
932           bits & (mask & ANIM_EVENT_CLICK_PART_ALL));
933 }
934
935 static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask)
936 {
937   struct GraphicInfo *c = &part->control_info;
938
939   boolean clickable_self = FALSE;
940   boolean clickable_triggered = FALSE;
941
942   if (mask & ANIM_EVENT_CLICK_SELF)
943     clickable_self = (c->init_event & ANIM_EVENT_CLICK_SELF ||
944                       c->anim_event & ANIM_EVENT_CLICK_SELF);
945
946   clickable_triggered = (matchesAnimEventMask(c->init_event, mask) ||
947                          matchesAnimEventMask(c->anim_event, mask));
948
949   return (clickable_self || clickable_triggered);
950 }
951
952 static boolean isClickedPart(struct GlobalAnimPartControlInfo *part,
953                              int mx, int my, boolean clicked)
954 {
955   struct GraphicInfo *g = &part->graphic_info;
956   int part_x = part->viewport_x + part->x;
957   int part_y = part->viewport_y + part->y;
958   int part_width  = g->width;
959   int part_height = g->height;
960
961   // check if mouse click was detected at all
962   if (!clicked)
963     return FALSE;
964
965   // check if mouse click is inside the animation part's viewport
966   if (mx <  part->viewport_x ||
967       mx >= part->viewport_x + part->viewport_width ||
968       my <  part->viewport_y ||
969       my >= part->viewport_y + part->viewport_height)
970     return FALSE;
971
972   // check if mouse click is inside the animation part's graphic
973   if (mx <  part_x ||
974       mx >= part_x + part_width ||
975       my <  part_y ||
976       my >= part_y + part_height)
977     return FALSE;
978
979   return TRUE;
980 }
981
982 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
983 {
984   struct GraphicInfo *g = &part->graphic_info;
985   struct GraphicInfo *c = &part->control_info;
986   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
987
988   if (viewport_changed)
989     state |= ANIM_STATE_RESTART;
990
991   if (state & ANIM_STATE_RESTART)
992   {
993     // when drawing animations to fading buffer, only start fixed animations
994     if (drawing_to_fading_buffer && (c->x == ARG_UNDEFINED_VALUE ||
995                                      c->y == ARG_UNDEFINED_VALUE))
996       return ANIM_STATE_INACTIVE;
997
998     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
999
1000     part->init_delay_counter =
1001       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
1002
1003     part->anim_delay_counter =
1004       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
1005
1006     part->init_event_state = c->init_event;
1007     part->anim_event_state = c->anim_event;
1008
1009     part->initial_anim_sync_frame =
1010       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
1011
1012     if (c->direction & MV_HORIZONTAL)
1013     {
1014       int pos_bottom = part->viewport_height - g->height;
1015
1016       if (c->position == POS_TOP)
1017         part->y = 0;
1018       else if (c->position == POS_UPPER)
1019         part->y = GetSimpleRandom(pos_bottom / 2);
1020       else if (c->position == POS_MIDDLE)
1021         part->y = pos_bottom / 2;
1022       else if (c->position == POS_LOWER)
1023         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
1024       else if (c->position == POS_BOTTOM)
1025         part->y = pos_bottom;
1026       else
1027         part->y = GetSimpleRandom(pos_bottom);
1028
1029       if (c->direction == MV_RIGHT)
1030       {
1031         part->step_xoffset = c->step_offset;
1032         part->x = -g->width + part->step_xoffset;
1033       }
1034       else
1035       {
1036         part->step_xoffset = -c->step_offset;
1037         part->x = part->viewport_width + part->step_xoffset;
1038       }
1039
1040       part->step_yoffset = 0;
1041     }
1042     else if (c->direction & MV_VERTICAL)
1043     {
1044       int pos_right = part->viewport_width - g->width;
1045
1046       if (c->position == POS_LEFT)
1047         part->x = 0;
1048       else if (c->position == POS_RIGHT)
1049         part->x = pos_right;
1050       else
1051         part->x = GetSimpleRandom(pos_right);
1052
1053       if (c->direction == MV_DOWN)
1054       {
1055         part->step_yoffset = c->step_offset;
1056         part->y = -g->height + part->step_yoffset;
1057       }
1058       else
1059       {
1060         part->step_yoffset = -c->step_offset;
1061         part->y = part->viewport_height + part->step_yoffset;
1062       }
1063
1064       part->step_xoffset = 0;
1065     }
1066     else
1067     {
1068       part->x = 0;
1069       part->y = 0;
1070
1071       part->step_xoffset = 0;
1072       part->step_yoffset = 0;
1073     }
1074
1075     if (c->x != ARG_UNDEFINED_VALUE)
1076       part->x = c->x;
1077     if (c->y != ARG_UNDEFINED_VALUE)
1078       part->y = c->y;
1079
1080     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
1081       part->step_xoffset = c->step_xoffset;
1082     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
1083       part->step_yoffset = c->step_yoffset;
1084
1085     if (part->init_delay_counter == 0 &&
1086         part->init_event_state == ANIM_EVENT_NONE)
1087       PlayGlobalAnimSoundAndMusic(part);
1088   }
1089
1090   if (part->clicked &&
1091       part->init_event_state != ANIM_EVENT_NONE)
1092   {
1093     if (part->initial_anim_sync_frame > 0)
1094       part->initial_anim_sync_frame -= part->init_delay_counter - 1;
1095
1096     part->init_delay_counter = 1;
1097     part->init_event_state = ANIM_EVENT_NONE;
1098
1099     part->clicked = FALSE;
1100   }
1101
1102   if (part->clicked &&
1103       part->anim_event_state != ANIM_EVENT_NONE)
1104   {
1105     part->anim_delay_counter = 1;
1106     part->anim_event_state = ANIM_EVENT_NONE;
1107
1108     part->clicked = FALSE;
1109   }
1110
1111   if (part->init_delay_counter > 0)
1112   {
1113     part->init_delay_counter--;
1114
1115     if (part->init_delay_counter == 0)
1116     {
1117       part->init_event_state = ANIM_EVENT_NONE;
1118
1119       PlayGlobalAnimSoundAndMusic(part);
1120     }
1121
1122     return ANIM_STATE_WAITING;
1123   }
1124
1125   if (part->init_event_state != ANIM_EVENT_NONE)
1126     return ANIM_STATE_WAITING;
1127
1128   // animation part is now running/visible and therefore clickable
1129   part->clickable = TRUE;
1130
1131   // check if moving animation has left the visible screen area
1132   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
1133       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
1134       (part->y <= -g->height             && part->step_yoffset <= 0) ||
1135       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
1136   {
1137     // do not wait for "anim" events for off-screen animations
1138     part->anim_event_state = ANIM_EVENT_NONE;
1139
1140     // do not stop animation before "anim" or "post" counter are finished
1141     if (part->anim_delay_counter == 0 &&
1142         part->post_delay_counter == 0)
1143     {
1144       StopGlobalAnimSoundAndMusic(part);
1145
1146       part->post_delay_counter =
1147         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1148
1149       if (part->post_delay_counter > 0)
1150         return ANIM_STATE_RUNNING;
1151
1152       // drawing last frame not needed here -- animation not visible anymore
1153       return ANIM_STATE_RESTART;
1154     }
1155   }
1156
1157   if (part->anim_delay_counter > 0)
1158   {
1159     part->anim_delay_counter--;
1160
1161     if (part->anim_delay_counter == 0)
1162     {
1163       part->anim_event_state = ANIM_EVENT_NONE;
1164
1165       StopGlobalAnimSoundAndMusic(part);
1166
1167       part->post_delay_counter =
1168         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1169
1170       if (part->post_delay_counter > 0)
1171         return ANIM_STATE_RUNNING;
1172
1173       // additional state "RUNNING" required to not skip drawing last frame
1174       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
1175     }
1176   }
1177
1178   if (part->post_delay_counter > 0)
1179   {
1180     part->post_delay_counter--;
1181
1182     if (part->post_delay_counter == 0)
1183       return ANIM_STATE_RESTART;
1184
1185     return ANIM_STATE_WAITING;
1186   }
1187
1188   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
1189                        anim_sync_frame))
1190     return ANIM_STATE_RUNNING;
1191
1192 #if 0
1193   {
1194     static unsigned int last_counter = -1;
1195     unsigned int counter = Counter();
1196
1197     printf("::: NEXT ANIM PART [%d, %d]\n",
1198            anim_sync_frame, counter - last_counter);
1199
1200     last_counter = counter;
1201   }
1202 #endif
1203
1204   part->x += part->step_xoffset;
1205   part->y += part->step_yoffset;
1206
1207   return ANIM_STATE_RUNNING;
1208 }
1209
1210 void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
1211 {
1212   struct GlobalAnimPartControlInfo *part;
1213   struct GraphicInfo *c = &anim->control_info;
1214   int state, active_part_nr;
1215
1216 #if 0
1217   printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1218          anim->mode_nr, anim->nr, anim->num_parts);
1219   printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
1220 #endif
1221
1222 #if 0
1223   printf("::: %s(%d): %d, %d, %d [%d]\n",
1224          (action == ANIM_START ? "ANIM_START" :
1225           action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
1226           action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
1227          anim->nr,
1228          anim->state & ANIM_STATE_RESTART,
1229          anim->state & ANIM_STATE_WAITING,
1230          anim->state & ANIM_STATE_RUNNING,
1231          anim->num_parts);
1232 #endif
1233
1234   switch (action)
1235   {
1236     case ANIM_START:
1237       anim->state = anim->last_state = ANIM_STATE_RESTART;
1238       anim->active_part_nr = anim->last_active_part_nr = 0;
1239       anim->part_counter = 0;
1240
1241       break;
1242
1243     case ANIM_CONTINUE:
1244       if (anim->state == ANIM_STATE_INACTIVE)
1245         return;
1246
1247       anim->state = anim->last_state;
1248       anim->active_part_nr = anim->last_active_part_nr;
1249
1250       break;
1251
1252     case ANIM_STOP:
1253       anim->state = ANIM_STATE_INACTIVE;
1254
1255       {
1256         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1257         int i;
1258
1259         for (i = 0; i < num_parts; i++)
1260           StopGlobalAnimSoundAndMusic(&anim->part[i]);
1261       }
1262
1263       return;
1264
1265     default:
1266       break;
1267   }
1268
1269   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
1270   {
1271     int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1272     int i;
1273
1274 #if 0
1275     printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1276            anim->mode_nr, anim->nr, num_parts);
1277 #endif
1278
1279     for (i = 0; i < num_parts; i++)
1280     {
1281       part = &anim->part[i];
1282
1283       switch (action)
1284       {
1285         case ANIM_START:
1286           anim->state = ANIM_STATE_RUNNING;
1287           part->state = ANIM_STATE_RESTART;
1288
1289           break;
1290
1291         case ANIM_CONTINUE:
1292           if (part->state == ANIM_STATE_INACTIVE)
1293             continue;
1294
1295           break;
1296
1297         case ANIM_STOP:
1298           part->state = ANIM_STATE_INACTIVE;
1299
1300           continue;
1301
1302         default:
1303           break;
1304       }
1305
1306       part->state = HandleGlobalAnim_Part(part, part->state);
1307
1308       // when animation mode is "once", stop after animation was played once
1309       if (c->anim_mode & ANIM_ONCE &&
1310           part->state & ANIM_STATE_RESTART)
1311         part->state = ANIM_STATE_INACTIVE;
1312     }
1313
1314     anim->last_state = anim->state;
1315     anim->last_active_part_nr = anim->active_part_nr;
1316
1317     return;
1318   }
1319
1320   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
1321     anim->active_part_nr = getGlobalAnimationPart(anim);
1322
1323   part = &anim->part[anim->active_part_nr];
1324
1325   part->state = ANIM_STATE_RUNNING;
1326
1327   anim->state = HandleGlobalAnim_Part(part, anim->state);
1328
1329   if (anim->state & ANIM_STATE_RESTART)
1330     anim->part_counter++;
1331
1332   // when animation mode is "once", stop after all animations were played once
1333   if (c->anim_mode & ANIM_ONCE &&
1334       anim->part_counter == anim->num_parts)
1335     anim->state = ANIM_STATE_INACTIVE;
1336
1337   state = anim->state;
1338   active_part_nr = anim->active_part_nr;
1339
1340   // while the animation parts are pausing (waiting or inactive), play the base
1341   // (main) animation; this corresponds to the "boring player animation" logic
1342   // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!)
1343   if (anim->has_base)
1344   {
1345     if (anim->state == ANIM_STATE_WAITING ||
1346         anim->state == ANIM_STATE_INACTIVE)
1347     {
1348       anim->active_part_nr = anim->num_parts;   // part nr of base animation
1349       part = &anim->part[anim->active_part_nr];
1350
1351       if (anim->state != anim->last_state)
1352         part->state = ANIM_STATE_RESTART;
1353
1354       anim->state = ANIM_STATE_RUNNING;
1355       part->state = HandleGlobalAnim_Part(part, part->state);
1356     }
1357   }
1358
1359   anim->last_state = state;
1360   anim->last_active_part_nr = active_part_nr;
1361 }
1362
1363 void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
1364 {
1365   int i;
1366
1367 #if 0
1368   printf("::: HandleGlobalAnim_Mode: %d => %d\n",
1369          ctrl->nr, ctrl->num_anims);
1370 #endif
1371
1372   for (i = 0; i < ctrl->num_anims; i++)
1373     HandleGlobalAnim_Main(&ctrl->anim[i], action);
1374 }
1375
1376 static void HandleGlobalAnim(int action, int game_mode)
1377 {
1378 #if 0
1379   printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
1380 #endif
1381
1382   HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
1383 }
1384
1385 static void DoAnimationExt()
1386 {
1387   int i;
1388
1389 #if 0
1390   printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
1391 #endif
1392
1393   // global animations now synchronized with frame delay of screen update
1394   anim_sync_frame++;
1395
1396   for (i = 0; i < NUM_GAME_MODES; i++)
1397     HandleGlobalAnim(ANIM_CONTINUE, i);
1398
1399 #if 0
1400   // force screen redraw in next frame to continue drawing global animations
1401   redraw_mask = REDRAW_ALL;
1402 #endif
1403 }
1404
1405 static void InitGlobalAnim_Clickable()
1406 {
1407   int mode_nr;
1408
1409   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
1410   {
1411     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
1412     int anim_nr;
1413
1414     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
1415     {
1416       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
1417       int part_nr;
1418
1419       for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++)
1420       {
1421         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
1422
1423         part->clickable = FALSE;
1424       }
1425     }
1426   }
1427 }
1428
1429 static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked)
1430 {
1431   boolean any_part_clicked = FALSE;
1432   int mode_nr;
1433
1434   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
1435   {
1436     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
1437     int anim_nr;
1438
1439     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
1440     {
1441       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
1442       int part_nr;
1443
1444       for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++)
1445       {
1446         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
1447
1448         if (!clicked)
1449         {
1450           part->clicked = FALSE;
1451
1452           continue;
1453         }
1454
1455         if (part->clickable &&
1456             isClickedPart(part, mx, my, clicked))
1457         {
1458 #if 0
1459           printf("::: %d.%d CLICKED\n", anim_nr, part_nr);
1460 #endif
1461
1462           if (isClickablePart(part, ANIM_EVENT_CLICK_SELF))
1463             any_part_clicked = part->clicked = TRUE;
1464
1465           // check if this click is defined to trigger other animations
1466           int old_anim_nr = part->old_anim_nr;
1467           int old_part_nr = part->old_nr;
1468           int mask = ANIM_EVENT_CLICK_ANIM_1 << old_anim_nr;
1469
1470           if (part->is_base)
1471             mask |= ANIM_EVENT_CLICK_PART_ALL;
1472           else
1473             mask |= ANIM_EVENT_CLICK_PART_1 << old_part_nr;
1474
1475           int anim2_nr;
1476
1477           for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++)
1478           {
1479             struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr];
1480             int part2_nr;
1481
1482             for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++)
1483             {
1484               struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr];
1485
1486               if (isClickablePart(part2, mask))
1487                 any_part_clicked = part2->clicked = TRUE;
1488
1489 #if 0
1490               struct GraphicInfo *c = &part2->control_info;
1491
1492               printf("::: - %d.%d: 0x%08x, 0x%08x [0x%08x]",
1493                      anim2_nr, part2_nr, c->init_event, c->anim_event, mask);
1494
1495               if (isClickablePart(part2, mask))
1496                 printf(" <--- TRIGGERED BY %d.%d",
1497                        anim_nr, part_nr);
1498
1499               printf("\n");
1500 #endif
1501             }
1502           }
1503         }
1504       }
1505     }
1506   }
1507
1508   return any_part_clicked;
1509 }
1510
1511 static void ResetGlobalAnim_Clickable()
1512 {
1513   InitGlobalAnim_Clickable();
1514 }
1515
1516 static void ResetGlobalAnim_Clicked()
1517 {
1518   InitGlobalAnim_Clicked(-1, -1, FALSE);
1519 }
1520
1521 boolean HandleGlobalAnimClicks(int mx, int my, int button)
1522 {
1523   static boolean click_consumed = FALSE;
1524   static int last_button = 0;
1525   boolean press_event;
1526   boolean release_event;
1527   boolean click_consumed_current = click_consumed;
1528
1529   /* check if button state has changed since last invocation */
1530   press_event   = (button != 0 && last_button == 0);
1531   release_event = (button == 0 && last_button != 0);
1532   last_button = button;
1533
1534   if (press_event)
1535   {
1536     click_consumed = InitGlobalAnim_Clicked(mx, my, TRUE);
1537     click_consumed_current = click_consumed;
1538   }
1539
1540   if (release_event)
1541     click_consumed = FALSE;
1542
1543   return click_consumed_current;
1544 }