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