rnd-20010120-5-src
[rocksndiamonds.git] / src / cartoons.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2001 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * cartoons.c                                               *
12 ***********************************************************/
13
14 #include "cartoons.h"
15 #include "main.h"
16 #include "tools.h"
17
18
19 static void HandleAnimation(int);
20 static boolean AnimateToon(int, boolean);
21 static void DrawAnim(Bitmap *, GC, int, int, int, int, int, int, int, int);
22
23 struct AnimInfo
24 {
25   int width, height;
26   int src_x, src_y;
27   int frames;
28   int frames_per_second;
29   int stepsize;
30   boolean pingpong;
31   int direction;
32   int position;
33 };
34
35 /* values for cartoon figures */
36 #define NUM_TOONS       18
37
38 #define DWARF_XSIZE     40
39 #define DWARF_YSIZE     48
40 #define DWARF_X         2
41 #define DWARF_Y         72
42 #define DWARF2_Y        186
43 #define DWARF_FRAMES    8
44 #define DWARF_FPS       10
45 #define DWARF_STEPSIZE  4
46 #define JUMPER_XSIZE    48
47 #define JUMPER_YSIZE    56
48 #define JUMPER_X        2
49 #define JUMPER_Y        125
50 #define JUMPER_FRAMES   8
51 #define JUMPER_FPS      10
52 #define JUMPER_STEPSIZE 4
53 #define CLOWN_XSIZE     80
54 #define CLOWN_YSIZE     110
55 #define CLOWN_X         327
56 #define CLOWN_Y         10
57 #define CLOWN_FRAMES    1
58 #define CLOWN_FPS       10
59 #define CLOWN_STEPSIZE  4
60 #define BIRD_XSIZE      32
61 #define BIRD_YSIZE      30
62 #define BIRD1_X         2
63 #define BIRD1_Y         2
64 #define BIRD2_X         2
65 #define BIRD2_Y         37
66 #define BIRD_FRAMES     8
67 #define BIRD_FPS        20
68 #define BIRD_STEPSIZE   4
69
70 #define GAMETOON_XSIZE          TILEX
71 #define GAMETOON_YSIZE          TILEY
72 #define GAMETOON_FRAMES_4       4
73 #define GAMETOON_FRAMES_8       8
74 #define GAMETOON_FPS            20
75 #define GAMETOON_STEPSIZE       4
76
77 #define ANIMDIR_LEFT    1
78 #define ANIMDIR_RIGHT   2
79 #define ANIMDIR_UP      4
80 #define ANIMDIR_DOWN    8
81
82 #define ANIMPOS_ANY     0
83 #define ANIMPOS_LEFT    1
84 #define ANIMPOS_RIGHT   2
85 #define ANIMPOS_UP      4
86 #define ANIMPOS_DOWN    8
87 #define ANIMPOS_UPPER   16
88
89 #define ANIM_START      0
90 #define ANIM_CONTINUE   1
91 #define ANIM_STOP       2
92
93 void InitAnimation()
94 {
95   HandleAnimation(ANIM_START);
96 }
97
98 void StopAnimation()
99 {
100   HandleAnimation(ANIM_STOP);
101 }
102
103 void DoAnimation()
104 {
105   HandleAnimation(ANIM_CONTINUE);
106 }
107
108 void HandleAnimation(int mode)
109 {
110   static unsigned long animstart_delay = -1;
111   static unsigned long animstart_delay_value = 0;
112   static boolean anim_restart = TRUE;
113   static boolean reset_delay = TRUE;
114   static int toon_nr = 0;
115   int draw_mode;
116
117   if (!setup.toons)
118     return;
119
120   switch(mode)
121   {
122     case ANIM_START:
123       anim_restart = TRUE;
124       reset_delay = TRUE;
125
126       /* Fill empty backbuffer for animation functions */
127       if (setup.direct_draw && game_status == PLAYING)
128       {
129         int xx,yy;
130
131         SetDrawtoField(DRAW_BACKBUFFER);
132
133         for(xx=0; xx<SCR_FIELDX; xx++)
134           for(yy=0; yy<SCR_FIELDY; yy++)
135             DrawScreenField(xx,yy);
136         DrawAllPlayers();
137
138         SetDrawtoField(DRAW_DIRECT);
139       }
140
141       if (setup.soft_scrolling && game_status == PLAYING)
142       {
143         int fx = FX, fy = FY;
144
145         fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
146         fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
147
148         BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
149       }
150
151       return;
152       break;
153     case ANIM_CONTINUE:
154       break;
155     case ANIM_STOP:
156       redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
157
158       /* Redraw background even when in direct drawing mode */
159       draw_mode = setup.direct_draw;
160       setup.direct_draw = FALSE;
161
162       BackToFront();
163
164       setup.direct_draw = draw_mode;
165
166       return;
167       break;
168     default:
169       break;
170   }
171
172   if (reset_delay)
173   {
174     animstart_delay = Counter();
175     animstart_delay_value = SimpleRND(3000);
176     reset_delay = FALSE;
177   }
178
179   if (anim_restart)
180   {
181     if (!DelayReached(&animstart_delay, animstart_delay_value))
182       return;
183
184     toon_nr = SimpleRND(NUM_TOONS);
185   }
186
187   anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart);
188 }
189
190 boolean AnimateToon(int toon_nr, boolean restart)
191 {
192   static int pos_x = 0, pos_y = 0;
193   static int delta_x = 0, delta_y = 0;
194   static int frame = 0, frame_step = 1;
195   static boolean horiz_move, vert_move;
196   static unsigned long anim_delay = 0;
197   static unsigned long anim_delay_value = 0;
198   static int width,height;
199   static int pad_x,pad_y;
200   static int cut_x,cut_y;
201   static int src_x, src_y;
202   static int dest_x, dest_y;
203   static struct AnimInfo toon[NUM_TOONS] =
204   {
205     {
206       DWARF_XSIZE, DWARF_YSIZE,
207       DWARF_X, DWARF_Y,
208       DWARF_FRAMES,
209       DWARF_FPS,
210       DWARF_STEPSIZE,
211       ANIM_NORMAL,
212       ANIMDIR_RIGHT,
213       ANIMPOS_DOWN
214     },
215     {
216       DWARF_XSIZE, DWARF_YSIZE,
217       DWARF_X, DWARF2_Y,
218       DWARF_FRAMES,
219       DWARF_FPS,
220       DWARF_STEPSIZE,
221       ANIM_NORMAL,
222       ANIMDIR_LEFT,
223       ANIMPOS_DOWN
224     },
225     {
226       JUMPER_XSIZE, JUMPER_YSIZE,
227       JUMPER_X, JUMPER_Y,
228       JUMPER_FRAMES,
229       JUMPER_FPS,
230       JUMPER_STEPSIZE,
231       ANIM_NORMAL,
232       ANIMDIR_RIGHT,
233       ANIMPOS_DOWN
234     },
235     {
236       CLOWN_XSIZE, CLOWN_YSIZE,
237       CLOWN_X, CLOWN_Y,
238       CLOWN_FRAMES,
239       CLOWN_FPS,
240       CLOWN_STEPSIZE,
241       ANIM_NORMAL,
242       ANIMDIR_UP,
243       ANIMPOS_ANY
244     },
245     {
246       BIRD_XSIZE, BIRD_YSIZE,
247       BIRD1_X, BIRD1_Y,
248       BIRD_FRAMES,
249       BIRD_FPS,
250       BIRD_STEPSIZE,
251       ANIM_OSCILLATE,
252       ANIMDIR_RIGHT,
253       ANIMPOS_UPPER
254     },
255     {
256       BIRD_XSIZE, BIRD_YSIZE,
257       BIRD2_X, BIRD2_Y,
258       BIRD_FRAMES,
259       BIRD_FPS,
260       BIRD_STEPSIZE,
261       ANIM_OSCILLATE,
262       ANIMDIR_LEFT,
263       ANIMPOS_UPPER
264     },
265     {
266       GAMETOON_XSIZE, GAMETOON_YSIZE,
267       ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
268       ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
269       GAMETOON_FRAMES_4,
270       GAMETOON_FPS,
271       GAMETOON_STEPSIZE,
272       ANIM_NORMAL,
273       ANIMDIR_LEFT,
274       ANIMPOS_DOWN
275     },
276     {
277       GAMETOON_XSIZE, GAMETOON_YSIZE,
278       ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
279       ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
280       GAMETOON_FRAMES_4,
281       GAMETOON_FPS,
282       GAMETOON_STEPSIZE,
283       ANIM_NORMAL,
284       ANIMDIR_RIGHT,
285       ANIMPOS_DOWN
286     },
287     {
288       GAMETOON_XSIZE, GAMETOON_YSIZE,
289       ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
290       ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
291       GAMETOON_FRAMES_4,
292       GAMETOON_FPS,
293       GAMETOON_STEPSIZE,
294       ANIM_NORMAL,
295       ANIMDIR_LEFT,
296       ANIMPOS_DOWN
297     },
298     {
299       GAMETOON_XSIZE, GAMETOON_YSIZE,
300       ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
301       ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
302       GAMETOON_FRAMES_4,
303       GAMETOON_FPS,
304       GAMETOON_STEPSIZE,
305       ANIM_NORMAL,
306       ANIMDIR_RIGHT,
307       ANIMPOS_DOWN
308     },
309     {
310       GAMETOON_XSIZE, GAMETOON_YSIZE,
311       ((GFX_MOLE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
312       ((GFX_MOLE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
313       GAMETOON_FRAMES_4,
314       GAMETOON_FPS,
315       GAMETOON_STEPSIZE,
316       ANIM_NORMAL,
317       ANIMDIR_LEFT,
318       ANIMPOS_DOWN
319     },
320     {
321       GAMETOON_XSIZE, GAMETOON_YSIZE,
322       ((GFX_MOLE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
323       ((GFX_MOLE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
324       GAMETOON_FRAMES_4,
325       GAMETOON_FPS,
326       GAMETOON_STEPSIZE,
327       ANIM_NORMAL,
328       ANIMDIR_RIGHT,
329       ANIMPOS_DOWN
330     },
331     {
332       GAMETOON_XSIZE, GAMETOON_YSIZE,
333       ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
334       ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
335       GAMETOON_FRAMES_4,
336       GAMETOON_FPS,
337       GAMETOON_STEPSIZE,
338       ANIM_NORMAL,
339       ANIMDIR_LEFT,
340       ANIMPOS_DOWN
341     },
342     {
343       GAMETOON_XSIZE, GAMETOON_YSIZE,
344       ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
345       ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
346       GAMETOON_FRAMES_4,
347       GAMETOON_FPS,
348       GAMETOON_STEPSIZE,
349       ANIM_NORMAL,
350       ANIMDIR_RIGHT,
351       ANIMPOS_DOWN
352     },
353     {
354       GAMETOON_XSIZE, GAMETOON_YSIZE,
355       ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
356       ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
357       GAMETOON_FRAMES_4,
358       GAMETOON_FPS,
359       GAMETOON_STEPSIZE,
360       ANIM_NORMAL,
361       ANIMDIR_LEFT,
362       ANIMPOS_DOWN
363     },
364     {
365       GAMETOON_XSIZE, GAMETOON_YSIZE,
366       ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
367       ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
368       GAMETOON_FRAMES_4,
369       GAMETOON_FPS,
370       GAMETOON_STEPSIZE,
371       ANIM_NORMAL,
372       ANIMDIR_RIGHT,
373       ANIMPOS_DOWN
374     },
375     {
376       GAMETOON_XSIZE, GAMETOON_YSIZE,
377       ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
378       ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
379       GAMETOON_FRAMES_8,
380       GAMETOON_FPS,
381       GAMETOON_STEPSIZE,
382       ANIM_NORMAL,
383       ANIMDIR_LEFT,
384       ANIMPOS_ANY
385     },
386     {
387       GAMETOON_XSIZE, GAMETOON_YSIZE,
388       ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
389       ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
390       GAMETOON_FRAMES_8,
391       GAMETOON_FPS,
392       GAMETOON_STEPSIZE,
393       ANIM_NORMAL,
394       ANIMDIR_RIGHT,
395       ANIMPOS_ANY
396     },
397   };
398   struct AnimInfo *anim = &toon[toon_nr];
399   int anim_bitmap_nr = (toon_nr < 6 ? PIX_TOONS : PIX_HEROES);
400   Bitmap *anim_bitmap = pix[anim_bitmap_nr];
401   GC anim_clip_gc = pix[anim_bitmap_nr]->stored_clip_gc;
402
403   if (restart)
404   {
405     horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
406     vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
407     anim_delay_value = 1000/anim->frames_per_second;
408     frame = 0;
409
410     if (horiz_move)
411     {
412       if (anim->position==ANIMPOS_UP)
413         pos_y = 0;
414       else if (anim->position==ANIMPOS_DOWN)
415         pos_y = FULL_SYSIZE-anim->height;
416       else if (anim->position==ANIMPOS_UPPER)
417         pos_y = SimpleRND((FULL_SYSIZE-anim->height)/2);
418       else
419         pos_y = SimpleRND(FULL_SYSIZE-anim->height);
420
421       if (anim->direction==ANIMDIR_RIGHT)
422       {
423         delta_x = anim->stepsize;
424         pos_x = -anim->width+delta_x;
425       }
426       else
427       {
428         delta_x = -anim->stepsize;
429         pos_x = FULL_SXSIZE+delta_x;
430       }
431       delta_y = 0;
432     }
433     else
434     {
435       if (anim->position==ANIMPOS_LEFT)
436         pos_x = 0;
437       else if (anim->position==ANIMPOS_RIGHT)
438         pos_x = FULL_SXSIZE-anim->width;
439       else
440         pos_x = SimpleRND(FULL_SXSIZE-anim->width);
441
442       if (anim->direction==ANIMDIR_DOWN)
443       {
444         delta_y = anim->stepsize;
445         pos_y = -anim->height+delta_y;
446       }
447       else
448       {
449         delta_y = -anim->stepsize;
450         pos_y = FULL_SYSIZE+delta_y;
451       }
452       delta_x = 0;
453     }
454   }
455
456   if (pos_x <= -anim->width  - anim->stepsize ||
457       pos_x >=  FULL_SXSIZE  + anim->stepsize ||
458       pos_y <= -anim->height - anim->stepsize ||
459       pos_y >=  FULL_SYSIZE  + anim->stepsize)
460     return(TRUE);
461
462   if (!DelayReached(&anim_delay, anim_delay_value))
463   {
464     if ((game_status == HELPSCREEN ||
465          (game_status == MAINMENU && redraw_mask & REDRAW_MICROLEVEL))
466         && !restart)
467       DrawAnim(anim_bitmap, anim_clip_gc,
468                src_x + cut_x, src_y + cut_y, width, height,
469                REAL_SX + dest_x, REAL_SY + dest_y, pad_x, pad_y);
470
471     return(FALSE);
472   }
473
474   if (pos_x<-anim->width)
475     pos_x = -anim->width;
476   else if (pos_x>FULL_SXSIZE)
477     pos_x = FULL_SXSIZE;
478   if (pos_y<-anim->height)
479     pos_y = -anim->height;
480   else if (pos_y>FULL_SYSIZE)
481     pos_y = FULL_SYSIZE;
482
483   pad_x = (horiz_move ? anim->stepsize : 0);
484   pad_y = (vert_move  ? anim->stepsize : 0);
485   src_x = anim->src_x + frame * anim->width;
486   src_y = anim->src_y;
487   dest_x = pos_x;
488   dest_y = pos_y;
489   cut_x = cut_y = 0;
490   width  = anim->width;
491   height = anim->height;
492
493   if (pos_x<0)
494   {
495     dest_x = 0;
496     width += pos_x;
497     cut_x = -pos_x;
498   }
499   else if (pos_x>FULL_SXSIZE-anim->width)
500     width -= (pos_x - (FULL_SXSIZE-anim->width));
501
502   if (pos_y<0)
503   {
504     dest_y = 0;
505     height += pos_y;
506     cut_y = -pos_y;
507   }
508   else if (pos_y>FULL_SYSIZE-anim->height)
509     height -= (pos_y - (FULL_SYSIZE-anim->height));
510
511   DrawAnim(anim_bitmap,anim_clip_gc,
512            src_x+cut_x,src_y+cut_y, width,height,
513            REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y);
514
515   pos_x += delta_x;
516   pos_y += delta_y;
517   frame += frame_step;
518
519   if (frame<0 || frame>=anim->frames)
520   {
521     if (anim->pingpong)
522     {
523       frame_step *= -1;
524       frame = (frame<0 ? 1 : anim->frames-2);
525     }
526     else
527       frame = (frame<0 ? anim->frames-1 : 0);
528   }
529
530   return(FALSE);
531 }
532
533 void DrawAnim(Bitmap *toon_bitmap, GC toon_clip_gc,
534               int src_x, int src_y, int width, int height,
535               int dest_x, int dest_y, int pad_x, int pad_y)
536 {
537   int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
538
539 #if 1
540   /* special method to avoid flickering interference with BackToFront() */
541   BlitBitmap(backbuffer, pix[PIX_DB_DOOR], dest_x-pad_x, dest_y-pad_y,
542              width+2*pad_x, height+2*pad_y, buf_x, buf_y);
543   SetClipOrigin(toon_bitmap, toon_clip_gc, dest_x-src_x, dest_y-src_y);
544   BlitBitmapMasked(toon_bitmap, backbuffer,
545                    src_x, src_y, width, height, dest_x, dest_y);
546   BlitBitmap(backbuffer, window, dest_x-pad_x, dest_y-pad_y,
547              width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
548   BackToFront();
549   BlitBitmap(pix[PIX_DB_DOOR], backbuffer, buf_x, buf_y,
550             width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
551 #else
552   /* normal method, causing flickering interference with BackToFront() */
553   BlitBitmap(backbuffer, pix[PIX_DB_DOOR], dest_x-pad_x, dest_y-pad_y,
554              width+2*pad_x, height+2*pad_y, buf_x, buf_y);
555   SetClipOrigin(toon_bitmap,toon_clip_gc, buf_x-src_x+pad_x,buf_y-src_y+pad_y);
556   BlitBitmapMasked(toon_bitmap, pix[PIX_DB_DOOR],
557                    src_x, src_y, width, height, buf_x+pad_x, buf_y+pad_y);
558   BlitBitmap(pix[PIX_DB_DOOR], window, buf_x, buf_y,
559              width+2*pad_x, height+2*pad_y, dest_x-pad_x, dest_y-pad_y);
560 #endif
561
562   FlushDisplay();
563 }