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