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