8aee8a261633890fb2640692db382286a762df41
[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         DrawAllPlayers();
138
139         SetDrawtoField(DRAW_DIRECT);
140       }
141
142       if (soft_scrolling_on && game_status == PLAYING)
143       {
144         int fx = FX, fy = FY;
145
146         fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
147         fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
148
149         XCopyArea(display,fieldbuffer,backbuffer,gc,
150                   fx,fy, SXSIZE,SYSIZE,
151                   SX,SY);
152       }
153
154       return;
155       break;
156     case ANIM_CONTINUE:
157       break;
158     case ANIM_STOP:
159       redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
160
161       /* Redraw background even when in direct drawing mode */
162       draw_mode = direct_draw_on;
163       direct_draw_on = FALSE;
164
165       BackToFront();
166
167       direct_draw_on = draw_mode;
168
169       return;
170       break;
171     default:
172       break;
173   }
174
175   if (reset_delay)
176   {
177     animstart_delay = Counter();
178     animstart_delay_value = SimpleRND(3000);
179     reset_delay = FALSE;
180   }
181
182   if (anim_restart)
183   {
184     if (!DelayReached(&animstart_delay, animstart_delay_value))
185       return;
186
187     toon_nr = SimpleRND(NUM_TOONS);
188   }
189
190   anim_restart = reset_delay = AnimateToon(toon_nr,anim_restart);
191 }
192
193 BOOL AnimateToon(int toon_nr, BOOL restart)
194 {
195   static pos_x = 0, pos_y = 0;
196   static delta_x = 0, delta_y = 0;
197   static int frame = 0, frame_step = 1;
198   static BOOL horiz_move, vert_move;
199   static long anim_delay = 0;
200   static int anim_delay_value = 0;
201   static int width,height;
202   static int pad_x,pad_y;
203   static int cut_x,cut_y;
204   static int src_x, src_y;
205   static int dest_x, dest_y;
206   static struct AnimInfo toon[NUM_TOONS] =
207   {
208     {
209       DWARF_XSIZE, DWARF_YSIZE,
210       DWARF_X, DWARF_Y,
211       DWARF_FRAMES,
212       DWARF_FPS,
213       DWARF_STEPSIZE,
214       ANIM_NORMAL,
215       ANIMDIR_RIGHT,
216       ANIMPOS_DOWN
217     },
218     {
219       DWARF_XSIZE, DWARF_YSIZE,
220       DWARF_X, DWARF2_Y,
221       DWARF_FRAMES,
222       DWARF_FPS,
223       DWARF_STEPSIZE,
224       ANIM_NORMAL,
225       ANIMDIR_LEFT,
226       ANIMPOS_DOWN
227     },
228     {
229       JUMPER_XSIZE, JUMPER_YSIZE,
230       JUMPER_X, JUMPER_Y,
231       JUMPER_FRAMES,
232       JUMPER_FPS,
233       JUMPER_STEPSIZE,
234       ANIM_NORMAL,
235       ANIMDIR_RIGHT,
236       ANIMPOS_DOWN
237     },
238     {
239       CLOWN_XSIZE, CLOWN_YSIZE,
240       CLOWN_X, CLOWN_Y,
241       CLOWN_FRAMES,
242       CLOWN_FPS,
243       CLOWN_STEPSIZE,
244       ANIM_NORMAL,
245       ANIMDIR_UP,
246       ANIMPOS_ANY
247     },
248     {
249       BIRD_XSIZE, BIRD_YSIZE,
250       BIRD1_X, BIRD1_Y,
251       BIRD_FRAMES,
252       BIRD_FPS,
253       BIRD_STEPSIZE,
254       ANIM_OSCILLATE,
255       ANIMDIR_RIGHT,
256       ANIMPOS_UPPER
257     },
258     {
259       BIRD_XSIZE, BIRD_YSIZE,
260       BIRD2_X, BIRD2_Y,
261       BIRD_FRAMES,
262       BIRD_FPS,
263       BIRD_STEPSIZE,
264       ANIM_OSCILLATE,
265       ANIMDIR_LEFT,
266       ANIMPOS_UPPER
267     },
268     {
269       GAMETOON_XSIZE, GAMETOON_YSIZE,
270       ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
271       ((GFX_SPIELER1_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
272       GAMETOON_FRAMES_4,
273       GAMETOON_FPS,
274       GAMETOON_STEPSIZE,
275       ANIM_NORMAL,
276       ANIMDIR_LEFT,
277       ANIMPOS_DOWN
278     },
279     {
280       GAMETOON_XSIZE, GAMETOON_YSIZE,
281       ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
282       ((GFX_SPIELER1_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
283       GAMETOON_FRAMES_4,
284       GAMETOON_FPS,
285       GAMETOON_STEPSIZE,
286       ANIM_NORMAL,
287       ANIMDIR_RIGHT,
288       ANIMPOS_DOWN
289     },
290     {
291       GAMETOON_XSIZE, GAMETOON_YSIZE,
292       ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
293       ((GFX_PINGUIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
294       GAMETOON_FRAMES_4,
295       GAMETOON_FPS,
296       GAMETOON_STEPSIZE,
297       ANIM_NORMAL,
298       ANIMDIR_LEFT,
299       ANIMPOS_DOWN
300     },
301     {
302       GAMETOON_XSIZE, GAMETOON_YSIZE,
303       ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
304       ((GFX_PINGUIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
305       GAMETOON_FRAMES_4,
306       GAMETOON_FPS,
307       GAMETOON_STEPSIZE,
308       ANIM_NORMAL,
309       ANIMDIR_RIGHT,
310       ANIMPOS_DOWN
311     },
312     {
313       GAMETOON_XSIZE, GAMETOON_YSIZE,
314       ((GFX_MAULWURF_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
315       ((GFX_MAULWURF_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
316       GAMETOON_FRAMES_4,
317       GAMETOON_FPS,
318       GAMETOON_STEPSIZE,
319       ANIM_NORMAL,
320       ANIMDIR_LEFT,
321       ANIMPOS_DOWN
322     },
323     {
324       GAMETOON_XSIZE, GAMETOON_YSIZE,
325       ((GFX_MAULWURF_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
326       ((GFX_MAULWURF_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
327       GAMETOON_FRAMES_4,
328       GAMETOON_FPS,
329       GAMETOON_STEPSIZE,
330       ANIM_NORMAL,
331       ANIMDIR_RIGHT,
332       ANIMPOS_DOWN
333     },
334     {
335       GAMETOON_XSIZE, GAMETOON_YSIZE,
336       ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
337       ((GFX_SCHWEIN_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
338       GAMETOON_FRAMES_4,
339       GAMETOON_FPS,
340       GAMETOON_STEPSIZE,
341       ANIM_NORMAL,
342       ANIMDIR_LEFT,
343       ANIMPOS_DOWN
344     },
345     {
346       GAMETOON_XSIZE, GAMETOON_YSIZE,
347       ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
348       ((GFX_SCHWEIN_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
349       GAMETOON_FRAMES_4,
350       GAMETOON_FPS,
351       GAMETOON_STEPSIZE,
352       ANIM_NORMAL,
353       ANIMDIR_RIGHT,
354       ANIMPOS_DOWN
355     },
356     {
357       GAMETOON_XSIZE, GAMETOON_YSIZE,
358       ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
359       ((GFX_DRACHE_LEFT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
360       GAMETOON_FRAMES_4,
361       GAMETOON_FPS,
362       GAMETOON_STEPSIZE,
363       ANIM_NORMAL,
364       ANIMDIR_LEFT,
365       ANIMPOS_DOWN
366     },
367     {
368       GAMETOON_XSIZE, GAMETOON_YSIZE,
369       ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
370       ((GFX_DRACHE_RIGHT - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
371       GAMETOON_FRAMES_4,
372       GAMETOON_FPS,
373       GAMETOON_STEPSIZE,
374       ANIM_NORMAL,
375       ANIMDIR_RIGHT,
376       ANIMPOS_DOWN
377     },
378     {
379       GAMETOON_XSIZE, GAMETOON_YSIZE,
380       ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
381       ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
382       GAMETOON_FRAMES_8,
383       GAMETOON_FPS,
384       GAMETOON_STEPSIZE,
385       ANIM_NORMAL,
386       ANIMDIR_LEFT,
387       ANIMPOS_ANY
388     },
389     {
390       GAMETOON_XSIZE, GAMETOON_YSIZE,
391       ((GFX_SONDE - GFX_START_ROCKSHEROES) % HEROES_PER_LINE)*TILEX,
392       ((GFX_SONDE - GFX_START_ROCKSHEROES) / HEROES_PER_LINE)*TILEY,
393       GAMETOON_FRAMES_8,
394       GAMETOON_FPS,
395       GAMETOON_STEPSIZE,
396       ANIM_NORMAL,
397       ANIMDIR_RIGHT,
398       ANIMPOS_ANY
399     },
400   };
401   struct AnimInfo *anim = &toon[toon_nr];
402   Pixmap anim_pixmap = (toon_nr < 6 ? pix[PIX_TOONS] : pix[PIX_HEROES]);
403   GC anim_clip_gc = (toon_nr < 6 ? clip_gc[PIX_TOONS] : clip_gc[PIX_HEROES]);
404
405   if (restart)
406   {
407     horiz_move = (anim->direction & (ANIMDIR_LEFT | ANIMDIR_RIGHT));
408     vert_move = (anim->direction & (ANIMDIR_UP | ANIMDIR_DOWN));
409     anim_delay_value = 1000/anim->frames_per_second;
410     frame = 0;
411
412     if (horiz_move)
413     {
414       if (anim->position==ANIMPOS_UP)
415         pos_y = 0;
416       else if (anim->position==ANIMPOS_DOWN)
417         pos_y = FULL_SYSIZE-anim->height;
418       else if (anim->position==ANIMPOS_UPPER)
419         pos_y = SimpleRND((FULL_SYSIZE-anim->height)/2);
420       else
421         pos_y = SimpleRND(FULL_SYSIZE-anim->height);
422
423       if (anim->direction==ANIMDIR_RIGHT)
424       {
425         delta_x = anim->stepsize;
426         pos_x = -anim->width+delta_x;
427       }
428       else
429       {
430         delta_x = -anim->stepsize;
431         pos_x = FULL_SXSIZE+delta_x;
432       }
433       delta_y = 0;
434     }
435     else
436     {
437       if (anim->position==ANIMPOS_LEFT)
438         pos_x = 0;
439       else if (anim->position==ANIMPOS_RIGHT)
440         pos_x = FULL_SXSIZE-anim->width;
441       else
442         pos_x = SimpleRND(FULL_SXSIZE-anim->width);
443
444       if (anim->direction==ANIMDIR_DOWN)
445       {
446         delta_y = anim->stepsize;
447         pos_y = -anim->height+delta_y;
448       }
449       else
450       {
451         delta_y = -anim->stepsize;
452         pos_y = FULL_SYSIZE+delta_y;
453       }
454       delta_x = 0;
455     }
456   }
457
458   if (pos_x <= -anim->width  - anim->stepsize ||
459       pos_x >=  FULL_SXSIZE  + anim->stepsize ||
460       pos_y <= -anim->height - anim->stepsize ||
461       pos_y >=  FULL_SYSIZE  + anim->stepsize)
462     return(TRUE);
463
464   if (!DelayReached(&anim_delay, anim_delay_value))
465   {
466     if (game_status==HELPSCREEN && !restart)
467       DrawAnim(anim_pixmap,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_pixmap,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(Pixmap toon_pixmap, 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   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
542             width+2*pad_x,height+2*pad_y, buf_x,buf_y);
543   XSetClipOrigin(display,toon_clip_gc,dest_x-src_x,dest_y-src_y);
544   XCopyArea(display,toon_pixmap,backbuffer,toon_clip_gc,
545             src_x,src_y, width,height, dest_x,dest_y);
546   XCopyArea(display,backbuffer,window,gc, 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   XCopyArea(display,pix[PIX_DB_DOOR],backbuffer,gc, 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   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,dest_x-pad_x,dest_y-pad_y,
554             width+2*pad_x,height+2*pad_y, buf_x,buf_y);
555   XSetClipOrigin(display,toon_clip_gc,
556                  buf_x-src_x+pad_x,buf_y-src_y+pad_y);
557   XCopyArea(display,toon_pixmap,pix[PIX_DB_DOOR],toon_clip_gc,
558             src_x,src_y, width,height, buf_x+pad_x,buf_y+pad_y);
559   XCopyArea(display,pix[PIX_DB_DOOR],window,gc, buf_x,buf_y,
560             width+2*pad_x,height+2*pad_y, dest_x-pad_x,dest_y-pad_y);
561 #endif
562
563   XFlush(display);
564 }