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