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