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