rnd-19980812
[rocksndiamonds.git] / src / tools.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 *  tools.c                                                 *
13 ***********************************************************/
14
15 #ifdef __FreeBSD__
16 #include <machine/joystick.h>
17 #endif
18
19 #include "tools.h"
20 #include "game.h"
21 #include "events.h"
22 #include "sound.h"
23 #include "misc.h"
24 #include "buttons.h"
25 #include "joystick.h"
26 #include "cartoons.h"
27
28 #include <math.h>
29
30 void SetDrawtoField(int mode)
31 {
32   if (mode == DRAW_BUFFERED && soft_scrolling_on)
33   {
34     FX = TILEX;
35     FY = TILEY;
36     BX1 = -1;
37     BY1 = -1;
38     BX2 = SCR_FIELDX;
39     BY2 = SCR_FIELDY;
40     redraw_x1 = 1;
41     redraw_y1 = 1;
42
43     drawto_field = fieldbuffer;
44   }
45   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
46   {
47     FX = SX;
48     FY = SY;
49     BX1 = 0;
50     BY1 = 0;
51     BX2 = SCR_FIELDX - 1;
52     BY2 = SCR_FIELDY - 1;
53     redraw_x1 = 0;
54     redraw_y1 = 0;
55
56     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
57   }
58 }
59
60 void BackToFront()
61 {
62   int x,y;
63   Drawable buffer = (drawto_field != window ? drawto_field : backbuffer);
64
65   if (direct_draw_on && game_status == PLAYING)
66     redraw_mask &= ~REDRAW_MAIN;
67
68
69
70   /*
71   if (ScreenMovPos && redraw_mask & REDRAW_FIELD)
72   {
73     redraw_mask |= REDRAW_FIELD;
74
75     printf("FULL SCREEN REDRAW FORCED by ScreenMovPos == %d\n", ScreenMovPos);
76   }
77   */
78
79
80
81   /*
82   if (ScreenMovPos && redraw_mask & REDRAW_TILES)
83   {
84     redraw_mask |= REDRAW_FIELD;
85
86     printf("FULL SCREEN REDRAW FORCED by ScreenMovPos == %d\n", ScreenMovPos);
87   }
88   */
89
90
91   /*
92   if (ScreenMovPos && !(redraw_mask & REDRAW_FIELD))
93   {
94     printf("OOPS!\n");
95
96     *((int *)NULL) = 0;
97   }
98   */
99
100   /*
101   if (IN_SCR_FIELD(JX2,JY2))
102     redraw[redraw_x1 + JX2][redraw_y1 + JY2] = 0;
103     */
104
105
106   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
107     redraw_mask |= REDRAW_FIELD;
108
109   if (redraw_mask & REDRAW_FIELD)
110     redraw_mask &= ~REDRAW_TILES;
111
112   /*
113   {
114     static int lastFrame = 0;
115
116     printf("FrameCounter: %d\n", FrameCounter);
117
118     if (FrameCounter != lastFrame + 1)
119     {
120       printf("SYNC LOST! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
121
122       if (FrameCounter > 100)
123         *((int *)NULL) = 0;
124     }
125
126     lastFrame = FrameCounter;
127   }
128   */
129
130   if (!redraw_mask)
131     return;
132
133   if (redraw_mask & REDRAW_ALL)
134   {
135     XCopyArea(display,backbuffer,window,gc,
136               0,0, WIN_XSIZE,WIN_YSIZE,
137               0,0);
138     redraw_mask = 0;
139   }
140
141   if (redraw_mask & REDRAW_FIELD)
142   {
143     int fx = FX + (PlayerMovDir & (MV_LEFT|MV_RIGHT) ? ScreenMovPos : 0);
144     int fy = FY + (PlayerMovDir & (MV_UP|MV_DOWN)    ? ScreenMovPos : 0);
145
146     if (game_status == PLAYING)
147     {
148       XCopyArea(display,buffer,window,gc,
149                 fx,fy, SXSIZE,SYSIZE,
150                 SX,SY);
151
152       /*
153       printf("FULL SCREEN REDRAW / ScreenMovPos == %d\n", ScreenMovPos);
154       */
155
156     }
157     else
158       XCopyArea(display,backbuffer,window,gc,
159                 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
160                 REAL_SX,REAL_SY);
161     redraw_mask &= ~REDRAW_MAIN;
162   }
163
164   if (redraw_mask & REDRAW_DOORS)
165   {
166     if (redraw_mask & REDRAW_DOOR_1)
167       XCopyArea(display,backbuffer,window,gc,
168                 DX,DY, DXSIZE,DYSIZE,
169                 DX,DY);
170     if (redraw_mask & REDRAW_DOOR_2)
171     {
172       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
173         XCopyArea(display,backbuffer,window,gc,
174                   VX,VY, VXSIZE,VYSIZE,
175                   VX,VY);
176       else
177       {
178         if (redraw_mask & REDRAW_VIDEO_1)
179           XCopyArea(display,backbuffer,window,gc,
180                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
181                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
182                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
183         if (redraw_mask & REDRAW_VIDEO_2)
184           XCopyArea(display,backbuffer,window,gc,
185                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
186                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
187                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
188         if (redraw_mask & REDRAW_VIDEO_3)
189           XCopyArea(display,backbuffer,window,gc,
190                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
191                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
192                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
193       }
194     }
195     redraw_mask &= ~REDRAW_DOORS;
196   }
197
198   if (redraw_mask & REDRAW_MICROLEV)
199   {
200     XCopyArea(display,backbuffer,window,gc,
201               MICROLEV_XPOS,MICROLEV_YPOS, MICROLEV_XSIZE,MICROLEV_YSIZE,
202               MICROLEV_XPOS,MICROLEV_YPOS);
203     XCopyArea(display,backbuffer,window,gc,
204               SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE,
205               SX,MICROLABEL_YPOS);
206     redraw_mask &= ~REDRAW_MICROLEV;
207   }
208
209   if (redraw_mask & REDRAW_TILES)
210   {
211     for(x=0; x<SCR_FIELDX; x++)
212       for(y=0; y<SCR_FIELDY; y++)
213         if (redraw[redraw_x1 + x][redraw_y1 + y])
214           XCopyArea(display,buffer,window,gc,
215                     FX+x*TILEX,FX+y*TILEY, TILEX,TILEY,
216                     SX+x*TILEX,SY+y*TILEY);
217   }
218
219   XFlush(display);
220
221   for(x=0; x<MAX_BUF_XSIZE; x++)
222     for(y=0; y<MAX_BUF_YSIZE; y++)
223       redraw[x][y] = 0;
224   redraw_tiles = 0;
225   redraw_mask = 0;
226 }
227
228 void FadeToFront()
229 {
230
231 /*
232   long fading_delay = 300000;
233
234   if (fading_on && (redraw_mask & REDRAW_FIELD))
235   {
236 */
237
238 /*
239     int x,y;
240
241     XFillRectangle(display,window,gc,
242                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
243     XFlush(display);
244
245     for(i=0;i<2*FULL_SYSIZE;i++)
246     {
247       for(y=0;y<FULL_SYSIZE;y++)
248       {
249         XCopyArea(display,backbuffer,window,gc,
250                   REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
251       }
252       XFlush(display);
253       Delay(10000);
254     }
255 */
256
257 /*
258     for(i=1;i<FULL_SYSIZE;i+=2)
259       XCopyArea(display,backbuffer,window,gc,
260                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
261     XFlush(display);
262     Delay(fading_delay);
263 */
264
265 /*
266     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
267     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
268               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
269     XFlush(display);
270     Delay(fading_delay);
271
272     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
273     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
274               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
275     XFlush(display);
276     Delay(fading_delay);
277
278     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
279     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
280               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
281     XFlush(display);
282     Delay(fading_delay);
283
284     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
285     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
286               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
287     XFlush(display);
288     Delay(fading_delay);
289
290     redraw_mask &= ~REDRAW_MAIN;
291   }
292 */
293
294   BackToFront();
295 }
296
297 void ClearWindow()
298 {
299   XFillRectangle(display,backbuffer,gc,
300                  REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE);
301
302   if (soft_scrolling_on && game_status==PLAYING)
303   {
304     XFillRectangle(display,fieldbuffer,gc,
305                    0,0, FXSIZE,FYSIZE);
306     SetDrawtoField(DRAW_BUFFERED);
307   }
308   else
309     SetDrawtoField(DRAW_BACKBUFFER);
310
311   if (direct_draw_on && game_status==PLAYING)
312   {
313     XFillRectangle(display,window,gc,
314                    REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE);
315     SetDrawtoField(DRAW_DIRECT);
316   }
317
318   redraw_mask |= REDRAW_FIELD;
319 }
320
321 void DrawText(int x, int y, char *text, int font, int col)
322 {
323   DrawTextExt(drawto, gc, x, y, text, font, col);
324   if (x < DX)
325     redraw_mask |= REDRAW_FIELD;
326   else if (y < VY)
327     redraw_mask |= REDRAW_DOOR_1;
328 }
329
330 void DrawTextExt(Drawable d, GC gc, int x, int y,
331                  char *text, int font, int font_color)
332 {
333   int font_width, font_height, font_start;
334   int font_pixmap;
335
336   if (font!=FS_SMALL && font!=FS_BIG)
337     font = FS_SMALL;
338   if (font_color<FC_RED || font_color>FC_SPECIAL2)
339     font_color = FC_RED;
340
341   font_width =
342     (font==FS_BIG ? FONT1_XSIZE :
343      font_color<FC_SPECIAL1 ? FONT2_XSIZE :
344      font_color<FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
345   font_height =
346     (font==FS_BIG ? FONT1_XSIZE :
347      font_color<FC_SPECIAL2 ? FONT2_XSIZE: FONT4_XSIZE);
348   font_pixmap = (font==FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
349   font_start =
350     font_color*(font==FS_BIG ? FONT1_YSIZE : FONT2_YSIZE)*FONT_LINES_PER_FONT;
351
352   while(*text)
353   {
354     char c = *text++;
355
356     if (c>='a' && c<='z')
357       c = 'A' + (c - 'a');
358     else if (c=='ä' || c=='Ä')
359       c = 91;
360     else if (c=='ö' || c=='Ö')
361       c = 92;
362     else if (c=='ü' || c=='Ü')
363       c = 93;
364
365     if (c>=32 && c<=95)
366       XCopyArea(display,pix[font_pixmap],d,gc,
367                 ((c-32) % FONT_CHARS_PER_LINE)*font_width,
368                 ((c-32) / FONT_CHARS_PER_LINE)*font_height + font_start,
369                 font_width,font_height, x,y);
370
371     x += font_width;
372   }
373 }
374
375 void DrawPlayerField()
376 {
377   int x = JX, y = JY;
378   int sx = SCROLLX(x), sy = SCROLLY(y);
379
380   int sxx = 0, syy = 0;
381
382   int element = Feld[x][y];
383   int graphic, phase;
384   BOOL draw_thru_mask = FALSE;
385
386   if (PlayerGone)
387     return;
388
389 #if DEBUG
390   if (!IN_LEV_FIELD(x,y) || !IN_SCR_FIELD(sx,sy))
391   {
392     printf("DrawPlayerField(): x = %d, y = %d\n",x,y);
393     printf("DrawPlayerField(): This should never happen!\n");
394     return;
395   }
396 #endif
397
398   if (element == EL_EXPLODING)
399     return;
400
401   if (direct_draw_on)
402     SetDrawtoField(DRAW_BUFFERED);
403
404   /* draw things behind the player (EL_PFORTE* || mole/penguin/pig/dragon) */
405
406   if (Store[x][y])
407   {
408     DrawGraphic(sx,sy, el2gfx(Store[x][y]));
409     draw_thru_mask = TRUE;
410   }
411   else if (element!=EL_LEERRAUM && element!=EL_DYNAMIT && element!=EL_DYNABOMB)
412   {
413     DrawLevelField(x,y);
414     draw_thru_mask = TRUE;
415   }
416
417   /* draw player himself */
418
419   if (PlayerMovDir==MV_LEFT)
420     graphic = (PlayerPushing ? GFX_SPIELER_PUSH_LEFT : GFX_SPIELER_LEFT);
421   else if (PlayerMovDir==MV_RIGHT)
422     graphic = (PlayerPushing ? GFX_SPIELER_PUSH_RIGHT : GFX_SPIELER_RIGHT);
423   else if (PlayerMovDir==MV_UP)
424     graphic = GFX_SPIELER_UP;
425   else  /* MV_DOWN || MV_NO_MOVING */
426     graphic = GFX_SPIELER_DOWN;
427
428   graphic += PlayerFrame;
429
430
431   if (PlayerMovPos)
432   {
433     if (PlayerMovDir == MV_LEFT || PlayerMovDir == MV_RIGHT)
434       sxx = PlayerMovPos;
435     else
436       syy = PlayerMovPos;
437   }
438
439
440   if (draw_thru_mask)
441     DrawGraphicThruMask(sx, sy, graphic);
442   else
443     DrawGraphicShifted(sx,sy,sxx,syy,graphic,CUT_NO_CUTTING);
444   /*
445     DrawGraphic(sx + sxx, sy + syy, graphic);
446     */
447
448
449   /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */
450
451   if (element == EL_DYNAMIT || element == EL_DYNABOMB)
452   {
453     graphic = el2gfx(element);
454
455     if (element == EL_DYNAMIT)
456     {
457       if ((phase = (48-MovDelay[x][y])/6) > 6)
458         phase = 6;
459     }
460     else
461     {
462       if ((phase = ((48-MovDelay[x][y])/3) % 8) > 3)
463         phase = 7-phase;
464     }
465
466     DrawGraphicThruMask(sx,sy, graphic + phase);
467   }
468
469   if (direct_draw_on)
470   {
471     int dest_x = SX+SCROLLX(x)*TILEX;
472     int dest_y = SY+SCROLLY(y)*TILEY;
473
474     XCopyArea(display,drawto_field,window,gc,
475               dest_x,dest_y, TILEX,TILEY, dest_x,dest_y);
476     SetDrawtoField(DRAW_DIRECT);
477   }
478 }
479
480 static int getGraphicAnimationPhase(int frames, int delay, int mode)
481 {
482   int phase;
483
484   if (mode == ANIM_OSCILLATE)
485   {
486     int max_anim_frames = frames*2 - 2;
487     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
488     phase = (phase < frames ? phase : max_anim_frames - phase);
489   }
490   else
491     phase = (FrameCounter % (delay * frames)) / delay;
492
493   return(phase);
494 }
495
496 void DrawGraphicAnimation(int x, int y, int graphic,
497                           int frames, int delay, int mode)
498 {
499   int phase = getGraphicAnimationPhase(frames, delay, mode);
500
501 /*
502   int phase;
503
504   if (mode == ANIM_OSCILLATE)
505   {
506     int max_anim_frames = frames*2 - 2;
507     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
508     phase = (phase < frames ? phase : max_anim_frames - phase);
509   }
510   else
511     phase = (FrameCounter % (delay * frames)) / delay;
512 */
513
514   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
515     DrawGraphic(SCROLLX(x),SCROLLY(y), graphic + phase);
516 }
517
518 void DrawGraphic(int x, int y, int graphic)
519 {
520
521 #if DEBUG
522   if (!IN_SCR_FIELD(x,y))
523   {
524     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
525     printf("DrawGraphic(): This should never happen!\n");
526     return;
527   }
528 #endif
529
530   DrawGraphicExt(drawto_field, gc, x, y, graphic);
531   redraw_tiles++;
532   redraw[redraw_x1 + x][redraw_y1 + y] = TRUE;
533   redraw_mask |= REDRAW_TILES;
534 }
535
536 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
537 {
538   DrawGraphicExtHiRes(d, gc, FX+x*TILEX, FY+y*TILEY, graphic);
539 }
540
541 void DrawGraphicExtHiRes(Drawable d, GC gc, int x, int y, int graphic)
542 {
543   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
544   {
545     graphic -= GFX_START_ROCKSSCREEN;
546     XCopyArea(display,pix[PIX_BACK],d,gc,
547               SX+(graphic % GFX_PER_LINE)*TILEX,
548               SY+(graphic / GFX_PER_LINE)*TILEY,
549               TILEX,TILEY, x,y);
550   }
551   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
552   {
553     graphic -= GFX_START_ROCKSHEROES;
554     XCopyArea(display,pix[PIX_HEROES],d,gc,
555               (graphic % HEROES_PER_LINE)*TILEX,
556               (graphic / HEROES_PER_LINE)*TILEY,
557               TILEX,TILEY, x,y);
558   }
559   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
560   {
561     graphic -= GFX_START_ROCKSFONT;
562     XCopyArea(display,pix[PIX_BIGFONT],d,gc,
563               (graphic % FONT_CHARS_PER_LINE)*TILEX,
564               (graphic / FONT_CHARS_PER_LINE)*TILEY +
565               FC_SPECIAL1*TILEY*FONT_LINES_PER_FONT,
566               TILEX,TILEY, x,y);
567   }
568   else
569     XFillRectangle(display,d,gc, x,y, TILEX,TILEY);
570 }
571
572 void DrawGraphicThruMask(int x, int y, int graphic)
573 {
574   int src_x,src_y, dest_x,dest_y;
575
576 #if DEBUG
577   if (!IN_SCR_FIELD(x,y))
578   {
579     printf("DrawGraphicThruMask(): x = %d, y = %d\n",x,y);
580     printf("DrawGraphicThruMask(): This should never happen!\n");
581     return;
582   }
583 #endif
584
585   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
586   {
587     graphic -= GFX_START_ROCKSSCREEN;
588     src_x  = SX+(graphic % GFX_PER_LINE)*TILEX;
589     src_y  = SY+(graphic / GFX_PER_LINE)*TILEY;
590     dest_x = FX+x*TILEX;
591     dest_y = FY+y*TILEY;
592
593     XSetClipOrigin(display,clip_gc[PIX_BACK],dest_x-src_x,dest_y-src_y);
594     XCopyArea(display,pix[PIX_BACK],drawto_field,clip_gc[PIX_BACK],
595               src_x,src_y, TILEX,TILEY, dest_x,dest_y);
596   }
597   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
598   {
599     graphic -= GFX_START_ROCKSHEROES;
600     src_x  = (graphic % HEROES_PER_LINE)*TILEX;
601     src_y  = (graphic / HEROES_PER_LINE)*TILEY;
602     dest_x = FX+x*TILEX;
603     dest_y = FY+y*TILEY;
604
605     XSetClipOrigin(display,clip_gc[PIX_HEROES],dest_x-src_x,dest_y-src_y);
606     XCopyArea(display,pix[PIX_HEROES],drawto_field,clip_gc[PIX_HEROES],
607               src_x,src_y, TILEX,TILEY, dest_x,dest_y);
608   }
609   else
610   {
611     DrawGraphic(x,y,graphic);
612     return;
613   }
614
615   redraw_tiles++;
616   redraw[redraw_x1 + x][redraw_y1 + y]=TRUE;
617   redraw_mask|=REDRAW_TILES;
618 }
619
620 void DrawElementThruMask(int x, int y, int element)
621 {
622   DrawGraphicThruMask(x,y,el2gfx(element));
623 }
624
625 void DrawMiniGraphic(int x, int y, int graphic)
626 {
627   DrawMiniGraphicExt(drawto, gc, x, y, graphic);
628   redraw_tiles++;
629   redraw[x/2][y/2]=TRUE;
630   redraw_mask|=REDRAW_TILES;
631 }
632
633 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
634 {
635   DrawMiniGraphicExtHiRes(d,gc, SX+x*MINI_TILEX,SY+y*MINI_TILEY, graphic);
636 }
637
638 void DrawMiniGraphicExtHiRes(Drawable d, GC gc, int x, int y, int graphic)
639 {
640   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
641   {
642     graphic -= GFX_START_ROCKSSCREEN;
643     XCopyArea(display,pix[PIX_BACK],d,gc,
644               MINI_GFX_STARTX+(graphic % MINI_GFX_PER_LINE)*MINI_TILEX,
645               MINI_GFX_STARTY+(graphic / MINI_GFX_PER_LINE)*MINI_TILEY,
646               MINI_TILEX,MINI_TILEY, x,y);
647   }
648   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
649   {
650     graphic -= GFX_START_ROCKSFONT;
651     XCopyArea(display,pix[PIX_SMALLFONT],d,gc,
652               (graphic % FONT_CHARS_PER_LINE)*FONT4_XSIZE,
653               (graphic / FONT_CHARS_PER_LINE)*FONT4_YSIZE +
654               FC_SPECIAL2*FONT2_YSIZE*FONT_LINES_PER_FONT,
655               MINI_TILEX,MINI_TILEY, x,y);
656   }
657   else
658     XFillRectangle(display,d,gc, x,y, MINI_TILEX,MINI_TILEY);
659 }
660
661 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int cut_mode)
662 {
663   int width = TILEX, height = TILEY;
664   int cx = 0, cy = 0;
665
666   if (graphic < 0)
667   {
668     DrawGraphic(x,y,graphic);
669     return;
670   }
671
672   if (dx || dy)                 /* Verschiebung der Grafik? */
673   {
674     if (x < BX1)                /* Element kommt von links ins Bild */
675     {
676       x = BX1;
677       width = dx;
678       cx = TILEX - dx;
679       dx = 0;
680     }
681     else if (x > BX2)           /* Element kommt von rechts ins Bild */
682     {
683       x = BX2;
684       width = -dx;
685       dx = TILEX + dx;
686     }
687     else if (x==BX1 && dx<0)    /* Element verläßt links das Bild */
688     {
689       width += dx;
690       cx = -dx;
691       dx = 0;
692     }
693     else if (x==BX2 && dx>0)    /* Element verläßt rechts das Bild */
694       width -= dx;
695     else if (dx)                /* allg. Bewegung in x-Richtung */
696       redraw[redraw_x1 + x + SIGN(dx)][redraw_y1 + y] = TRUE;
697
698     if (y < BY1)                /* Element kommt von oben ins Bild */
699     {
700       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
701         return;
702
703       y = BY1;
704       height = dy;
705       cy = TILEY - dy;
706       dy = 0;
707     }
708     else if (y > BY2)           /* Element kommt von unten ins Bild */
709     {
710       y = BY2;
711       height = -dy;
712       dy = TILEY + dy;
713     }
714     else if (y==BY1 && dy<0)    /* Element verläßt oben das Bild */
715     {
716       height += dy;
717       cy = -dy;
718       dy = 0;
719     }
720     else if (dy > 0 && cut_mode==CUT_ABOVE)
721     {
722       if (y == BY2)             /* Element unterhalb des Bildes */
723         return;
724
725       height = dy;
726       cy = TILEY-dy;
727       dy = TILEY;
728       redraw[redraw_x1 + x][redraw_y1 + y + 1] = TRUE;
729     }                           /* Element verläßt unten das Bild */
730     else if (dy > 0 && (y == BY2 || cut_mode==CUT_BELOW))
731       height -= dy;
732     else if (dy)                /* allg. Bewegung in y-Richtung */
733       redraw[redraw_x1 + x][redraw_y1 + y + SIGN(dy)] = TRUE;
734   }
735
736   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
737   {
738     graphic -= GFX_START_ROCKSSCREEN;
739     XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
740               SX+(graphic % GFX_PER_LINE)*TILEX+cx,
741               SY+(graphic / GFX_PER_LINE)*TILEY+cy,
742               width,height, FX+x*TILEX+dx,FY+y*TILEY+dy);
743   }
744   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
745   {
746     graphic -= GFX_START_ROCKSHEROES;
747     XCopyArea(display,pix[PIX_HEROES],drawto_field,gc,
748               (graphic % HEROES_PER_LINE)*TILEX+cx,
749               (graphic / HEROES_PER_LINE)*TILEY+cy,
750               width,height, FX+x*TILEX+dx,FY+y*TILEY+dy);
751   }
752
753 #if DEBUG
754   if (!IN_SCR_FIELD(x,y))
755   {
756     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
757     printf("DrawGraphicShifted(): This should never happen!\n");
758     return;
759   }
760 #endif
761
762   redraw_tiles++;
763   redraw[redraw_x1 + x][redraw_y1 + y] = TRUE;
764   redraw_mask |= REDRAW_TILES;
765 }
766
767 void DrawElementShifted(int x, int y, int dx, int dy, int element,int cut_mode)
768 {
769   int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
770   int graphic = el2gfx(element);
771   int phase4 = ABS(MovPos[ux][uy])/(TILEX/4);
772   int phase  = phase4 / 2;
773   int dir = MovDir[ux][uy];
774
775   if (element==EL_PACMAN || element==EL_KAEFER || element==EL_FLIEGER)
776   {
777     graphic += 4*!phase;
778
779     if (dir == MV_UP)
780       graphic += 1;
781     else if (dir == MV_LEFT)
782       graphic += 2;
783     else if (dir == MV_DOWN)
784       graphic += 3;
785   }
786   else if (element==EL_MAULWURF || element==EL_PINGUIN ||
787            element==EL_SCHWEIN || element==EL_DRACHE)
788   {
789     if (dir==MV_LEFT)
790       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_LEFT :
791                  element==EL_PINGUIN ? GFX_PINGUIN_LEFT :
792                  element==EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
793     else if (dir==MV_RIGHT)
794       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_RIGHT :
795                  element==EL_PINGUIN ? GFX_PINGUIN_RIGHT :
796                  element==EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
797     else if (dir==MV_UP)
798       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_UP :
799                  element==EL_PINGUIN ? GFX_PINGUIN_UP :
800                  element==EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
801     else
802       graphic = (element==EL_MAULWURF ? GFX_MAULWURF_DOWN :
803                  element==EL_PINGUIN ? GFX_PINGUIN_DOWN :
804                  element==EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
805
806     graphic += phase4;
807   }
808   else if (element==EL_SONDE)
809   {
810     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
811   }
812   else if (element==EL_BUTTERFLY || element==EL_FIREFLY)
813   {
814     graphic += !phase;
815   }
816   else if ((element==EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
817   {
818     graphic += phase * (element==EL_FELSBROCKEN ? 2 : 1);
819   }
820   else if ((element==EL_SIEB_LEER || element==EL_SIEB2_LEER ||
821             element==EL_SIEB_VOLL || element==EL_SIEB2_VOLL) && SiebAktiv)
822   {
823     graphic += 3-(SiebAktiv%8)/2;
824   }
825   else if (IS_AMOEBOID(element))
826   {
827     graphic = (element==EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
828     graphic += (x+2*y) % 4;
829   }
830   else if (element==EL_MAUER_LEBT)
831   {
832     BOOL links_massiv = FALSE, rechts_massiv = FALSE;
833
834     if (!IN_LEV_FIELD(ux-1,uy) || IS_MAUER(Feld[ux-1][uy]))
835       links_massiv = TRUE;
836     if (!IN_LEV_FIELD(ux+1,uy) || IS_MAUER(Feld[ux+1][uy]))
837       rechts_massiv = TRUE;
838
839     if (links_massiv && rechts_massiv)
840       graphic = GFX_MAUERWERK;
841     else if (links_massiv)
842       graphic = GFX_MAUER_R;
843     else if (rechts_massiv)
844       graphic = GFX_MAUER_L;
845   }
846
847   if (dx || dy)
848     DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode);
849   else
850     DrawGraphic(x,y, graphic);
851 }
852
853 void ErdreichAnbroeckeln(int x, int y)
854 {
855   int i, width, height, cx,cy;
856   int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
857   int element, graphic;
858   int snip = 4;
859   static int xy[4][2] =
860   {
861     { 0,-1 },
862     { -1,0 },
863     { +1,0 },
864     { 0,+1 }
865   };
866
867   if (!IN_LEV_FIELD(ux,uy))
868     return;
869
870   element = Feld[ux][uy];
871
872   if (element==EL_ERDREICH)
873   {
874     if (!IN_SCR_FIELD(x,y))
875       return;
876
877     graphic = GFX_ERDENRAND;
878
879     for(i=0;i<4;i++)
880     {
881       int uxx,uyy;
882
883       uxx = ux+xy[i][0];
884       uyy = uy+xy[i][1];
885       if (!IN_LEV_FIELD(uxx,uyy))
886         element = EL_BETON;
887       else
888         element = Feld[uxx][uyy];
889
890 /*
891       if (element==EL_ERDREICH || IS_SOLID(element))
892         continue;
893 */
894       if (element==EL_ERDREICH)
895         continue;
896
897       if (i==1 || i==2)
898       {
899         width = snip;
900         height = TILEY;
901         cx = (i==2 ? TILEX-snip : 0);
902         cy = 0;
903       }
904       else
905       {
906         width = TILEX;
907         height = snip;
908         cx = 0;
909         cy = (i==3 ? TILEY-snip : 0);
910       }
911
912       XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
913                 SX+(graphic % GFX_PER_LINE)*TILEX+cx,
914                 SY+(graphic / GFX_PER_LINE)*TILEY+cy,
915                 width,height, FX+x*TILEX+cx,FY+y*TILEY+cy);
916     }
917
918     redraw_tiles++;
919     redraw[redraw_x1 + x][redraw_y1 + y] = TRUE;
920   }
921   else
922   {
923     graphic = GFX_ERDENRAND;
924
925     for(i=0;i<4;i++)
926     {
927       int xx,yy,uxx,uyy;
928
929       xx = x+xy[i][0];
930       yy = y+xy[i][1];
931       uxx = ux+xy[i][0];
932       uyy = uy+xy[i][1];
933 /*
934       if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH ||
935           !IN_SCR_FIELD(xx,yy) || IS_SOLID(element))
936         continue;
937 */
938
939       if (!IN_LEV_FIELD(uxx,uyy) || Feld[uxx][uyy]!=EL_ERDREICH ||
940           !IN_SCR_FIELD(xx,yy))
941         continue;
942
943       if (i==1 || i==2)
944       {
945         width = snip;
946         height = TILEY;
947         cx = (i==1 ? TILEX-snip : 0);
948         cy = 0;
949       }
950       else
951       {
952         width = TILEX;
953         height = snip;
954         cx = 0;
955         cy = (i==0 ? TILEY-snip : 0);
956       }
957
958       XCopyArea(display,pix[PIX_BACK],drawto_field,gc,
959                 SX+(graphic % GFX_PER_LINE)*TILEX+cx,
960                 SY+(graphic / GFX_PER_LINE)*TILEY+cy,
961                 width,height, FX+xx*TILEX+cx,FY+yy*TILEY+cy);
962
963       redraw_tiles++;
964       redraw[redraw_x1 + xx][redraw_y1 + yy] = TRUE;
965     }
966   }
967 }
968
969 void DrawScreenElement(int x, int y, int element)
970 {
971   DrawElementShifted(x,y,0,0,element,CUT_NO_CUTTING);
972   ErdreichAnbroeckeln(x,y);
973 }
974
975 void DrawLevelElement(int x, int y, int element)
976 {
977   if (IN_LEV_FIELD(x,y) && IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
978     DrawScreenElement(SCROLLX(x),SCROLLY(y),element);
979 }
980
981 void DrawScreenField(int x, int y)
982 {
983   int ux = UNSCROLLX(x), uy = UNSCROLLY(y);
984   int element;
985
986   if (!IN_LEV_FIELD(ux,uy))
987   {
988     DrawScreenElement(x,y,EL_BETON);
989     return;
990   }
991
992   element = Feld[ux][uy];
993
994   if (IS_MOVING(ux,uy))
995   {
996     int horiz_move = (MovDir[ux][uy]==MV_LEFT || MovDir[ux][uy]==MV_RIGHT);
997     BOOL cut_mode = CUT_NO_CUTTING;
998
999     if (Store[ux][uy]==EL_MORAST_LEER ||
1000         Store[ux][uy]==EL_SIEB_LEER ||
1001         Store[ux][uy]==EL_SIEB2_LEER ||
1002         Store[ux][uy]==EL_AMOEBE_NASS)
1003       cut_mode = CUT_ABOVE;
1004     else if (Store[ux][uy]==EL_MORAST_VOLL ||
1005         Store[ux][uy]==EL_SIEB_VOLL ||
1006         Store[ux][uy]==EL_SIEB2_VOLL ||
1007         Store[ux][uy]==EL_SALZSAEURE)
1008       cut_mode = CUT_BELOW;
1009
1010     if (cut_mode==CUT_ABOVE)
1011       DrawElementShifted(x,y,0,0,Store[ux][uy],CUT_NO_CUTTING);
1012     else
1013       DrawScreenElement(x,y,EL_LEERRAUM);
1014
1015     if (horiz_move)
1016       DrawElementShifted(x,y,MovPos[ux][uy],0,element,CUT_NO_CUTTING);
1017     else
1018       DrawElementShifted(x,y,0,MovPos[ux][uy],element,cut_mode);
1019   }
1020   else if (IS_BLOCKED(ux,uy))
1021   {
1022     int oldx,oldy;
1023     int sx, sy;
1024     int horiz_move;
1025     BOOL cut_mode = CUT_NO_CUTTING;
1026
1027     Blocked2Moving(ux,uy,&oldx,&oldy);
1028     sx = SCROLLX(oldx);
1029     sy = SCROLLY(oldy);
1030     horiz_move = (MovDir[oldx][oldy]==MV_LEFT || MovDir[oldx][oldy]==MV_RIGHT);
1031
1032     if (Store[oldx][oldy]==EL_MORAST_LEER ||
1033         Store[oldx][oldy]==EL_SIEB_LEER ||
1034         Store[oldx][oldy]==EL_SIEB2_LEER ||
1035         Store[oldx][oldy]==EL_AMOEBE_NASS)
1036       cut_mode = CUT_ABOVE;
1037
1038     DrawScreenElement(x,y,EL_LEERRAUM);
1039     element = Feld[oldx][oldy];
1040
1041     if (horiz_move)
1042       DrawElementShifted(sx,sy,MovPos[oldx][oldy],0,element,CUT_NO_CUTTING);
1043     else
1044       DrawElementShifted(sx,sy,0,MovPos[oldx][oldy],element,cut_mode);
1045   }
1046   else if (IS_DRAWABLE(element))
1047     DrawScreenElement(x,y,element);
1048   else
1049     DrawScreenElement(x,y,EL_LEERRAUM);
1050 }
1051
1052 void DrawLevelField(int x, int y)
1053 {
1054   if (IN_SCR_FIELD(SCROLLX(x),SCROLLY(y)))
1055     DrawScreenField(SCROLLX(x),SCROLLY(y));
1056   else if (IS_MOVING(x,y))
1057   {
1058     int newx,newy;
1059
1060     Moving2Blocked(x,y,&newx,&newy);
1061     if (IN_SCR_FIELD(SCROLLX(newx),SCROLLY(newy)))
1062       DrawScreenField(SCROLLX(newx),SCROLLY(newy));
1063   }
1064   else if (IS_BLOCKED(x,y))
1065   {
1066     int oldx,oldy;
1067
1068     Blocked2Moving(x,y,&oldx,&oldy);
1069     if (IN_SCR_FIELD(SCROLLX(oldx),SCROLLY(oldy)))
1070       DrawScreenField(SCROLLX(oldx),SCROLLY(oldy));
1071   }
1072 }
1073
1074 void DrawMiniElement(int x, int y, int element)
1075 {
1076   int graphic;
1077
1078   if (!element)
1079   {
1080     DrawMiniGraphic(x,y,-1);
1081     return;
1082   }
1083
1084   graphic = el2gfx(element);
1085   DrawMiniGraphic(x,y,graphic);
1086
1087   redraw_tiles++;
1088   redraw[x/2][y/2]=TRUE;
1089   redraw_mask|=REDRAW_TILES;
1090 }
1091
1092 void DrawMiniElementOrWall(int x, int y, int scroll_x, int scroll_y)
1093 {
1094   if (x+scroll_x<-1 || x+scroll_x>lev_fieldx ||
1095       y+scroll_y<-1 || y+scroll_y>lev_fieldy)
1096     DrawMiniElement(x,y,EL_LEERRAUM);
1097   else if (x+scroll_x==-1 || x+scroll_x==lev_fieldx ||
1098            y+scroll_y==-1 || y+scroll_y==lev_fieldy)
1099     DrawMiniElement(x,y,EL_BETON);
1100   else
1101     DrawMiniElement(x,y,Feld[x+scroll_x][y+scroll_y]);
1102 }
1103
1104 void DrawMicroElement(int xpos, int ypos, int element)
1105 {
1106   int graphic;
1107
1108   if (element==EL_LEERRAUM)
1109     return;
1110
1111   graphic = el2gfx(element);
1112
1113   XCopyArea(display,pix[PIX_BACK],drawto,gc,
1114             MICRO_GFX_STARTX+(graphic % MICRO_GFX_PER_LINE)*MICRO_TILEX,
1115             MICRO_GFX_STARTY+(graphic / MICRO_GFX_PER_LINE)*MICRO_TILEY,
1116             MICRO_TILEX,MICRO_TILEY, xpos,ypos);
1117 }
1118
1119 void DrawLevel()
1120 {
1121   int x,y;
1122
1123   ClearWindow();
1124
1125   for(x=BX1; x<=BX2; x++)
1126     for(y=BY1; y<=BY2; y++)
1127       DrawScreenField(x,y);
1128
1129   redraw_mask |= REDRAW_FIELD;
1130 }
1131
1132 void DrawMiniLevel(int scroll_x, int scroll_y)
1133 {
1134   int x,y;
1135
1136   ClearWindow();
1137
1138   for(x=0;x<2*SCR_FIELDX;x++)
1139     for(y=0;y<2*SCR_FIELDY;y++)
1140       DrawMiniElementOrWall(x,y,scroll_x,scroll_y);
1141
1142   redraw_mask |= REDRAW_FIELD;
1143 }
1144
1145 void DrawMicroLevel(int xpos, int ypos)
1146 {
1147   int x,y;
1148
1149   XFillRectangle(display,drawto,gc,
1150                  xpos-MICRO_TILEX,ypos-MICRO_TILEY,
1151                  MICRO_TILEX*(STD_LEV_FIELDX+2),
1152                  MICRO_TILEY*(STD_LEV_FIELDY+2));
1153   if (lev_fieldx < STD_LEV_FIELDX)
1154     xpos += (STD_LEV_FIELDX - lev_fieldx)/2 * MICRO_TILEX;
1155   if (lev_fieldy < STD_LEV_FIELDY)
1156     ypos += (STD_LEV_FIELDY - lev_fieldy)/2 * MICRO_TILEY;
1157
1158   for(x=-1;x<=STD_LEV_FIELDX;x++)
1159     for(y=-1;y<=STD_LEV_FIELDY;y++)
1160       if (x>=0 && x<lev_fieldx && y>=0 && y<lev_fieldy)
1161         DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
1162                          Feld[x][y]=Ur[x][y]);
1163       else if (x>=-1 && x<lev_fieldx+1 && y>=-1 && y<lev_fieldy+1)
1164         DrawMicroElement(xpos+MICRO_TILEX*x,ypos+MICRO_TILEY*y,
1165                          EL_BETON);
1166
1167   XFillRectangle(display,drawto,gc, SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE);
1168
1169   if (level.name)
1170   {
1171     int len = strlen(level.name);
1172     int lxpos = SX+(SXSIZE-len*FONT4_XSIZE)/2;
1173     int lypos = MICROLABEL_YPOS;
1174
1175     DrawText(lxpos,lypos,level.name,FS_SMALL,FC_SPECIAL2);
1176   }
1177
1178   redraw_mask |= REDRAW_MICROLEV;
1179 }
1180
1181 int AYS_in_range(int x, int y)
1182 {
1183   if (y>DY+249 && y<DY+278)
1184   {
1185     if (x>DX+1 && x<DX+48)
1186       return(1);
1187     else if (x>DX+51 && x<DX+98) 
1188       return(2);
1189   }
1190   return(0);
1191 }
1192
1193 BOOL AreYouSure(char *text, unsigned int ays_state)
1194 {
1195   int mx,my, ty, result = -1;
1196   unsigned int old_door_state;
1197
1198   old_door_state = GetDoorState();
1199
1200   CloseDoor(DOOR_CLOSE_1);
1201
1202   /* Alten Türinhalt sichern */
1203   XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1204             DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1205             DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1);
1206
1207   /* Fragetext schreiben */
1208   XFillRectangle(display,pix[PIX_DB_DOOR],gc,
1209                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1,DXSIZE,DYSIZE);
1210
1211   for(ty=0;ty<13;ty++)
1212   {
1213     int tx,tl,tc;
1214     char txt[256];
1215
1216     if (!(*text))
1217       break;
1218     for(tl=0,tx=0;tx<7;tl++,tx++)
1219     {
1220       tc=*(text+tx);
1221       if (!tc || tc==32)
1222         break;
1223     }
1224     if (!tl)
1225     { 
1226       text++; 
1227       ty--; 
1228       continue; 
1229     }
1230     sprintf(txt,text); 
1231     txt[tl]=0;
1232     DrawTextExt(pix[PIX_DB_DOOR],gc,
1233                 DOOR_GFX_PAGEX1+51-(tl*14)/2,SY+ty*16,txt,FS_SMALL,FC_YELLOW);
1234     text+=(tl+(tc==32));
1235   }
1236
1237   if (ays_state & AYS_ASK)
1238     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1239               DOOR_GFX_PAGEX4,OK_BUTTON_GFX_YPOS,
1240               DXSIZE,OK_BUTTON_YSIZE,
1241               DOOR_GFX_PAGEX1,OK_BUTTON_YPOS);
1242   else if (ays_state & AYS_CONFIRM)
1243     XCopyArea(display,pix[PIX_DOOR],pix[PIX_DB_DOOR],gc,
1244               DOOR_GFX_PAGEX4,CONFIRM_BUTTON_GFX_YPOS,
1245               DXSIZE,CONFIRM_BUTTON_YSIZE,
1246               DOOR_GFX_PAGEX1,CONFIRM_BUTTON_YPOS);
1247
1248   OpenDoor(DOOR_OPEN_1);
1249   ClearEventQueue();
1250
1251   if (!(ays_state & AYS_ASK) && !(ays_state & AYS_CONFIRM))
1252     return(FALSE);
1253
1254   if (game_status != MAINMENU)
1255     InitAnimation();
1256
1257   button_status = MB_RELEASED;
1258
1259   while(result<0)
1260   {
1261     DoAnimation();
1262     Delay(10000);
1263
1264     if (XPending(display))
1265     {
1266       XEvent event;
1267
1268       XNextEvent(display, &event);
1269       switch(event.type)
1270       {
1271         case Expose:
1272           HandleExposeEvent((XExposeEvent *) &event);
1273           break;
1274         case UnmapNotify:
1275           SleepWhileUnmapped();
1276           break;
1277         case ButtonPress:
1278         case ButtonRelease:
1279         case MotionNotify:
1280         {
1281           int choice;
1282
1283           if (event.type == MotionNotify)
1284           {
1285             motion_status = TRUE;
1286             mx = ((XMotionEvent *) &event)->x;
1287             my = ((XMotionEvent *) &event)->y;
1288           }
1289           else
1290           {
1291             motion_status = FALSE;
1292             mx = ((XButtonEvent *) &event)->x;
1293             my = ((XButtonEvent *) &event)->y;
1294             if (event.type==ButtonPress)
1295               button_status = ((XButtonEvent *) &event)->button;
1296             else
1297               button_status = MB_RELEASED;
1298           }
1299
1300           if (ays_state & AYS_ASK)
1301             choice = CheckChooseButtons(mx,my,button_status);
1302           else
1303             choice = CheckConfirmButton(mx,my,button_status);
1304
1305           switch(choice)
1306           {
1307             case BUTTON_OK:
1308               result = TRUE;
1309               break;
1310             case BUTTON_NO:
1311               result = FALSE;
1312               break;
1313             case BUTTON_CONFIRM:
1314               result = TRUE|FALSE;
1315               break;
1316             default:
1317               break;
1318           }
1319           break;
1320         }
1321         case KeyPress:
1322           switch(XLookupKeysym((XKeyEvent *)&event,
1323                                ((XKeyEvent *)&event)->state))
1324           {
1325             case XK_Return:
1326               result = 1;
1327               break;
1328             case XK_Escape:
1329               result = 0;
1330               break;
1331           }
1332           break;
1333         case FocusIn:
1334         case FocusOut:
1335           HandleFocusEvent((XFocusChangeEvent *) &event);
1336           break;
1337         default:
1338           break;
1339       }
1340     }
1341     else if (JoystickButton() == JOY_BUTTON_NEW_PRESSED)
1342     {
1343       int joy=Joystick();
1344
1345       if (joy & JOY_BUTTON_1)
1346         result = 1;
1347       else if (joy & JOY_BUTTON_2)
1348         result = 0;
1349     }
1350   }
1351
1352   if (game_status != MAINMENU)
1353     StopAnimation();
1354
1355   if (!(ays_state & AYS_STAY_OPEN))
1356   {
1357     CloseDoor(DOOR_CLOSE_1);
1358
1359     if (!(ays_state & AYS_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1360     {
1361       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1362                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1363                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1364       OpenDoor(DOOR_OPEN_1);
1365     }
1366   }
1367
1368   return(result);
1369 }
1370
1371 unsigned int OpenDoor(unsigned int door_state)
1372 {
1373   unsigned int new_door_state;
1374
1375   if (door_state & DOOR_COPY_BACK)
1376   {
1377     XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1378               DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE+VYSIZE,
1379               DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1380     door_state &= ~DOOR_COPY_BACK;
1381   }
1382
1383   new_door_state = MoveDoor(door_state);
1384
1385 /*
1386   ClearEventQueue();
1387 */
1388
1389   return(new_door_state);
1390 }
1391
1392 unsigned int CloseDoor(unsigned int door_state)
1393 {
1394   unsigned int new_door_state;
1395
1396   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1397             DX,DY, DXSIZE,DYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1398   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1399             VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1400
1401   new_door_state = MoveDoor(door_state);
1402
1403 /*
1404   ClearEventQueue();
1405 */
1406
1407   return(new_door_state);
1408 }
1409
1410 unsigned int GetDoorState()
1411 {
1412   return(MoveDoor(DOOR_GET_STATE));
1413 }
1414
1415 unsigned int MoveDoor(unsigned int door_state)
1416 {
1417   static unsigned int door1 = DOOR_OPEN_1;
1418   static unsigned int door2 = DOOR_CLOSE_2;
1419   int x, start, stepsize = 4, door_anim_delay = stepsize*5000;
1420
1421   if (door_state == DOOR_GET_STATE)
1422     return(door1 | door2);
1423
1424   if (door1==DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1425     door_state &= ~DOOR_OPEN_1;
1426   else if (door1==DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1427     door_state &= ~DOOR_CLOSE_1;
1428   if (door2==DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1429     door_state &= ~DOOR_OPEN_2;
1430   else if (door2==DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1431     door_state &= ~DOOR_CLOSE_2;
1432
1433   if (quick_doors)
1434   {
1435     stepsize = 20;
1436     door_anim_delay = 0;
1437     StopSound(SND_OEFFNEN);
1438   }
1439
1440   if (door_state & DOOR_ACTION)
1441   {
1442     if (!(door_state & DOOR_NO_DELAY))
1443       PlaySoundStereo(SND_OEFFNEN,PSND_MAX_RIGHT);
1444
1445     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1446
1447     for(x=start;x<=DXSIZE;x+=stepsize)
1448     {
1449       if (door_state & DOOR_ACTION_1)
1450       {
1451         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1452         int j = (DXSIZE - i)/3;
1453
1454         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1455                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1+i/2,
1456                   DXSIZE,DYSIZE-i/2, DX,DY);
1457
1458         XFillRectangle(display,drawto,gc,DX,DY+DYSIZE-i/2,DXSIZE,i/2);
1459
1460         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1461                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1462         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1463                   DXSIZE,DOOR_GFX_PAGEY1, i,77, DX+DXSIZE-i,DY+j);
1464         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1465                   DXSIZE,DOOR_GFX_PAGEY1+140, i,63, DX+DXSIZE-i,DY+140+j);
1466         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1467                        DX-DXSIZE+i,DY-(DOOR_GFX_PAGEY1+j));
1468         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1469                   DXSIZE-i,DOOR_GFX_PAGEY1+j, i,77-j, DX,DY);
1470         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1471                   DXSIZE-i,DOOR_GFX_PAGEY1+140, i,63, DX,DY+140-j);
1472
1473         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1474                   DXSIZE-i,DOOR_GFX_PAGEY1+77, i,63,
1475                   DX,DY+77-j);
1476         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1477                   DXSIZE-i,DOOR_GFX_PAGEY1+203, i,77,
1478                   DX,DY+203-j);
1479         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1480                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1481         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1482                   DXSIZE,DOOR_GFX_PAGEY1+77, i,63,
1483                   DX+DXSIZE-i,DY+77+j);
1484         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1485                   DXSIZE,DOOR_GFX_PAGEY1+203, i,77-j,
1486                   DX+DXSIZE-i,DY+203+j);
1487
1488         redraw_mask |= REDRAW_DOOR_1;
1489       }
1490
1491       if (door_state & DOOR_ACTION_2)
1492       {
1493         int i = (door_state & DOOR_OPEN_2 ? VXSIZE-x : x);
1494         int j = (VXSIZE - i)/3;
1495
1496         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1497                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2+i/2,
1498                   VXSIZE,VYSIZE-i/2, VX,VY);
1499
1500         XFillRectangle(display,drawto,gc,VX,VY+VYSIZE-i/2,VXSIZE,i/2);
1501
1502         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1503                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1504         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1505                   VXSIZE,DOOR_GFX_PAGEY2, i,VYSIZE/2, VX+VXSIZE-i,VY+j);
1506         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1507                        VX-VXSIZE+i,VY-(DOOR_GFX_PAGEY2+j));
1508         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1509                   VXSIZE-i,DOOR_GFX_PAGEY2+j, i,VYSIZE/2-j, VX,VY);
1510
1511         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1512                   VXSIZE-i,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2,
1513                   VX,VY+VYSIZE/2-j);
1514         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1515                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1516         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1517                   VXSIZE,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2-j,
1518                   VX+VXSIZE-i,VY+VYSIZE/2+j);
1519
1520         redraw_mask |= REDRAW_DOOR_2;
1521       }
1522
1523       BackToFront();
1524       Delay(door_anim_delay);
1525
1526       if (game_status==MAINMENU)
1527         DoAnimation();
1528     }
1529   }
1530
1531   if (door_state & DOOR_ACTION_1)
1532     door1 = door_state & DOOR_ACTION_1;
1533   if (door_state & DOOR_ACTION_2)
1534     door2 = door_state & DOOR_ACTION_2;
1535
1536   return(door1 | door2);
1537 }
1538
1539 int ReadPixel(Drawable d, int x, int y)
1540 {
1541   static XImage *pixelimage;
1542
1543   pixelimage = XGetImage(display, d, x,y, 1,1, AllPlanes, ZPixmap);
1544   return(XGetPixel(pixelimage,0,0));
1545 }
1546
1547 int el2gfx(int element)
1548 {
1549   switch(element)
1550   {
1551     case EL_LEERRAUM:           return(-1);
1552     case EL_ERDREICH:           return(GFX_ERDREICH);
1553     case EL_MAUERWERK:          return(GFX_MAUERWERK);
1554     case EL_FELSBODEN:          return(GFX_FELSBODEN);
1555     case EL_FELSBROCKEN:        return(GFX_FELSBROCKEN);
1556     case EL_SCHLUESSEL:         return(GFX_SCHLUESSEL);
1557     case EL_EDELSTEIN:          return(GFX_EDELSTEIN);
1558     case EL_AUSGANG_ZU:         return(GFX_AUSGANG_ZU);
1559     case EL_AUSGANG_ACT:        return(GFX_AUSGANG_ACT);
1560     case EL_AUSGANG_AUF:        return(GFX_AUSGANG_AUF);
1561     case EL_SPIELFIGUR:         return(GFX_SPIELFIGUR);
1562     case EL_SPIELER1:           return(GFX_SPIELER1);
1563     case EL_SPIELER2:           return(GFX_SPIELER2);
1564     case EL_SPIELER3:           return(GFX_SPIELER3);
1565     case EL_SPIELER4:           return(GFX_SPIELER4);
1566     case EL_KAEFER:             return(GFX_KAEFER);
1567     case EL_KAEFER_R:           return(GFX_KAEFER_R);
1568     case EL_KAEFER_O:           return(GFX_KAEFER_O);
1569     case EL_KAEFER_L:           return(GFX_KAEFER_L);
1570     case EL_KAEFER_U:           return(GFX_KAEFER_U);
1571     case EL_FLIEGER:            return(GFX_FLIEGER);
1572     case EL_FLIEGER_R:          return(GFX_FLIEGER_R);
1573     case EL_FLIEGER_O:          return(GFX_FLIEGER_O);
1574     case EL_FLIEGER_L:          return(GFX_FLIEGER_L);
1575     case EL_FLIEGER_U:          return(GFX_FLIEGER_U);
1576     case EL_BUTTERFLY:          return(GFX_BUTTERFLY);
1577     case EL_BUTTERFLY_R:        return(GFX_BUTTERFLY_R);
1578     case EL_BUTTERFLY_O:        return(GFX_BUTTERFLY_O);
1579     case EL_BUTTERFLY_L:        return(GFX_BUTTERFLY_L);
1580     case EL_BUTTERFLY_U:        return(GFX_BUTTERFLY_U);
1581     case EL_FIREFLY:            return(GFX_FIREFLY);
1582     case EL_FIREFLY_R:          return(GFX_FIREFLY_R);
1583     case EL_FIREFLY_O:          return(GFX_FIREFLY_O);
1584     case EL_FIREFLY_L:          return(GFX_FIREFLY_L);
1585     case EL_FIREFLY_U:          return(GFX_FIREFLY_U);
1586     case EL_MAMPFER:            return(GFX_MAMPFER);
1587     case EL_ROBOT:              return(GFX_ROBOT);
1588     case EL_BETON:              return(GFX_BETON);
1589     case EL_DIAMANT:            return(GFX_DIAMANT);
1590     case EL_MORAST_LEER:        return(GFX_MORAST_LEER);
1591     case EL_MORAST_VOLL:        return(GFX_MORAST_VOLL);
1592     case EL_TROPFEN:            return(GFX_TROPFEN);
1593     case EL_BOMBE:              return(GFX_BOMBE);
1594     case EL_SIEB_LEER:          return(GFX_SIEB_LEER);
1595     case EL_SIEB_VOLL:          return(GFX_SIEB_VOLL);
1596     case EL_SIEB_TOT:           return(GFX_SIEB_TOT);
1597     case EL_SALZSAEURE:         return(GFX_SALZSAEURE);
1598     case EL_AMOEBE_TOT:         return(GFX_AMOEBE_TOT);
1599     case EL_AMOEBE_NASS:        return(GFX_AMOEBE_NASS);
1600     case EL_AMOEBE_NORM:        return(GFX_AMOEBE_NORM);
1601     case EL_AMOEBE_VOLL:        return(GFX_AMOEBE_VOLL);
1602     case EL_AMOEBE_BD:          return(GFX_AMOEBE_BD);
1603     case EL_AMOEBA2DIAM:        return(GFX_AMOEBA2DIAM);
1604     case EL_KOKOSNUSS:          return(GFX_KOKOSNUSS);
1605     case EL_LIFE:               return(GFX_LIFE);
1606     case EL_LIFE_ASYNC:         return(GFX_LIFE_ASYNC);
1607     case EL_DYNAMIT:            return(GFX_DYNAMIT);
1608     case EL_BADEWANNE:          return(GFX_BADEWANNE);
1609     case EL_BADEWANNE1:         return(GFX_BADEWANNE1);
1610     case EL_BADEWANNE2:         return(GFX_BADEWANNE2);
1611     case EL_BADEWANNE3:         return(GFX_BADEWANNE3);
1612     case EL_BADEWANNE4:         return(GFX_BADEWANNE4);
1613     case EL_BADEWANNE5:         return(GFX_BADEWANNE5);
1614     case EL_ABLENK_AUS:         return(GFX_ABLENK_AUS);
1615     case EL_ABLENK_EIN:         return(GFX_ABLENK_EIN);
1616     case EL_SCHLUESSEL1:        return(GFX_SCHLUESSEL1);
1617     case EL_SCHLUESSEL2:        return(GFX_SCHLUESSEL2);
1618     case EL_SCHLUESSEL3:        return(GFX_SCHLUESSEL3);
1619     case EL_SCHLUESSEL4:        return(GFX_SCHLUESSEL4);
1620     case EL_PFORTE1:            return(GFX_PFORTE1);
1621     case EL_PFORTE2:            return(GFX_PFORTE2);
1622     case EL_PFORTE3:            return(GFX_PFORTE3);
1623     case EL_PFORTE4:            return(GFX_PFORTE4);
1624     case EL_PFORTE1X:           return(GFX_PFORTE1X);
1625     case EL_PFORTE2X:           return(GFX_PFORTE2X);
1626     case EL_PFORTE3X:           return(GFX_PFORTE3X);
1627     case EL_PFORTE4X:           return(GFX_PFORTE4X);
1628     case EL_DYNAMIT_AUS:        return(GFX_DYNAMIT_AUS);
1629     case EL_PACMAN:             return(GFX_PACMAN);
1630     case EL_PACMAN_R:           return(GFX_PACMAN_R);
1631     case EL_PACMAN_O:           return(GFX_PACMAN_O);
1632     case EL_PACMAN_L:           return(GFX_PACMAN_L);
1633     case EL_PACMAN_U:           return(GFX_PACMAN_U);
1634     case EL_UNSICHTBAR:         return(GFX_UNSICHTBAR);
1635     case EL_ERZ_EDEL:           return(GFX_ERZ_EDEL);
1636     case EL_ERZ_DIAM:           return(GFX_ERZ_DIAM);
1637     case EL_BIRNE_AUS:          return(GFX_BIRNE_AUS);
1638     case EL_BIRNE_EIN:          return(GFX_BIRNE_EIN);
1639     case EL_ZEIT_VOLL:          return(GFX_ZEIT_VOLL);
1640     case EL_ZEIT_LEER:          return(GFX_ZEIT_LEER);
1641     case EL_MAUER_LEBT:         return(GFX_MAUER_LEBT);
1642     case EL_EDELSTEIN_BD:       return(GFX_EDELSTEIN_BD);
1643     case EL_EDELSTEIN_GELB:     return(GFX_EDELSTEIN_GELB);
1644     case EL_EDELSTEIN_ROT:      return(GFX_EDELSTEIN_ROT);
1645     case EL_EDELSTEIN_LILA:     return(GFX_EDELSTEIN_LILA);
1646     case EL_ERZ_EDEL_BD:        return(GFX_ERZ_EDEL_BD);
1647     case EL_ERZ_EDEL_GELB:      return(GFX_ERZ_EDEL_GELB);
1648     case EL_ERZ_EDEL_ROT:       return(GFX_ERZ_EDEL_ROT);
1649     case EL_ERZ_EDEL_LILA:      return(GFX_ERZ_EDEL_LILA);
1650     case EL_MAMPFER2:           return(GFX_MAMPFER2);
1651     case EL_SIEB2_LEER:         return(GFX_SIEB2_LEER);
1652     case EL_SIEB2_VOLL:         return(GFX_SIEB2_VOLL);
1653     case EL_SIEB2_TOT:          return(GFX_SIEB2_TOT);
1654     case EL_DYNABOMB:           return(GFX_DYNABOMB);
1655     case EL_DYNABOMB_NR:        return(GFX_DYNABOMB_NR);
1656     case EL_DYNABOMB_SZ:        return(GFX_DYNABOMB_SZ);
1657     case EL_DYNABOMB_XL:        return(GFX_DYNABOMB_XL);
1658     case EL_SOKOBAN_OBJEKT:     return(GFX_SOKOBAN_OBJEKT);
1659     case EL_SOKOBAN_FELD_LEER:  return(GFX_SOKOBAN_FELD_LEER);
1660     case EL_SOKOBAN_FELD_VOLL:  return(GFX_SOKOBAN_FELD_VOLL);
1661     case EL_MAULWURF:           return(GFX_MAULWURF);
1662     case EL_PINGUIN:            return(GFX_PINGUIN);
1663     case EL_SCHWEIN:            return(GFX_SCHWEIN);
1664     case EL_DRACHE:             return(GFX_DRACHE);
1665     case EL_SONDE:              return(GFX_SONDE);
1666     case EL_PFEIL_L:            return(GFX_PFEIL_L);
1667     case EL_PFEIL_R:            return(GFX_PFEIL_R);
1668     case EL_PFEIL_O:            return(GFX_PFEIL_O);
1669     case EL_PFEIL_U:            return(GFX_PFEIL_U);
1670     default:
1671     {
1672       if (IS_CHAR(element))
1673         return(GFX_CHAR_START + (element-EL_CHAR_START));
1674       else
1675         return(-1);
1676     }
1677   }
1678 }