removed explicitly setting draw order for pointer-style 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 //                  https://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 #include "tape.h"
21
22
23 #define DEBUG_ANIM_DELAY                0
24 #define DEBUG_ANIM_EVENTS               0
25
26
27 // values for global toon animation definition
28 #define NUM_GLOBAL_TOON_ANIMS           1
29 #define NUM_GLOBAL_TOON_PARTS           MAX_NUM_TOONS
30
31 // values for global animation definition (including toons)
32 #define NUM_GLOBAL_ANIMS_AND_TOONS      (NUM_GLOBAL_ANIMS +             \
33                                          NUM_GLOBAL_TOON_ANIMS)
34 #define NUM_GLOBAL_ANIM_PARTS_AND_TOONS MAX(NUM_GLOBAL_ANIM_PARTS_ALL,  \
35                                             NUM_GLOBAL_TOON_PARTS)
36
37 #define ANIM_CLASS_BIT_TITLE_INITIAL    0
38 #define ANIM_CLASS_BIT_TITLE            1
39 #define ANIM_CLASS_BIT_MAIN             2
40 #define ANIM_CLASS_BIT_NAMES            3
41 #define ANIM_CLASS_BIT_SCORES           4
42 #define ANIM_CLASS_BIT_SCORESONLY       5
43 #define ANIM_CLASS_BIT_SUBMENU          6
44 #define ANIM_CLASS_BIT_MENU             7
45 #define ANIM_CLASS_BIT_TOONS            8
46 #define ANIM_CLASS_BIT_NO_TITLE         9
47
48 #define NUM_ANIM_CLASSES                10
49
50 #define ANIM_CLASS_NONE                 0
51 #define ANIM_CLASS_TITLE_INITIAL        (1 << ANIM_CLASS_BIT_TITLE_INITIAL)
52 #define ANIM_CLASS_TITLE                (1 << ANIM_CLASS_BIT_TITLE)
53 #define ANIM_CLASS_MAIN                 (1 << ANIM_CLASS_BIT_MAIN)
54 #define ANIM_CLASS_NAMES                (1 << ANIM_CLASS_BIT_NAMES)
55 #define ANIM_CLASS_SCORES               (1 << ANIM_CLASS_BIT_SCORES)
56 #define ANIM_CLASS_SCORESONLY           (1 << ANIM_CLASS_BIT_SCORESONLY)
57 #define ANIM_CLASS_SUBMENU              (1 << ANIM_CLASS_BIT_SUBMENU)
58 #define ANIM_CLASS_MENU                 (1 << ANIM_CLASS_BIT_MENU)
59 #define ANIM_CLASS_TOONS                (1 << ANIM_CLASS_BIT_TOONS)
60 #define ANIM_CLASS_NO_TITLE             (1 << ANIM_CLASS_BIT_NO_TITLE)
61
62 #define ANIM_CLASS_TOONS_SCORES         (ANIM_CLASS_TOONS       |       \
63                                          ANIM_CLASS_SCORES      |       \
64                                          ANIM_CLASS_NO_TITLE)
65
66 #define ANIM_CLASS_TOONS_SCORESONLY     (ANIM_CLASS_TOONS       |       \
67                                          ANIM_CLASS_SCORES      |       \
68                                          ANIM_CLASS_SCORESONLY  |       \
69                                          ANIM_CLASS_NO_TITLE)
70
71 #define ANIM_CLASS_TOONS_MENU_MAIN      (ANIM_CLASS_TOONS       |       \
72                                          ANIM_CLASS_MENU        |       \
73                                          ANIM_CLASS_MAIN        |       \
74                                          ANIM_CLASS_NO_TITLE)
75
76 #define ANIM_CLASS_TOONS_MENU_SUBMENU   (ANIM_CLASS_TOONS       |       \
77                                          ANIM_CLASS_MENU        |       \
78                                          ANIM_CLASS_SUBMENU     |       \
79                                          ANIM_CLASS_NO_TITLE)
80
81 #define ANIM_CLASS_TOONS_MENU_SUBMENU_2 (ANIM_CLASS_TOONS       |       \
82                                          ANIM_CLASS_MENU        |       \
83                                          ANIM_CLASS_SUBMENU     |       \
84                                          ANIM_CLASS_NAMES       |       \
85                                          ANIM_CLASS_NO_TITLE)
86
87 // values for global animation states
88 #define ANIM_STATE_INACTIVE             0
89 #define ANIM_STATE_RESTART              (1 << 0)
90 #define ANIM_STATE_WAITING              (1 << 1)
91 #define ANIM_STATE_RUNNING              (1 << 2)
92
93 // values for global animation control
94 #define ANIM_NO_ACTION                  0
95 #define ANIM_START                      1
96 #define ANIM_CONTINUE                   2
97 #define ANIM_STOP                       3
98
99
100 struct GlobalAnimPartControlInfo
101 {
102   int old_nr;           // position before mapping animation parts linearly
103   int old_anim_nr;      // position before mapping animations linearly
104
105   int nr;
106   int anim_nr;
107   int mode_nr;
108
109   boolean is_base;      // animation part is base/main/default animation part
110
111   int sound;
112   int music;
113   int graphic;
114
115   struct GraphicInfo graphic_info;
116   struct GraphicInfo control_info;
117
118   boolean class_playfield_or_door;
119
120   int viewport_x;
121   int viewport_y;
122   int viewport_width;
123   int viewport_height;
124
125   int x, y;
126   int step_xoffset, step_yoffset;
127
128   int tile_x, tile_y;
129   int tile_xoffset, tile_yoffset;
130
131   unsigned int initial_anim_sync_frame;
132   unsigned int anim_random_frame;
133
134   DelayCounter step_delay;
135
136   int init_delay_counter;
137   int anim_delay_counter;
138   int post_delay_counter;
139
140   int fade_delay_counter;
141   int fade_alpha;
142
143   boolean init_event_state;
144   boolean anim_event_state;
145
146   boolean triggered;
147   boolean clickable;
148   boolean clicked;
149
150   int drawing_stage;
151
152   int state;
153   int last_anim_status;
154 };
155
156 struct GlobalAnimMainControlInfo
157 {
158   struct GlobalAnimPartControlInfo base;
159   struct GlobalAnimPartControlInfo part[NUM_GLOBAL_ANIM_PARTS_AND_TOONS];
160
161   int nr;
162   int mode_nr;
163
164   struct GraphicInfo control_info;
165
166   int num_parts;        // number of animation parts, but without base part
167   int num_parts_all;    // number of animation parts, including base part
168   int part_counter;
169   int active_part_nr;
170
171   boolean has_base;     // animation has base/main/default animation part
172
173   int last_x, last_y;
174
175   int init_delay_counter;
176
177   int state;
178
179   int last_state, last_active_part_nr;
180 };
181
182 struct GlobalAnimControlInfo
183 {
184   struct GlobalAnimMainControlInfo anim[NUM_GLOBAL_ANIMS_AND_TOONS];
185
186   int nr;
187   int num_anims;
188 };
189
190 struct GameModeAnimClass
191 {
192   int game_mode;
193   int class;
194 } game_mode_anim_classes_list[] =
195 {
196   { GAME_MODE_TITLE_INITIAL_1,          ANIM_CLASS_TITLE_INITIAL        },
197   { GAME_MODE_TITLE_INITIAL_2,          ANIM_CLASS_TITLE_INITIAL        },
198   { GAME_MODE_TITLE_INITIAL_3,          ANIM_CLASS_TITLE_INITIAL        },
199   { GAME_MODE_TITLE_INITIAL_4,          ANIM_CLASS_TITLE_INITIAL        },
200   { GAME_MODE_TITLE_INITIAL_5,          ANIM_CLASS_TITLE_INITIAL        },
201   { GAME_MODE_TITLE_1,                  ANIM_CLASS_TITLE                },
202   { GAME_MODE_TITLE_2,                  ANIM_CLASS_TITLE                },
203   { GAME_MODE_TITLE_3,                  ANIM_CLASS_TITLE                },
204   { GAME_MODE_TITLE_4,                  ANIM_CLASS_TITLE                },
205   { GAME_MODE_TITLE_5,                  ANIM_CLASS_TITLE                },
206   { GAME_MODE_NAMES,                    ANIM_CLASS_TOONS_MENU_SUBMENU   },
207   { GAME_MODE_LEVELS,                   ANIM_CLASS_TOONS_MENU_SUBMENU   },
208   { GAME_MODE_LEVELNR,                  ANIM_CLASS_TOONS_MENU_SUBMENU   },
209   { GAME_MODE_INFO,                     ANIM_CLASS_TOONS_MENU_SUBMENU   },
210   { GAME_MODE_SETUP,                    ANIM_CLASS_TOONS_MENU_SUBMENU   },
211   { GAME_MODE_PSEUDO_NAMESONLY,         ANIM_CLASS_TOONS_MENU_SUBMENU_2 },
212   { GAME_MODE_PSEUDO_TYPENAMES,         ANIM_CLASS_TOONS_MENU_SUBMENU_2 },
213   { GAME_MODE_PSEUDO_MAINONLY,          ANIM_CLASS_TOONS_MENU_MAIN      },
214   { GAME_MODE_PSEUDO_TYPENAME,          ANIM_CLASS_TOONS_MENU_MAIN      },
215   { GAME_MODE_PSEUDO_SCORESOLD,         ANIM_CLASS_TOONS_SCORESONLY     },
216   { GAME_MODE_PSEUDO_SCORESNEW,         ANIM_CLASS_TOONS_SCORESONLY     },
217   { GAME_MODE_SCOREINFO,                ANIM_CLASS_TOONS_SCORES         },
218   { GAME_MODE_EDITOR,                   ANIM_CLASS_NO_TITLE             },
219   { GAME_MODE_PLAYING,                  ANIM_CLASS_NO_TITLE             },
220
221   { -1,                                 -1                              }
222 };
223
224 struct AnimClassGameMode
225 {
226   int class_bit;
227   int game_mode;
228 } anim_class_game_modes_list[] =
229 {
230   { ANIM_CLASS_BIT_TITLE_INITIAL,       GAME_MODE_TITLE_INITIAL         },
231   { ANIM_CLASS_BIT_TITLE,               GAME_MODE_TITLE                 },
232   { ANIM_CLASS_BIT_MAIN,                GAME_MODE_MAIN                  },
233   { ANIM_CLASS_BIT_NAMES,               GAME_MODE_NAMES                 },
234   { ANIM_CLASS_BIT_SCORES,              GAME_MODE_SCORES                },
235   { ANIM_CLASS_BIT_SCORESONLY,          GAME_MODE_PSEUDO_SCORESONLY     },
236   { ANIM_CLASS_BIT_SUBMENU,             GAME_MODE_PSEUDO_SUBMENU        },
237   { ANIM_CLASS_BIT_MENU,                GAME_MODE_PSEUDO_MENU           },
238   { ANIM_CLASS_BIT_TOONS,               GAME_MODE_PSEUDO_TOONS          },
239   { ANIM_CLASS_BIT_NO_TITLE,            GAME_MODE_PSEUDO_NO_TITLE       },
240
241   { -1,                                 -1                              }
242 };
243
244 // forward declaration for internal use
245 static void DoGlobalAnim_DelayAction(struct GlobalAnimPartControlInfo *, int);
246 static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *);
247 static void HandleGlobalAnim(int, int);
248 static void DoAnimationExt(void);
249 static void ResetGlobalAnim_Clickable(void);
250 static void ResetGlobalAnim_Clicked(void);
251
252 static struct GlobalAnimControlInfo global_anim_ctrl[NUM_GAME_MODES];
253
254 static unsigned int anim_sync_frame = 0;
255
256 static int game_mode_anim_classes[NUM_GAME_MODES];
257 static int anim_class_game_modes[NUM_ANIM_CLASSES];
258
259 static int anim_status_last_before_fading = GAME_MODE_DEFAULT;
260 static int anim_status_last = GAME_MODE_DEFAULT;
261 static int anim_classes_last = ANIM_CLASS_NONE;
262
263 static boolean drawing_to_fading_buffer = FALSE;
264
265 static boolean handle_click = FALSE;
266
267
268 // ============================================================================
269 // generic animation frame calculation
270 // ============================================================================
271
272 int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
273                       int sync_frame)
274 {
275   int frame = 0;
276
277   if (delay < 1)                        // delay must be at least 1
278     delay = 1;
279
280   sync_frame += start_frame * delay;
281
282   if (mode & ANIM_LOOP)                 // looping animation
283   {
284     frame = (sync_frame % (delay * num_frames)) / delay;
285   }
286   else if (mode & ANIM_LINEAR)          // linear (non-looping) animation
287   {
288     frame = sync_frame / delay;
289
290     if (frame > num_frames - 1)
291       frame = num_frames - 1;
292   }
293   else if (mode & ANIM_PINGPONG)        // oscillate (border frames once)
294   {
295     int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1);
296
297     frame = (sync_frame % (delay * max_anim_frames)) / delay;
298     frame = (frame < num_frames ? frame : max_anim_frames - frame);
299   }
300   else if (mode & ANIM_PINGPONG2)       // oscillate (border frames twice)
301   {
302     int max_anim_frames = 2 * num_frames;
303
304     frame = (sync_frame % (delay * max_anim_frames)) / delay;
305     frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
306   }
307   else if (mode & ANIM_RANDOM)          // play frames in random order
308   {
309     // note: expect different frames for the same delay cycle!
310
311     if (gfx.anim_random_frame < 0)
312       frame = GetSimpleRandom(num_frames);
313     else
314       frame = gfx.anim_random_frame % num_frames;
315   }
316   else if (mode & ANIM_LEVEL_NR)        // play frames by level number
317   {
318     int level_pos = level_nr - gfx.anim_first_level;
319
320     frame = level_pos % num_frames;
321   }
322   else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY))
323   {
324     frame = sync_frame % num_frames;
325   }
326
327   if (mode & ANIM_REVERSE)              // use reverse animation direction
328     frame = num_frames - frame - 1;
329
330   return frame;
331 }
332
333
334 // ============================================================================
335 // global animation functions
336 // ============================================================================
337
338 static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim)
339 {
340   struct GraphicInfo *c = &anim->control_info;
341   int last_anim_random_frame = gfx.anim_random_frame;
342   int part_nr;
343
344   gfx.anim_random_frame = -1;   // (use simple, ad-hoc random numbers)
345
346   part_nr = getAnimationFrame(anim->num_parts, 1,
347                               c->anim_mode, c->anim_start_frame,
348                               anim->part_counter);
349
350   gfx.anim_random_frame = last_anim_random_frame;
351
352   return part_nr;
353 }
354
355 static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2)
356 {
357   const struct GlobalAnimPartControlInfo *o1 =
358     (struct GlobalAnimPartControlInfo *)obj1;
359   const struct GlobalAnimPartControlInfo *o2 =
360     (struct GlobalAnimPartControlInfo *)obj2;
361   int compare_result;
362
363   // do not sort animations parts by draw order (as it would be confusing)
364   compare_result = o1->nr - o2->nr;
365
366   return compare_result;
367 }
368
369 static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2)
370 {
371   const struct GlobalAnimMainControlInfo *o1 =
372     (struct GlobalAnimMainControlInfo *)obj1;
373   const struct GlobalAnimMainControlInfo *o2 =
374     (struct GlobalAnimMainControlInfo *)obj2;
375   int compare_result;
376
377   if (o1->control_info.draw_order != o2->control_info.draw_order)
378     compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
379   else
380     compare_result = o1->nr - o2->nr;
381
382   return compare_result;
383 }
384
385 static boolean isPausedOnPlayfieldOrDoor(struct GlobalAnimPartControlInfo *part)
386 {
387   // only pause playfield and door animations when playing
388   if (game_status != GAME_MODE_PLAYING)
389     return FALSE;
390
391   // do not pause animations when game ended (and engine is running)
392   if (checkGameEnded())
393     return FALSE;
394
395   // only pause animations on playfield and doors
396   if (!part->class_playfield_or_door)
397     return FALSE;
398
399   // only pause animations when engine is paused or request dialog is active
400   if (!tape.pausing && !game.request_active)
401     return FALSE;
402
403   return TRUE;
404 }
405
406 static void InitToonControls(void)
407 {
408   int mode_nr_toons = GAME_MODE_PSEUDO_TOONS;
409   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr_toons];
410   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[ctrl->num_anims];
411   int mode_nr, anim_nr, part_nr;
412   int control = IMG_INTERNAL_GLOBAL_TOON_DEFAULT;
413   int num_toons = MAX_NUM_TOONS;
414   int i;
415
416   if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
417     num_toons = global.num_toons;
418
419   mode_nr = mode_nr_toons;
420   anim_nr = ctrl->num_anims;
421
422   anim->nr = anim_nr;
423   anim->mode_nr = mode_nr;
424   anim->control_info = graphic_info[control];
425
426   anim->num_parts = 0;
427   anim->num_parts_all = 0;
428   anim->part_counter = 0;
429   anim->active_part_nr = 0;
430
431   anim->has_base = FALSE;
432
433   anim->last_x = POS_OFFSCREEN;
434   anim->last_y = POS_OFFSCREEN;
435
436   anim->init_delay_counter = 0;
437
438   anim->state = ANIM_STATE_INACTIVE;
439
440   part_nr = 0;
441
442   for (i = 0; i < num_toons; i++)
443   {
444     struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
445     int sound = SND_UNDEFINED;
446     int music = MUS_UNDEFINED;
447     int graphic = IMG_TOON_1 + i;
448
449     control = graphic;
450
451     part->nr = part_nr;
452     part->anim_nr = anim_nr;
453     part->mode_nr = mode_nr;
454
455     part->is_base = FALSE;
456
457     part->sound = sound;
458     part->music = music;
459     part->graphic = graphic;
460
461     part->graphic_info = graphic_info[graphic];
462     part->control_info = graphic_info[control];
463
464     part->graphic_info.anim_delay *= part->graphic_info.step_delay;
465
466     part->control_info.init_delay_fixed = 0;
467     part->control_info.init_delay_random = 150;
468
469     part->control_info.x = ARG_UNDEFINED_VALUE;
470     part->control_info.y = ARG_UNDEFINED_VALUE;
471
472     part->initial_anim_sync_frame = 0;
473     part->anim_random_frame = -1;
474
475     part->step_delay.count = 0;
476     part->step_delay.value = graphic_info[control].step_delay;
477
478     part->state = ANIM_STATE_INACTIVE;
479     part->last_anim_status = -1;
480
481     anim->num_parts++;
482     anim->num_parts_all++;
483
484     part_nr++;
485   }
486
487   ctrl->num_anims++;
488 }
489
490 static void InitGlobalAnimControls(void)
491 {
492   int i, m, a, p;
493   int mode_nr, anim_nr, part_nr;
494   int sound, music, graphic, control;
495
496   anim_sync_frame = 0;
497
498   for (m = 0; m < NUM_GAME_MODES; m++)
499   {
500     mode_nr = m;
501
502     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
503
504     ctrl->nr = mode_nr;
505     ctrl->num_anims = 0;
506
507     anim_nr = 0;
508
509     for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
510     {
511       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
512       int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
513
514       control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
515
516       // if no base animation parameters defined, use default values
517       if (control == IMG_UNDEFINED)
518         control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
519
520       anim->nr = anim_nr;
521       anim->mode_nr = mode_nr;
522       anim->control_info = graphic_info[control];
523
524       anim->num_parts = 0;
525       anim->num_parts_all = 0;
526       anim->part_counter = 0;
527       anim->active_part_nr = 0;
528
529       anim->has_base = FALSE;
530
531       anim->last_x = POS_OFFSCREEN;
532       anim->last_y = POS_OFFSCREEN;
533
534       anim->init_delay_counter = 0;
535
536       anim->state = ANIM_STATE_INACTIVE;
537
538       part_nr = 0;
539
540       for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
541       {
542         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
543
544         sound   = global_anim_info[a].sound[p][m];
545         music   = global_anim_info[a].music[p][m];
546         graphic = global_anim_info[a].graphic[p][m];
547         control = global_anim_info[ctrl_id].graphic[p][m];
548
549         if (graphic == IMG_UNDEFINED || graphic_info[graphic].bitmap == NULL ||
550             control == IMG_UNDEFINED)
551           continue;
552
553 #if 0
554         Debug("anim:InitGlobalAnimControls",
555               "mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]",
556               m, a, p, mode_nr, anim_nr, part_nr, control);
557 #endif
558
559 #if 0
560         Debug("anim:InitGlobalAnimControls",
561               "mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]",
562               m, a, p, mode_nr, anim_nr, part_nr, sound);
563 #endif
564
565         part->old_nr = p;
566         part->old_anim_nr = a;
567
568         part->nr = part_nr;
569         part->anim_nr = anim_nr;
570         part->mode_nr = mode_nr;
571
572         part->sound = sound;
573         part->music = music;
574         part->graphic = graphic;
575
576         part->graphic_info = graphic_info[graphic];
577         part->control_info = graphic_info[control];
578
579         part->initial_anim_sync_frame = 0;
580         part->anim_random_frame = -1;
581
582         part->step_delay.count = 0;
583         part->step_delay.value = graphic_info[control].step_delay;
584
585         part->state = ANIM_STATE_INACTIVE;
586         part->last_anim_status = -1;
587
588         anim->num_parts_all++;
589
590         if (p < GLOBAL_ANIM_ID_PART_BASE)
591         {
592           part->is_base = FALSE;
593
594           anim->num_parts++;
595           part_nr++;
596         }
597         else
598         {
599           part->is_base = TRUE;
600
601           anim->base = *part;
602           anim->has_base = TRUE;
603         }
604
605         // force pointer-style animations to pass-through clicks
606         if (part->control_info.class == get_hash_from_key("pointer") &&
607             part->control_info.style == STYLE_DEFAULT)
608           part->control_info.style |= STYLE_PASSTHROUGH;
609       }
610
611       if (anim->num_parts > 0 || anim->has_base)
612       {
613         ctrl->num_anims++;
614         anim_nr++;
615       }
616     }
617   }
618
619   InitToonControls();
620
621   // sort all animations according to draw_order and animation number
622   for (m = 0; m < NUM_GAME_MODES; m++)
623   {
624     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[m];
625
626     // sort all main animations for this game mode
627     qsort(ctrl->anim, ctrl->num_anims,
628           sizeof(struct GlobalAnimMainControlInfo),
629           compareGlobalAnimMainControlInfo);
630
631     for (a = 0; a < ctrl->num_anims; a++)
632     {
633       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a];
634
635       // sort all animation parts for this main animation
636       qsort(anim->part, anim->num_parts,
637             sizeof(struct GlobalAnimPartControlInfo),
638             compareGlobalAnimPartControlInfo);
639     }
640   }
641
642   for (i = 0; i < NUM_GAME_MODES; i++)
643     game_mode_anim_classes[i] = ANIM_CLASS_NONE;
644   for (i = 0; game_mode_anim_classes_list[i].game_mode != -1; i++)
645     game_mode_anim_classes[game_mode_anim_classes_list[i].game_mode] =
646       game_mode_anim_classes_list[i].class;
647
648   for (i = 0; i < NUM_ANIM_CLASSES; i++)
649     anim_class_game_modes[i] = GAME_MODE_DEFAULT;
650   for (i = 0; anim_class_game_modes_list[i].game_mode != -1; i++)
651     anim_class_game_modes[anim_class_game_modes_list[i].class_bit] =
652       anim_class_game_modes_list[i].game_mode;
653
654   anim_status_last_before_fading = GAME_MODE_LOADING;
655   anim_status_last = GAME_MODE_LOADING;
656   anim_classes_last = ANIM_CLASS_NONE;
657 }
658
659 static void SetGlobalAnimEventsForCustomElements(int list_pos)
660 {
661   int num_events = GetGlobalAnimEventValueCount(list_pos);
662   int i;
663
664   for (i = 0; i < num_events; i++)
665   {
666     int event = GetGlobalAnimEventValue(list_pos, i);
667
668     if (event & ANIM_EVENT_CE_CHANGE)
669     {
670       int nr = (event >> ANIM_EVENT_CE_BIT) & 0xff;
671
672       if (nr >= 0 && nr < NUM_CUSTOM_ELEMENTS)
673         element_info[EL_CUSTOM_START + nr].has_anim_event = TRUE;
674     }
675   }
676 }
677
678 void InitGlobalAnimEventsForCustomElements(void)
679 {
680   int m, a, p;
681   int control;
682
683   // custom element events for global animations only relevant while playing
684   m = GAME_MODE_PLAYING;
685
686   for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
687   {
688     int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
689
690     control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
691
692     // if no base animation parameters defined, use default values
693     if (control == IMG_UNDEFINED)
694       control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
695
696     SetGlobalAnimEventsForCustomElements(graphic_info[control].init_event);
697     SetGlobalAnimEventsForCustomElements(graphic_info[control].anim_event);
698
699     for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
700     {
701       control = global_anim_info[ctrl_id].graphic[p][m];
702
703       if (control == IMG_UNDEFINED)
704         continue;
705
706       SetGlobalAnimEventsForCustomElements(graphic_info[control].init_event);
707       SetGlobalAnimEventsForCustomElements(graphic_info[control].anim_event);
708     }
709   }
710 }
711
712 void InitGlobalAnimations(void)
713 {
714   InitGlobalAnimControls();
715 }
716
717 static void BlitGlobalAnimation(struct GlobalAnimPartControlInfo *part,
718                                 Bitmap *src_bitmap, int src_x0, int src_y0,
719                                 int drawing_target)
720 {
721   struct GraphicInfo *g = &part->graphic_info;
722   struct GraphicInfo *c = &part->control_info;
723   void (*blit_bitmap)(Bitmap *, Bitmap *, int, int, int, int, int, int) =
724     (g->draw_masked ? BlitBitmapMasked : BlitBitmap);
725   void (*blit_screen)(Bitmap *, int, int, int, int, int, int) =
726     (g->draw_masked ? BlitToScreenMasked : BlitToScreen);
727   Bitmap *fade_bitmap =
728     (drawing_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
729      drawing_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
730   int alpha = (c->fade_mode & FADE_MODE_FADE ? part->fade_alpha : g->alpha);
731   int x, y;
732
733   for (y = 0; y < c->stacked_yfactor; y++)
734   {
735     for (x = 0; x < c->stacked_xfactor; x++)
736     {
737       int src_x = src_x0;
738       int src_y = src_y0;
739       int dst_x = part->x + x * (g->width  + c->stacked_xoffset);
740       int dst_y = part->y + y * (g->height + c->stacked_yoffset);
741       int cut_x = 0;
742       int cut_y = 0;
743       int width  = g->width;
744       int height = g->height;
745
746       if (dst_x < 0)
747       {
748         width += dst_x;
749         cut_x = -dst_x;
750         dst_x = 0;
751       }
752       else if (dst_x > part->viewport_width - g->width)
753       {
754         width -= (dst_x - (part->viewport_width - g->width));
755       }
756
757       if (dst_y < 0)
758       {
759         height += dst_y;
760         cut_y  = -dst_y;
761         dst_y = 0;
762       }
763       else if (dst_y > part->viewport_height - g->height)
764       {
765         height -= (dst_y - (part->viewport_height - g->height));
766       }
767
768       if (width <= 0 || height <= 0)
769         continue;
770
771       src_x += cut_x;
772       src_y += cut_y;
773
774       dst_x += part->viewport_x;
775       dst_y += part->viewport_y;
776
777       SetBitmapAlphaNextBlit(src_bitmap, alpha);
778
779       if (drawing_target == DRAW_TO_SCREEN)
780         blit_screen(src_bitmap, src_x, src_y, width, height,
781                     dst_x, dst_y);
782       else
783         blit_bitmap(src_bitmap, fade_bitmap, src_x, src_y, width, height,
784                     dst_x, dst_y);
785     }
786   }
787 }
788
789 static void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage)
790 {
791   int game_mode_anim_action[NUM_GAME_MODES];
792   int mode_nr;
793
794   if (!setup.toons)
795     return;
796
797   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1 &&
798       drawing_target == DRAW_TO_SCREEN)
799     DoAnimationExt();
800
801   // always start with reliable default values (no animation actions)
802   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
803     game_mode_anim_action[mode_nr] = ANIM_NO_ACTION;
804
805   if (global.anim_status != anim_status_last)
806   {
807     boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING);
808     boolean after_fading  = (anim_status_last   == GAME_MODE_PSEUDO_FADING);
809     int anim_classes_next = game_mode_anim_classes[global.anim_status_next];
810     int i;
811
812     if (drawing_target == DRAW_TO_FADE_TARGET)
813       after_fading = TRUE;
814
815     // special case: changing from/to these screens is done without fading
816     if (global.anim_status == GAME_MODE_PSEUDO_TYPENAME  ||
817         global.anim_status == GAME_MODE_PSEUDO_TYPENAMES ||
818         anim_status_last   == GAME_MODE_PSEUDO_TYPENAME  ||
819         anim_status_last   == GAME_MODE_PSEUDO_TYPENAMES)
820       after_fading = TRUE;
821
822     // ---------- part 1 ------------------------------------------------------
823     // start or stop global animations by change of game mode
824     // (special handling of animations for "current screen" and "all screens")
825
826     if (global.anim_status_next != anim_status_last_before_fading)
827     {
828       // stop animations for last screen before fading to new screen
829       game_mode_anim_action[anim_status_last] = ANIM_STOP;
830
831       // start animations for current screen after fading to new screen
832       game_mode_anim_action[global.anim_status] = ANIM_START;
833     }
834
835     // start animations for all screens after loading new artwork set
836     if (anim_status_last == GAME_MODE_LOADING)
837       game_mode_anim_action[GAME_MODE_DEFAULT] = ANIM_START;
838
839     // ---------- part 2 ------------------------------------------------------
840     // start or stop global animations by change of animation class
841     // (generic handling of animations for "class of screens")
842
843     for (i = 0; i < NUM_ANIM_CLASSES; i++)
844     {
845       int anim_class_check = (1 << i);
846       int anim_class_game_mode = anim_class_game_modes[i];
847       int anim_class_last = anim_classes_last & anim_class_check;
848       int anim_class_next = anim_classes_next & anim_class_check;
849
850       // stop animations for changed screen class before fading to new screen
851       if (before_fading && anim_class_last && !anim_class_next)
852         game_mode_anim_action[anim_class_game_mode] = ANIM_STOP;
853
854       // start animations for changed screen class after fading to new screen
855       if (after_fading && !anim_class_last && anim_class_next)
856         game_mode_anim_action[anim_class_game_mode] = ANIM_START;
857     }
858
859     if (drawing_target == DRAW_TO_SCREEN)
860     {
861       if (after_fading)
862       {
863         anim_classes_last = anim_classes_next;
864         anim_status_last_before_fading = global.anim_status;
865       }
866
867       anim_status_last = global.anim_status;
868
869       // start or stop animations determined to be started or stopped above
870       for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
871         if (game_mode_anim_action[mode_nr] != ANIM_NO_ACTION)
872           HandleGlobalAnim(game_mode_anim_action[mode_nr], mode_nr);
873     }
874     else if (drawing_target == DRAW_TO_FADE_TARGET)
875     {
876       drawing_to_fading_buffer = TRUE;
877
878       // start animations determined to be (temporary) started above
879       for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
880         if (game_mode_anim_action[mode_nr] == ANIM_START)
881           HandleGlobalAnim(ANIM_START, mode_nr);
882     }
883   }
884
885   // when restarting global animations, do not redraw them, but stop here
886   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_RESTART)
887     return;
888
889   if (global.anim_status == GAME_MODE_LOADING)
890     return;
891
892   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
893   {
894     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
895     int anim_nr;
896
897     // when preparing source fading buffer, only draw animations to be stopped
898     if (drawing_target == DRAW_TO_FADE_SOURCE &&
899         game_mode_anim_action[mode_nr] != ANIM_STOP)
900       continue;
901
902     // when preparing target fading buffer, only draw animations to be started
903     if (drawing_target == DRAW_TO_FADE_TARGET &&
904         game_mode_anim_action[mode_nr] != ANIM_START)
905       continue;
906
907 #if 0
908     if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
909         mode_nr != game_status)
910       continue;
911 #endif
912
913     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
914     {
915       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
916       struct GraphicInfo *c = &anim->control_info;
917       int part_first, part_last;
918       int part_nr;
919
920       if (!(anim->state & ANIM_STATE_RUNNING))
921         continue;
922
923       part_first = part_last = anim->active_part_nr;
924
925       if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
926       {
927         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
928
929         part_first = 0;
930         part_last = num_parts - 1;
931       }
932
933       for (part_nr = part_first; part_nr <= part_last; part_nr++)
934       {
935         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
936         struct GraphicInfo *g = &part->graphic_info;
937         Bitmap *src_bitmap;
938         int src_x, src_y;
939         int sync_frame;
940         int frame;
941         int last_anim_random_frame = gfx.anim_random_frame;
942
943         if (!(part->state & ANIM_STATE_RUNNING))
944           continue;
945
946         if (part->drawing_stage != drawing_stage)
947           continue;
948
949         // if game is paused, also pause playfield and door animations
950         if (isPausedOnPlayfieldOrDoor(part))
951           part->initial_anim_sync_frame++;
952
953         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
954
955         // re-initialize random animation frame after animation delay
956         if (g->anim_mode == ANIM_RANDOM &&
957             sync_frame % g->anim_delay == 0 &&
958             sync_frame > 0)
959           part->anim_random_frame = GetSimpleRandom(g->anim_frames);
960
961         gfx.anim_random_frame = part->anim_random_frame;
962
963         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
964                                   g->anim_mode, g->anim_start_frame,
965                                   sync_frame);
966
967         gfx.anim_random_frame = last_anim_random_frame;
968
969         getGlobalAnimGraphicSource(part->graphic, frame, &src_bitmap,
970                                    &src_x, &src_y);
971
972         BlitGlobalAnimation(part, src_bitmap, src_x, src_y, drawing_target);
973       }
974     }
975   }
976
977   if (drawing_target == DRAW_TO_FADE_TARGET)
978   {
979     // stop animations determined to be (temporary) started above
980     for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
981       if (game_mode_anim_action[mode_nr] == ANIM_START)
982         HandleGlobalAnim(ANIM_STOP, mode_nr);
983
984     drawing_to_fading_buffer = FALSE;
985   }
986 }
987
988 void DrawGlobalAnimations(int drawing_target, int drawing_stage)
989 {
990   int last_cursor_mode_override = gfx.cursor_mode_override;
991
992   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
993   {
994     ResetGlobalAnim_Clickable();
995
996     gfx.cursor_mode_override = CURSOR_UNDEFINED;
997   }
998
999   DrawGlobalAnimationsExt(drawing_target, drawing_stage);
1000
1001   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_2)
1002   {
1003     ResetGlobalAnim_Clicked();
1004   }
1005
1006   if (gfx.cursor_mode_override != last_cursor_mode_override)
1007     SetMouseCursor(gfx.cursor_mode);
1008 }
1009
1010 static boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
1011 {
1012   int viewport_x;
1013   int viewport_y;
1014   int viewport_width;
1015   int viewport_height;
1016   boolean changed = FALSE;
1017
1018   if (part->last_anim_status == global.anim_status &&
1019       part->control_info.class != get_hash_from_key("pointer"))
1020     return FALSE;
1021
1022   part->last_anim_status = global.anim_status;
1023
1024   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
1025
1026   part->class_playfield_or_door = FALSE;
1027
1028   if (part->control_info.class == get_hash_from_key("window") ||
1029       part->control_info.class == get_hash_from_key("border"))
1030   {
1031     viewport_x = 0;
1032     viewport_y = 0;
1033     viewport_width  = WIN_XSIZE;
1034     viewport_height = WIN_YSIZE;
1035
1036     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
1037   }
1038   else if (part->control_info.class == get_hash_from_key("pointer"))
1039   {
1040     int mx = MIN(MAX(0, gfx.mouse_x), WIN_XSIZE - 1);
1041     int my = MIN(MAX(0, gfx.mouse_y), WIN_YSIZE - 1);
1042
1043     // prevent displaying off-screen custom mouse cursor in upper left corner
1044     if (gfx.mouse_x == POS_OFFSCREEN &&
1045         gfx.mouse_y == POS_OFFSCREEN)
1046       mx = my = POS_OFFSCREEN;
1047
1048     viewport_x = mx - part->control_info.x;
1049     viewport_y = my - part->control_info.y;
1050     viewport_width  = part->graphic_info.width;
1051     viewport_height = part->graphic_info.height;
1052
1053     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_3;
1054
1055     // do not use global animation mouse pointer when reloading artwork
1056     if (global.anim_status != GAME_MODE_LOADING)
1057       gfx.cursor_mode_override = CURSOR_NONE;
1058   }
1059   else if (part->control_info.class == get_hash_from_key("door_1"))
1060   {
1061     viewport_x = DX;
1062     viewport_y = DY;
1063     viewport_width  = DXSIZE;
1064     viewport_height = DYSIZE;
1065
1066     part->class_playfield_or_door = TRUE;
1067   }
1068   else if (part->control_info.class == get_hash_from_key("door_2"))
1069   {
1070     if (part->mode_nr == GAME_MODE_EDITOR)
1071     {
1072       viewport_x = EX;
1073       viewport_y = EY;
1074       viewport_width  = EXSIZE;
1075       viewport_height = EYSIZE;
1076     }
1077     else
1078     {
1079       viewport_x = VX;
1080       viewport_y = VY;
1081       viewport_width  = VXSIZE;
1082       viewport_height = VYSIZE;
1083     }
1084
1085     part->class_playfield_or_door = TRUE;
1086   }
1087   else          // default: "playfield"
1088   {
1089     viewport_x = REAL_SX;
1090     viewport_y = REAL_SY;
1091     viewport_width  = FULL_SXSIZE;
1092     viewport_height = FULL_SYSIZE;
1093
1094     part->class_playfield_or_door = TRUE;
1095   }
1096
1097   if (viewport_x != part->viewport_x ||
1098       viewport_y != part->viewport_y ||
1099       viewport_width  != part->viewport_width ||
1100       viewport_height != part->viewport_height)
1101   {
1102     part->viewport_x = viewport_x;
1103     part->viewport_y = viewport_y;
1104     part->viewport_width  = viewport_width;
1105     part->viewport_height = viewport_height;
1106
1107     if (part->control_info.class != get_hash_from_key("pointer"))
1108       changed = TRUE;
1109   }
1110
1111   return changed;
1112 }
1113
1114 static void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
1115 {
1116   int sound = part->sound;
1117
1118   if (sound == SND_UNDEFINED)
1119     return;
1120
1121   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
1122       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
1123     return;
1124
1125   // !!! TODO: ADD STEREO POSITION FOR MOVING ANIMATIONS !!!
1126   if (IS_LOOP_SOUND(sound))
1127     PlaySoundLoop(sound);
1128   else
1129     PlaySound(sound);
1130
1131 #if 0
1132   Debug("anim:PlayGlobalAnimSound", "PLAY SOUND %d.%d.%d: %d",
1133          part->anim_nr, part->nr, part->mode_nr, sound);
1134 #endif
1135 }
1136
1137 static void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
1138 {
1139   int sound = part->sound;
1140
1141   if (sound == SND_UNDEFINED)
1142     return;
1143
1144   StopSound(sound);
1145
1146 #if 0
1147   Debug("anim:StopGlobalAnimSound", "STOP SOUND %d.%d.%d: %d",
1148         part->anim_nr, part->nr, part->mode_nr, sound);
1149 #endif
1150 }
1151
1152 static void PlayGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
1153 {
1154   int music = part->music;
1155
1156   if (music == MUS_UNDEFINED)
1157     return;
1158
1159   if (!setup.sound_music)
1160     return;
1161
1162   if (IS_LOOP_MUSIC(music))
1163     PlayMusicLoop(music);
1164   else
1165     PlayMusic(music);
1166
1167 #if 0
1168   Debug("anim:PlayGlobalAnimMusic", "PLAY MUSIC %d.%d.%d: %d",
1169         part->anim_nr, part->nr, part->mode_nr, music);
1170 #endif
1171 }
1172
1173 static void StopGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
1174 {
1175   int music = part->music;
1176
1177   if (music == MUS_UNDEFINED)
1178     return;
1179
1180   char *anim_music = getMusicInfoEntryFilename(music);
1181   char *curr_music = getCurrentlyPlayingMusicFilename();
1182
1183   // do not stop music if global anim music differs from current music
1184   if (!strEqual(curr_music, anim_music))
1185     return;
1186
1187   StopMusic();
1188
1189 #if 0
1190   Debug("anim:StopGlobalAnimMusic", "STOP MUSIC %d.%d.%d: %d",
1191         part->anim_nr, part->nr, part->mode_nr, music);
1192 #endif
1193 }
1194
1195 static void PlayGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
1196 {
1197   // when drawing animations to fading buffer, do not play sounds or music
1198   if (drawing_to_fading_buffer)
1199     return;
1200
1201   PlayGlobalAnimSound(part);
1202   PlayGlobalAnimMusic(part);
1203 }
1204
1205 static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
1206 {
1207   StopGlobalAnimSound(part);
1208   StopGlobalAnimMusic(part);
1209 }
1210
1211 static void PlayGlobalAnimSoundIfLoop(struct GlobalAnimPartControlInfo *part)
1212 {
1213   // when drawing animations to fading buffer, do not play sounds
1214   if (drawing_to_fading_buffer)
1215     return;
1216
1217   // loop sounds only expire when playing
1218   if (game_status != GAME_MODE_PLAYING)
1219     return;
1220
1221   // check if any sound is defined for this animation part
1222   if (part->sound == SND_UNDEFINED)
1223     return;
1224
1225   // normal (non-loop) sounds do not expire when playing
1226   if (!IS_LOOP_SOUND(part->sound))
1227     return;
1228
1229   // prevent expiring loop sounds when playing
1230   PlayGlobalAnimSound(part);
1231 }
1232
1233 static boolean checkGlobalAnimEvent(int anim_event, int mask)
1234 {
1235   int mask_anim_only = mask & ~ANIM_EVENT_PART_MASK;
1236   int mask_ce_only   = mask & ~ANIM_EVENT_PAGE_MASK;
1237
1238   if (mask & ANIM_EVENT_ANY)
1239     return (anim_event & ANIM_EVENT_ANY);
1240   else if (mask & ANIM_EVENT_SELF)
1241     return (anim_event & ANIM_EVENT_SELF);
1242   else if (mask & ANIM_EVENT_UNCLICK_ANY)
1243     return (anim_event & ANIM_EVENT_UNCLICK_ANY);
1244   else if (mask & ANIM_EVENT_CE_CHANGE)
1245     return (anim_event == mask ||
1246             anim_event == mask_ce_only);
1247   else
1248     return (anim_event == mask ||
1249             anim_event == mask_anim_only);
1250 }
1251
1252 static boolean isClickablePart(struct GlobalAnimPartControlInfo *part, int mask)
1253 {
1254   struct GraphicInfo *c = &part->control_info;
1255   int i;
1256
1257   if (part->init_event_state)
1258   {
1259     int num_init_events = GetGlobalAnimEventValueCount(c->init_event);
1260
1261     for (i = 0; i < num_init_events; i++)
1262     {
1263       int init_event = GetGlobalAnimEventValue(c->init_event, i);
1264
1265       if (checkGlobalAnimEvent(init_event, mask))
1266         return TRUE;
1267     }
1268   }
1269   else if (part->anim_event_state)
1270   {
1271     int num_anim_events = GetGlobalAnimEventValueCount(c->anim_event);
1272
1273     for (i = 0; i < num_anim_events; i++)
1274     {
1275       int anim_event = GetGlobalAnimEventValue(c->anim_event, i);
1276
1277       if (checkGlobalAnimEvent(anim_event, mask))
1278         return TRUE;
1279     }
1280   }
1281
1282   return FALSE;
1283 }
1284
1285 static boolean isInsidePartStacked(struct GlobalAnimPartControlInfo *part,
1286                                    int mx, int my)
1287 {
1288   struct GraphicInfo *g = &part->graphic_info;
1289   struct GraphicInfo *c = &part->control_info;
1290   int part_x = part->viewport_x + part->x;
1291   int part_y = part->viewport_y + part->y;
1292   int part_width  = g->width;
1293   int part_height = g->height;
1294   int x, y;
1295
1296   for (y = 0; y < c->stacked_yfactor; y++)
1297   {
1298     for (x = 0; x < c->stacked_xfactor; x++)
1299     {
1300       int part_stacked_x = part_x + x * (part_width  + c->stacked_xoffset);
1301       int part_stacked_y = part_y + y * (part_height + c->stacked_yoffset);
1302
1303       if (mx >= part_stacked_x &&
1304           mx <  part_stacked_x + part_width &&
1305           my >= part_stacked_y &&
1306           my <  part_stacked_y + part_height)
1307         return TRUE;
1308     }
1309   }
1310
1311   return FALSE;
1312 }
1313
1314 static boolean isClickedPart(struct GlobalAnimPartControlInfo *part,
1315                              int mx, int my, boolean clicked)
1316 {
1317   // check if mouse click was detected at all
1318   if (!clicked)
1319     return FALSE;
1320
1321   // check if mouse click is outside the animation part's viewport
1322   if (mx <  part->viewport_x ||
1323       mx >= part->viewport_x + part->viewport_width ||
1324       my <  part->viewport_y ||
1325       my >= part->viewport_y + part->viewport_height)
1326     return FALSE;
1327
1328   // check if mouse click is inside the animation part's (stacked) graphic
1329   if (isInsidePartStacked(part, mx, my))
1330     return TRUE;
1331
1332   return FALSE;
1333 }
1334
1335 static boolean clickBlocked(struct GlobalAnimPartControlInfo *part)
1336 {
1337   return ((part->control_info.style & STYLE_BLOCK) ? TRUE : FALSE);
1338 }
1339
1340 static boolean clickConsumed(struct GlobalAnimPartControlInfo *part)
1341 {
1342   return ((part->control_info.style & STYLE_PASSTHROUGH) ? FALSE : TRUE);
1343 }
1344
1345 static void SetGlobalAnimPartTileXY(struct GlobalAnimPartControlInfo *part)
1346 {
1347   // calculate playfield position (with scrolling) for related CE tile
1348   // (do not use FX/FY, which are incorrect during envelope requests)
1349   int FX0 = 2 * TILEX_VAR;      // same as FX during DRAW_TO_FIELDBUFFER
1350   int FY0 = 2 * TILEY_VAR;      // same as FY during DRAW_TO_FIELDBUFFER
1351   int fx = getFieldbufferOffsetX_RND(ScreenMovDir, ScreenGfxPos);
1352   int fy = getFieldbufferOffsetY_RND(ScreenMovDir, ScreenGfxPos);
1353   int sx = FX0 + SCREENX(part->tile_x) * TILEX_VAR;
1354   int sy = FY0 + SCREENY(part->tile_y) * TILEY_VAR;
1355   int cx = SX - REAL_SX;
1356   int cy = SY - REAL_SY;
1357   int x = sx - fx + cx;
1358   int y = sy - fy + cy;
1359
1360   part->tile_xoffset += part->step_xoffset;
1361   part->tile_yoffset += part->step_yoffset;
1362
1363   part->x = x + part->tile_xoffset;
1364   part->y = y + part->tile_yoffset;
1365 }
1366
1367 static void InitGlobalAnim_Triggered(struct GlobalAnimPartControlInfo *part,
1368                                      boolean *click_consumed,
1369                                      boolean *any_event_action,
1370                                      int event_value, char *info_text)
1371 {
1372   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr];
1373
1374   int gic_anim_nr = part->old_anim_nr + 1;      // X as in "anim_X"
1375   int gic_part_nr = part->old_nr + 1;           // Y as in "part_Y"
1376   int mask = event_value | (gic_anim_nr << ANIM_EVENT_ANIM_BIT);
1377
1378   if (!part->is_base)
1379     mask |= gic_part_nr << ANIM_EVENT_PART_BIT;
1380
1381   int anim2_nr;
1382
1383   for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++)
1384   {
1385     struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr];
1386     int part2_nr;
1387
1388     for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++)
1389     {
1390       struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr];
1391
1392       if (!(part2->state & (ANIM_STATE_RUNNING | ANIM_STATE_WAITING)))
1393         continue;
1394
1395       if (isClickablePart(part2, mask))
1396       {
1397         part2->triggered = TRUE;
1398         *click_consumed |= clickConsumed(part);         // click was on "part"!
1399
1400 #if DEBUG_ANIM_EVENTS
1401         Debug("anim:InitGlobalAnim_Triggered",
1402               "%d.%d TRIGGERED BY %s OF %d.%d",
1403               part2->old_anim_nr + 1, part2->old_nr + 1, info_text,
1404               part->old_anim_nr + 1, part->old_nr + 1);
1405 #endif
1406 #if 0
1407         Debug("anim:InitGlobalAnim_Triggered",
1408               "%d.%d TRIGGER CLICKED [%d]", anim2_nr, part2_nr,
1409               part2->control_info.anim_event_action);
1410 #endif
1411
1412         // after executing event action, ignore any further actions
1413         if (!*any_event_action && DoGlobalAnim_EventAction(part2))
1414           *any_event_action = TRUE;
1415       }
1416
1417 #if 0
1418       struct GraphicInfo *c = &part2->control_info;
1419
1420       if (isClickablePart(part2, mask))
1421         Debug("anim:InitGlobalAnim_Triggered",
1422               "%d.%d: 0x%08x, 0x%08x [0x%08x] <--- TRIGGERED BY %d.%d",
1423               anim2_nr, part2_nr, c->init_event, c->anim_event, mask,
1424               anim_nr, part_nr);
1425       else
1426         Debug("anim:InitGlobalAnim_Triggered",
1427               "%d.%d: 0x%08x, 0x%08x [0x%08x]",
1428               anim2_nr, part2_nr, c->init_event, c->anim_event, mask);
1429 #endif
1430     }
1431   }
1432 }
1433
1434 static void InitGlobalAnim_Triggered_ByCustomElement(int nr, int page,
1435                                                      int x, int y,
1436                                                      int trigger_x,
1437                                                      int trigger_y)
1438 {
1439   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[GAME_MODE_PLAYING];
1440
1441   int event_value = ANIM_EVENT_CE_CHANGE;
1442   int event_bits = (nr << ANIM_EVENT_CE_BIT) | (page << ANIM_EVENT_PAGE_BIT);
1443   int mask = event_value | event_bits;
1444   int anim2_nr;
1445
1446   for (anim2_nr = 0; anim2_nr < ctrl->num_anims; anim2_nr++)
1447   {
1448     struct GlobalAnimMainControlInfo *anim2 = &ctrl->anim[anim2_nr];
1449     int part2_nr;
1450
1451     for (part2_nr = 0; part2_nr < anim2->num_parts_all; part2_nr++)
1452     {
1453       struct GlobalAnimPartControlInfo *part2 = &anim2->part[part2_nr];
1454
1455       if (!(part2->state & (ANIM_STATE_RUNNING | ANIM_STATE_WAITING)))
1456         continue;
1457
1458       if (isClickablePart(part2, mask) && !part2->triggered)
1459       {
1460         struct GraphicInfo *c = &part2->control_info;
1461
1462         if (c->position == POS_CE ||
1463             c->position == POS_CE_TRIGGER)
1464         {
1465           // store CE tile and offset position to handle scrolling
1466           part2->tile_x = (c->position == POS_CE_TRIGGER ? trigger_x : x);
1467           part2->tile_y = (c->position == POS_CE_TRIGGER ? trigger_y : y);
1468           part2->tile_xoffset = c->x;
1469           part2->tile_yoffset = c->y;
1470
1471           // set resulting animation position relative to CE tile position
1472           // (but only for ".init_event", not ".anim_event" type events)
1473           if (part2->init_event_state)
1474             SetGlobalAnimPartTileXY(part2);
1475
1476           // restart animation (by using current sync frame)
1477           part2->initial_anim_sync_frame = anim_sync_frame;
1478         }
1479
1480         part2->triggered = TRUE;
1481
1482         // do not trigger any other animation if CE change event was consumed
1483         if (c->style == STYLE_CONSUME_CE_EVENT)
1484           return;
1485
1486 #if 0
1487         Debug("anim:InitGlobalAnim_Triggered_ByCustomElement",
1488               "%d.%d TRIGGERED BY CE %d", anim2_nr, part2_nr, nr + 1);
1489 #endif
1490       }
1491     }
1492   }
1493 }
1494
1495 static void HandleGlobalAnimDelay(struct GlobalAnimPartControlInfo *part,
1496                                   int delay_type, char *info_text)
1497 {
1498 #if DEBUG_ANIM_DELAY
1499   Debug("anim:HandleGlobalAnimDelay", "%d.%d %s",
1500         part->old_anim_nr + 1, part->old_nr + 1, info_text);
1501 #endif
1502
1503   DoGlobalAnim_DelayAction(part, delay_type);
1504 }
1505
1506 static void HandleGlobalAnimEvent(struct GlobalAnimPartControlInfo *part,
1507                                   int event_value, char *info_text)
1508 {
1509 #if DEBUG_ANIM_EVENTS
1510   Debug("anim:HandleGlobalAnimEvent", "%d.%d %s",
1511         part->old_anim_nr + 1, part->old_nr + 1, info_text);
1512 #endif
1513
1514   boolean click_consumed = FALSE;
1515   boolean any_event_action = FALSE;
1516
1517   // check if this event is defined to trigger other animations
1518   InitGlobalAnim_Triggered(part, &click_consumed, &any_event_action,
1519                            event_value, info_text);
1520 }
1521
1522 static int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part,
1523                                  int state)
1524 {
1525   if (handle_click && !part->clicked)
1526     return state;
1527
1528   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[part->mode_nr];
1529   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[part->anim_nr];
1530   struct GraphicInfo *g = &part->graphic_info;
1531   struct GraphicInfo *c = &part->control_info;
1532   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
1533   int alpha = (g->alpha != -1 ? g->alpha : SDL_ALPHA_OPAQUE);
1534
1535   // if game is paused, also pause playfield and door animations
1536   if (isPausedOnPlayfieldOrDoor(part))
1537     return state;
1538
1539   if (viewport_changed)
1540     state |= ANIM_STATE_RESTART;
1541
1542   if (state & ANIM_STATE_RESTART)
1543   {
1544     // when drawing animations to fading buffer, only start fixed animations
1545     if (drawing_to_fading_buffer && (c->x == ARG_UNDEFINED_VALUE ||
1546                                      c->y == ARG_UNDEFINED_VALUE))
1547       return ANIM_STATE_INACTIVE;
1548
1549     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
1550
1551     part->init_delay_counter =
1552       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
1553
1554     part->anim_delay_counter =
1555       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
1556
1557     part->post_delay_counter = 0;
1558
1559     part->init_event_state = (c->init_event != ANIM_EVENT_UNDEFINED);
1560     part->anim_event_state = (c->anim_event != ANIM_EVENT_UNDEFINED);
1561
1562     part->initial_anim_sync_frame =
1563       (g->anim_global_sync || g->anim_global_anim_sync ? 0 :
1564        anim_sync_frame + part->init_delay_counter);
1565
1566     // do not re-initialize random animation frame after fade-in
1567     if (part->anim_random_frame == -1)
1568       part->anim_random_frame = GetSimpleRandom(g->anim_frames);
1569
1570     if (c->fade_mode & FADE_MODE_FADE)
1571     {
1572       // when fading in screen, first frame is 100 % transparent or opaque
1573       part->fade_delay_counter = c->fade_delay + 1;
1574       part->fade_alpha = (c->fade_mode == FADE_MODE_FADE_IN ? 0 : alpha);
1575     }
1576     else
1577     {
1578       part->fade_delay_counter = 0;
1579       part->fade_alpha = -1;
1580     }
1581
1582     if (c->direction & MV_HORIZONTAL)
1583     {
1584       int pos_bottom = part->viewport_height - g->height;
1585
1586       if (c->position == POS_TOP)
1587         part->y = 0;
1588       else if (c->position == POS_UPPER)
1589         part->y = GetSimpleRandom(pos_bottom / 2);
1590       else if (c->position == POS_MIDDLE)
1591         part->y = pos_bottom / 2;
1592       else if (c->position == POS_LOWER)
1593         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
1594       else if (c->position == POS_BOTTOM)
1595         part->y = pos_bottom;
1596       else
1597         part->y = GetSimpleRandom(pos_bottom);
1598
1599       if (c->direction == MV_RIGHT)
1600       {
1601         part->step_xoffset = c->step_offset;
1602         part->x = -g->width + part->step_xoffset;
1603       }
1604       else
1605       {
1606         part->step_xoffset = -c->step_offset;
1607         part->x = part->viewport_width + part->step_xoffset;
1608       }
1609
1610       part->step_yoffset = 0;
1611     }
1612     else if (c->direction & MV_VERTICAL)
1613     {
1614       int pos_right = part->viewport_width - g->width;
1615
1616       if (c->position == POS_LEFT)
1617         part->x = 0;
1618       else if (c->position == POS_RIGHT)
1619         part->x = pos_right;
1620       else
1621         part->x = GetSimpleRandom(pos_right);
1622
1623       if (c->direction == MV_DOWN)
1624       {
1625         part->step_yoffset = c->step_offset;
1626         part->y = -g->height + part->step_yoffset;
1627       }
1628       else
1629       {
1630         part->step_yoffset = -c->step_offset;
1631         part->y = part->viewport_height + part->step_yoffset;
1632       }
1633
1634       part->step_xoffset = 0;
1635     }
1636     else
1637     {
1638       part->x = 0;
1639       part->y = 0;
1640
1641       part->step_xoffset = 0;
1642       part->step_yoffset = 0;
1643     }
1644
1645     if (part->control_info.class != get_hash_from_key("pointer"))
1646     {
1647       if (c->x != ARG_UNDEFINED_VALUE)
1648         part->x = c->x;
1649       if (c->y != ARG_UNDEFINED_VALUE)
1650         part->y = c->y;
1651     }
1652
1653     if (c->position == POS_LAST &&
1654         anim->last_x > -g->width  && anim->last_x < part->viewport_width &&
1655         anim->last_y > -g->height && anim->last_y < part->viewport_height)
1656     {
1657       part->x = anim->last_x;
1658       part->y = anim->last_y;
1659     }
1660
1661     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
1662       part->step_xoffset = c->step_xoffset;
1663     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
1664       part->step_yoffset = c->step_yoffset;
1665
1666     if (part->init_delay_counter == 0 &&
1667         !part->init_event_state)
1668     {
1669       PlayGlobalAnimSoundAndMusic(part);
1670
1671       HandleGlobalAnimDelay(part, ANIM_DELAY_INIT,  "START [INIT_DELAY]");
1672       HandleGlobalAnimEvent(part, ANIM_EVENT_START, "START [ANIM]");
1673     }
1674     else
1675     {
1676       HandleGlobalAnimEvent(part, ANIM_EVENT_INIT, "START [INIT_DELAY/EVENT]");
1677     }
1678   }
1679
1680   if (part->clicked &&
1681       part->init_event_state)
1682   {
1683     if (part->initial_anim_sync_frame > 0)
1684       part->initial_anim_sync_frame = anim_sync_frame;
1685
1686     part->init_delay_counter = 1;
1687     part->init_event_state = FALSE;
1688
1689     part->clicked = FALSE;
1690   }
1691
1692   if (part->clicked &&
1693       part->anim_event_state)
1694   {
1695     part->anim_delay_counter = 1;
1696     part->anim_event_state = FALSE;
1697
1698     part->clicked = FALSE;
1699   }
1700
1701   if (part->init_delay_counter > 0)
1702   {
1703     part->init_delay_counter--;
1704
1705     if (part->init_delay_counter == 0)
1706     {
1707       part->init_event_state = FALSE;
1708
1709       PlayGlobalAnimSoundAndMusic(part);
1710
1711       HandleGlobalAnimDelay(part, ANIM_DELAY_INIT,  "START [INIT_DELAY]");
1712       HandleGlobalAnimEvent(part, ANIM_EVENT_START, "START [ANIM]");
1713
1714       // continue with state ANIM_STATE_RUNNING (set below)
1715     }
1716     else
1717     {
1718       return ANIM_STATE_WAITING;
1719     }
1720   }
1721
1722   if (part->init_event_state)
1723     return ANIM_STATE_WAITING;
1724
1725   // animation part is now running/visible and therefore clickable
1726   part->clickable = TRUE;
1727
1728   // check if moving animation has left the visible screen area
1729   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
1730       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
1731       (part->y <= -g->height             && part->step_yoffset <= 0) ||
1732       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
1733   {
1734     // do not wait for "anim" events for off-screen animations
1735     part->anim_event_state = FALSE;
1736
1737     // do not stop animation before "anim" or "post" counter are finished
1738     if (part->anim_delay_counter == 0 &&
1739         part->post_delay_counter == 0)
1740     {
1741       StopGlobalAnimSoundAndMusic(part);
1742
1743       HandleGlobalAnimEvent(part, ANIM_EVENT_END, "END [ANIM/OFF-SCREEN]");
1744
1745       part->post_delay_counter =
1746         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1747
1748       if (part->post_delay_counter > 0)
1749         return ANIM_STATE_RUNNING;
1750
1751       // drawing last frame not needed here -- animation not visible anymore
1752       return ANIM_STATE_RESTART;
1753     }
1754   }
1755
1756   if (part->anim_delay_counter > 0)
1757   {
1758     part->anim_delay_counter--;
1759
1760     if (part->anim_delay_counter == 0)
1761     {
1762       part->anim_event_state = FALSE;
1763
1764       StopGlobalAnimSoundAndMusic(part);
1765
1766       HandleGlobalAnimDelay(part, ANIM_DELAY_ANIM, "END [ANIM_DELAY]");
1767       HandleGlobalAnimEvent(part, ANIM_EVENT_END,  "END [ANIM_DELAY/EVENT]");
1768
1769       part->post_delay_counter =
1770         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1771
1772       if (part->post_delay_counter > 0)
1773         return ANIM_STATE_RUNNING;
1774
1775       // additional state "RUNNING" required to not skip drawing last frame
1776       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
1777     }
1778   }
1779
1780   if (part->post_delay_counter > 0)
1781   {
1782     part->post_delay_counter--;
1783
1784     if (part->post_delay_counter == 0)
1785     {
1786       HandleGlobalAnimDelay(part, ANIM_DELAY_POST, "END [POST_DELAY]");
1787       HandleGlobalAnimEvent(part, ANIM_EVENT_POST, "END [POST_DELAY]");
1788
1789       return ANIM_STATE_RESTART;
1790     }
1791
1792     return ANIM_STATE_WAITING;
1793   }
1794
1795   if (part->fade_delay_counter > 0)
1796   {
1797     part->fade_delay_counter--;
1798     part->fade_alpha = alpha * (c->fade_mode == FADE_MODE_FADE_IN ?
1799                                 c->fade_delay - part->fade_delay_counter :
1800                                 part->fade_delay_counter) / c->fade_delay;
1801   }
1802
1803   // special case to prevent expiring loop sounds when playing
1804   PlayGlobalAnimSoundIfLoop(part);
1805
1806   if (!DelayReachedExt(&part->step_delay, anim_sync_frame))
1807     return ANIM_STATE_RUNNING;
1808
1809 #if 0
1810   {
1811     static unsigned int last_counter = -1;
1812     unsigned int counter = Counter();
1813
1814     Debug("anim:HandleGlobalAnim_Part", "NEXT ANIM PART [%d, %d]",
1815           anim_sync_frame, counter - last_counter);
1816
1817     last_counter = counter;
1818   }
1819 #endif
1820
1821   if (c->position == POS_CE ||
1822       c->position == POS_CE_TRIGGER)
1823   {
1824     SetGlobalAnimPartTileXY(part);
1825   }
1826   else
1827   {
1828     part->x += part->step_xoffset;
1829     part->y += part->step_yoffset;
1830   }
1831
1832   anim->last_x = part->x;
1833   anim->last_y = part->y;
1834
1835   return ANIM_STATE_RUNNING;
1836 }
1837
1838 static void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim,
1839                                   int action)
1840 {
1841   struct GlobalAnimPartControlInfo *part;
1842   struct GraphicInfo *c = &anim->control_info;
1843   int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1844   int state, active_part_nr;
1845   int i;
1846
1847 #if 0
1848   Debug("anim:HandleGlobalAnim_Main", "%d, %d => %d",
1849          anim->mode_nr, anim->nr, anim->num_parts);
1850   Debug("anim:HandleGlobalAnim_Main",
1851         "%d, %d, %d", global.num_toons, setup.toons, num_toons);
1852 #endif
1853
1854 #if 0
1855   Debug("anim:HandleGlobalAnim_Main", "%s(%d): %d, %d, %d [%d]",
1856         (action == ANIM_START ? "ANIM_START" :
1857          action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
1858          action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
1859         anim->nr,
1860         anim->state & ANIM_STATE_RESTART,
1861         anim->state & ANIM_STATE_WAITING,
1862         anim->state & ANIM_STATE_RUNNING,
1863         anim->num_parts);
1864 #endif
1865
1866   switch (action)
1867   {
1868     case ANIM_START:
1869       anim->state = anim->last_state = ANIM_STATE_RESTART;
1870       anim->active_part_nr = anim->last_active_part_nr = 0;
1871       anim->part_counter = 0;
1872
1873       break;
1874
1875     case ANIM_CONTINUE:
1876       if (anim->state == ANIM_STATE_INACTIVE)
1877         return;
1878
1879       anim->state = anim->last_state;
1880       anim->active_part_nr = anim->last_active_part_nr;
1881
1882       break;
1883
1884     case ANIM_STOP:
1885       anim->state = ANIM_STATE_INACTIVE;
1886
1887       for (i = 0; i < num_parts; i++)
1888         StopGlobalAnimSoundAndMusic(&anim->part[i]);
1889
1890       return;
1891
1892     default:
1893       break;
1894   }
1895
1896   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
1897   {
1898 #if 0
1899     Debug("anim:HandleGlobalAnim_Main", "%d, %d => %d",
1900           anim->mode_nr, anim->nr, num_parts);
1901 #endif
1902
1903     for (i = 0; i < num_parts; i++)
1904     {
1905       part = &anim->part[i];
1906
1907       switch (action)
1908       {
1909         case ANIM_START:
1910           anim->state = ANIM_STATE_RUNNING;
1911           part->state = ANIM_STATE_RESTART;
1912
1913           break;
1914
1915         case ANIM_CONTINUE:
1916           if (part->state == ANIM_STATE_INACTIVE)
1917             continue;
1918
1919           break;
1920
1921         case ANIM_STOP:
1922           part->state = ANIM_STATE_INACTIVE;
1923
1924           continue;
1925
1926         default:
1927           break;
1928       }
1929
1930       part->state = HandleGlobalAnim_Part(part, part->state);
1931
1932       // when animation mode is "once", stop after animation was played once
1933       if (c->anim_mode & ANIM_ONCE &&
1934           part->state & ANIM_STATE_RESTART)
1935         part->state = ANIM_STATE_INACTIVE;
1936     }
1937
1938     anim->last_state = anim->state;
1939     anim->last_active_part_nr = anim->active_part_nr;
1940
1941     return;
1942   }
1943
1944   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
1945     anim->active_part_nr = getGlobalAnimationPart(anim);
1946
1947   part = &anim->part[anim->active_part_nr];
1948
1949   // first set all animation parts to "inactive", ...
1950   for (i = 0; i < num_parts; i++)
1951     anim->part[i].state = ANIM_STATE_INACTIVE;
1952
1953   // ... then set current animation part to "running" ...
1954   part->state = ANIM_STATE_RUNNING;
1955
1956   // ... unless it is waiting for an initial event
1957   if (part->init_event_state)
1958     part->state = ANIM_STATE_WAITING;
1959
1960   anim->state = HandleGlobalAnim_Part(part, anim->state);
1961
1962   if (anim->state & ANIM_STATE_RESTART)
1963     anim->part_counter++;
1964
1965   // when animation mode is "once", stop after all animations were played once
1966   if (c->anim_mode & ANIM_ONCE &&
1967       anim->part_counter == anim->num_parts)
1968     anim->state = ANIM_STATE_INACTIVE;
1969
1970   state = anim->state;
1971   active_part_nr = anim->active_part_nr;
1972
1973   // while the animation parts are pausing (waiting or inactive), play the base
1974   // (main) animation; this corresponds to the "boring player animation" logic
1975   // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!)
1976   if (anim->has_base)
1977   {
1978     if (anim->state == ANIM_STATE_WAITING ||
1979         anim->state == ANIM_STATE_INACTIVE)
1980     {
1981       anim->active_part_nr = anim->num_parts;   // part nr of base animation
1982       part = &anim->part[anim->active_part_nr];
1983
1984       if (anim->state != anim->last_state)
1985         part->state = ANIM_STATE_RESTART;
1986
1987       anim->state = ANIM_STATE_RUNNING;
1988       part->state = HandleGlobalAnim_Part(part, part->state);
1989     }
1990   }
1991
1992   anim->last_state = state;
1993   anim->last_active_part_nr = active_part_nr;
1994 }
1995
1996 static void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
1997 {
1998   int i;
1999
2000 #if 0
2001   Debug("anim:HandleGlobalAnim_Mode", "%d => %d", ctrl->nr, ctrl->num_anims);
2002 #endif
2003
2004   for (i = 0; i < ctrl->num_anims; i++)
2005     HandleGlobalAnim_Main(&ctrl->anim[i], action);
2006 }
2007
2008 static void HandleGlobalAnim(int action, int game_mode)
2009 {
2010 #if 0
2011   Debug("anim:HandleGlobalAnim", "mode == %d", game_status);
2012 #endif
2013
2014   HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
2015 }
2016
2017 static void DoAnimationExt(void)
2018 {
2019   int i;
2020
2021 #if 0
2022   Debug("anim:DoAnimationExt", "%d, %d", anim_sync_frame, Counter());
2023 #endif
2024
2025   // global animations now synchronized with frame delay of screen update
2026   anim_sync_frame++;
2027
2028   for (i = 0; i < NUM_GAME_MODES; i++)
2029     HandleGlobalAnim(ANIM_CONTINUE, i);
2030
2031 #if 0
2032   // force screen redraw in next frame to continue drawing global animations
2033   redraw_mask = REDRAW_ALL;
2034 #endif
2035 }
2036
2037 static void DoGlobalAnim_DelayAction(struct GlobalAnimPartControlInfo *part,
2038                                      int delay_type)
2039 {
2040   int delay_action =
2041     (delay_type == ANIM_DELAY_INIT ? part->control_info.init_delay_action :
2042      delay_type == ANIM_DELAY_ANIM ? part->control_info.anim_delay_action :
2043      delay_type == ANIM_DELAY_POST ? part->control_info.post_delay_action :
2044      ANIM_DELAY_ACTION_NONE);
2045
2046   if (delay_action == ANIM_DELAY_ACTION_NONE)
2047     return;
2048
2049   PushUserEvent(USEREVENT_ANIM_DELAY_ACTION, delay_action, 0);
2050 }
2051
2052 static boolean DoGlobalAnim_EventAction(struct GlobalAnimPartControlInfo *part)
2053 {
2054   int event_action = (part->init_event_state ?
2055                       part->control_info.init_event_action :
2056                       part->control_info.anim_event_action);
2057
2058   if (event_action == ANIM_EVENT_ACTION_NONE)
2059     return FALSE;
2060
2061   if (event_action < MAX_IMAGE_FILES)
2062     PushUserEvent(USEREVENT_ANIM_EVENT_ACTION, event_action, 0);
2063   else
2064     OpenURLFromHash(anim_url_hash, event_action);
2065
2066   // check if further actions are allowed to be executed
2067   if (part->control_info.style & STYLE_MULTIPLE_ACTIONS)
2068     return FALSE;
2069
2070   return TRUE;
2071 }
2072
2073 static void InitGlobalAnim_Clickable(void)
2074 {
2075   int mode_nr;
2076
2077   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
2078   {
2079     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
2080     int anim_nr;
2081
2082     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
2083     {
2084       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
2085       int part_nr;
2086
2087       for (part_nr = 0; part_nr < anim->num_parts_all; part_nr++)
2088       {
2089         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
2090
2091         if (part->triggered)
2092           part->clicked = TRUE;
2093
2094         part->triggered = FALSE;
2095         part->clickable = FALSE;
2096       }
2097     }
2098   }
2099 }
2100
2101 #define ANIM_CLICKED_RESET      0
2102 #define ANIM_CLICKED_PRESSED    1
2103 #define ANIM_CLICKED_RELEASED   2
2104
2105 static boolean InitGlobalAnim_Clicked(int mx, int my, int clicked_event)
2106 {
2107   boolean click_consumed = FALSE;
2108   boolean anything_clicked = FALSE;
2109   boolean any_part_clicked = FALSE;
2110   boolean any_event_action = FALSE;
2111   int mode_nr;
2112   int i;
2113
2114   // check game modes in reverse draw order (to stop when clicked)
2115   for (mode_nr = NUM_GAME_MODES - 1; mode_nr >= 0; mode_nr--)
2116   {
2117     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
2118     int anim_nr;
2119
2120     // check animations in reverse draw order (to stop when clicked)
2121     for (anim_nr = ctrl->num_anims - 1; anim_nr >= 0; anim_nr--)
2122     {
2123       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
2124       int part_nr;
2125
2126       // check animation parts in reverse draw order (to stop when clicked)
2127       for (part_nr = anim->num_parts_all - 1; part_nr >= 0; part_nr--)
2128       {
2129         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
2130
2131         // if request dialog is active, only handle pointer-style animations
2132         if (game.request_active &&
2133             part->control_info.class != get_hash_from_key("pointer"))
2134           continue;
2135
2136         if (clicked_event == ANIM_CLICKED_RESET)
2137         {
2138           part->clicked = FALSE;
2139
2140           continue;
2141         }
2142
2143         if (!part->clickable)
2144           continue;
2145
2146         if (!(part->state & ANIM_STATE_RUNNING))
2147           continue;
2148
2149         // always handle "any" click events (clicking anywhere on screen) ...
2150         if (clicked_event == ANIM_CLICKED_PRESSED &&
2151             isClickablePart(part, ANIM_EVENT_ANY))
2152         {
2153 #if DEBUG_ANIM_EVENTS
2154           Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY ANY",
2155                 part->old_anim_nr + 1, part->old_nr + 1);
2156 #endif
2157
2158           anything_clicked = part->clicked = TRUE;
2159           click_consumed |= clickConsumed(part);
2160         }
2161
2162         // always handle "unclick:any" events (releasing anywhere on screen) ...
2163         if (clicked_event == ANIM_CLICKED_RELEASED &&
2164             isClickablePart(part, ANIM_EVENT_UNCLICK_ANY))
2165         {
2166 #if DEBUG_ANIM_EVENTS
2167           Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY UNCLICK:ANY",
2168                 part->old_anim_nr + 1, part->old_nr + 1);
2169 #endif
2170
2171           anything_clicked = part->clicked = TRUE;
2172           click_consumed |= clickConsumed(part);
2173         }
2174
2175         // ... but only handle the first (topmost) clickable animation
2176         if (any_part_clicked)
2177           continue;
2178
2179         if (clicked_event == ANIM_CLICKED_PRESSED &&
2180             isClickedPart(part, mx, my, TRUE))
2181         {
2182 #if 0
2183           Debug("anim:InitGlobalAnim_Clicked", "%d.%d CLICKED [%d]",
2184                 anim_nr, part_nr, part->control_info.anim_event_action);
2185 #endif
2186
2187           // after executing event action, ignore any further actions
2188           if (!any_event_action && DoGlobalAnim_EventAction(part))
2189             any_event_action = TRUE;
2190
2191           // determine if mouse clicks should be blocked from other animations
2192           any_part_clicked |= clickConsumed(part);
2193
2194           if (isClickablePart(part, ANIM_EVENT_SELF))
2195           {
2196 #if DEBUG_ANIM_EVENTS
2197             Debug("anim:InitGlobalAnim_Clicked", "%d.%d TRIGGERED BY SELF",
2198                   part->old_anim_nr + 1, part->old_nr + 1);
2199 #endif
2200
2201             anything_clicked = part->clicked = TRUE;
2202             click_consumed |= clickConsumed(part);
2203           }
2204
2205           // determine if mouse clicks should be blocked by this animation
2206           click_consumed |= clickBlocked(part);
2207
2208           // check if this click is defined to trigger other animations
2209           InitGlobalAnim_Triggered(part, &click_consumed, &any_event_action,
2210                                    ANIM_EVENT_CLICK, "CLICK");
2211         }
2212       }
2213     }
2214   }
2215
2216   if (anything_clicked)
2217   {
2218     handle_click = TRUE;
2219
2220     for (i = 0; i < NUM_GAME_MODES; i++)
2221       HandleGlobalAnim(ANIM_CONTINUE, i);
2222
2223     handle_click = FALSE;
2224
2225     // prevent ignoring release event if processed within same game frame
2226     StopProcessingEvents();
2227   }
2228
2229   return (click_consumed || any_event_action);
2230 }
2231
2232 static void ResetGlobalAnim_Clickable(void)
2233 {
2234   InitGlobalAnim_Clickable();
2235 }
2236
2237 static void ResetGlobalAnim_Clicked(void)
2238 {
2239   InitGlobalAnim_Clicked(-1, -1, ANIM_CLICKED_RESET);
2240 }
2241
2242 void RestartGlobalAnimsByStatus(int status)
2243 {
2244   int anim_status_last = global.anim_status;
2245
2246   global.anim_status = status;
2247
2248   // force restarting global animations by changed global animation status
2249   DrawGlobalAnimationsExt(DRAW_TO_SCREEN, DRAW_GLOBAL_ANIM_STAGE_RESTART);
2250
2251   global.anim_status = anim_status_last;
2252 }
2253
2254 void SetAnimStatusBeforeFading(int status)
2255 {
2256   anim_status_last_before_fading = status;
2257 }
2258
2259 boolean HandleGlobalAnimClicks(int mx, int my, int button, boolean force_click)
2260 {
2261   static boolean click_consumed = FALSE;
2262   static int last_button = 0;
2263   boolean press_event;
2264   boolean release_event;
2265   boolean click_consumed_current = click_consumed;
2266
2267   if (button != 0 && force_click)
2268     last_button = 0;
2269
2270   // check if button state has changed since last invocation
2271   press_event   = (button != 0 && last_button == 0);
2272   release_event = (button == 0 && last_button != 0);
2273   last_button = button;
2274
2275   if (press_event)
2276   {
2277     click_consumed = InitGlobalAnim_Clicked(mx, my, ANIM_CLICKED_PRESSED);
2278     click_consumed_current = click_consumed;
2279   }
2280
2281   if (release_event)
2282   {
2283     InitGlobalAnim_Clicked(mx, my, ANIM_CLICKED_RELEASED);
2284     click_consumed = FALSE;
2285   }
2286
2287   return click_consumed_current;
2288 }
2289
2290 int getGlobalAnimSyncFrame(void)
2291 {
2292   return anim_sync_frame;
2293 }
2294
2295 void HandleGlobalAnimEventByElementChange(int element, int page, int x, int y,
2296                                           int trigger_x, int trigger_y)
2297 {
2298   if (!IS_CUSTOM_ELEMENT(element))
2299     return;
2300
2301   // custom element stored as 0 to 255, change page stored as 1 to 32
2302   InitGlobalAnim_Triggered_ByCustomElement(element - EL_CUSTOM_START, page + 1,
2303                                            x, y, trigger_x, trigger_y);
2304 }