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