improved definition of constants for toon animations
[rocksndiamonds.git] / src / cartoons.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // cartoons.c
10 // ============================================================================
11
12 #include "cartoons.h"
13 #include "main.h"
14 #include "tools.h"
15
16
17 /* values for global toon animation definition */
18 #define NUM_GLOBAL_TOON_ANIMS           1
19 #define NUM_GLOBAL_TOON_PARTS           MAX_NUM_TOONS
20
21 /* values for global animation definition (including toons) */
22 #define NUM_GLOBAL_ANIMS_AND_TOONS      (NUM_GLOBAL_ANIMS +             \
23                                          NUM_GLOBAL_TOON_ANIMS)
24 #define NUM_GLOBAL_ANIM_PARTS_AND_TOONS MAX(NUM_GLOBAL_ANIM_PARTS_ALL,  \
25                                             NUM_GLOBAL_TOON_PARTS)
26
27 struct GlobalAnimPartControlInfo
28 {
29   int nr;
30   int anim_nr;
31   int mode_nr;
32
33   int graphic;
34   struct GraphicInfo graphic_info;
35   struct GraphicInfo control_info;
36
37   int x, y;
38   int step_xoffset, step_yoffset;
39
40   unsigned int initial_anim_sync_frame;
41   unsigned int step_delay, step_delay_value;
42
43   int init_delay_counter;
44   int anim_delay_counter;
45   int post_delay_counter;
46
47   int state;
48 };
49
50 struct GlobalAnimMainControlInfo
51 {
52   struct GlobalAnimPartControlInfo base;
53   struct GlobalAnimPartControlInfo part[NUM_GLOBAL_ANIM_PARTS_AND_TOONS];
54
55   int nr;
56   int mode_nr;
57
58   struct GraphicInfo control_info;
59
60   int num_parts;
61   int part_counter;
62   int active_part_nr;
63
64   boolean has_base;
65
66   int init_delay_counter;
67
68   int state;
69 };
70
71 struct GlobalAnimControlInfo
72 {
73   struct GlobalAnimMainControlInfo anim[NUM_GLOBAL_ANIMS_AND_TOONS];
74
75   int nr;
76   int num_anims;
77 };
78
79
80 /* forward declaration for internal use */
81 static void DoAnimationExt(void);
82
83 static struct GlobalAnimControlInfo global_anim_ctrl[NUM_SPECIAL_GFX_ARGS];
84 static struct ToonInfo toons[MAX_NUM_TOONS];
85
86 static unsigned int anim_sync_frame = 0;
87 static unsigned int anim_sync_frame_delay = 0;
88 static unsigned int anim_sync_frame_delay_value = GAME_FRAME_DELAY;
89
90 static boolean do_animations = FALSE;
91
92
93 static int getGlobalAnimationPart(struct GlobalAnimMainControlInfo *anim)
94 {
95   struct GraphicInfo *c = &anim->control_info;
96   int last_anim_random_frame = gfx.anim_random_frame;
97   int part_nr;
98
99   gfx.anim_random_frame = -1;   // (use simple, ad-hoc random numbers)
100
101   part_nr = getAnimationFrame(anim->num_parts, 1,
102                               c->anim_mode, c->anim_start_frame,
103                               anim->part_counter);
104
105   gfx.anim_random_frame = last_anim_random_frame;
106
107   return part_nr;
108 }
109
110 static void PrepareBackbuffer()
111 {
112   if (game_status != GAME_MODE_PLAYING)
113     return;
114
115   BlitScreenToBitmap(backbuffer);
116 }
117
118 boolean ToonNeedsRedraw()
119 {
120   return TRUE;
121 }
122
123 void InitToons()
124 {
125   int num_toons = MAX_NUM_TOONS;
126   int i;
127
128   if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
129     num_toons = global.num_toons;
130
131   for (i = 0; i < num_toons; i++)
132   {
133     int graphic = IMG_TOON_1 + i;
134     struct FileInfo *image = getImageListEntryFromImageID(graphic);
135
136     toons[i].bitmap = graphic_info[graphic].bitmap;
137
138     toons[i].src_x = graphic_info[graphic].src_x;
139     toons[i].src_y = graphic_info[graphic].src_y;
140
141     toons[i].width  = graphic_info[graphic].width;
142     toons[i].height = graphic_info[graphic].height;
143
144     toons[i].anim_frames      = graphic_info[graphic].anim_frames;
145     toons[i].anim_delay       = graphic_info[graphic].anim_delay;
146     toons[i].anim_mode        = graphic_info[graphic].anim_mode;
147     toons[i].anim_start_frame = graphic_info[graphic].anim_start_frame;
148
149     toons[i].step_offset = graphic_info[graphic].step_offset;
150     toons[i].step_delay  = graphic_info[graphic].step_delay;
151
152     toons[i].direction = image->parameter[GFX_ARG_DIRECTION];
153     toons[i].position = image->parameter[GFX_ARG_POSITION];
154   }
155
156   InitToonScreen(bitmap_db_toons,
157                  BackToFront, PrepareBackbuffer, ToonNeedsRedraw,
158                  toons, num_toons,
159                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
160                  GAME_FRAME_DELAY);
161 }
162
163 static void InitToonControls()
164 {
165   struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[GAME_MODE_DEFAULT];
166   struct GlobalAnimMainControlInfo *anim = &ctrl->anim[ctrl->num_anims];
167   int mode_nr, anim_nr, part_nr;
168   int control = IMG_INTERNAL_GLOBAL_TOON_DEFAULT;
169   int num_toons = MAX_NUM_TOONS;
170   int i;
171
172   if (global.num_toons >= 0 && global.num_toons < MAX_NUM_TOONS)
173     num_toons = global.num_toons;
174
175   mode_nr = GAME_MODE_DEFAULT;
176   anim_nr = ctrl->num_anims;
177
178   anim->nr = anim_nr;
179   anim->mode_nr = mode_nr;
180   anim->control_info = graphic_info[control];
181
182   anim->num_parts = 0;
183   anim->part_counter = 0;
184   anim->active_part_nr = 0;
185
186   anim->has_base = FALSE;
187
188   anim->init_delay_counter = 0;
189
190   anim->state = ANIM_STATE_INACTIVE;
191
192   part_nr = 0;
193
194   for (i = 0; i < num_toons; i++)
195   {
196     struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
197     int graphic = IMG_TOON_1 + i;
198     int control = graphic;
199
200     part->nr = part_nr;
201     part->anim_nr = anim_nr;
202     part->mode_nr = mode_nr;
203     part->graphic = graphic;
204     part->graphic_info = graphic_info[graphic];
205     part->control_info = graphic_info[control];
206
207     part->graphic_info.anim_delay *= part->graphic_info.step_delay;
208
209     part->control_info.init_delay_fixed = 0;
210     part->control_info.init_delay_random = 150;
211
212     part->control_info.x = ARG_UNDEFINED_VALUE;
213     part->control_info.y = ARG_UNDEFINED_VALUE;
214
215     part->step_delay = 0;
216     part->step_delay_value = graphic_info[control].step_delay;
217
218     part->state = ANIM_STATE_INACTIVE;
219
220     anim->num_parts++;
221     part_nr++;
222   }
223
224   ctrl->num_anims++;
225 }
226
227 void InitGlobalAnimControls()
228 {
229   int m, a, p;
230   int mode_nr, anim_nr, part_nr;
231   int graphic, control;
232
233   anim_sync_frame = 0;
234
235   ResetDelayCounter(&anim_sync_frame_delay);
236
237   for (m = 0; m < NUM_SPECIAL_GFX_ARGS; m++)
238   {
239     mode_nr = m;
240
241     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
242
243     ctrl->nr = mode_nr;
244     ctrl->num_anims = 0;
245
246     anim_nr = 0;
247
248     for (a = 0; a < NUM_GLOBAL_ANIMS; a++)
249     {
250       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
251       int ctrl_id = GLOBAL_ANIM_ID_CONTROL_FIRST + a;
252
253       control = global_anim_info[ctrl_id].graphic[GLOBAL_ANIM_ID_PART_BASE][m];
254
255       // if no base animation parameters defined, use default values
256       if (control == IMG_UNDEFINED)
257         control = IMG_INTERNAL_GLOBAL_ANIM_DEFAULT;
258
259       anim->nr = anim_nr;
260       anim->mode_nr = mode_nr;
261       anim->control_info = graphic_info[control];
262
263       anim->num_parts = 0;
264       anim->part_counter = 0;
265       anim->active_part_nr = 0;
266
267       anim->has_base = FALSE;
268
269       anim->init_delay_counter = 0;
270
271       anim->state = ANIM_STATE_INACTIVE;
272
273       part_nr = 0;
274
275       for (p = 0; p < NUM_GLOBAL_ANIM_PARTS_ALL; p++)
276       {
277         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
278
279         graphic = global_anim_info[a].graphic[p][m];
280         control = global_anim_info[ctrl_id].graphic[p][m];
281
282         if (graphic == IMG_UNDEFINED || graphic_info[graphic].bitmap == NULL ||
283             control == IMG_UNDEFINED)
284           continue;
285
286 #if 0
287         printf("::: mode == %d, anim = %d, part = %d [%d, %d, %d] [%d]\n",
288                m, a, p, mode_nr, anim_nr, part_nr, control);
289 #endif
290
291         part->nr = part_nr;
292         part->anim_nr = anim_nr;
293         part->mode_nr = mode_nr;
294         part->graphic = graphic;
295         part->graphic_info = graphic_info[graphic];
296         part->control_info = graphic_info[control];
297
298         part->step_delay = 0;
299         part->step_delay_value = graphic_info[control].step_delay;
300
301         part->state = ANIM_STATE_INACTIVE;
302
303         if (p < GLOBAL_ANIM_ID_PART_BASE)
304         {
305           anim->num_parts++;
306           part_nr++;
307         }
308         else
309         {
310           anim->base = *part;
311           anim->has_base = TRUE;
312         }
313       }
314
315       if (anim->num_parts > 0 || anim->has_base)
316       {
317         ctrl->num_anims++;
318         anim_nr++;
319       }
320     }
321   }
322
323   InitToonControls();
324 }
325
326 void DrawGlobalAnim()
327 {
328   int mode_nr;
329
330   if (game_status == GAME_MODE_LOADING)
331     do_animations = FALSE;
332
333   if (!do_animations || !setup.toons)
334     return;
335
336   DoAnimationExt();
337
338   for (mode_nr = 0; mode_nr < NUM_SPECIAL_GFX_ARGS; mode_nr++)
339   {
340     struct GlobalAnimControlInfo *ctrl = &global_anim_ctrl[mode_nr];
341     int anim_nr;
342
343     if (mode_nr != GFX_SPECIAL_ARG_DEFAULT &&
344         mode_nr != game_status)
345       continue;
346
347     for (anim_nr = 0; anim_nr < ctrl->num_anims; anim_nr++)
348     {
349       struct GlobalAnimMainControlInfo *anim = &ctrl->anim[anim_nr];
350       struct GraphicInfo *c = &anim->control_info;
351       int part_first, part_last;
352       int part_nr;
353
354       if (!(anim->state & ANIM_STATE_RUNNING))
355         continue;
356
357       part_first = part_last = anim->active_part_nr;
358
359       if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
360       {
361         int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
362
363         part_first = 0;
364         part_last = num_parts - 1;
365       }
366
367       for (part_nr = part_first; part_nr <= part_last; part_nr++)
368       {
369         struct GlobalAnimPartControlInfo *part = &anim->part[part_nr];
370         struct GraphicInfo *g = &part->graphic_info;
371         Bitmap *src_bitmap;
372         int src_x, src_y;
373         int width  = g->width;
374         int height = g->height;
375         int dst_x = part->x;
376         int dst_y = part->y;
377         int cut_x = 0;
378         int cut_y = 0;
379         int sync_frame;
380         int frame;
381
382         if (!(part->state & ANIM_STATE_RUNNING))
383           continue;
384
385         if (part->x < 0)
386         {
387           dst_x = 0;
388           width += part->x;
389           cut_x = -part->x;
390         }
391         else if (part->x > FULL_SXSIZE - g->width)
392           width -= (part->x - (FULL_SXSIZE - g->width));
393
394         if (part->y < 0)
395         {
396           dst_y = 0;
397           height += part->y;
398           cut_y = -part->y;
399         }
400         else if (part->y > FULL_SYSIZE - g->height)
401           height -= (part->y - (FULL_SYSIZE - g->height));
402
403         dst_x += REAL_SX;
404         dst_y += REAL_SY;
405
406         sync_frame = anim_sync_frame - part->initial_anim_sync_frame;
407         frame = getAnimationFrame(g->anim_frames, g->anim_delay,
408                                   g->anim_mode, g->anim_start_frame,
409                                   sync_frame);
410
411         getFixedGraphicSource(part->graphic, frame, &src_bitmap,
412                               &src_x, &src_y);
413
414         src_x += cut_x;
415         src_y += cut_y;
416
417         BlitToScreenMasked(src_bitmap, src_x, src_y, width, height,
418                            dst_x, dst_y);
419       }
420     }
421   }
422 }
423
424 int HandleGlobalAnim_Part(struct GlobalAnimPartControlInfo *part, int state)
425 {
426   struct GraphicInfo *g = &part->graphic_info;
427   struct GraphicInfo *c = &part->control_info;
428
429   if (state & ANIM_STATE_RESTART)
430   {
431     ResetDelayCounterExt(&part->step_delay, anim_sync_frame);
432
433     part->init_delay_counter =
434       (c->init_delay_fixed + GetSimpleRandom(c->init_delay_random));
435
436     part->anim_delay_counter =
437       (c->anim_delay_fixed + GetSimpleRandom(c->anim_delay_random));
438
439     part->initial_anim_sync_frame =
440       (g->anim_global_sync ? 0 : anim_sync_frame + part->init_delay_counter);
441
442     if (c->direction & MV_HORIZONTAL)
443     {
444       int pos_bottom = FULL_SYSIZE - g->height;
445
446       if (c->position == POS_TOP)
447         part->y = 0;
448       else if (c->position == POS_UPPER)
449         part->y = GetSimpleRandom(pos_bottom / 2);
450       else if (c->position == POS_MIDDLE)
451         part->y = pos_bottom / 2;
452       else if (c->position == POS_LOWER)
453         part->y = pos_bottom / 2 + GetSimpleRandom(pos_bottom / 2);
454       else if (c->position == POS_BOTTOM)
455         part->y = pos_bottom;
456       else
457         part->y = GetSimpleRandom(pos_bottom);
458
459       if (c->direction == MV_RIGHT)
460       {
461         part->step_xoffset = c->step_offset;
462         part->x = -g->width + part->step_xoffset;
463       }
464       else
465       {
466         part->step_xoffset = -c->step_offset;
467         part->x = FULL_SXSIZE + part->step_xoffset;
468       }
469
470       part->step_yoffset = 0;
471     }
472     else if (c->direction & MV_VERTICAL)
473     {
474       int pos_right = FULL_SXSIZE - g->width;
475
476       if (c->position == POS_LEFT)
477         part->x = 0;
478       else if (c->position == POS_RIGHT)
479         part->x = pos_right;
480       else
481         part->x = GetSimpleRandom(pos_right);
482
483       if (c->direction == MV_DOWN)
484       {
485         part->step_yoffset = c->step_offset;
486         part->y = -g->height + part->step_yoffset;
487       }
488       else
489       {
490         part->step_yoffset = -c->step_offset;
491         part->y = FULL_SYSIZE + part->step_yoffset;
492       }
493
494       part->step_xoffset = 0;
495     }
496     else
497     {
498       part->x = 0;
499       part->y = 0;
500
501       part->step_xoffset = 0;
502       part->step_yoffset = 0;
503     }
504
505     if (c->x != ARG_UNDEFINED_VALUE)
506       part->x = c->x;
507     if (c->y != ARG_UNDEFINED_VALUE)
508       part->y = c->y;
509
510     if (c->step_xoffset != ARG_UNDEFINED_VALUE)
511       part->step_xoffset = c->step_xoffset;
512     if (c->step_yoffset != ARG_UNDEFINED_VALUE)
513       part->step_yoffset = c->step_yoffset;
514   }
515
516   if (part->init_delay_counter > 0)
517   {
518     part->init_delay_counter--;
519
520     return ANIM_STATE_WAITING;
521   }
522
523   if ((part->x <= -g->width    && part->step_xoffset <= 0) ||
524       (part->x >=  FULL_SXSIZE && part->step_xoffset >= 0) ||
525       (part->y <= -g->height   && part->step_yoffset <= 0) ||
526       (part->y >=  FULL_SYSIZE && part->step_yoffset >= 0))
527     return ANIM_STATE_RESTART;
528
529   if (part->anim_delay_counter > 0)
530   {
531     part->anim_delay_counter--;
532
533     if (part->anim_delay_counter == 0)
534     {
535       part->post_delay_counter =
536         (c->post_delay_fixed + GetSimpleRandom(c->post_delay_random));
537
538       if (part->post_delay_counter > 0)
539         return ANIM_STATE_RUNNING;
540
541       return ANIM_STATE_RESTART | ANIM_STATE_RUNNING;
542     }
543   }
544
545   if (part->post_delay_counter > 0)
546   {
547     part->post_delay_counter--;
548
549     if (part->post_delay_counter == 0)
550       return ANIM_STATE_RESTART;
551
552     return ANIM_STATE_WAITING;
553   }
554
555   if (!DelayReachedExt(&part->step_delay, part->step_delay_value,
556                        anim_sync_frame))
557     return ANIM_STATE_RUNNING;
558
559 #if 0
560   {
561     static unsigned int last_counter = -1;
562     unsigned int counter = Counter();
563
564     printf("::: NEXT ANIM PART [%d, %d]\n",
565            anim_sync_frame, counter - last_counter);
566
567     last_counter = counter;
568   }
569 #endif
570
571   part->x += part->step_xoffset;
572   part->y += part->step_yoffset;
573
574   return ANIM_STATE_RUNNING;
575 }
576
577 void HandleGlobalAnim_Main(struct GlobalAnimMainControlInfo *anim, int action)
578 {
579   struct GlobalAnimPartControlInfo *part;
580   struct GraphicInfo *c = &anim->control_info;
581   boolean skip = FALSE;
582
583 #if 0
584   printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
585          anim->mode_nr, anim->nr, anim->num_parts);
586   printf("::: %d, %d, %d\n", global.num_toons, setup.toons, num_toons);
587 #endif
588
589 #if 0
590   printf("::: %s(%d): %d, %d, %d [%d]\n",
591          (action == ANIM_START ? "ANIM_START" :
592           action == ANIM_CONTINUE ? "ANIM_CONTINUE" :
593           action == ANIM_STOP ? "ANIM_STOP" : "(should not happen)"),
594          anim->nr,
595          anim->state & ANIM_STATE_RESTART,
596          anim->state & ANIM_STATE_WAITING,
597          anim->state & ANIM_STATE_RUNNING,
598          anim->num_parts);
599 #endif
600
601   switch (action)
602   {
603     case ANIM_START:
604       anim->state = ANIM_STATE_RESTART;
605       anim->part_counter = 0;
606       anim->active_part_nr = 0;
607       skip = TRUE;
608
609       break;
610
611     case ANIM_CONTINUE:
612       if (anim->state == ANIM_STATE_INACTIVE)
613         skip = TRUE;
614
615       break;
616
617     case ANIM_STOP:
618       anim->state = ANIM_STATE_INACTIVE;
619       skip = TRUE;
620
621       break;
622
623     default:
624       break;
625   }
626
627   if (c->anim_mode & ANIM_ALL || anim->num_parts == 0)
628   {
629     int num_parts = anim->num_parts + (anim->has_base ? 1 : 0);
630     int i;
631
632 #if 0
633     printf("::: HandleGlobalAnim_Main: %d, %d => %d\n",
634            anim->mode_nr, anim->nr, num_parts);
635 #endif
636
637     for (i = 0; i < num_parts; i++)
638     {
639       part = &anim->part[i];
640
641       switch (action)
642       {
643         case ANIM_START:
644           anim->state = ANIM_STATE_RUNNING;
645           part->state = ANIM_STATE_RESTART;
646           skip = TRUE;
647
648           break;
649
650         case ANIM_CONTINUE:
651           if (part->state == ANIM_STATE_INACTIVE)
652             skip = TRUE;
653
654           break;
655
656         case ANIM_STOP:
657           part->state = ANIM_STATE_INACTIVE;
658           skip = TRUE;
659
660           break;
661
662         default:
663           break;
664       }
665
666       if (skip)
667         continue;
668
669       part->state = HandleGlobalAnim_Part(part, part->state);
670     }
671
672     return;
673   }
674
675   if (skip)
676     return;
677
678   if (anim->state & ANIM_STATE_RESTART)         // directly after restart
679     anim->active_part_nr = getGlobalAnimationPart(anim);
680
681   part = &anim->part[anim->active_part_nr];
682
683   part->state = ANIM_STATE_RUNNING;
684
685   anim->state = HandleGlobalAnim_Part(part, anim->state);
686
687   if (anim->state & ANIM_STATE_RESTART)
688     anim->part_counter++;
689 }
690
691 void HandleGlobalAnim_Mode(struct GlobalAnimControlInfo *ctrl, int action)
692 {
693   int i;
694
695 #if 0
696   printf("::: HandleGlobalAnim_Mode: %d => %d\n",
697          ctrl->nr, ctrl->num_anims);
698 #endif
699
700   for (i = 0; i < ctrl->num_anims; i++)
701     HandleGlobalAnim_Main(&ctrl->anim[i], action);
702 }
703
704 void HandleGlobalAnim(int action)
705 {
706 #if 0
707   printf("::: HandleGlobalAnim [mode == %d]\n", game_status);
708 #endif
709
710   HandleGlobalAnim_Mode(&global_anim_ctrl[GAME_MODE_DEFAULT], action);
711   HandleGlobalAnim_Mode(&global_anim_ctrl[game_status], action);
712 }
713
714 void InitAnimation()
715 {
716   // HandleAnimation(ANIM_START);
717
718 #if 0
719   printf("::: InitAnimation\n");
720 #endif
721
722   // InitCounter();
723
724   InitGlobalAnimControls();
725
726   HandleGlobalAnim(ANIM_START);
727
728   do_animations = TRUE;
729 }
730
731 void StopAnimation()
732 {
733   // HandleAnimation(ANIM_STOP);
734
735 #if 0
736   printf("::: StopAnimation\n");
737 #endif
738
739   HandleGlobalAnim(ANIM_STOP);
740
741   do_animations = FALSE;
742 }
743
744 static void DoAnimationExt()
745 {
746 #if 0
747   printf("::: DoAnimation [%d, %d]\n", anim_sync_frame, Counter());
748 #endif
749
750 #if 1
751   WaitUntilDelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value);
752   anim_sync_frame++;
753 #else
754   if (DelayReached(&anim_sync_frame_delay, anim_sync_frame_delay_value))
755     anim_sync_frame++;
756 #endif
757
758   HandleGlobalAnim(ANIM_CONTINUE);
759
760 #if 1
761   // force screen redraw in next frame to continue drawing global animations
762   redraw_mask = REDRAW_ALL;
763 #endif
764 }
765
766 void DoAnimation()
767 {
768   // HandleAnimation(ANIM_CONTINUE);
769
770 #if 1
771   // force screen redraw in next frame to continue drawing global animations
772   redraw_mask = REDRAW_ALL;
773 #endif
774 }