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