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