added 'position: last' for global animations to continue from last position
[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 matchesAnimEventMask(int bits, int mask)
938 {
939   return (bits & (mask & ANIM_EVENT_CLICK_ANIM_ALL) &&
940           bits & (mask & ANIM_EVENT_CLICK_PART_ALL));
941 }
942
943 static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask)
944 {
945   struct GraphicInfo *c = &part->control_info;
946
947   boolean clickable_any = FALSE;
948   boolean clickable_self = FALSE;
949   boolean clickable_triggered = FALSE;
950
951   if (mask & ANIM_EVENT_CLICK_ANY)
952     clickable_any = (c->init_event & ANIM_EVENT_CLICK_ANY ||
953                      c->anim_event & ANIM_EVENT_CLICK_ANY);
954
955   if (mask & ANIM_EVENT_CLICK_SELF)
956     clickable_self = (c->init_event & ANIM_EVENT_CLICK_SELF ||
957                       c->anim_event & ANIM_EVENT_CLICK_SELF);
958
959   clickable_triggered = (matchesAnimEventMask(c->init_event, mask) ||
960                          matchesAnimEventMask(c->anim_event, mask));
961
962   return (clickable_any || clickable_self || clickable_triggered);
963 }
964
965 static boolean isClickedPart(struct GlobalAnimPartControlInfo *part,
966                              int mx, int my, boolean clicked)
967 {
968   struct GraphicInfo *g = &part->graphic_info;
969   int part_x = part->viewport_x + part->x;
970   int part_y = part->viewport_y + part->y;
971   int part_width  = g->width;
972   int part_height = g->height;
973
974   // check if mouse click was detected at all
975   if (!clicked)
976     return FALSE;
977
978   // check if mouse click is inside the animation part's viewport
979   if (mx <  part->viewport_x ||
980       mx >= part->viewport_x + part->viewport_width ||
981       my <  part->viewport_y ||
982       my >= part->viewport_y + part->viewport_height)
983     return FALSE;
984
985   // check if mouse click is inside the animation part's graphic
986   if (mx <  part_x ||
987       mx >= part_x + part_width ||
988       my <  part_y ||
989       my >= part_y + part_height)
990     return FALSE;
991
992   return TRUE;
993 }
994
995 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
996 {
997   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr];
998   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[part->anim_nr];
999   struct GraphicInfo *g = &part->graphic_info;
1000   struct GraphicInfo *c = &part->control_info;
1001   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
1002
1003   if (viewport_changed)
1004     state |= ANIM_STATE_RESTART;
1005
1006   if (state & ANIM_STATE_RESTART)
1007   {
1008     // when drawing animations to fading buffer, only start fixed animations
1009     if (drawing_to_fading_buffer && (c->x == ARG_UNDEFINED_VALUE ||
1010                                      c->y == ARG_UNDEFINED_VALUE))
1011       return ANIM_STATE_INACTIVE;
1012
1013     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
1014
1015     part->init_delay_counter =
1016       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
1017
1018     part->anim_delay_counter =
1019       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
1020
1021     part->init_event_state = c->init_event;
1022     part->anim_event_state = c->anim_event;
1023
1024     part->initial_anim_sync_frame =
1025       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
1026
1027     if (c->direction & MV_HORIZONTAL)
1028     {
1029       int pos_bottom = part->viewport_height - g->height;
1030
1031       if (c->position == POS_TOP)
1032         part->y = 0;
1033       else if (c->position == POS_UPPER)
1034         part->y = GetSimpleRandom(pos_bottom / 2);
1035       else if (c->position == POS_MIDDLE)
1036         part->y = pos_bottom / 2;
1037       else if (c->position == POS_LOWER)
1038         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
1039       else if (c->position == POS_BOTTOM)
1040         part->y = pos_bottom;
1041       else
1042         part->y = GetSimpleRandom(pos_bottom);
1043
1044       if (c->direction == MV_RIGHT)
1045       {
1046         part->step_xoffset = c->step_offset;
1047         part->x = -g->width + part->step_xoffset;
1048       }
1049       else
1050       {
1051         part->step_xoffset = -c->step_offset;
1052         part->x = part->viewport_width + part->step_xoffset;
1053       }
1054
1055       part->step_yoffset = 0;
1056     }
1057     else if (c->direction & MV_VERTICAL)
1058     {
1059       int pos_right = part->viewport_width - g->width;
1060
1061       if (c->position == POS_LEFT)
1062         part->x = 0;
1063       else if (c->position == POS_RIGHT)
1064         part->x = pos_right;
1065       else
1066         part->x = GetSimpleRandom(pos_right);
1067
1068       if (c->direction == MV_DOWN)
1069       {
1070         part->step_yoffset = c->step_offset;
1071         part->y = -g->height + part->step_yoffset;
1072       }
1073       else
1074       {
1075         part->step_yoffset = -c->step_offset;
1076         part->y = part->viewport_height + part->step_yoffset;
1077       }
1078
1079       part->step_xoffset = 0;
1080     }
1081     else
1082     {
1083       part->x = 0;
1084       part->y = 0;
1085
1086       part->step_xoffset = 0;
1087       part->step_yoffset = 0;
1088     }
1089
1090     if (c->x != ARG_UNDEFINED_VALUE)
1091       part->x = c->x;
1092     if (c->y != ARG_UNDEFINED_VALUE)
1093       part->y = c->y;
1094
1095     if (c->position == POS_LAST &&
1096         anim->last_x > -g->width  && anim->last_x < part->viewport_width &&
1097         anim->last_y > -g->height && anim->last_y < part->viewport_height)
1098     {
1099       part->x = anim->last_x;
1100       part->y = anim->last_y;
1101     }
1102
1103     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
1104       part->step_xoffset = c->step_xoffset;
1105     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
1106       part->step_yoffset = c->step_yoffset;
1107
1108     if (part->init_delay_counter == 0 &&
1109         part->init_event_state == ANIM_EVENT_NONE)
1110       PlayGlobalAnimSoundAndMusic(part);
1111   }
1112
1113   if (part->clicked &&
1114       part->init_event_state != ANIM_EVENT_NONE)
1115   {
1116     if (part->initial_anim_sync_frame > 0)
1117       part->initial_anim_sync_frame -= part->init_delay_counter - 1;
1118
1119     part->init_delay_counter = 1;
1120     part->init_event_state = ANIM_EVENT_NONE;
1121
1122     part->clicked = FALSE;
1123   }
1124
1125   if (part->clicked &&
1126       part->anim_event_state != ANIM_EVENT_NONE)
1127   {
1128     part->anim_delay_counter = 1;
1129     part->anim_event_state = ANIM_EVENT_NONE;
1130
1131     part->clicked = FALSE;
1132   }
1133
1134   if (part->init_delay_counter > 0)
1135   {
1136     part->init_delay_counter--;
1137
1138     if (part->init_delay_counter == 0)
1139     {
1140       part->init_event_state = ANIM_EVENT_NONE;
1141
1142       PlayGlobalAnimSoundAndMusic(part);
1143     }
1144
1145     return ANIM_STATE_WAITING;
1146   }
1147
1148   if (part->init_event_state != ANIM_EVENT_NONE)
1149     return ANIM_STATE_WAITING;
1150
1151   // animation part is now running/visible and therefore clickable
1152   part->clickable = TRUE;
1153
1154   // check if moving animation has left the visible screen area
1155   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
1156       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
1157       (part->y <= -g->height             && part->step_yoffset <= 0) ||
1158       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
1159   {
1160     // do not wait for "anim" events for off-screen animations
1161     part->anim_event_state = ANIM_EVENT_NONE;
1162
1163     // do not stop animation before "anim" or "post" counter are finished
1164     if (part->anim_delay_counter == 0 &&
1165         part->post_delay_counter == 0)
1166     {
1167       StopGlobalAnimSoundAndMusic(part);
1168
1169       part->post_delay_counter =
1170         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1171
1172       if (part->post_delay_counter > 0)
1173         return ANIM_STATE_RUNNING;
1174
1175       // drawing last frame not needed here -- animation not visible anymore
1176       return ANIM_STATE_RESTART;
1177     }
1178   }
1179
1180   if (part->anim_delay_counter > 0)
1181   {
1182     part->anim_delay_counter--;
1183
1184     if (part->anim_delay_counter == 0)
1185     {
1186       part->anim_event_state = ANIM_EVENT_NONE;
1187
1188       StopGlobalAnimSoundAndMusic(part);
1189
1190       part->post_delay_counter =
1191         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1192
1193       if (part->post_delay_counter > 0)
1194         return ANIM_STATE_RUNNING;
1195
1196       // additional state "RUNNING" required to not skip drawing last frame
1197       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
1198     }
1199   }
1200
1201   if (part->post_delay_counter > 0)
1202   {
1203     part->post_delay_counter--;
1204
1205     if (part->post_delay_counter == 0)
1206       return ANIM_STATE_RESTART;
1207
1208     return ANIM_STATE_WAITING;
1209   }
1210
1211   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
1212                        anim_sync_frame))
1213     return ANIM_STATE_RUNNING;
1214
1215 #if 0
1216   {
1217     static unsigned int last_counter = -1;
1218     unsigned int counter = Counter();
1219
1220     printf("::: NEXT ANIM PART [%d, %d]\n",
1221            anim_sync_frame, counter - last_counter);
1222
1223     last_counter = counter;
1224   }
1225 #endif
1226
1227   part->x += part->step_xoffset;
1228   part->y += part->step_yoffset;
1229
1230   anim->last_x = part->x;
1231   anim->last_y = part->y;
1232
1233   return ANIM_STATE_RUNNING;
1234 }
1235
1236 void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
1237 {
1238   struct GlobalAnimPartControlInfo *part;
1239   struct GraphicInfo *c = &anim->control_info;
1240   int state, active_part_nr;
1241
1242 #if 0
1243   printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1244          anim->mode_nr, anim->nr, anim->num_parts);
1245   printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
1246 #endif
1247
1248 #if 0
1249   printf("::: %s(%d): %d, %d, %d [%d]\n",
1250          (action == ANIM_START ? "ANIM_START" :
1251           action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
1252           action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
1253          anim->nr,
1254          anim->state & ANIM_STATE_RESTART,
1255          anim->state & ANIM_STATE_WAITING,
1256          anim->state & ANIM_STATE_RUNNING,
1257          anim->num_parts);
1258 #endif
1259
1260   switch (action)
1261   {
1262     case ANIM_START:
1263       anim->state = anim->last_state = ANIM_STATE_RESTART;
1264       anim->active_part_nr = anim->last_active_part_nr = 0;
1265       anim->part_counter = 0;
1266
1267       break;
1268
1269     case ANIM_CONTINUE:
1270       if (anim->state == ANIM_STATE_INACTIVE)
1271         return;
1272
1273       anim->state = anim->last_state;
1274       anim->active_part_nr = anim->last_active_part_nr;
1275
1276       break;
1277
1278     case ANIM_STOP:
1279       anim->state = ANIM_STATE_INACTIVE;
1280
1281       {
1282         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1283         int i;
1284
1285         for (i = 0; i < num_parts; i++)
1286           StopGlobalAnimSoundAndMusic(&anim->part[i]);
1287       }
1288
1289       return;
1290
1291     default:
1292       break;
1293   }
1294
1295   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
1296   {
1297     int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1298     int i;
1299
1300 #if 0
1301     printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1302            anim->mode_nr, anim->nr, num_parts);
1303 #endif
1304
1305     for (i = 0; i < num_parts; i++)
1306     {
1307       part = &anim->part[i];
1308
1309       switch (action)
1310       {
1311         case ANIM_START:
1312           anim->state = ANIM_STATE_RUNNING;
1313           part->state = ANIM_STATE_RESTART;
1314
1315           break;
1316
1317         case ANIM_CONTINUE:
1318           if (part->state == ANIM_STATE_INACTIVE)
1319             continue;
1320
1321           break;
1322
1323         case ANIM_STOP:
1324           part->state = ANIM_STATE_INACTIVE;
1325
1326           continue;
1327
1328         default:
1329           break;
1330       }
1331
1332       part->state = HandleGlobalAnim_Part(part, part->state);
1333
1334       // when animation mode is "once", stop after animation was played once
1335       if (c->anim_mode & ANIM_ONCE &&
1336           part->state & ANIM_STATE_RESTART)
1337         part->state = ANIM_STATE_INACTIVE;
1338     }
1339
1340     anim->last_state = anim->state;
1341     anim->last_active_part_nr = anim->active_part_nr;
1342
1343     return;
1344   }
1345
1346   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
1347     anim->active_part_nr = getGlobalAnimationPart(anim);
1348
1349   part = &anim->part[anim->active_part_nr];
1350
1351   part->state = ANIM_STATE_RUNNING;
1352
1353   anim->state = HandleGlobalAnim_Part(part, anim->state);
1354
1355   if (anim->state & ANIM_STATE_RESTART)
1356     anim->part_counter++;
1357
1358   // when animation mode is "once", stop after all animations were played once
1359   if (c->anim_mode & ANIM_ONCE &&
1360       anim->part_counter == anim->num_parts)
1361     anim->state = ANIM_STATE_INACTIVE;
1362
1363   state = anim->state;
1364   active_part_nr = anim->active_part_nr;
1365
1366   // while the animation parts are pausing (waiting or inactive), play the base
1367   // (main) animation; this corresponds to the "boring player animation" logic
1368   // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!)
1369   if (anim->has_base)
1370   {
1371     if (anim->state == ANIM_STATE_WAITING ||
1372         anim->state == ANIM_STATE_INACTIVE)
1373     {
1374       anim->active_part_nr = anim->num_parts;   // part nr of base animation
1375       part = &anim->part[anim->active_part_nr];
1376
1377       if (anim->state != anim->last_state)
1378         part->state = ANIM_STATE_RESTART;
1379
1380       anim->state = ANIM_STATE_RUNNING;
1381       part->state = HandleGlobalAnim_Part(part, part->state);
1382     }
1383   }
1384
1385   anim->last_state = state;
1386   anim->last_active_part_nr = active_part_nr;
1387 }
1388
1389 void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
1390 {
1391   int i;
1392
1393 #if 0
1394   printf("::: HandleGlobalAnim_Mode: %d => %d\n",
1395          ctrl->nr, ctrl->num_anims);
1396 #endif
1397
1398   for (i = 0; i < ctrl->num_anims; i++)
1399     HandleGlobalAnim_Main(&ctrl->anim[i], action);
1400 }
1401
1402 static void HandleGlobalAnim(int action, int game_mode)
1403 {
1404 #if 0
1405   printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
1406 #endif
1407
1408   HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
1409 }
1410
1411 static void DoAnimationExt()
1412 {
1413   int i;
1414
1415 #if 0
1416   printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
1417 #endif
1418
1419   // global animations now synchronized with frame delay of screen update
1420   anim_sync_frame++;
1421
1422   for (i = 0; i < NUM_GAME_MODES; i++)
1423     HandleGlobalAnim(ANIM_CONTINUE, i);
1424
1425 #if 0
1426   // force screen redraw in next frame to continue drawing global animations
1427   redraw_mask = REDRAW_ALL;
1428 #endif
1429 }
1430
1431 static void InitGlobalAnim_Clickable()
1432 {
1433   int mode_nr;
1434
1435   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
1436   {
1437     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
1438     int anim_nr;
1439
1440     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
1441     {
1442       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
1443       int part_nr;
1444
1445       for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++)
1446       {
1447         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
1448
1449         part->clickable = FALSE;
1450       }
1451     }
1452   }
1453 }
1454
1455 static boolean InitGlobalAnim_Clicked(int mx, int my, boolean clicked)
1456 {
1457   boolean any_part_clicked = FALSE;
1458   int mode_nr;
1459
1460   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
1461   {
1462     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
1463     int anim_nr;
1464
1465     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
1466     {
1467       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
1468       int part_nr;
1469
1470       for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++)
1471       {
1472         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
1473
1474         if (!clicked)
1475         {
1476           part->clicked = FALSE;
1477
1478           continue;
1479         }
1480
1481         if (!part->clickable)
1482           continue;
1483
1484         if (isClickablePart(part, ANIM_EVENT_CLICK_ANY))
1485           any_part_clicked = part->clicked = TRUE;
1486
1487         if (isClickedPart(part, mx, my, clicked))
1488         {
1489 #if 0
1490           printf("::: %d.%d CLICKED\n", anim_nr, part_nr);
1491 #endif
1492
1493           if (isClickablePart(part, ANIM_EVENT_CLICK_SELF))
1494             any_part_clicked = part->clicked = TRUE;
1495
1496           // check if this click is defined to trigger other animations
1497           int old_anim_nr = part->old_anim_nr;
1498           int old_part_nr = part->old_nr;
1499           int mask = ANIM_EVENT_CLICK_ANIM_1 << old_anim_nr;
1500
1501           if (part->is_base)
1502             mask |= ANIM_EVENT_CLICK_PART_ALL;
1503           else
1504             mask |= ANIM_EVENT_CLICK_PART_1 << old_part_nr;
1505
1506           int anim2_nr;
1507
1508           for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++)
1509           {
1510             struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr];
1511             int part2_nr;
1512
1513             for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++)
1514             {
1515               struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr];
1516
1517               if (isClickablePart(part2, mask))
1518                 any_part_clicked = part2->clicked = TRUE;
1519
1520 #if 0
1521               struct GraphicInfo *c = &part2->control_info;
1522
1523               printf("::: - %d.%d: 0x%08x, 0x%08x [0x%08x]",
1524                      anim2_nr, part2_nr, c->init_event, c->anim_event, mask);
1525
1526               if (isClickablePart(part2, mask))
1527                 printf(" <--- TRIGGERED BY %d.%d",
1528                        anim_nr, part_nr);
1529
1530               printf("\n");
1531 #endif
1532             }
1533           }
1534         }
1535       }
1536     }
1537   }
1538
1539   return any_part_clicked;
1540 }
1541
1542 static void ResetGlobalAnim_Clickable()
1543 {
1544   InitGlobalAnim_Clickable();
1545 }
1546
1547 static void ResetGlobalAnim_Clicked()
1548 {
1549   InitGlobalAnim_Clicked(-1, -1, FALSE);
1550 }
1551
1552 boolean HandleGlobalAnimClicks(int mx, int my, int button)
1553 {
1554   static boolean click_consumed = FALSE;
1555   static int last_button = 0;
1556   boolean press_event;
1557   boolean release_event;
1558   boolean click_consumed_current = click_consumed;
1559
1560   /* check if button state has changed since last invocation */
1561   press_event   = (button != 0 && last_button == 0);
1562   release_event = (button == 0 && last_button != 0);
1563   last_button = button;
1564
1565   if (press_event)
1566   {
1567     click_consumed = InitGlobalAnim_Clicked(mx, my, TRUE);
1568     click_consumed_current = click_consumed;
1569   }
1570
1571   if (release_event)
1572     click_consumed = FALSE;
1573
1574   return click_consumed_current;
1575 }