b2f2eb2b8f4ca5528a8d79f1a1b8b64f16c3a419
[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 struct GlobalAnimPartControlInfo
28 {
29   int nr;
30   int anim_nr;
31   int mode_nr;
32
33   int graphic;
34   struct GraphicInfo graphic_info;
35   struct GraphicInfo control_info;
36
37   int viewport_x;
38   int viewport_y;
39   int viewport_width;
40   int viewport_height;
41
42   int x, y;
43   int step_xoffset, step_yoffset;
44
45   unsigned int initial_anim_sync_frame;
46   unsigned int step_delay, step_delay_value;
47
48   int init_delay_counter;
49   int anim_delay_counter;
50   int post_delay_counter;
51
52   int drawing_stage;
53
54   int state;
55   int last_game_status;
56 };
57
58 struct GlobalAnimMainControlInfo
59 {
60   struct GlobalAnimPartControlInfo base;
61   struct GlobalAnimPartControlInfo part[NUM_GLOBAL_ANIM_PARTS_AND_TOONS];
62
63   int nr;
64   int mode_nr;
65
66   struct GraphicInfo control_info;
67
68   int num_parts;
69   int part_counter;
70   int active_part_nr;
71
72   boolean has_base;
73
74   int init_delay_counter;
75
76   int state;
77 };
78
79 struct GlobalAnimControlInfo
80 {
81   struct GlobalAnimMainControlInfo anim[NUM_GLOBAL_ANIMS_AND_TOONS];
82
83   int nr;
84   int num_anims;
85 };
86
87
88 /* forward declaration for internal use */
89 static void DoAnimationExt(void);
90
91 static struct GlobalAnimControlInfo global_anim_ctrl[NUM_SPECIAL_GFX_ARGS];
92 static struct ToonInfo toons[MAX_NUM_TOONS];
93
94 static unsigned int anim_sync_frame = 0;
95 static unsigned int anim_sync_frame_delay = 0;
96 static unsigned int anim_sync_frame_delay_value = GAME_FRAME_DELAY;
97
98 static boolean do_animations = FALSE;
99
100
101 static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim)
102 {
103   struct GraphicInfo *c = &anim->control_info;
104   int last_anim_random_frame = gfx.anim_random_frame;
105   int part_nr;
106
107   gfx.anim_random_frame = -1;   // (use simple, ad-hoc random numbers)
108
109   part_nr = getAnimationFrame(anim->num_parts, 1,
110                               c->anim_mode, c->anim_start_frame,
111                               anim->part_counter);
112
113   gfx.anim_random_frame = last_anim_random_frame;
114
115   return part_nr;
116 }
117
118 static void PrepareBackbuffer()
119 {
120   if (game_status != GAME_MODE_PLAYING)
121     return;
122
123   BlitScreenToBitmap(backbuffer);
124 }
125
126 boolean ToonNeedsRedraw()
127 {
128   return TRUE;
129 }
130
131 void InitToons()
132 {
133   int num_toons = MAX_NUM_TOONS;
134   int i;
135
136   if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
137     num_toons = global.num_toons;
138
139   for (i = 0; i < num_toons; i++)
140   {
141     int graphic = IMG_TOON_1 + i;
142     struct FileInfo *image = getImageListEntryFromImageID(graphic);
143
144     toons[i].bitmap = graphic_info[graphic].bitmap;
145
146     toons[i].src_x = graphic_info[graphic].src_x;
147     toons[i].src_y = graphic_info[graphic].src_y;
148
149     toons[i].width  = graphic_info[graphic].width;
150     toons[i].height = graphic_info[graphic].height;
151
152     toons[i].anim_frames      = graphic_info[graphic].anim_frames;
153     toons[i].anim_delay       = graphic_info[graphic].anim_delay;
154     toons[i].anim_mode        = graphic_info[graphic].anim_mode;
155     toons[i].anim_start_frame = graphic_info[graphic].anim_start_frame;
156
157     toons[i].step_offset = graphic_info[graphic].step_offset;
158     toons[i].step_delay  = graphic_info[graphic].step_delay;
159
160     toons[i].direction = image->parameter[GFX_ARG_DIRECTION];
161     toons[i].position = image->parameter[GFX_ARG_POSITION];
162   }
163
164   InitToonScreen(bitmap_db_toons,
165                  BackToFront, PrepareBackbuffer, ToonNeedsRedraw,
166                  toons, num_toons,
167                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
168                  GAME_FRAME_DELAY);
169 }
170
171 static void InitToonControls()
172 {
173   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[GAME_MODE_DEFAULT];
174   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[ctrl->num_anims];
175   int mode_nr, anim_nr, part_nr;
176   int control = IMG_INTERNAL_GLOBAL_TOON_DEFAULT;
177   int num_toons = MAX_NUM_TOONS;
178   int i;
179
180   if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
181     num_toons = global.num_toons;
182
183   mode_nr = GAME_MODE_DEFAULT;
184   anim_nr = ctrl->num_anims;
185
186   anim->nr = anim_nr;
187   anim->mode_nr = mode_nr;
188   anim->control_info = graphic_info[control];
189
190   anim->num_parts = 0;
191   anim->part_counter = 0;
192   anim->active_part_nr = 0;
193
194   anim->has_base = FALSE;
195
196   anim->init_delay_counter = 0;
197
198   anim->state = ANIM_STATE_INACTIVE;
199
200   part_nr = 0;
201
202   for (i = 0; i < num_toons; i++)
203   {
204     struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
205     int graphic = IMG_TOON_1 + i;
206     int control = graphic;
207
208     part->nr = part_nr;
209     part->anim_nr = anim_nr;
210     part->mode_nr = mode_nr;
211     part->graphic = graphic;
212     part->graphic_info = graphic_info[graphic];
213     part->control_info = graphic_info[control];
214
215     part->graphic_info.anim_delay *= part->graphic_info.step_delay;
216
217     part->control_info.init_delay_fixed = 0;
218     part->control_info.init_delay_random = 150;
219
220     part->control_info.x = ARG_UNDEFINED_VALUE;
221     part->control_info.y = ARG_UNDEFINED_VALUE;
222
223     part->initial_anim_sync_frame = 0;
224
225     part->step_delay = 0;
226     part->step_delay_value = graphic_info[control].step_delay;
227
228     part->state = ANIM_STATE_INACTIVE;
229     part->last_game_status = -1;
230
231     anim->num_parts++;
232     part_nr++;
233   }
234
235   ctrl->num_anims++;
236 }
237
238 void InitGlobalAnimControls()
239 {
240   int m, a, p;
241   int mode_nr, anim_nr, part_nr;
242   int graphic, control;
243
244   anim_sync_frame = 0;
245
246   ResetDelayCounter(&anim_sync_frame_delay);
247
248   for (m = 0; m < NUM_SPECIAL_GFX_ARGS; m++)
249   {
250     mode_nr = m;
251
252     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
253
254     ctrl->nr = mode_nr;
255     ctrl->num_anims = 0;
256
257     anim_nr = 0;
258
259     for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
260     {
261       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
262       int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
263
264       control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
265
266       // if no base animation parameters defined, use default values
267       if (control == IMG_UNDEFINED)
268         control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
269
270       anim->nr = anim_nr;
271       anim->mode_nr = mode_nr;
272       anim->control_info = graphic_info[control];
273
274       anim->num_parts = 0;
275       anim->part_counter = 0;
276       anim->active_part_nr = 0;
277
278       anim->has_base = FALSE;
279
280       anim->init_delay_counter = 0;
281
282       anim->state = ANIM_STATE_INACTIVE;
283
284       part_nr = 0;
285
286       for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
287       {
288         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
289
290         graphic = global_anim_info[a].graphic[p][m];
291         control = global_anim_info[ctrl_id].graphic[p][m];
292
293         if (graphic == IMG_UNDEFINED || graphic_info[graphic].bitmap == NULL ||
294             control == IMG_UNDEFINED)
295           continue;
296
297 #if 0
298         printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n",
299                m, a, p, mode_nr, anim_nr, part_nr, control);
300 #endif
301
302         part->nr = part_nr;
303         part->anim_nr = anim_nr;
304         part->mode_nr = mode_nr;
305         part->graphic = graphic;
306         part->graphic_info = graphic_info[graphic];
307         part->control_info = graphic_info[control];
308
309         part->initial_anim_sync_frame = 0;
310
311         part->step_delay = 0;
312         part->step_delay_value = graphic_info[control].step_delay;
313
314         part->state = ANIM_STATE_INACTIVE;
315         part->last_game_status = -1;
316
317         if (p < GLOBAL_ANIM_ID_PART_BASE)
318         {
319           anim->num_parts++;
320           part_nr++;
321         }
322         else
323         {
324           anim->base = *part;
325           anim->has_base = TRUE;
326         }
327       }
328
329       if (anim->num_parts > 0 || anim->has_base)
330       {
331         ctrl->num_anims++;
332         anim_nr++;
333       }
334     }
335   }
336
337   InitToonControls();
338 }
339
340 void DrawGlobalAnimExt(int drawing_stage)
341 {
342   int mode_nr;
343
344   if (game_status == GAME_MODE_LOADING)
345     do_animations = FALSE;
346
347   if (!do_animations || !setup.toons)
348     return;
349
350   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
351     DoAnimationExt();
352
353   for (mode_nr = 0; mode_nr < NUM_SPECIAL_GFX_ARGS; mode_nr++)
354   {
355     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
356     int anim_nr;
357
358     if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
359         mode_nr != game_status)
360       continue;
361
362     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
363     {
364       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
365       struct GraphicInfo *c = &anim->control_info;
366       int part_first, part_last;
367       int part_nr;
368
369       if (!(anim->state & ANIM_STATE_RUNNING))
370         continue;
371
372       part_first = part_last = anim->active_part_nr;
373
374       if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
375       {
376         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
377
378         part_first = 0;
379         part_last = num_parts - 1;
380       }
381
382       for (part_nr = part_first; part_nr <= part_last; part_nr++)
383       {
384         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
385         struct GraphicInfo *g = &part->graphic_info;
386         Bitmap *src_bitmap;
387         int src_x, src_y;
388         int width  = g->width;
389         int height = g->height;
390         int dst_x = part->x;
391         int dst_y = part->y;
392         int cut_x = 0;
393         int cut_y = 0;
394         int sync_frame;
395         int frame;
396
397         if (!(part->state & ANIM_STATE_RUNNING))
398           continue;
399
400         if (part->drawing_stage != drawing_stage)
401           continue;
402
403         if (part->x < 0)
404         {
405           dst_x = 0;
406           width += part->x;
407           cut_x = -part->x;
408         }
409         else if (part->x > part->viewport_width - g->width)
410           width -= (part->x - (part->viewport_width - g->width));
411
412         if (part->y < 0)
413         {
414           dst_y = 0;
415           height += part->y;
416           cut_y = -part->y;
417         }
418         else if (part->y > part->viewport_height - g->height)
419           height -= (part->y - (part->viewport_height - g->height));
420
421         dst_x += part->viewport_x;
422         dst_y += part->viewport_y;
423
424         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
425         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
426                                   g->anim_mode, g->anim_start_frame,
427                                   sync_frame);
428
429         getFixedGraphicSource(part->graphic, frame, &src_bitmap,
430                               &src_x, &src_y);
431
432         src_x += cut_x;
433         src_y += cut_y;
434
435         BlitToScreenMasked(src_bitmap, src_x, src_y, width, height,
436                            dst_x, dst_y);
437       }
438     }
439   }
440 }
441
442 void DrawGlobalAnim(int drawing_stage)
443 {
444   if (!do_animations || !setup.toons)
445     return;
446
447   DrawGlobalAnimExt(drawing_stage);
448 }
449
450 boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
451 {
452   int viewport_x;
453   int viewport_y;
454   int viewport_width;
455   int viewport_height;
456   boolean changed = FALSE;
457
458   if (part->last_game_status == game_status)
459     return FALSE;
460
461   part->last_game_status = game_status;
462
463   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
464
465   if (part->control_info.class == get_hash_from_key("window") ||
466       part->control_info.class == get_hash_from_key("border"))
467   {
468     viewport_x = 0;
469     viewport_y = 0;
470     viewport_width  = WIN_XSIZE;
471     viewport_height = WIN_YSIZE;
472
473     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
474   }
475   else if (part->control_info.class == get_hash_from_key("door_1"))
476   {
477     viewport_x = DX;
478     viewport_y = DY;
479     viewport_width  = DXSIZE;
480     viewport_height = DYSIZE;
481   }
482   else if (part->control_info.class == get_hash_from_key("door_2"))
483   {
484     viewport_x = VX;
485     viewport_y = VY;
486     viewport_width  = VXSIZE;
487     viewport_height = VYSIZE;
488   }
489   else          // default: "playfield"
490   {
491     viewport_x = REAL_SX;
492     viewport_y = REAL_SY;
493     viewport_width  = FULL_SXSIZE;
494     viewport_height = FULL_SYSIZE;
495   }
496
497   if (viewport_x != part->viewport_x ||
498       viewport_y != part->viewport_y ||
499       viewport_width  != part->viewport_width ||
500       viewport_height != part->viewport_height)
501   {
502     part->viewport_x = viewport_x;
503     part->viewport_y = viewport_y;
504     part->viewport_width  = viewport_width;
505     part->viewport_height = viewport_height;
506
507     changed = TRUE;
508   }
509
510   return changed;
511 }
512
513 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
514 {
515   struct GraphicInfo *g = &part->graphic_info;
516   struct GraphicInfo *c = &part->control_info;
517   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
518
519   if (viewport_changed)
520     state |= ANIM_STATE_RESTART;
521
522   if (state & ANIM_STATE_RESTART)
523   {
524     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
525
526     part->init_delay_counter =
527       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
528
529     part->anim_delay_counter =
530       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
531
532     part->initial_anim_sync_frame =
533       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
534
535     if (c->direction & MV_HORIZONTAL)
536     {
537       int pos_bottom = part->viewport_height - g->height;
538
539       if (c->position == POS_TOP)
540         part->y = 0;
541       else if (c->position == POS_UPPER)
542         part->y = GetSimpleRandom(pos_bottom / 2);
543       else if (c->position == POS_MIDDLE)
544         part->y = pos_bottom / 2;
545       else if (c->position == POS_LOWER)
546         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
547       else if (c->position == POS_BOTTOM)
548         part->y = pos_bottom;
549       else
550         part->y = GetSimpleRandom(pos_bottom);
551
552       if (c->direction == MV_RIGHT)
553       {
554         part->step_xoffset = c->step_offset;
555         part->x = -g->width + part->step_xoffset;
556       }
557       else
558       {
559         part->step_xoffset = -c->step_offset;
560         part->x = part->viewport_width + part->step_xoffset;
561       }
562
563       part->step_yoffset = 0;
564     }
565     else if (c->direction & MV_VERTICAL)
566     {
567       int pos_right = part->viewport_width - g->width;
568
569       if (c->position == POS_LEFT)
570         part->x = 0;
571       else if (c->position == POS_RIGHT)
572         part->x = pos_right;
573       else
574         part->x = GetSimpleRandom(pos_right);
575
576       if (c->direction == MV_DOWN)
577       {
578         part->step_yoffset = c->step_offset;
579         part->y = -g->height + part->step_yoffset;
580       }
581       else
582       {
583         part->step_yoffset = -c->step_offset;
584         part->y = part->viewport_height + part->step_yoffset;
585       }
586
587       part->step_xoffset = 0;
588     }
589     else
590     {
591       part->x = 0;
592       part->y = 0;
593
594       part->step_xoffset = 0;
595       part->step_yoffset = 0;
596     }
597
598     if (c->x != ARG_UNDEFINED_VALUE)
599       part->x = c->x;
600     if (c->y != ARG_UNDEFINED_VALUE)
601       part->y = c->y;
602
603     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
604       part->step_xoffset = c->step_xoffset;
605     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
606       part->step_yoffset = c->step_yoffset;
607   }
608
609   if (part->init_delay_counter > 0)
610   {
611     part->init_delay_counter--;
612
613     return ANIM_STATE_WAITING;
614   }
615
616   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
617       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
618       (part->y <= -g->height             && part->step_yoffset <= 0) ||
619       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
620     return ANIM_STATE_RESTART;
621
622   if (part->anim_delay_counter > 0)
623   {
624     part->anim_delay_counter--;
625
626     if (part->anim_delay_counter == 0)
627     {
628       part->post_delay_counter =
629         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
630
631       if (part->post_delay_counter > 0)
632         return ANIM_STATE_RUNNING;
633
634       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
635     }
636   }
637
638   if (part->post_delay_counter > 0)
639   {
640     part->post_delay_counter--;
641
642     if (part->post_delay_counter == 0)
643       return ANIM_STATE_RESTART;
644
645     return ANIM_STATE_WAITING;
646   }
647
648   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
649                        anim_sync_frame))
650     return ANIM_STATE_RUNNING;
651
652 #if 0
653   {
654     static unsigned int last_counter = -1;
655     unsigned int counter = Counter();
656
657     printf("::: NEXT ANIM PART [%d, %d]\n",
658            anim_sync_frame, counter - last_counter);
659
660     last_counter = counter;
661   }
662 #endif
663
664   part->x += part->step_xoffset;
665   part->y += part->step_yoffset;
666
667   return ANIM_STATE_RUNNING;
668 }
669
670 void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
671 {
672   struct GlobalAnimPartControlInfo *part;
673   struct GraphicInfo *c = &anim->control_info;
674   boolean skip = FALSE;
675
676 #if 0
677   printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
678          anim->mode_nr, anim->nr, anim->num_parts);
679   printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
680 #endif
681
682 #if 0
683   printf("::: %s(%d): %d, %d, %d [%d]\n",
684          (action == ANIM_START ? "ANIM_START" :
685           action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
686           action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
687          anim->nr,
688          anim->state & ANIM_STATE_RESTART,
689          anim->state & ANIM_STATE_WAITING,
690          anim->state & ANIM_STATE_RUNNING,
691          anim->num_parts);
692 #endif
693
694   switch (action)
695   {
696     case ANIM_START:
697       anim->state = ANIM_STATE_RESTART;
698       anim->part_counter = 0;
699       anim->active_part_nr = 0;
700       skip = TRUE;
701
702       break;
703
704     case ANIM_CONTINUE:
705       if (anim->state == ANIM_STATE_INACTIVE)
706         skip = TRUE;
707
708       break;
709
710     case ANIM_STOP:
711       anim->state = ANIM_STATE_INACTIVE;
712       skip = TRUE;
713
714       break;
715
716     default:
717       break;
718   }
719
720   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
721   {
722     int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
723     int i;
724
725 #if 0
726     printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
727            anim->mode_nr, anim->nr, num_parts);
728 #endif
729
730     for (i = 0; i < num_parts; i++)
731     {
732       part = &anim->part[i];
733
734       switch (action)
735       {
736         case ANIM_START:
737           anim->state = ANIM_STATE_RUNNING;
738           part->state = ANIM_STATE_RESTART;
739           skip = TRUE;
740
741           break;
742
743         case ANIM_CONTINUE:
744           if (part->state == ANIM_STATE_INACTIVE)
745             skip = TRUE;
746
747           break;
748
749         case ANIM_STOP:
750           part->state = ANIM_STATE_INACTIVE;
751           skip = TRUE;
752
753           break;
754
755         default:
756           break;
757       }
758
759       if (skip)
760         continue;
761
762       part->state = HandleGlobalAnim_Part(part, part->state);
763     }
764
765     return;
766   }
767
768   if (skip)
769     return;
770
771   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
772     anim->active_part_nr = getGlobalAnimationPart(anim);
773
774   part = &anim->part[anim->active_part_nr];
775
776   part->state = ANIM_STATE_RUNNING;
777
778   anim->state = HandleGlobalAnim_Part(part, anim->state);
779
780   if (anim->state & ANIM_STATE_RESTART)
781     anim->part_counter++;
782 }
783
784 void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
785 {
786   int i;
787
788 #if 0
789   printf("::: HandleGlobalAnim_Mode: %d => %d\n",
790          ctrl->nr, ctrl->num_anims);
791 #endif
792
793   for (i = 0; i < ctrl->num_anims; i++)
794     HandleGlobalAnim_Main(&ctrl->anim[i], action);
795 }
796
797 void HandleGlobalAnim(int action)
798 {
799 #if 0
800   printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
801 #endif
802
803   HandleGlobalAnim_Mode(&global_anim_ctrl[GAME_MODE_DEFAULT], action);
804   HandleGlobalAnim_Mode(&global_anim_ctrl[game_status], action);
805 }
806
807 void InitAnimation()
808 {
809   // HandleAnimation(ANIM_START);
810
811 #if 0
812   printf("::: InitAnimation\n");
813 #endif
814
815   // InitCounter();
816
817   InitGlobalAnimControls();
818
819   HandleGlobalAnim(ANIM_START);
820
821   do_animations = TRUE;
822 }
823
824 void StopAnimation()
825 {
826   // HandleAnimation(ANIM_STOP);
827
828 #if 0
829   printf("::: StopAnimation\n");
830 #endif
831
832   HandleGlobalAnim(ANIM_STOP);
833
834   do_animations = FALSE;
835 }
836
837 static void DoAnimationExt()
838 {
839 #if 0
840   printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
841 #endif
842
843 #if 1
844   WaitUntilDelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value);
845   anim_sync_frame++;
846 #else
847   if (DelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value))
848     anim_sync_frame++;
849 #endif
850
851   HandleGlobalAnim(ANIM_CONTINUE);
852
853 #if 1
854   // force screen redraw in next frame to continue drawing global animations
855   redraw_mask = REDRAW_ALL;
856 #endif
857 }
858
859 void DoAnimation()
860 {
861   // HandleAnimation(ANIM_CONTINUE);
862
863 #if 1
864   // force screen redraw in next frame to continue drawing global animations
865   redraw_mask = REDRAW_ALL;
866 #endif
867 }