fixed new animation mode (modifier) 'once' 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 mode_nr;
409
410   if (global.anim_status != anim_status_last)
411   {
412     boolean before_fading = (global.anim_status == GAME_MODE_PSEUDO_FADING);
413     boolean after_fading  = (anim_status_last   == GAME_MODE_PSEUDO_FADING);
414     int anim_classes_next = game_mode_anim_classes[global.anim_status_next];
415     int i;
416
417     // ---------- part 1 ------------------------------------------------------
418     // start or stop global animations by change of game mode
419     // (special handling of animations for "current screen" and "all screens")
420
421     // stop animations for last screen
422     HandleGlobalAnim(ANIM_STOP, anim_status_last);
423
424     // start animations for current screen
425     HandleGlobalAnim(ANIM_START, global.anim_status);
426
427     // start animations for all screens after loading new artwork set
428     if (anim_status_last == GAME_MODE_LOADING)
429       HandleGlobalAnim(ANIM_START, GAME_MODE_DEFAULT);
430
431     // ---------- part 2 ------------------------------------------------------
432     // start or stop global animations by change of animation class
433     // (generic handling of animations for "class of screens")
434
435     for (i = 0; i < NUM_ANIM_CLASSES; i++)
436     {
437       int anim_class_check = (1 << i);
438       int anim_class_game_mode = anim_class_game_modes[i];
439       int anim_class_last = anim_classes_last & anim_class_check;
440       int anim_class_next = anim_classes_next & anim_class_check;
441
442       // stop animations for changed screen class before fading to new screen
443       if (before_fading && anim_class_last && !anim_class_next)
444         HandleGlobalAnim(ANIM_STOP, anim_class_game_mode);
445
446       // start animations for changed screen class after fading to new screen
447       if (after_fading && !anim_class_last && anim_class_next)
448         HandleGlobalAnim(ANIM_START, anim_class_game_mode);
449     }
450
451     if (after_fading)
452       anim_classes_last = anim_classes_next;
453
454     anim_status_last = global.anim_status;
455   }
456
457   if (!setup.toons || global.anim_status == GAME_MODE_LOADING)
458     return;
459
460   if (drawing_stage == DRAW_GLOBAL_ANIM_STAGE_1)
461     DoAnimationExt();
462
463   for (mode_nr = 0; mode_nr < NUM_GAME_MODES; mode_nr++)
464   {
465     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
466     int anim_nr;
467
468 #if 0
469     if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
470         mode_nr != game_status)
471       continue;
472 #endif
473
474     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
475     {
476       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
477       struct GraphicInfo *c = &anim->control_info;
478       int part_first, part_last;
479       int part_nr;
480
481       if (!(anim->state & ANIM_STATE_RUNNING))
482         continue;
483
484       part_first = part_last = anim->active_part_nr;
485
486       if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
487       {
488         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
489
490         part_first = 0;
491         part_last = num_parts - 1;
492       }
493
494       for (part_nr = part_first; part_nr <= part_last; part_nr++)
495       {
496         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
497         struct GraphicInfo *g = &part->graphic_info;
498         Bitmap *src_bitmap;
499         int src_x, src_y;
500         int width  = g->width;
501         int height = g->height;
502         int dst_x = part->x;
503         int dst_y = part->y;
504         int cut_x = 0;
505         int cut_y = 0;
506         int sync_frame;
507         int frame;
508
509         if (!(part->state & ANIM_STATE_RUNNING))
510           continue;
511
512         if (part->drawing_stage != drawing_stage)
513           continue;
514
515         if (part->x < 0)
516         {
517           dst_x = 0;
518           width += part->x;
519           cut_x = -part->x;
520         }
521         else if (part->x > part->viewport_width - g->width)
522           width -= (part->x - (part->viewport_width - g->width));
523
524         if (part->y < 0)
525         {
526           dst_y = 0;
527           height += part->y;
528           cut_y = -part->y;
529         }
530         else if (part->y > part->viewport_height - g->height)
531           height -= (part->y - (part->viewport_height - g->height));
532
533         dst_x += part->viewport_x;
534         dst_y += part->viewport_y;
535
536         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
537         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
538                                   g->anim_mode, g->anim_start_frame,
539                                   sync_frame);
540
541         getFixedGraphicSource(part->graphic, frame, &src_bitmap,
542                               &src_x, &src_y);
543
544         src_x += cut_x;
545         src_y += cut_y;
546
547         BlitToScreenMasked(src_bitmap, src_x, src_y, width, height,
548                            dst_x, dst_y);
549       }
550     }
551   }
552 }
553
554 void DrawGlobalAnim(int drawing_stage)
555 {
556   DrawGlobalAnimExt(drawing_stage);
557 }
558
559 boolean SetGlobalAnimPart_Viewport(struct GlobalAnimPartControlInfo *part)
560 {
561   int viewport_x;
562   int viewport_y;
563   int viewport_width;
564   int viewport_height;
565   boolean changed = FALSE;
566
567   if (part->last_anim_status == global.anim_status)
568     return FALSE;
569
570   part->last_anim_status = global.anim_status;
571
572   part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_1;
573
574   if (part->control_info.class == get_hash_from_key("window") ||
575       part->control_info.class == get_hash_from_key("border"))
576   {
577     viewport_x = 0;
578     viewport_y = 0;
579     viewport_width  = WIN_XSIZE;
580     viewport_height = WIN_YSIZE;
581
582     part->drawing_stage = DRAW_GLOBAL_ANIM_STAGE_2;
583   }
584   else if (part->control_info.class == get_hash_from_key("door_1"))
585   {
586     viewport_x = DX;
587     viewport_y = DY;
588     viewport_width  = DXSIZE;
589     viewport_height = DYSIZE;
590   }
591   else if (part->control_info.class == get_hash_from_key("door_2"))
592   {
593     viewport_x = VX;
594     viewport_y = VY;
595     viewport_width  = VXSIZE;
596     viewport_height = VYSIZE;
597   }
598   else          // default: "playfield"
599   {
600     viewport_x = REAL_SX;
601     viewport_y = REAL_SY;
602     viewport_width  = FULL_SXSIZE;
603     viewport_height = FULL_SYSIZE;
604   }
605
606   if (viewport_x != part->viewport_x ||
607       viewport_y != part->viewport_y ||
608       viewport_width  != part->viewport_width ||
609       viewport_height != part->viewport_height)
610   {
611     part->viewport_x = viewport_x;
612     part->viewport_y = viewport_y;
613     part->viewport_width  = viewport_width;
614     part->viewport_height = viewport_height;
615
616     changed = TRUE;
617   }
618
619   return changed;
620 }
621
622 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
623 {
624   struct GraphicInfo *g = &part->graphic_info;
625   struct GraphicInfo *c = &part->control_info;
626   boolean viewport_changed = SetGlobalAnimPart_Viewport(part);
627
628   if (viewport_changed)
629     state |= ANIM_STATE_RESTART;
630
631   if (state & ANIM_STATE_RESTART)
632   {
633     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
634
635     part->init_delay_counter =
636       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
637
638     part->anim_delay_counter =
639       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
640
641     part->initial_anim_sync_frame =
642       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
643
644     if (c->direction & MV_HORIZONTAL)
645     {
646       int pos_bottom = part->viewport_height - g->height;
647
648       if (c->position == POS_TOP)
649         part->y = 0;
650       else if (c->position == POS_UPPER)
651         part->y = GetSimpleRandom(pos_bottom / 2);
652       else if (c->position == POS_MIDDLE)
653         part->y = pos_bottom / 2;
654       else if (c->position == POS_LOWER)
655         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
656       else if (c->position == POS_BOTTOM)
657         part->y = pos_bottom;
658       else
659         part->y = GetSimpleRandom(pos_bottom);
660
661       if (c->direction == MV_RIGHT)
662       {
663         part->step_xoffset = c->step_offset;
664         part->x = -g->width + part->step_xoffset;
665       }
666       else
667       {
668         part->step_xoffset = -c->step_offset;
669         part->x = part->viewport_width + part->step_xoffset;
670       }
671
672       part->step_yoffset = 0;
673     }
674     else if (c->direction & MV_VERTICAL)
675     {
676       int pos_right = part->viewport_width - g->width;
677
678       if (c->position == POS_LEFT)
679         part->x = 0;
680       else if (c->position == POS_RIGHT)
681         part->x = pos_right;
682       else
683         part->x = GetSimpleRandom(pos_right);
684
685       if (c->direction == MV_DOWN)
686       {
687         part->step_yoffset = c->step_offset;
688         part->y = -g->height + part->step_yoffset;
689       }
690       else
691       {
692         part->step_yoffset = -c->step_offset;
693         part->y = part->viewport_height + part->step_yoffset;
694       }
695
696       part->step_xoffset = 0;
697     }
698     else
699     {
700       part->x = 0;
701       part->y = 0;
702
703       part->step_xoffset = 0;
704       part->step_yoffset = 0;
705     }
706
707     if (c->x != ARG_UNDEFINED_VALUE)
708       part->x = c->x;
709     if (c->y != ARG_UNDEFINED_VALUE)
710       part->y = c->y;
711
712     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
713       part->step_xoffset = c->step_xoffset;
714     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
715       part->step_yoffset = c->step_yoffset;
716   }
717
718   if (part->init_delay_counter > 0)
719   {
720     part->init_delay_counter--;
721
722     return ANIM_STATE_WAITING;
723   }
724
725   if ((part->x <= -g->width              && part->step_xoffset <= 0) ||
726       (part->x >=  part->viewport_width  && part->step_xoffset >= 0) ||
727       (part->y <= -g->height             && part->step_yoffset <= 0) ||
728       (part->y >=  part->viewport_height && part->step_yoffset >= 0))
729     return ANIM_STATE_RESTART;
730
731   if (part->anim_delay_counter > 0)
732   {
733     part->anim_delay_counter--;
734
735     if (part->anim_delay_counter == 0)
736     {
737       part->post_delay_counter =
738         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
739
740       if (part->post_delay_counter > 0)
741         return ANIM_STATE_RUNNING;
742
743       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
744     }
745   }
746
747   if (part->post_delay_counter > 0)
748   {
749     part->post_delay_counter--;
750
751     if (part->post_delay_counter == 0)
752       return ANIM_STATE_RESTART;
753
754     return ANIM_STATE_WAITING;
755   }
756
757   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
758                        anim_sync_frame))
759     return ANIM_STATE_RUNNING;
760
761 #if 0
762   {
763     static unsigned int last_counter = -1;
764     unsigned int counter = Counter();
765
766     printf("::: NEXT ANIM PART [%d, %d]\n",
767            anim_sync_frame, counter - last_counter);
768
769     last_counter = counter;
770   }
771 #endif
772
773   part->x += part->step_xoffset;
774   part->y += part->step_yoffset;
775
776   return ANIM_STATE_RUNNING;
777 }
778
779 void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
780 {
781   struct GlobalAnimPartControlInfo *part;
782   struct GraphicInfo *c = &anim->control_info;
783
784 #if 0
785   printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
786          anim->mode_nr, anim->nr, anim->num_parts);
787   printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
788 #endif
789
790 #if 0
791   printf("::: %s(%d): %d, %d, %d [%d]\n",
792          (action == ANIM_START ? "ANIM_START" :
793           action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
794           action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
795          anim->nr,
796          anim->state & ANIM_STATE_RESTART,
797          anim->state & ANIM_STATE_WAITING,
798          anim->state & ANIM_STATE_RUNNING,
799          anim->num_parts);
800 #endif
801
802   switch (action)
803   {
804     case ANIM_START:
805       anim->state = ANIM_STATE_RESTART;
806       anim->part_counter = 0;
807       anim->active_part_nr = 0;
808
809       break;
810
811     case ANIM_CONTINUE:
812       if (anim->state == ANIM_STATE_INACTIVE)
813         return;
814
815       break;
816
817     case ANIM_STOP:
818       anim->state = ANIM_STATE_INACTIVE;
819
820       return;
821
822     default:
823       break;
824   }
825
826   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
827   {
828     int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
829     int i;
830
831 #if 0
832     printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
833            anim->mode_nr, anim->nr, num_parts);
834 #endif
835
836     for (i = 0; i < num_parts; i++)
837     {
838       part = &anim->part[i];
839
840       switch (action)
841       {
842         case ANIM_START:
843           anim->state = ANIM_STATE_RUNNING;
844           part->state = ANIM_STATE_RESTART;
845
846           break;
847
848         case ANIM_CONTINUE:
849           if (part->state == ANIM_STATE_INACTIVE)
850             continue;
851
852           break;
853
854         case ANIM_STOP:
855           part->state = ANIM_STATE_INACTIVE;
856
857           continue;
858
859         default:
860           break;
861       }
862
863       part->state = HandleGlobalAnim_Part(part, part->state);
864
865       // when animation mode is "once", stop after animation was played once
866       if (c->anim_mode & ANIM_ONCE &&
867           part->state & ANIM_STATE_RESTART)
868         part->state = ANIM_STATE_INACTIVE;
869     }
870
871     return;
872   }
873
874   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
875     anim->active_part_nr = getGlobalAnimationPart(anim);
876
877   part = &anim->part[anim->active_part_nr];
878
879   part->state = ANIM_STATE_RUNNING;
880
881   anim->state = HandleGlobalAnim_Part(part, anim->state);
882
883   if (anim->state & ANIM_STATE_RESTART)
884     anim->part_counter++;
885
886   // when animation mode is "once", stop after all animations were played once
887   if (c->anim_mode & ANIM_ONCE &&
888       anim->part_counter == anim->num_parts)
889     anim->state = ANIM_STATE_INACTIVE;
890 }
891
892 void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
893 {
894   int i;
895
896 #if 0
897   printf("::: HandleGlobalAnim_Mode: %d => %d\n",
898          ctrl->nr, ctrl->num_anims);
899 #endif
900
901   for (i = 0; i < ctrl->num_anims; i++)
902     HandleGlobalAnim_Main(&ctrl->anim[i], action);
903 }
904
905 static void HandleGlobalAnim(int action, int game_mode)
906 {
907 #if 0
908   printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
909 #endif
910
911   HandleGlobalAnim_Mode(&global_anim_ctrl[game_mode], action);
912 }
913
914 void InitAnimation()
915 {
916 }
917
918 void StopAnimation()
919 {
920 }
921
922 static void DoAnimationExt()
923 {
924   int i;
925
926 #if 0
927   printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
928 #endif
929
930 #if 1
931   WaitUntilDelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value);
932   anim_sync_frame++;
933 #else
934   if (DelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value))
935     anim_sync_frame++;
936 #endif
937
938   for (i = 0; i < NUM_GAME_MODES; i++)
939     HandleGlobalAnim(ANIM_CONTINUE, i);
940
941 #if 1
942   // force screen redraw in next frame to continue drawing global animations
943   redraw_mask = REDRAW_ALL;
944 #endif
945 }
946
947 void DoAnimation()
948 {
949   // HandleAnimation(ANIM_CONTINUE);
950
951 #if 1
952   // force screen redraw in next frame to continue drawing global animations
953   redraw_mask = REDRAW_ALL;
954 #endif
955 }