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