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