rnd-19990205-1
[rocksndiamonds.git] / src / cartoons.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  cartoons.c                                              *
12 ***********************************************************/
13
14 #include "cartoons.h"
15 #include "main.h"
16 #include "misc.h"
17 #include "tools.h"
18
19 static void HandleAnimation(int);
20 static boolean AnimateToon(int, boolean);
21 static void DrawAnim(Pixmap, 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         XCopyArea(display,fieldbuffer,backbuffer,gc,
149                   fx,fy, SXSIZE,SYSIZE,
150                   SX,SY);
151       }
152
153       return;
154       break;
155     case ANIM_CONTINUE:
156       break;
157     case ANIM_STOP:
158       redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
159
160       /* Redraw background even when in direct drawing mode */
161       draw_mode = setup.direct_draw;
162       setup.direct_draw = FALSE;
163
164       BackToFront();
165
166       setup.direct_draw = draw_mode;
167
168       return;
169       break;
170     default:
171       break;
172   }
173
174   if (reset_delay)
175   {
176     animstart_delay = Counter();
177     animstart_delay_value = SimpleRND(3000);
178     reset_delay = FALSE;
179   }
180
181   if (anim_restart)
182   {
183     if (!DelayReached(&animstart_delay, animstart_delay_value))
184       return;
185
186     toon_nr = SimpleRND(NUM_TOONS);
187   }
188
189   anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart);
190 }
191
192 boolean AnimateToon(int toon_nr, boolean restart)
193 {
194   static int pos_x = 0, pos_y = 0;
195   static int delta_x = 0, delta_y = 0;
196   static int frame = 0, frame_step = 1;
197   static boolean horiz_move, vert_move;
198   static unsigned long anim_delay = 0;
199   static unsigned long anim_delay_value = 0;
200   static int width,height;
201   static int pad_x,pad_y;
202   static int cut_x,cut_y;
203   static int src_x, src_y;
204   static int dest_x, dest_y;
205   static struct AnimInfo toon[NUM_TOONS] =
206   {
207     {
208       DWARF_XSIZE, DWARF_YSIZE,
209       DWARF_X, DWARF_Y,
210       DWARF_FRAMES,
211       DWARF_FPS,
212       DWARF_STEPSIZE,
213       ANIM_NORMAL,
214       ANIMDIR_RIGHT,
215       ANIMPOS_DOWN
216     },
217     {
218       DWARF_XSIZE, DWARF_YSIZE,
219       DWARF_X, DWARF2_Y,
220       DWARF_FRAMES,
221       DWARF_FPS,
222       DWARF_STEPSIZE,
223       ANIM_NORMAL,
224       ANIMDIR_LEFT,
225       ANIMPOS_DOWN
226     },
227     {
228       JUMPER_XSIZE, JUMPER_YSIZE,
229       JUMPER_X, JUMPER_Y,
230       JUMPER_FRAMES,
231       JUMPER_FPS,
232       JUMPER_STEPSIZE,
233       ANIM_NORMAL,
234       ANIMDIR_RIGHT,
235       ANIMPOS_DOWN
236     },
237     {
238       CLOWN_XSIZE, CLOWN_YSIZE,
239       CLOWN_X, CLOWN_Y,
240       CLOWN_FRAMES,
241       CLOWN_FPS,
242       CLOWN_STEPSIZE,
243       ANIM_NORMAL,
244       ANIMDIR_UP,
245       ANIMPOS_ANY
246     },
247     {
248       BIRD_XSIZE, BIRD_YSIZE,
249       BIRD1_X, BIRD1_Y,
250       BIRD_FRAMES,
251       BIRD_FPS,
252       BIRD_STEPSIZE,
253       ANIM_OSCILLATE,
254       ANIMDIR_RIGHT,
255       ANIMPOS_UPPER
256     },
257     {
258       BIRD_XSIZE, BIRD_YSIZE,
259       BIRD2_X, BIRD2_Y,
260       BIRD_FRAMES,
261       BIRD_FPS,
262       BIRD_STEPSIZE,
263       ANIM_OSCILLATE,
264       ANIMDIR_LEFT,
265       ANIMPOS_UPPER
266     },
267     {
268       GAMETOON_XSIZE, GAMETOON_YSIZE,
269       ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
270       ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
271       GAMETOON_FRAMES_4,
272       GAMETOON_FPS,
273       GAMETOON_STEPSIZE,
274       ANIM_NORMAL,
275       ANIMDIR_LEFT,
276       ANIMPOS_DOWN
277     },
278     {
279       GAMETOON_XSIZE, GAMETOON_YSIZE,
280       ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
281       ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
282       GAMETOON_FRAMES_4,
283       GAMETOON_FPS,
284       GAMETOON_STEPSIZE,
285       ANIM_NORMAL,
286       ANIMDIR_RIGHT,
287       ANIMPOS_DOWN
288     },
289     {
290       GAMETOON_XSIZE, GAMETOON_YSIZE,
291       ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
292       ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
293       GAMETOON_FRAMES_4,
294       GAMETOON_FPS,
295       GAMETOON_STEPSIZE,
296       ANIM_NORMAL,
297       ANIMDIR_LEFT,
298       ANIMPOS_DOWN
299     },
300     {
301       GAMETOON_XSIZE, GAMETOON_YSIZE,
302       ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
303       ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
304       GAMETOON_FRAMES_4,
305       GAMETOON_FPS,
306       GAMETOON_STEPSIZE,
307       ANIM_NORMAL,
308       ANIMDIR_RIGHT,
309       ANIMPOS_DOWN
310     },
311     {
312       GAMETOON_XSIZE, GAMETOON_YSIZE,
313       ((GFX_MAULWURF_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
314       ((GFX_MAULWURF_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
315       GAMETOON_FRAMES_4,
316       GAMETOON_FPS,
317       GAMETOON_STEPSIZE,
318       ANIM_NORMAL,
319       ANIMDIR_LEFT,
320       ANIMPOS_DOWN
321     },
322     {
323       GAMETOON_XSIZE, GAMETOON_YSIZE,
324       ((GFX_MAULWURF_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
325       ((GFX_MAULWURF_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
326       GAMETOON_FRAMES_4,
327       GAMETOON_FPS,
328       GAMETOON_STEPSIZE,
329       ANIM_NORMAL,
330       ANIMDIR_RIGHT,
331       ANIMPOS_DOWN
332     },
333     {
334       GAMETOON_XSIZE, GAMETOON_YSIZE,
335       ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
336       ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
337       GAMETOON_FRAMES_4,
338       GAMETOON_FPS,
339       GAMETOON_STEPSIZE,
340       ANIM_NORMAL,
341       ANIMDIR_LEFT,
342       ANIMPOS_DOWN
343     },
344     {
345       GAMETOON_XSIZE, GAMETOON_YSIZE,
346       ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
347       ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
348       GAMETOON_FRAMES_4,
349       GAMETOON_FPS,
350       GAMETOON_STEPSIZE,
351       ANIM_NORMAL,
352       ANIMDIR_RIGHT,
353       ANIMPOS_DOWN
354     },
355     {
356       GAMETOON_XSIZE, GAMETOON_YSIZE,
357       ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
358       ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
359       GAMETOON_FRAMES_4,
360       GAMETOON_FPS,
361       GAMETOON_STEPSIZE,
362       ANIM_NORMAL,
363       ANIMDIR_LEFT,
364       ANIMPOS_DOWN
365     },
366     {
367       GAMETOON_XSIZE, GAMETOON_YSIZE,
368       ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
369       ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
370       GAMETOON_FRAMES_4,
371       GAMETOON_FPS,
372       GAMETOON_STEPSIZE,
373       ANIM_NORMAL,
374       ANIMDIR_RIGHT,
375       ANIMPOS_DOWN
376     },
377     {
378       GAMETOON_XSIZE, GAMETOON_YSIZE,
379       ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
380       ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
381       GAMETOON_FRAMES_8,
382       GAMETOON_FPS,
383       GAMETOON_STEPSIZE,
384       ANIM_NORMAL,
385       ANIMDIR_LEFT,
386       ANIMPOS_ANY
387     },
388     {
389       GAMETOON_XSIZE, GAMETOON_YSIZE,
390       ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
391       ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
392       GAMETOON_FRAMES_8,
393       GAMETOON_FPS,
394       GAMETOON_STEPSIZE,
395       ANIM_NORMAL,
396       ANIMDIR_RIGHT,
397       ANIMPOS_ANY
398     },
399   };
400   struct AnimInfo *anim = &toon[toon_nr];
401   Pixmap anim_pixmap = (toon_nr < 6 ? pix[PIX_TOONS] : pix[PIX_HEROES]);
402   GC anim_clip_gc = (toon_nr < 6 ? clip_gc[PIX_TOONS] : clip_gc[PIX_HEROES]);
403
404   if (restart)
405   {
406     horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
407     vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
408     anim_delay_value = 1000/anim->frames_per_second;
409     frame = 0;
410
411     if (horiz_move)
412     {
413       if (anim->position==ANIMPOS_UP)
414         pos_y = 0;
415       else if (anim->position==ANIMPOS_DOWN)
416         pos_y = FULL_SYSIZE-anim->height;
417       else if (anim->position==ANIMPOS_UPPER)
418         pos_y = SimpleRND((FULL_SYSIZE-anim->height)/2);
419       else
420         pos_y = SimpleRND(FULL_SYSIZE-anim->height);
421
422       if (anim->direction==ANIMDIR_RIGHT)
423       {
424         delta_x = anim->stepsize;
425         pos_x = -anim->width+delta_x;
426       }
427       else
428       {
429         delta_x = -anim->stepsize;
430         pos_x = FULL_SXSIZE+delta_x;
431       }
432       delta_y = 0;
433     }
434     else
435     {
436       if (anim->position==ANIMPOS_LEFT)
437         pos_x = 0;
438       else if (anim->position==ANIMPOS_RIGHT)
439         pos_x = FULL_SXSIZE-anim->width;
440       else
441         pos_x = SimpleRND(FULL_SXSIZE-anim->width);
442
443       if (anim->direction==ANIMDIR_DOWN)
444       {
445         delta_y = anim->stepsize;
446         pos_y = -anim->height+delta_y;
447       }
448       else
449       {
450         delta_y = -anim->stepsize;
451         pos_y = FULL_SYSIZE+delta_y;
452       }
453       delta_x = 0;
454     }
455   }
456
457   if (pos_x <= -anim->width  - anim->stepsize ||
458       pos_x >=  FULL_SXSIZE  + anim->stepsize ||
459       pos_y <= -anim->height - anim->stepsize ||
460       pos_y >=  FULL_SYSIZE  + anim->stepsize)
461     return(TRUE);
462
463   if (!DelayReached(&anim_delay, anim_delay_value))
464   {
465     if ((game_status == HELPSCREEN ||
466          (game_status == MAINMENU && redraw_mask & REDRAW_MICROLEVEL))
467         && !restart)
468       DrawAnim(anim_pixmap, anim_clip_gc,
469                src_x + cut_x, src_y + cut_y, width, height,
470                REAL_SX + dest_x, REAL_SY + dest_y, pad_x, pad_y);
471
472     return(FALSE);
473   }
474
475   if (pos_x<-anim->width)
476     pos_x = -anim->width;
477   else if (pos_x>FULL_SXSIZE)
478     pos_x = FULL_SXSIZE;
479   if (pos_y<-anim->height)
480     pos_y = -anim->height;
481   else if (pos_y>FULL_SYSIZE)
482     pos_y = FULL_SYSIZE;
483
484   pad_x = (horiz_move ? anim->stepsize : 0);
485   pad_y = (vert_move  ? anim->stepsize : 0);
486   src_x = anim->src_x + frame * anim->width;
487   src_y = anim->src_y;
488   dest_x = pos_x;
489   dest_y = pos_y;
490   cut_x = cut_y = 0;
491   width  = anim->width;
492   height = anim->height;
493
494   if (pos_x<0)
495   {
496     dest_x = 0;
497     width += pos_x;
498     cut_x = -pos_x;
499   }
500   else if (pos_x>FULL_SXSIZE-anim->width)
501     width -= (pos_x - (FULL_SXSIZE-anim->width));
502
503   if (pos_y<0)
504   {
505     dest_y = 0;
506     height += pos_y;
507     cut_y = -pos_y;
508   }
509   else if (pos_y>FULL_SYSIZE-anim->height)
510     height -= (pos_y - (FULL_SYSIZE-anim->height));
511
512   DrawAnim(anim_pixmap,anim_clip_gc,
513            src_x+cut_x,src_y+cut_y, width,height,
514            REAL_SX+dest_x,REAL_SY+dest_y, pad_x,pad_y);
515
516   pos_x += delta_x;
517   pos_y += delta_y;
518   frame += frame_step;
519
520   if (frame<0 || frame>=anim->frames)
521   {
522     if (anim->pingpong)
523     {
524       frame_step *= -1;
525       frame = (frame<0 ? 1 : anim->frames-2);
526     }
527     else
528       frame = (frame<0 ? anim->frames-1 : 0);
529   }
530
531   return(FALSE);
532 }
533
534 void DrawAnim(Pixmap toon_pixmap, GC toon_clip_gc,
535               int src_x, int src_y, int width, int height,
536               int dest_x, int dest_y, int pad_x, int pad_y)
537 {
538   int buf_x = DOOR_GFX_PAGEX3, buf_y = DOOR_GFX_PAGEY1;
539
540 #if 1
541   /* special method to avoid flickering interference with BackToFront() */
542   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
543             width+2*pad_x,height+2*pad_y, buf_x,buf_y);
544   XSetClipOrigin(display,toon_clip_gc,dest_x-src_x,dest_y-src_y);
545   XCopyArea(display,toon_pixmap,backbuffer,toon_clip_gc,
546             src_x,src_y, width,height, dest_x,dest_y);
547   XCopyArea(display,backbuffer,window,gc, dest_x-pad_x,dest_y-pad_y,
548             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
549   BackToFront();
550   XCopyArea(display,pix[PIX_DB_DOOR],backbuffer,gc, buf_x,buf_y,
551             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
552 #else
553   /* normal method, causing flickering interference with BackToFront() */
554   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
555             width+2*pad_x,height+2*pad_y, buf_x,buf_y);
556   XSetClipOrigin(display,toon_clip_gc,
557                  buf_x-src_x+pad_x,buf_y-src_y+pad_y);
558   XCopyArea(display,toon_pixmap,pix[PIX_DB_DOOR],toon_clip_gc,
559             src_x,src_y, width,height, buf_x+pad_x,buf_y+pad_y);
560   XCopyArea(display,pix[PIX_DB_DOOR],window,gc, buf_x,buf_y,
561             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
562 #endif
563
564   XFlush(display);
565 }