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