added support for '.draw_order' for global 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
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         dst_x += part->viewport_x;
587         dst_y += part->viewport_y;
588
589         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
590         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
591                                   g->anim_mode, g->anim_start_frame,
592                                   sync_frame);
593
594         getFixedGraphicSource(part->graphic, frame, &src_bitmap,
595                               &src_x, &src_y);
596
597         src_x += cut_x;
598         src_y += cut_y;
599
600         BlitToScreenMasked(src_bitmap, src_x, src_y, width, height,
601                            dst_x, dst_y);
602       }
603     }
604   }
605 }
606
607 void DrawGlobalAnim(int drawing_stage)
608 {
609   DrawGlobalAnimExt(drawing_stage);
610 }
611
612 boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
613 {
614   int viewport_x;
615   int viewport_y;
616   int viewport_width;
617   int viewport_height;
618   boolean changed = FALSE;
619
620   if (part->last_anim_status == global.anim_status)
621     return FALSE;
622
623   part->last_anim_status = global.anim_status;
624
625   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
626
627   if (part->control_info.class == get_hash_from_key("window") ||
628       part->control_info.class == get_hash_from_key("border"))
629   {
630     viewport_x = 0;
631     viewport_y = 0;
632     viewport_width  = WIN_XSIZE;
633     viewport_height = WIN_YSIZE;
634
635     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
636   }
637   else if (part->control_info.class == get_hash_from_key("door_1"))
638   {
639     viewport_x = DX;
640     viewport_y = DY;
641     viewport_width  = DXSIZE;
642     viewport_height = DYSIZE;
643   }
644   else if (part->control_info.class == get_hash_from_key("door_2"))
645   {
646     viewport_x = VX;
647     viewport_y = VY;
648     viewport_width  = VXSIZE;
649     viewport_height = VYSIZE;
650   }
651   else          // default: "playfield"
652   {
653     viewport_x = REAL_SX;
654     viewport_y = REAL_SY;
655     viewport_width  = FULL_SXSIZE;
656     viewport_height = FULL_SYSIZE;
657   }
658
659   if (viewport_x != part->viewport_x ||
660       viewport_y != part->viewport_y ||
661       viewport_width  != part->viewport_width ||
662       viewport_height != part->viewport_height)
663   {
664     part->viewport_x = viewport_x;
665     part->viewport_y = viewport_y;
666     part->viewport_width  = viewport_width;
667     part->viewport_height = viewport_height;
668
669     changed = TRUE;
670   }
671
672   return changed;
673 }
674
675 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
676 {
677   struct GraphicInfo *g = &part->graphic_info;
678   struct GraphicInfo *c = &part->control_info;
679   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
680
681   if (viewport_changed)
682     state |= ANIM_STATE_RESTART;
683
684   if (state & ANIM_STATE_RESTART)
685   {
686     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
687
688     part->init_delay_counter =
689       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
690
691     part->anim_delay_counter =
692       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
693
694     part->initial_anim_sync_frame =
695       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
696
697     if (c->direction & MV_HORIZONTAL)
698     {
699       int pos_bottom = part->viewport_height - g->height;
700
701       if (c->position == POS_TOP)
702         part->y = 0;
703       else if (c->position == POS_UPPER)
704         part->y = GetSimpleRandom(pos_bottom / 2);
705       else if (c->position == POS_MIDDLE)
706         part->y = pos_bottom / 2;
707       else if (c->position == POS_LOWER)
708         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
709       else if (c->position == POS_BOTTOM)
710         part->y = pos_bottom;
711       else
712         part->y = GetSimpleRandom(pos_bottom);
713
714       if (c->direction == MV_RIGHT)
715       {
716         part->step_xoffset = c->step_offset;
717         part->x = -g->width + part->step_xoffset;
718       }
719       else
720       {
721         part->step_xoffset = -c->step_offset;
722         part->x = part->viewport_width + part->step_xoffset;
723       }
724
725       part->step_yoffset = 0;
726     }
727     else if (c->direction & MV_VERTICAL)
728     {
729       int pos_right = part->viewport_width - g->width;
730
731       if (c->position == POS_LEFT)
732         part->x = 0;
733       else if (c->position == POS_RIGHT)
734         part->x = pos_right;
735       else
736         part->x = GetSimpleRandom(pos_right);
737
738       if (c->direction == MV_DOWN)
739       {
740         part->step_yoffset = c->step_offset;
741         part->y = -g->height + part->step_yoffset;
742       }
743       else
744       {
745         part->step_yoffset = -c->step_offset;
746         part->y = part->viewport_height + part->step_yoffset;
747       }
748
749       part->step_xoffset = 0;
750     }
751     else
752     {
753       part->x = 0;
754       part->y = 0;
755
756       part->step_xoffset = 0;
757       part->step_yoffset = 0;
758     }
759
760     if (c->x != ARG_UNDEFINED_VALUE)
761       part->x = c->x;
762     if (c->y != ARG_UNDEFINED_VALUE)
763       part->y = c->y;
764
765     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
766       part->step_xoffset = c->step_xoffset;
767     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
768       part->step_yoffset = c->step_yoffset;
769   }
770
771   if (part->init_delay_counter > 0)
772   {
773     part->init_delay_counter--;
774
775     return ANIM_STATE_WAITING;
776   }
777
778   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
779       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
780       (part->y <= -g->height             && part->step_yoffset <= 0) ||
781       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
782     return ANIM_STATE_RESTART;
783
784   if (part->anim_delay_counter > 0)
785   {
786     part->anim_delay_counter--;
787
788     if (part->anim_delay_counter == 0)
789     {
790       part->post_delay_counter =
791         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
792
793       if (part->post_delay_counter > 0)
794         return ANIM_STATE_RUNNING;
795
796       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
797     }
798   }
799
800   if (part->post_delay_counter > 0)
801   {
802     part->post_delay_counter--;
803
804     if (part->post_delay_counter == 0)
805       return ANIM_STATE_RESTART;
806
807     return ANIM_STATE_WAITING;
808   }
809
810   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
811                        anim_sync_frame))
812     return ANIM_STATE_RUNNING;
813
814 #if 0
815   {
816     static unsigned int last_counter = -1;
817     unsigned int counter = Counter();
818
819     printf("::: NEXT ANIM PART [%d, %d]\n",
820            anim_sync_frame, counter - last_counter);
821
822     last_counter = counter;
823   }
824 #endif
825
826   part->x += part->step_xoffset;
827   part->y += part->step_yoffset;
828
829   return ANIM_STATE_RUNNING;
830 }
831
832 void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
833 {
834   struct GlobalAnimPartControlInfo *part;
835   struct GraphicInfo *c = &anim->control_info;
836
837 #if 0
838   printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
839          anim->mode_nr, anim->nr, anim->num_parts);
840   printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
841 #endif
842
843 #if 0
844   printf("::: %s(%d): %d, %d, %d [%d]\n",
845          (action == ANIM_START ? "ANIM_START" :
846           action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
847           action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
848          anim->nr,
849          anim->state & ANIM_STATE_RESTART,
850          anim->state & ANIM_STATE_WAITING,
851          anim->state & ANIM_STATE_RUNNING,
852          anim->num_parts);
853 #endif
854
855   switch (action)
856   {
857     case ANIM_START:
858       anim->state = ANIM_STATE_RESTART;
859       anim->part_counter = 0;
860       anim->active_part_nr = 0;
861
862       break;
863
864     case ANIM_CONTINUE:
865       if (anim->state == ANIM_STATE_INACTIVE)
866         return;
867
868       break;
869
870     case ANIM_STOP:
871       anim->state = ANIM_STATE_INACTIVE;
872
873       return;
874
875     default:
876       break;
877   }
878
879   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
880   {
881     int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
882     int i;
883
884 #if 0
885     printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
886            anim->mode_nr, anim->nr, num_parts);
887 #endif
888
889     for (i = 0; i < num_parts; i++)
890     {
891       part = &anim->part[i];
892
893       switch (action)
894       {
895         case ANIM_START:
896           anim->state = ANIM_STATE_RUNNING;
897           part->state = ANIM_STATE_RESTART;
898
899           break;
900
901         case ANIM_CONTINUE:
902           if (part->state == ANIM_STATE_INACTIVE)
903             continue;
904
905           break;
906
907         case ANIM_STOP:
908           part->state = ANIM_STATE_INACTIVE;
909
910           continue;
911
912         default:
913           break;
914       }
915
916       part->state = HandleGlobalAnim_Part(part, part->state);
917
918       // when animation mode is "once", stop after animation was played once
919       if (c->anim_mode & ANIM_ONCE &&
920           part->state & ANIM_STATE_RESTART)
921         part->state = ANIM_STATE_INACTIVE;
922     }
923
924     return;
925   }
926
927   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
928     anim->active_part_nr = getGlobalAnimationPart(anim);
929
930   part = &anim->part[anim->active_part_nr];
931
932   part->state = ANIM_STATE_RUNNING;
933
934   anim->state = HandleGlobalAnim_Part(part, anim->state);
935
936   if (anim->state & ANIM_STATE_RESTART)
937     anim->part_counter++;
938
939   // when animation mode is "once", stop after all animations were played once
940   if (c->anim_mode & ANIM_ONCE &&
941       anim->part_counter == anim->num_parts)
942     anim->state = ANIM_STATE_INACTIVE;
943 }
944
945 void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
946 {
947   int i;
948
949 #if 0
950   printf("::: HandleGlobalAnim_Mode: %d => %d\n",
951          ctrl->nr, ctrl->num_anims);
952 #endif
953
954   for (i = 0; i < ctrl->num_anims; i++)
955     HandleGlobalAnim_Main(&ctrl->anim[i], action);
956 }
957
958 static void HandleGlobalAnim(int action, int game_mode)
959 {
960 #if 0
961   printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
962 #endif
963
964   HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
965 }
966
967 void InitAnimation()
968 {
969 }
970
971 void StopAnimation()
972 {
973 }
974
975 static void DoAnimationExt()
976 {
977   int i;
978
979 #if 0
980   printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
981 #endif
982
983 #if 1
984   WaitUntilDelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value);
985   anim_sync_frame++;
986 #else
987   if (DelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value))
988     anim_sync_frame++;
989 #endif
990
991   for (i = 0; i < NUM_GAME_MODES; i++)
992     HandleGlobalAnim(ANIM_CONTINUE, i);
993
994 #if 1
995   // force screen redraw in next frame to continue drawing global animations
996   redraw_mask = REDRAW_ALL;
997 #endif
998 }
999
1000 void DoAnimation()
1001 {
1002   // HandleAnimation(ANIM_CONTINUE);
1003
1004 #if 1
1005   // force screen redraw in next frame to continue drawing global animations
1006   redraw_mask = REDRAW_ALL;
1007 #endif
1008 }