added value to constants for global animations control
[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_stage)
521 {
522   int mode_nr;
523
524   if (global.anim_status != anim_status_last)
525   {
526     boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING);
527     boolean after_fading  = (anim_status_last   == GAME_MODE_PSEUDO_FADING);
528     int anim_classes_next = game_mode_anim_classes[global.anim_status_next];
529     int i;
530
531     // ---------- part 1 ------------------------------------------------------
532     // start or stop global animations by change of game mode
533     // (special handling of animations for "current screen" and "all screens")
534
535     // stop animations for last screen
536     HandleGlobalAnim(ANIM_STOP, anim_status_last);
537
538     // start animations for current screen
539     HandleGlobalAnim(ANIM_START, global.anim_status);
540
541     // start animations for all screens after loading new artwork set
542     if (anim_status_last == GAME_MODE_LOADING)
543       HandleGlobalAnim(ANIM_START, GAME_MODE_DEFAULT);
544
545     // ---------- part 2 ------------------------------------------------------
546     // start or stop global animations by change of animation class
547     // (generic handling of animations for "class of screens")
548
549     for (i = 0; i < NUM_ANIM_CLASSES; i++)
550     {
551       int anim_class_check = (1 << i);
552       int anim_class_game_mode = anim_class_game_modes[i];
553       int anim_class_last = anim_classes_last & anim_class_check;
554       int anim_class_next = anim_classes_next & anim_class_check;
555
556       // stop animations for changed screen class before fading to new screen
557       if (before_fading && anim_class_last && !anim_class_next)
558         HandleGlobalAnim(ANIM_STOP, anim_class_game_mode);
559
560       // start animations for changed screen class after fading to new screen
561       if (after_fading && !anim_class_last && anim_class_next)
562         HandleGlobalAnim(ANIM_START, anim_class_game_mode);
563     }
564
565     if (after_fading)
566       anim_classes_last = anim_classes_next;
567
568     anim_status_last = global.anim_status;
569   }
570
571   if (!setup.toons || global.anim_status == GAME_MODE_LOADING)
572     return;
573
574   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
575     DoAnimationExt();
576
577   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
578   {
579     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
580     int anim_nr;
581
582 #if 0
583     if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
584         mode_nr != game_status)
585       continue;
586 #endif
587
588     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
589     {
590       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
591       struct GraphicInfo *c = &anim->control_info;
592       int part_first, part_last;
593       int part_nr;
594
595       if (!(anim->state & ANIM_STATE_RUNNING))
596         continue;
597
598       part_first = part_last = anim->active_part_nr;
599
600       if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
601       {
602         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
603
604         part_first = 0;
605         part_last = num_parts - 1;
606       }
607
608       for (part_nr = part_first; part_nr <= part_last; part_nr++)
609       {
610         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
611         struct GraphicInfo *g = &part->graphic_info;
612         Bitmap *src_bitmap;
613         int src_x, src_y;
614         int width  = g->width;
615         int height = g->height;
616         int dst_x = part->x;
617         int dst_y = part->y;
618         int cut_x = 0;
619         int cut_y = 0;
620         int sync_frame;
621         int frame;
622
623         if (!(part->state & ANIM_STATE_RUNNING))
624           continue;
625
626         if (part->drawing_stage != drawing_stage)
627           continue;
628
629         if (part->x < 0)
630         {
631           dst_x = 0;
632           width += part->x;
633           cut_x = -part->x;
634         }
635         else if (part->x > part->viewport_width - g->width)
636           width -= (part->x - (part->viewport_width - g->width));
637
638         if (part->y < 0)
639         {
640           dst_y = 0;
641           height += part->y;
642           cut_y = -part->y;
643         }
644         else if (part->y > part->viewport_height - g->height)
645           height -= (part->y - (part->viewport_height - g->height));
646
647         if (width <= 0 || height <= 0)
648           continue;
649
650         dst_x += part->viewport_x;
651         dst_y += part->viewport_y;
652
653         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
654         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
655                                   g->anim_mode, g->anim_start_frame,
656                                   sync_frame);
657
658         getFixedGraphicSource(part->graphic, frame, &src_bitmap,
659                               &src_x, &src_y);
660
661         src_x += cut_x;
662         src_y += cut_y;
663
664         BlitToScreenMasked(src_bitmap, src_x, src_y, width, height,
665                            dst_x, dst_y);
666       }
667     }
668   }
669 }
670
671 void DrawGlobalAnimations(int drawing_stage)
672 {
673   DrawGlobalAnimationsExt(drawing_stage);
674 }
675
676 boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
677 {
678   int viewport_x;
679   int viewport_y;
680   int viewport_width;
681   int viewport_height;
682   boolean changed = FALSE;
683
684   if (part->last_anim_status == global.anim_status)
685     return FALSE;
686
687   part->last_anim_status = global.anim_status;
688
689   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
690
691   if (part->control_info.class == get_hash_from_key("window") ||
692       part->control_info.class == get_hash_from_key("border"))
693   {
694     viewport_x = 0;
695     viewport_y = 0;
696     viewport_width  = WIN_XSIZE;
697     viewport_height = WIN_YSIZE;
698
699     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
700   }
701   else if (part->control_info.class == get_hash_from_key("door_1"))
702   {
703     viewport_x = DX;
704     viewport_y = DY;
705     viewport_width  = DXSIZE;
706     viewport_height = DYSIZE;
707   }
708   else if (part->control_info.class == get_hash_from_key("door_2"))
709   {
710     viewport_x = VX;
711     viewport_y = VY;
712     viewport_width  = VXSIZE;
713     viewport_height = VYSIZE;
714   }
715   else          // default: "playfield"
716   {
717     viewport_x = REAL_SX;
718     viewport_y = REAL_SY;
719     viewport_width  = FULL_SXSIZE;
720     viewport_height = FULL_SYSIZE;
721   }
722
723   if (viewport_x != part->viewport_x ||
724       viewport_y != part->viewport_y ||
725       viewport_width  != part->viewport_width ||
726       viewport_height != part->viewport_height)
727   {
728     part->viewport_x = viewport_x;
729     part->viewport_y = viewport_y;
730     part->viewport_width  = viewport_width;
731     part->viewport_height = viewport_height;
732
733     changed = TRUE;
734   }
735
736   return changed;
737 }
738
739 static void PlayGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
740 {
741   int sound = part->sound;
742
743   if (sound == SND_UNDEFINED)
744     return;
745
746   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
747       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
748     return;
749
750   // !!! TODO: ADD STEREO POSITION FOR MOVING ANIMATIONS !!!
751   if (IS_LOOP_SOUND(sound))
752     PlaySoundLoop(sound);
753   else
754     PlaySound(sound);
755
756 #if 0
757   printf("::: PLAY SOUND %d.%d.%d: %d\n",
758          part->anim_nr, part->nr, part->mode_nr, sound);
759 #endif
760 }
761
762 static void StopGlobalAnimSound(struct GlobalAnimPartControlInfo *part)
763 {
764   int sound = part->sound;
765
766   if (sound == SND_UNDEFINED)
767     return;
768
769   StopSound(sound);
770
771 #if 0
772   printf("::: STOP SOUND %d.%d.%d: %d\n",
773          part->anim_nr, part->nr, part->mode_nr, sound);
774 #endif
775 }
776
777 static void PlayGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
778 {
779   int music = part->music;
780
781   if (music == MUS_UNDEFINED)
782     return;
783
784   if (!setup.sound_music)
785     return;
786
787   PlayMusic(music);
788
789 #if 0
790   printf("::: PLAY MUSIC %d.%d.%d: %d\n",
791          part->anim_nr, part->nr, part->mode_nr, music);
792 #endif
793 }
794
795 static void StopGlobalAnimMusic(struct GlobalAnimPartControlInfo *part)
796 {
797   int music = part->music;
798
799   if (music == MUS_UNDEFINED)
800     return;
801
802   StopMusic();
803
804 #if 0
805   printf("::: STOP MUSIC %d.%d.%d: %d\n",
806          part->anim_nr, part->nr, part->mode_nr, music);
807 #endif
808 }
809
810 static void PlayGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
811 {
812   PlayGlobalAnimSound(part);
813   PlayGlobalAnimMusic(part);
814 }
815
816 static void StopGlobalAnimSoundAndMusic(struct GlobalAnimPartControlInfo *part)
817 {
818   StopGlobalAnimSound(part);
819   StopGlobalAnimMusic(part);
820 }
821
822 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
823 {
824   struct GraphicInfo *g = &part->graphic_info;
825   struct GraphicInfo *c = &part->control_info;
826   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
827
828   if (viewport_changed)
829     state |= ANIM_STATE_RESTART;
830
831   if (state & ANIM_STATE_RESTART)
832   {
833     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
834
835     part->init_delay_counter =
836       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
837
838     part->anim_delay_counter =
839       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
840
841     part->initial_anim_sync_frame =
842       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
843
844     if (c->direction & MV_HORIZONTAL)
845     {
846       int pos_bottom = part->viewport_height - g->height;
847
848       if (c->position == POS_TOP)
849         part->y = 0;
850       else if (c->position == POS_UPPER)
851         part->y = GetSimpleRandom(pos_bottom / 2);
852       else if (c->position == POS_MIDDLE)
853         part->y = pos_bottom / 2;
854       else if (c->position == POS_LOWER)
855         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
856       else if (c->position == POS_BOTTOM)
857         part->y = pos_bottom;
858       else
859         part->y = GetSimpleRandom(pos_bottom);
860
861       if (c->direction == MV_RIGHT)
862       {
863         part->step_xoffset = c->step_offset;
864         part->x = -g->width + part->step_xoffset;
865       }
866       else
867       {
868         part->step_xoffset = -c->step_offset;
869         part->x = part->viewport_width + part->step_xoffset;
870       }
871
872       part->step_yoffset = 0;
873     }
874     else if (c->direction & MV_VERTICAL)
875     {
876       int pos_right = part->viewport_width - g->width;
877
878       if (c->position == POS_LEFT)
879         part->x = 0;
880       else if (c->position == POS_RIGHT)
881         part->x = pos_right;
882       else
883         part->x = GetSimpleRandom(pos_right);
884
885       if (c->direction == MV_DOWN)
886       {
887         part->step_yoffset = c->step_offset;
888         part->y = -g->height + part->step_yoffset;
889       }
890       else
891       {
892         part->step_yoffset = -c->step_offset;
893         part->y = part->viewport_height + part->step_yoffset;
894       }
895
896       part->step_xoffset = 0;
897     }
898     else
899     {
900       part->x = 0;
901       part->y = 0;
902
903       part->step_xoffset = 0;
904       part->step_yoffset = 0;
905     }
906
907     if (c->x != ARG_UNDEFINED_VALUE)
908       part->x = c->x;
909     if (c->y != ARG_UNDEFINED_VALUE)
910       part->y = c->y;
911
912     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
913       part->step_xoffset = c->step_xoffset;
914     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
915       part->step_yoffset = c->step_yoffset;
916
917     if (part->init_delay_counter == 0)
918       PlayGlobalAnimSoundAndMusic(part);
919   }
920
921   if (part->init_delay_counter > 0)
922   {
923     part->init_delay_counter--;
924
925     if (part->init_delay_counter == 0)
926       PlayGlobalAnimSoundAndMusic(part);
927
928     return ANIM_STATE_WAITING;
929   }
930
931   // check if moving animation has left the visible screen area
932   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
933       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
934       (part->y <= -g->height             && part->step_yoffset <= 0) ||
935       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
936   {
937     // do not stop animation before "anim" or "post" counter are finished
938     if (part->anim_delay_counter == 0 &&
939         part->post_delay_counter == 0)
940     {
941       StopGlobalAnimSoundAndMusic(part);
942
943       part->post_delay_counter =
944         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
945
946       if (part->post_delay_counter > 0)
947         return ANIM_STATE_RUNNING;
948
949       // drawing last frame not needed here -- animation not visible anymore
950       return ANIM_STATE_RESTART;
951     }
952   }
953
954   if (part->anim_delay_counter > 0)
955   {
956     part->anim_delay_counter--;
957
958     if (part->anim_delay_counter == 0)
959     {
960       StopGlobalAnimSoundAndMusic(part);
961
962       part->post_delay_counter =
963         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
964
965       if (part->post_delay_counter > 0)
966         return ANIM_STATE_RUNNING;
967
968       // additional state "RUNNING" required to not skip drawing last frame
969       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
970     }
971   }
972
973   if (part->post_delay_counter > 0)
974   {
975     part->post_delay_counter--;
976
977     if (part->post_delay_counter == 0)
978       return ANIM_STATE_RESTART;
979
980     return ANIM_STATE_WAITING;
981   }
982
983   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
984                        anim_sync_frame))
985     return ANIM_STATE_RUNNING;
986
987 #if 0
988   {
989     static unsigned int last_counter = -1;
990     unsigned int counter = Counter();
991
992     printf("::: NEXT ANIM PART [%d, %d]\n",
993            anim_sync_frame, counter - last_counter);
994
995     last_counter = counter;
996   }
997 #endif
998
999   part->x += part->step_xoffset;
1000   part->y += part->step_yoffset;
1001
1002   return ANIM_STATE_RUNNING;
1003 }
1004
1005 void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
1006 {
1007   struct GlobalAnimPartControlInfo *part;
1008   struct GraphicInfo *c = &anim->control_info;
1009   int state, active_part_nr;
1010
1011 #if 0
1012   printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1013          anim->mode_nr, anim->nr, anim->num_parts);
1014   printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
1015 #endif
1016
1017 #if 0
1018   printf("::: %s(%d): %d, %d, %d [%d]\n",
1019          (action == ANIM_START ? "ANIM_START" :
1020           action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
1021           action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
1022          anim->nr,
1023          anim->state & ANIM_STATE_RESTART,
1024          anim->state & ANIM_STATE_WAITING,
1025          anim->state & ANIM_STATE_RUNNING,
1026          anim->num_parts);
1027 #endif
1028
1029   switch (action)
1030   {
1031     case ANIM_START:
1032       anim->state = anim->last_state = ANIM_STATE_RESTART;
1033       anim->active_part_nr = anim->last_active_part_nr = 0;
1034       anim->part_counter = 0;
1035
1036       break;
1037
1038     case ANIM_CONTINUE:
1039       if (anim->state == ANIM_STATE_INACTIVE)
1040         return;
1041
1042       anim->state = anim->last_state;
1043       anim->active_part_nr = anim->last_active_part_nr;
1044
1045       break;
1046
1047     case ANIM_STOP:
1048       anim->state = ANIM_STATE_INACTIVE;
1049
1050       {
1051         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1052         int i;
1053
1054         for (i = 0; i < num_parts; i++)
1055           StopGlobalAnimSoundAndMusic(&anim->part[i]);
1056       }
1057
1058       return;
1059
1060     default:
1061       break;
1062   }
1063
1064   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
1065   {
1066     int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
1067     int i;
1068
1069 #if 0
1070     printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
1071            anim->mode_nr, anim->nr, num_parts);
1072 #endif
1073
1074     for (i = 0; i < num_parts; i++)
1075     {
1076       part = &anim->part[i];
1077
1078       switch (action)
1079       {
1080         case ANIM_START:
1081           anim->state = ANIM_STATE_RUNNING;
1082           part->state = ANIM_STATE_RESTART;
1083
1084           break;
1085
1086         case ANIM_CONTINUE:
1087           if (part->state == ANIM_STATE_INACTIVE)
1088             continue;
1089
1090           break;
1091
1092         case ANIM_STOP:
1093           part->state = ANIM_STATE_INACTIVE;
1094
1095           continue;
1096
1097         default:
1098           break;
1099       }
1100
1101       part->state = HandleGlobalAnim_Part(part, part->state);
1102
1103       // when animation mode is "once", stop after animation was played once
1104       if (c->anim_mode & ANIM_ONCE &&
1105           part->state & ANIM_STATE_RESTART)
1106         part->state = ANIM_STATE_INACTIVE;
1107     }
1108
1109     anim->last_state = anim->state;
1110     anim->last_active_part_nr = anim->active_part_nr;
1111
1112     return;
1113   }
1114
1115   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
1116     anim->active_part_nr = getGlobalAnimationPart(anim);
1117
1118   part = &anim->part[anim->active_part_nr];
1119
1120   part->state = ANIM_STATE_RUNNING;
1121
1122   anim->state = HandleGlobalAnim_Part(part, anim->state);
1123
1124   if (anim->state & ANIM_STATE_RESTART)
1125     anim->part_counter++;
1126
1127   // when animation mode is "once", stop after all animations were played once
1128   if (c->anim_mode & ANIM_ONCE &&
1129       anim->part_counter == anim->num_parts)
1130     anim->state = ANIM_STATE_INACTIVE;
1131
1132   state = anim->state;
1133   active_part_nr = anim->active_part_nr;
1134
1135   // while the animation parts are pausing (waiting or inactive), play the base
1136   // (main) animation; this corresponds to the "boring player animation" logic
1137   // (!!! KLUDGE WARNING: I THINK THIS IS A MESS THAT SHOULD BE CLEANED UP !!!)
1138   if (anim->has_base)
1139   {
1140     if (anim->state == ANIM_STATE_WAITING ||
1141         anim->state == ANIM_STATE_INACTIVE)
1142     {
1143       anim->active_part_nr = anim->num_parts;   // part nr of base animation
1144       part = &anim->part[anim->active_part_nr];
1145
1146       if (anim->state != anim->last_state)
1147         part->state = ANIM_STATE_RESTART;
1148
1149       anim->state = ANIM_STATE_RUNNING;
1150       part->state = HandleGlobalAnim_Part(part, part->state);
1151     }
1152   }
1153
1154   anim->last_state = state;
1155   anim->last_active_part_nr = active_part_nr;
1156 }
1157
1158 void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
1159 {
1160   int i;
1161
1162 #if 0
1163   printf("::: HandleGlobalAnim_Mode: %d => %d\n",
1164          ctrl->nr, ctrl->num_anims);
1165 #endif
1166
1167   for (i = 0; i < ctrl->num_anims; i++)
1168     HandleGlobalAnim_Main(&ctrl->anim[i], action);
1169 }
1170
1171 static void HandleGlobalAnim(int action, int game_mode)
1172 {
1173 #if 0
1174   printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
1175 #endif
1176
1177   HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
1178 }
1179
1180 static void DoAnimationExt()
1181 {
1182   int i;
1183
1184 #if 0
1185   printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
1186 #endif
1187
1188   // global animations now synchronized with frame delay of screen update
1189   anim_sync_frame++;
1190
1191   for (i = 0; i < NUM_GAME_MODES; i++)
1192     HandleGlobalAnim(ANIM_CONTINUE, i);
1193
1194 #if 1
1195   // force screen redraw in next frame to continue drawing global animations
1196   redraw_mask = REDRAW_ALL;
1197 #endif
1198 }