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