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