b9ea8becc2a44d2b84ea4e32e8424a95e96a7e87
[rocksndiamonds.git] / src / anim.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // anim.c
10 // ============================================================================
11
12 #include "anim.h"
13 #include "main.h"
14 #include "tools.h"
15
16
17 /* values for global toon animation definition */
18 #define NUM_GLOBAL_TOON_ANIMS           1
19 #define NUM_GLOBAL_TOON_PARTS           MAX_NUM_TOONS
20
21 /* values for global animation definition (including toons) */
22 #define NUM_GLOBAL_ANIMS_AND_TOONS      (NUM_GLOBAL_ANIMS +             \
23                                          NUM_GLOBAL_TOON_ANIMS)
24 #define NUM_GLOBAL_ANIM_PARTS_AND_TOONS MAX(NUM_GLOBAL_ANIM_PARTS_ALL,  \
25                                             NUM_GLOBAL_TOON_PARTS)
26
27 #define ANIM_CLASS_BIT_TITLE_INITIAL    0
28 #define ANIM_CLASS_BIT_TITLE            1
29 #define ANIM_CLASS_BIT_MAIN             2
30 #define ANIM_CLASS_BIT_SUBMENU          3
31 #define ANIM_CLASS_BIT_MENU             4
32 #define ANIM_CLASS_BIT_TOONS            5
33
34 #define NUM_ANIM_CLASSES                6
35
36 #define ANIM_CLASS_NONE                 0
37 #define ANIM_CLASS_TITLE_INITIAL        (1 << ANIM_CLASS_BIT_TITLE_INITIAL)
38 #define ANIM_CLASS_TITLE                (1 << ANIM_CLASS_BIT_TITLE)
39 #define ANIM_CLASS_MAIN                 (1 << ANIM_CLASS_BIT_MAIN)
40 #define ANIM_CLASS_SUBMENU              (1 << ANIM_CLASS_BIT_SUBMENU)
41 #define ANIM_CLASS_MENU                 (1 << ANIM_CLASS_BIT_MENU)
42 #define ANIM_CLASS_TOONS                (1 << ANIM_CLASS_BIT_TOONS)
43
44 #define ANIM_CLASS_TOONS_MENU_MAIN      (ANIM_CLASS_TOONS |     \
45                                          ANIM_CLASS_MENU  |     \
46                                          ANIM_CLASS_MAIN)
47
48 #define ANIM_CLASS_TOONS_MENU_SUBMENU   (ANIM_CLASS_TOONS |     \
49                                          ANIM_CLASS_MENU  |     \
50                                          ANIM_CLASS_SUBMENU)
51
52 /* values for global animation states */
53 #define ANIM_STATE_INACTIVE             0
54 #define ANIM_STATE_RESTART              (1 << 0)
55 #define ANIM_STATE_WAITING              (1 << 1)
56 #define ANIM_STATE_RUNNING              (1 << 2)
57
58 /* values for global animation control */
59 #define ANIM_NO_ACTION                  0
60 #define ANIM_START                      1
61 #define ANIM_CONTINUE                   2
62 #define ANIM_STOP                       3
63
64
65 struct GlobalAnimPartControlInfo
66 {
67   int nr;
68   int anim_nr;
69   int mode_nr;
70
71   int sound;
72   int music;
73   int graphic;
74
75   struct GraphicInfo graphic_info;
76   struct GraphicInfo control_info;
77
78   int viewport_x;
79   int viewport_y;
80   int viewport_width;
81   int viewport_height;
82
83   int x, y;
84   int step_xoffset, step_yoffset;
85
86   unsigned int initial_anim_sync_frame;
87   unsigned int step_delay, step_delay_value;
88
89   int init_delay_counter;
90   int anim_delay_counter;
91   int post_delay_counter;
92
93   int drawing_stage;
94
95   int state;
96   int last_anim_status;
97 };
98
99 struct GlobalAnimMainControlInfo
100 {
101   struct GlobalAnimPartControlInfo base;
102   struct GlobalAnimPartControlInfo part[NUM_GLOBAL_ANIM_PARTS_AND_TOONS];
103
104   int nr;
105   int mode_nr;
106
107   struct GraphicInfo control_info;
108
109   int num_parts;
110   int part_counter;
111   int active_part_nr;
112
113   boolean has_base;
114
115   int init_delay_counter;
116
117   int state;
118
119   int last_state, last_active_part_nr;
120 };
121
122 struct GlobalAnimControlInfo
123 {
124   struct GlobalAnimMainControlInfo anim[NUM_GLOBAL_ANIMS_AND_TOONS];
125
126   int nr;
127   int num_anims;
128 };
129
130 struct GameModeAnimClass
131 {
132   int game_mode;
133   int class;
134 } game_mode_anim_classes_list[] =
135 {
136   { GAME_MODE_TITLE_INITIAL_1,          ANIM_CLASS_TITLE_INITIAL        },
137   { GAME_MODE_TITLE_INITIAL_2,          ANIM_CLASS_TITLE_INITIAL        },
138   { GAME_MODE_TITLE_INITIAL_3,          ANIM_CLASS_TITLE_INITIAL        },
139   { GAME_MODE_TITLE_INITIAL_4,          ANIM_CLASS_TITLE_INITIAL        },
140   { GAME_MODE_TITLE_INITIAL_5,          ANIM_CLASS_TITLE_INITIAL        },
141   { GAME_MODE_TITLE_1,                  ANIM_CLASS_TITLE                },
142   { GAME_MODE_TITLE_2,                  ANIM_CLASS_TITLE                },
143   { GAME_MODE_TITLE_3,                  ANIM_CLASS_TITLE                },
144   { GAME_MODE_TITLE_4,                  ANIM_CLASS_TITLE                },
145   { GAME_MODE_TITLE_5,                  ANIM_CLASS_TITLE                },
146   { GAME_MODE_LEVELS,                   ANIM_CLASS_TOONS_MENU_SUBMENU   },
147   { GAME_MODE_LEVELNR,                  ANIM_CLASS_TOONS_MENU_SUBMENU   },
148   { GAME_MODE_INFO,                     ANIM_CLASS_TOONS_MENU_SUBMENU   },
149   { GAME_MODE_SETUP,                    ANIM_CLASS_TOONS_MENU_SUBMENU   },
150   { GAME_MODE_PSEUDO_MAINONLY,          ANIM_CLASS_TOONS_MENU_MAIN      },
151   { GAME_MODE_PSEUDO_TYPENAME,          ANIM_CLASS_TOONS_MENU_MAIN      },
152   { GAME_MODE_SCORES,                   ANIM_CLASS_TOONS                },
153
154   { -1,                                 -1                              }
155 };
156
157 struct AnimClassGameMode
158 {
159   int class_bit;
160   int game_mode;
161 } anim_class_game_modes_list[] =
162 {
163   { ANIM_CLASS_BIT_TITLE_INITIAL,       GAME_MODE_TITLE_INITIAL         },
164   { ANIM_CLASS_BIT_TITLE,               GAME_MODE_TITLE                 },
165   { ANIM_CLASS_BIT_MAIN,                GAME_MODE_MAIN                  },
166   { ANIM_CLASS_BIT_SUBMENU,             GAME_MODE_PSEUDO_SUBMENU        },
167   { ANIM_CLASS_BIT_MENU,                GAME_MODE_PSEUDO_MENU           },
168   { ANIM_CLASS_BIT_TOONS,               GAME_MODE_PSEUDO_TOONS          },
169
170   { -1,                                 -1                              }
171 };
172
173 /* forward declaration for internal use */
174 static void HandleGlobalAnim(int, int);
175 static void DoAnimationExt(void);
176
177 static struct GlobalAnimControlInfo global_anim_ctrl[NUM_GAME_MODES];
178
179 static unsigned int anim_sync_frame = 0;
180
181 static int game_mode_anim_classes[NUM_GAME_MODES];
182 static int anim_class_game_modes[NUM_ANIM_CLASSES];
183
184 static int anim_status_last = GAME_MODE_DEFAULT;
185 static int anim_classes_last = ANIM_CLASS_NONE;
186
187 static boolean drawing_to_fading_buffer = FALSE;
188
189
190 /* ========================================================================= */
191 /* generic animation frame calculation                                       */
192 /* ========================================================================= */
193
194 int getAnimationFrame(int num_frames, int delay, int mode, int start_frame,
195                       int sync_frame)
196 {
197   int frame = 0;
198
199   sync_frame += start_frame * delay;
200
201   if (mode & ANIM_LOOP)                 /* looping animation */
202   {
203     frame = (sync_frame % (delay * num_frames)) / delay;
204   }
205   else if (mode & ANIM_LINEAR)          /* linear (non-looping) animation */
206   {
207     frame = sync_frame / delay;
208
209     if (frame > num_frames - 1)
210       frame = num_frames - 1;
211   }
212   else if (mode & ANIM_PINGPONG)        /* oscillate (border frames once) */
213   {
214     int max_anim_frames = (num_frames > 1 ? 2 * num_frames - 2 : 1);
215
216     frame = (sync_frame % (delay * max_anim_frames)) / delay;
217     frame = (frame < num_frames ? frame : max_anim_frames - frame);
218   }
219   else if (mode & ANIM_PINGPONG2)       /* oscillate (border frames twice) */
220   {
221     int max_anim_frames = 2 * num_frames;
222
223     frame = (sync_frame % (delay * max_anim_frames)) / delay;
224     frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
225   }
226   else if (mode & ANIM_RANDOM)          /* play frames in random order */
227   {
228     /* note: expect different frames for the same delay cycle! */
229
230     if (gfx.anim_random_frame < 0)
231       frame = GetSimpleRandom(num_frames);
232     else
233       frame = gfx.anim_random_frame % num_frames;
234   }
235   else if (mode & (ANIM_CE_VALUE | ANIM_CE_SCORE | ANIM_CE_DELAY))
236   {
237     frame = sync_frame % num_frames;
238   }
239
240   if (mode & ANIM_REVERSE)              /* use reverse animation direction */
241     frame = num_frames - frame - 1;
242
243   return frame;
244 }
245
246
247 /* ========================================================================= */
248 /* global animation functions                                                */
249 /* ========================================================================= */
250
251 static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim)
252 {
253   struct GraphicInfo *c = &anim->control_info;
254   int last_anim_random_frame = gfx.anim_random_frame;
255   int part_nr;
256
257   gfx.anim_random_frame = -1;   // (use simple, ad-hoc random numbers)
258
259   part_nr = getAnimationFrame(anim->num_parts, 1,
260                               c->anim_mode, c->anim_start_frame,
261                               anim->part_counter);
262
263   gfx.anim_random_frame = last_anim_random_frame;
264
265   return part_nr;
266 }
267
268 static int compareGlobalAnimPartControlInfo(const void *obj1, const void *obj2)
269 {
270   const struct GlobalAnimPartControlInfo *o1 =
271     (struct GlobalAnimPartControlInfo *)obj1;
272   const struct GlobalAnimPartControlInfo *o2 =
273     (struct GlobalAnimPartControlInfo *)obj2;
274   int compare_result;
275
276   if (o1->control_info.draw_order != o2->control_info.draw_order)
277     compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
278   else
279     compare_result = o1->nr - o2->nr;
280
281   return compare_result;
282 }
283
284 static int compareGlobalAnimMainControlInfo(const void *obj1, const void *obj2)
285 {
286   const struct GlobalAnimMainControlInfo *o1 =
287     (struct GlobalAnimMainControlInfo *)obj1;
288   const struct GlobalAnimMainControlInfo *o2 =
289     (struct GlobalAnimMainControlInfo *)obj2;
290   int compare_result;
291
292   if (o1->control_info.draw_order != o2->control_info.draw_order)
293     compare_result = o1->control_info.draw_order - o2->control_info.draw_order;
294   else
295     compare_result = o1->nr - o2->nr;
296
297   return compare_result;
298 }
299
300 static void InitToonControls()
301 {
302   int mode_nr_toons = GAME_MODE_PSEUDO_TOONS;
303   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr_toons];
304   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[ctrl->num_anims];
305   int mode_nr, anim_nr, part_nr;
306   int control = IMG_INTERNAL_GLOBAL_TOON_DEFAULT;
307   int num_toons = MAX_NUM_TOONS;
308   int i;
309
310   if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
311     num_toons = global.num_toons;
312
313   mode_nr = mode_nr_toons;
314   anim_nr = ctrl->num_anims;
315
316   anim->nr = anim_nr;
317   anim->mode_nr = mode_nr;
318   anim->control_info = graphic_info[control];
319
320   anim->num_parts = 0;
321   anim->part_counter = 0;
322   anim->active_part_nr = 0;
323
324   anim->has_base = FALSE;
325
326   anim->init_delay_counter = 0;
327
328   anim->state = ANIM_STATE_INACTIVE;
329
330   part_nr = 0;
331
332   for (i = 0; i < num_toons; i++)
333   {
334     struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
335     int sound = SND_UNDEFINED;
336     int music = MUS_UNDEFINED;
337     int graphic = IMG_TOON_1 + i;
338     int control = graphic;
339
340     part->nr = part_nr;
341     part->anim_nr = anim_nr;
342     part->mode_nr = mode_nr;
343     part->sound = sound;
344     part->music = music;
345     part->graphic = graphic;
346     part->graphic_info = graphic_info[graphic];
347     part->control_info = graphic_info[control];
348
349     part->graphic_info.anim_delay *= part->graphic_info.step_delay;
350
351     part->control_info.init_delay_fixed = 0;
352     part->control_info.init_delay_random = 150;
353
354     part->control_info.x = ARG_UNDEFINED_VALUE;
355     part->control_info.y = ARG_UNDEFINED_VALUE;
356
357     part->initial_anim_sync_frame = 0;
358
359     part->step_delay = 0;
360     part->step_delay_value = graphic_info[control].step_delay;
361
362     part->state = ANIM_STATE_INACTIVE;
363     part->last_anim_status = -1;
364
365     anim->num_parts++;
366     part_nr++;
367   }
368
369   ctrl->num_anims++;
370 }
371
372 void InitGlobalAnimControls()
373 {
374   int i, m, a, p;
375   int mode_nr, anim_nr, part_nr;
376   int sound, music, graphic, control;
377
378   anim_sync_frame = 0;
379
380   for (m = 0; m < NUM_GAME_MODES; m++)
381   {
382     mode_nr = m;
383
384     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
385
386     ctrl->nr = mode_nr;
387     ctrl->num_anims = 0;
388
389     anim_nr = 0;
390
391     for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
392     {
393       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
394       int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
395
396       control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
397
398       // if no base animation parameters defined, use default values
399       if (control == IMG_UNDEFINED)
400         control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
401
402       anim->nr = anim_nr;
403       anim->mode_nr = mode_nr;
404       anim->control_info = graphic_info[control];
405
406       anim->num_parts = 0;
407       anim->part_counter = 0;
408       anim->active_part_nr = 0;
409
410       anim->has_base = FALSE;
411
412       anim->init_delay_counter = 0;
413
414       anim->state = ANIM_STATE_INACTIVE;
415
416       part_nr = 0;
417
418       for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
419       {
420         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
421
422         sound   = global_anim_info[a].sound[p][m];
423         music   = global_anim_info[a].music[p][m];
424         graphic = global_anim_info[a].graphic[p][m];
425         control = global_anim_info[ctrl_id].graphic[p][m];
426
427         if (graphic == IMG_UNDEFINED || graphic_info[graphic].bitmap == NULL ||
428             control == IMG_UNDEFINED)
429           continue;
430
431 #if 0
432         printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n",
433                m, a, p, mode_nr, anim_nr, part_nr, control);
434 #endif
435
436 #if 0
437         printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n",
438                m, a, p, mode_nr, anim_nr, part_nr, sound);
439 #endif
440
441         part->nr = part_nr;
442         part->anim_nr = anim_nr;
443         part->mode_nr = mode_nr;
444         part->sound = sound;
445         part->music = music;
446         part->graphic = graphic;
447         part->graphic_info = graphic_info[graphic];
448         part->control_info = graphic_info[control];
449
450         part->initial_anim_sync_frame = 0;
451
452         part->step_delay = 0;
453         part->step_delay_value = graphic_info[control].step_delay;
454
455         part->state = ANIM_STATE_INACTIVE;
456         part->last_anim_status = -1;
457
458         if (p < GLOBAL_ANIM_ID_PART_BASE)
459         {
460           anim->num_parts++;
461           part_nr++;
462         }
463         else
464         {
465           anim->base = *part;
466           anim->has_base = TRUE;
467         }
468       }
469
470       if (anim->num_parts > 0 || anim->has_base)
471       {
472         ctrl->num_anims++;
473         anim_nr++;
474       }
475     }
476   }
477
478   InitToonControls();
479
480   /* sort all animations according to draw_order and animation number */
481   for (m = 0; m < NUM_GAME_MODES; m++)
482   {
483     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[m];
484
485     /* sort all main animations for this game mode */
486     qsort(ctrl->anim, ctrl->num_anims,
487           sizeof(struct GlobalAnimMainControlInfo),
488           compareGlobalAnimMainControlInfo);
489
490     for (a = 0; a < ctrl->num_anims; a++)
491     {
492       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[a];
493
494       /* sort all animation parts for this main animation */
495       qsort(anim->part, anim->num_parts,
496             sizeof(struct GlobalAnimPartControlInfo),
497             compareGlobalAnimPartControlInfo);
498     }
499   }
500
501   for (i = 0; i < NUM_GAME_MODES; i++)
502     game_mode_anim_classes[i] = ANIM_CLASS_NONE;
503   for (i = 0; game_mode_anim_classes_list[i].game_mode != -1; i++)
504     game_mode_anim_classes[game_mode_anim_classes_list[i].game_mode] =
505       game_mode_anim_classes_list[i].class;
506
507   for (i = 0; i < NUM_ANIM_CLASSES; i++)
508     anim_class_game_modes[i] = GAME_MODE_DEFAULT;
509   for (i = 0; anim_class_game_modes_list[i].game_mode != -1; i++)
510     anim_class_game_modes[anim_class_game_modes_list[i].class_bit] =
511       anim_class_game_modes_list[i].game_mode;
512
513   anim_status_last = GAME_MODE_LOADING;
514   anim_classes_last = ANIM_CLASS_NONE;
515 }
516
517 void InitGlobalAnimations()
518 {
519   InitGlobalAnimControls();
520 }
521
522 void DrawGlobalAnimationsExt(int drawing_target, int drawing_stage)
523 {
524   Bitmap *fade_bitmap =
525     (drawing_target == DRAW_TO_FADE_SOURCE ? gfx.fade_bitmap_source :
526      drawing_target == DRAW_TO_FADE_TARGET ? gfx.fade_bitmap_target : NULL);
527   int game_mode_anim_action[NUM_GAME_MODES];
528   int mode_nr;
529
530   if (!setup.toons)
531     return;
532
533   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1 &&
534       drawing_target == DRAW_TO_SCREEN)
535     DoAnimationExt();
536
537   // always start with reliable default values (no animation actions)
538   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
539     game_mode_anim_action[mode_nr] = ANIM_NO_ACTION;
540
541   if (global.anim_status != anim_status_last)
542   {
543     boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING);
544     boolean after_fading  = (anim_status_last   == GAME_MODE_PSEUDO_FADING);
545     int anim_classes_next = game_mode_anim_classes[global.anim_status_next];
546     int i;
547
548     if (drawing_target == DRAW_TO_FADE_TARGET)
549       after_fading = TRUE;
550
551     // ---------- part 1 ------------------------------------------------------
552     // start or stop global animations by change of game mode
553     // (special handling of animations for "current screen" and "all screens")
554
555     // stop animations for last screen
556     game_mode_anim_action[anim_status_last] = ANIM_STOP;
557
558     // start animations for current screen
559     game_mode_anim_action[global.anim_status] = ANIM_START;
560
561     // start animations for all screens after loading new artwork set
562     if (anim_status_last == GAME_MODE_LOADING)
563       game_mode_anim_action[GAME_MODE_DEFAULT] = ANIM_START;
564
565     // ---------- part 2 ------------------------------------------------------
566     // start or stop global animations by change of animation class
567     // (generic handling of animations for "class of screens")
568
569     for (i = 0; i < NUM_ANIM_CLASSES; i++)
570     {
571       int anim_class_check = (1 << i);
572       int anim_class_game_mode = anim_class_game_modes[i];
573       int anim_class_last = anim_classes_last & anim_class_check;
574       int anim_class_next = anim_classes_next & anim_class_check;
575
576       // stop animations for changed screen class before fading to new screen
577       if (before_fading && anim_class_last && !anim_class_next)
578         game_mode_anim_action[anim_class_game_mode] = ANIM_STOP;
579
580       // start animations for changed screen class after fading to new screen
581       if (after_fading && !anim_class_last && anim_class_next)
582         game_mode_anim_action[anim_class_game_mode] = ANIM_START;
583     }
584
585     if (drawing_target == DRAW_TO_SCREEN)
586     {
587       if (after_fading)
588         anim_classes_last = anim_classes_next;
589
590       anim_status_last = global.anim_status;
591
592       // start or stop animations determined to be started or stopped above
593       for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
594         if (game_mode_anim_action[mode_nr] != ANIM_NO_ACTION)
595           HandleGlobalAnim(game_mode_anim_action[mode_nr], mode_nr);
596     }
597     else if (drawing_target == DRAW_TO_FADE_TARGET)
598     {
599       drawing_to_fading_buffer = TRUE;
600
601       // start animations determined to be (temporary) started above
602       for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
603         if (game_mode_anim_action[mode_nr] == ANIM_START)
604           HandleGlobalAnim(ANIM_START, mode_nr);
605     }
606   }
607
608   if (global.anim_status == GAME_MODE_LOADING)
609     return;
610
611   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
612   {
613     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
614     int anim_nr;
615
616     // when preparing source fading buffer, only draw animations to be stopped
617     if (drawing_target == DRAW_TO_FADE_SOURCE &&
618         game_mode_anim_action[mode_nr] != ANIM_STOP)
619       continue;
620
621     // when preparing target fading buffer, only draw animations to be started
622     if (drawing_target == DRAW_TO_FADE_TARGET &&
623         game_mode_anim_action[mode_nr] != ANIM_START)
624       continue;
625
626 #if 0
627     if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
628         mode_nr != game_status)
629       continue;
630 #endif
631
632     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
633     {
634       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
635       struct GraphicInfo *c = &anim->control_info;
636       int part_first, part_last;
637       int part_nr;
638
639       if (!(anim->state & ANIM_STATE_RUNNING))
640         continue;
641
642       part_first = part_last = anim->active_part_nr;
643
644       if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
645       {
646         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
647
648         part_first = 0;
649         part_last = num_parts - 1;
650       }
651
652       for (part_nr = part_first; part_nr <= part_last; part_nr++)
653       {
654         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
655         struct GraphicInfo *g = &part->graphic_info;
656         Bitmap *src_bitmap;
657         int src_x, src_y;
658         int width  = g->width;
659         int height = g->height;
660         int dst_x = part->x;
661         int dst_y = part->y;
662         int cut_x = 0;
663         int cut_y = 0;
664         int sync_frame;
665         int frame;
666
667         if (!(part->state & ANIM_STATE_RUNNING))
668           continue;
669
670         if (part->drawing_stage != drawing_stage)
671           continue;
672
673         if (part->x < 0)
674         {
675           dst_x = 0;
676           width += part->x;
677           cut_x = -part->x;
678         }
679         else if (part->x > part->viewport_width - g->width)
680           width -= (part->x - (part->viewport_width - g->width));
681
682         if (part->y < 0)
683         {
684           dst_y = 0;
685           height += part->y;
686           cut_y = -part->y;
687         }
688         else if (part->y > part->viewport_height - g->height)
689           height -= (part->y - (part->viewport_height - g->height));
690
691         if (width <= 0 || height <= 0)
692           continue;
693
694         dst_x += part->viewport_x;
695         dst_y += part->viewport_y;
696
697         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
698         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
699                                   g->anim_mode, g->anim_start_frame,
700                                   sync_frame);
701
702         getFixedGraphicSource(part->graphic, frame, &src_bitmap,
703                               &src_x, &src_y);
704
705         src_x += cut_x;
706         src_y += cut_y;
707
708         if (drawing_target == DRAW_TO_SCREEN)
709           BlitToScreenMasked(src_bitmap, src_x, src_y, width, height,
710                              dst_x, dst_y);
711         else
712           BlitBitmapMasked(src_bitmap, fade_bitmap, src_x, src_y, width, height,
713                            dst_x, dst_y);
714       }
715     }
716   }
717
718   if (drawing_target == DRAW_TO_FADE_TARGET)
719   {
720     // stop animations determined to be (temporary) started above
721     for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
722       if (game_mode_anim_action[mode_nr] == ANIM_START)
723         HandleGlobalAnim(ANIM_STOP, mode_nr);
724
725     drawing_to_fading_buffer = FALSE;
726   }
727 }
728
729 void DrawGlobalAnimations(int drawing_target, int drawing_stage)
730 {
731   DrawGlobalAnimationsExt(drawing_target, drawing_stage);
732 }
733
734 boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
735 {
736   int viewport_x;
737   int viewport_y;
738   int viewport_width;
739   int viewport_height;
740   boolean changed = FALSE;
741
742   if (part->last_anim_status == global.anim_status)
743     return FALSE;
744
745   part->last_anim_status = global.anim_status;
746
747   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
748
749   if (part->control_info.class == get_hash_from_key("window") ||
750       part->control_info.class == get_hash_from_key("border"))
751   {
752     viewport_x = 0;
753     viewport_y = 0;
754     viewport_width  = WIN_XSIZE;
755     viewport_height = WIN_YSIZE;
756
757     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
758   }
759   else if (part->control_info.class == get_hash_from_key("door_1"))
760   {
761     viewport_x = DX;
762     viewport_y = DY;
763     viewport_width  = DXSIZE;
764     viewport_height = DYSIZE;
765   }
766   else if (part->control_info.class == get_hash_from_key("door_2"))
767   {
768     viewport_x = VX;
769     viewport_y = VY;
770     viewport_width  = VXSIZE;
771     viewport_height = VYSIZE;
772   }
773   else          // default: "playfield"
774   {
775     viewport_x = REAL_SX;
776     viewport_y = REAL_SY;
777     viewport_width  = FULL_SXSIZE;
778     viewport_height = FULL_SYSIZE;
779   }
780
781   if (viewport_x != part->viewport_x ||
782       viewport_y != part->viewport_y ||
783       viewport_width  != part->viewport_width ||
784       viewport_height != part->viewport_height)
785   {
786     part->viewport_x = viewport_x;
787     part->viewport_y = viewport_y;
788     part->viewport_width  = viewport_width;
789     part->viewport_height = viewport_height;
790
791     changed = TRUE;
792   }
793
794   return changed;
795 }
796
797 static void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
798 {
799   int sound = part->sound;
800
801   if (sound == SND_UNDEFINED)
802     return;
803
804   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
805       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
806     return;
807
808   // !!! TODO: ADD STEREO POSITION FOR MOVING ANIMATIONS !!!
809   if (IS_LOOP_SOUND(sound))
810     PlaySoundLoop(sound);
811   else
812     PlaySound(sound);
813
814 #if 0
815   printf("::: PLAY SOUND %d.%d.%d: %d\n",
816          part->anim_nr, part->nr, part->mode_nr, sound);
817 #endif
818 }
819
820 static void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
821 {
822   int sound = part->sound;
823
824   if (sound == SND_UNDEFINED)
825     return;
826
827   StopSound(sound);
828
829 #if 0
830   printf("::: STOP SOUND %d.%d.%d: %d\n",
831          part->anim_nr, part->nr, part->mode_nr, sound);
832 #endif
833 }
834
835 static void PlayGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
836 {
837   int music = part->music;
838
839   if (music == MUS_UNDEFINED)
840     return;
841
842   if (!setup.sound_music)
843     return;
844
845   PlayMusic(music);
846
847 #if 0
848   printf("::: PLAY MUSIC %d.%d.%d: %d\n",
849          part->anim_nr, part->nr, part->mode_nr, music);
850 #endif
851 }
852
853 static void StopGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
854 {
855   int music = part->music;
856
857   if (music == MUS_UNDEFINED)
858     return;
859
860   StopMusic();
861
862 #if 0
863   printf("::: STOP MUSIC %d.%d.%d: %d\n",
864          part->anim_nr, part->nr, part->mode_nr, music);
865 #endif
866 }
867
868 static void PlayGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
869 {
870   // when drawing animations to fading buffer, do not play sounds or music
871   if (drawing_to_fading_buffer)
872     return;
873
874   PlayGlobalAnimSound(part);
875   PlayGlobalAnimMusic(part);
876 }
877
878 static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
879 {
880   StopGlobalAnimSound(part);
881   StopGlobalAnimMusic(part);
882 }
883
884 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
885 {
886   struct GraphicInfo *g = &part->graphic_info;
887   struct GraphicInfo *c = &part->control_info;
888   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
889
890   if (viewport_changed)
891     state |= ANIM_STATE_RESTART;
892
893   if (state & ANIM_STATE_RESTART)
894   {
895     // when drawing animations to fading buffer, only start fixed animations
896     if (drawing_to_fading_buffer && (c->x == ARG_UNDEFINED_VALUE ||
897                                      c->y == ARG_UNDEFINED_VALUE))
898       return ANIM_STATE_INACTIVE;
899
900     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
901
902     part->init_delay_counter =
903       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
904
905     part->anim_delay_counter =
906       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
907
908     part->initial_anim_sync_frame =
909       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
910
911     if (c->direction & MV_HORIZONTAL)
912     {
913       int pos_bottom = part->viewport_height - g->height;
914
915       if (c->position == POS_TOP)
916         part->y = 0;
917       else if (c->position == POS_UPPER)
918         part->y = GetSimpleRandom(pos_bottom / 2);
919       else if (c->position == POS_MIDDLE)
920         part->y = pos_bottom / 2;
921       else if (c->position == POS_LOWER)
922         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
923       else if (c->position == POS_BOTTOM)
924         part->y = pos_bottom;
925       else
926         part->y = GetSimpleRandom(pos_bottom);
927
928       if (c->direction == MV_RIGHT)
929       {
930         part->step_xoffset = c->step_offset;
931         part->x = -g->width + part->step_xoffset;
932       }
933       else
934       {
935         part->step_xoffset = -c->step_offset;
936         part->x = part->viewport_width + part->step_xoffset;
937       }
938
939       part->step_yoffset = 0;
940     }
941     else if (c->direction & MV_VERTICAL)
942     {
943       int pos_right = part->viewport_width - g->width;
944
945       if (c->position == POS_LEFT)
946         part->x = 0;
947       else if (c->position == POS_RIGHT)
948         part->x = pos_right;
949       else
950         part->x = GetSimpleRandom(pos_right);
951
952       if (c->direction == MV_DOWN)
953       {
954         part->step_yoffset = c->step_offset;
955         part->y = -g->height + part->step_yoffset;
956       }
957       else
958       {
959         part->step_yoffset = -c->step_offset;
960         part->y = part->viewport_height + part->step_yoffset;
961       }
962
963       part->step_xoffset = 0;
964     }
965     else
966     {
967       part->x = 0;
968       part->y = 0;
969
970       part->step_xoffset = 0;
971       part->step_yoffset = 0;
972     }
973
974     if (c->x != ARG_UNDEFINED_VALUE)
975       part->x = c->x;
976     if (c->y != ARG_UNDEFINED_VALUE)
977       part->y = c->y;
978
979     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
980       part->step_xoffset = c->step_xoffset;
981     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
982       part->step_yoffset = c->step_yoffset;
983
984     if (part->init_delay_counter == 0)
985       PlayGlobalAnimSoundAndMusic(part);
986   }
987
988   if (part->init_delay_counter > 0)
989   {
990     part->init_delay_counter--;
991
992     if (part->init_delay_counter == 0)
993       PlayGlobalAnimSoundAndMusic(part);
994
995     return ANIM_STATE_WAITING;
996   }
997
998   // check if moving animation has left the visible screen area
999   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
1000       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
1001       (part->y <= -g->height             && part->step_yoffset <= 0) ||
1002       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
1003   {
1004     // do not stop animation before "anim" or "post" counter are finished
1005     if (part->anim_delay_counter == 0 &&
1006         part->post_delay_counter == 0)
1007     {
1008       StopGlobalAnimSoundAndMusic(part);
1009
1010       part->post_delay_counter =
1011         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1012
1013       if (part->post_delay_counter > 0)
1014         return ANIM_STATE_RUNNING;
1015
1016       // drawing last frame not needed here -- animation not visible anymore
1017       return ANIM_STATE_RESTART;
1018     }
1019   }
1020
1021   if (part->anim_delay_counter > 0)
1022   {
1023     part->anim_delay_counter--;
1024
1025     if (part->anim_delay_counter == 0)
1026     {
1027       StopGlobalAnimSoundAndMusic(part);
1028
1029       part->post_delay_counter =
1030         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
1031
1032       if (part->post_delay_counter > 0)
1033         return ANIM_STATE_RUNNING;
1034
1035       // additional state "RUNNING" required to not skip drawing last frame
1036       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
1037     }
1038   }
1039
1040   if (part->post_delay_counter > 0)
1041   {
1042     part->post_delay_counter--;
1043
1044     if (part->post_delay_counter == 0)
1045       return ANIM_STATE_RESTART;
1046
1047     return ANIM_STATE_WAITING;
1048   }
1049
1050   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
1051                        anim_sync_frame))
1052     return ANIM_STATE_RUNNING;
1053
1054 #if 0
1055   {
1056     static unsigned int last_counter = -1;
1057     unsigned int counter = Counter();
1058
1059     printf("::: NEXT ANIM PART [%d, %d]\n",
1060            anim_sync_frame, counter - last_counter);
1061
1062     last_counter = counter;
1063   }
1064 #endif
1065
1066   part->x += part->step_xoffset;
1067   part->y += part->step_yoffset;
1068
1069   return ANIM_STATE_RUNNING;
1070 }
1071
1072 void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
1073 {
1074   struct GlobalAnimPartControlInfo *part;
1075   struct GraphicInfo *c = &anim->control_info;
1076   int state, active_part_nr;
1077
1078 #if 0
1079   printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1080          anim->mode_nr, anim->nr, anim->num_parts);
1081   printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
1082 #endif
1083
1084 #if 0
1085   printf("::: %s(%d): %d, %d, %d [%d]\n",
1086          (action == ANIM_START ? "ANIM_START" :
1087           action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
1088           action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
1089          anim->nr,
1090          anim->state & ANIM_STATE_RESTART,
1091          anim->state & ANIM_STATE_WAITING,
1092          anim->state & ANIM_STATE_RUNNING,
1093          anim->num_parts);
1094 #endif
1095
1096   switch (action)
1097   {
1098     case ANIM_START:
1099       anim->state = anim->last_state = ANIM_STATE_RESTART;
1100       anim->active_part_nr = anim->last_active_part_nr = 0;
1101       anim->part_counter = 0;
1102
1103       break;
1104
1105     case ANIM_CONTINUE:
1106       if (anim->state == ANIM_STATE_INACTIVE)
1107         return;
1108
1109       anim->state = anim->last_state;
1110       anim->active_part_nr = anim->last_active_part_nr;
1111
1112       break;
1113
1114     case ANIM_STOP:
1115       anim->state = ANIM_STATE_INACTIVE;
1116
1117       {
1118         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1119         int i;
1120
1121         for (i = 0; i < num_parts; i++)
1122           StopGlobalAnimSoundAndMusic(&anim->part[i]);
1123       }
1124
1125       return;
1126
1127     default:
1128       break;
1129   }
1130
1131   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
1132   {
1133     int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1134     int i;
1135
1136 #if 0
1137     printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1138            anim->mode_nr, anim->nr, num_parts);
1139 #endif
1140
1141     for (i = 0; i < num_parts; i++)
1142     {
1143       part = &anim->part[i];
1144
1145       switch (action)
1146       {
1147         case ANIM_START:
1148           anim->state = ANIM_STATE_RUNNING;
1149           part->state = ANIM_STATE_RESTART;
1150
1151           break;
1152
1153         case ANIM_CONTINUE:
1154           if (part->state == ANIM_STATE_INACTIVE)
1155             continue;
1156
1157           break;
1158
1159         case ANIM_STOP:
1160           part->state = ANIM_STATE_INACTIVE;
1161
1162           continue;
1163
1164         default:
1165           break;
1166       }
1167
1168       part->state = HandleGlobalAnim_Part(part, part->state);
1169
1170       // when animation mode is "once", stop after animation was played once
1171       if (c->anim_mode & ANIM_ONCE &&
1172           part->state & ANIM_STATE_RESTART)
1173         part->state = ANIM_STATE_INACTIVE;
1174     }
1175
1176     anim->last_state = anim->state;
1177     anim->last_active_part_nr = anim->active_part_nr;
1178
1179     return;
1180   }
1181
1182   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
1183     anim->active_part_nr = getGlobalAnimationPart(anim);
1184
1185   part = &anim->part[anim->active_part_nr];
1186
1187   part->state = ANIM_STATE_RUNNING;
1188
1189   anim->state = HandleGlobalAnim_Part(part, anim->state);
1190
1191   if (anim->state & ANIM_STATE_RESTART)
1192     anim->part_counter++;
1193
1194   // when animation mode is "once", stop after all animations were played once
1195   if (c->anim_mode & ANIM_ONCE &&
1196       anim->part_counter == anim->num_parts)
1197     anim->state = ANIM_STATE_INACTIVE;
1198
1199   state = anim->state;
1200   active_part_nr = anim->active_part_nr;
1201
1202   // while the animation parts are pausing (waiting or inactive), play the base
1203   // (main) animation; this corresponds to the "boring player animation" logic
1204   // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!)
1205   if (anim->has_base)
1206   {
1207     if (anim->state == ANIM_STATE_WAITING ||
1208         anim->state == ANIM_STATE_INACTIVE)
1209     {
1210       anim->active_part_nr = anim->num_parts;   // part nr of base animation
1211       part = &anim->part[anim->active_part_nr];
1212
1213       if (anim->state != anim->last_state)
1214         part->state = ANIM_STATE_RESTART;
1215
1216       anim->state = ANIM_STATE_RUNNING;
1217       part->state = HandleGlobalAnim_Part(part, part->state);
1218     }
1219   }
1220
1221   anim->last_state = state;
1222   anim->last_active_part_nr = active_part_nr;
1223 }
1224
1225 void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
1226 {
1227   int i;
1228
1229 #if 0
1230   printf("::: HandleGlobalAnim_Mode: %d => %d\n",
1231          ctrl->nr, ctrl->num_anims);
1232 #endif
1233
1234   for (i = 0; i < ctrl->num_anims; i++)
1235     HandleGlobalAnim_Main(&ctrl->anim[i], action);
1236 }
1237
1238 static void HandleGlobalAnim(int action, int game_mode)
1239 {
1240 #if 0
1241   printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
1242 #endif
1243
1244   HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
1245 }
1246
1247 static void DoAnimationExt()
1248 {
1249   int i;
1250
1251 #if 0
1252   printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
1253 #endif
1254
1255   // global animations now synchronized with frame delay of screen update
1256   anim_sync_frame++;
1257
1258   for (i = 0; i < NUM_GAME_MODES; i++)
1259     HandleGlobalAnim(ANIM_CONTINUE, i);
1260
1261 #if 0
1262   // force screen redraw in next frame to continue drawing global animations
1263   redraw_mask = REDRAW_ALL;
1264 #endif
1265 }