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