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