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