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