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