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