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