rnd-19990107-2
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  tools.c                                                 *
12 ***********************************************************/
13
14 #include <stdarg.h>
15
16 #ifdef __FreeBSD__
17 #include <machine/joystick.h>
18 #endif
19
20 #include "tools.h"
21 #include "game.h"
22 #include "events.h"
23 #include "sound.h"
24 #include "misc.h"
25 #include "buttons.h"
26 #include "joystick.h"
27 #include "cartoons.h"
28 #include "network.h"
29
30 #ifdef MSDOS
31 extern boolean wait_for_vsync;
32 #endif
33
34 void SetDrawtoField(int mode)
35 {
36   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
37   {
38     FX = TILEX;
39     FY = TILEY;
40     BX1 = -1;
41     BY1 = -1;
42     BX2 = SCR_FIELDX;
43     BY2 = SCR_FIELDY;
44     redraw_x1 = 1;
45     redraw_y1 = 1;
46
47     drawto_field = fieldbuffer;
48   }
49   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
50   {
51     FX = SX;
52     FY = SY;
53     BX1 = 0;
54     BY1 = 0;
55     BX2 = SCR_FIELDX - 1;
56     BY2 = SCR_FIELDY - 1;
57     redraw_x1 = 0;
58     redraw_y1 = 0;
59
60     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
61   }
62 }
63
64 void BackToFront()
65 {
66   int x,y;
67   Drawable buffer = (drawto_field == window ? backbuffer : drawto_field);
68
69   if (setup.direct_draw && game_status == PLAYING)
70     redraw_mask &= ~REDRAW_MAIN;
71
72   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
73     redraw_mask |= REDRAW_FIELD;
74
75   if (redraw_mask & REDRAW_FIELD)
76     redraw_mask &= ~REDRAW_TILES;
77
78   /*
79   if (redraw_mask & REDRAW_FIELD ||
80       (ScreenGfxPos && setup.soft_scrolling && game_status == PLAYING))
81     redraw_mask &= ~REDRAW_TILES;
82   */
83
84   if (!redraw_mask)
85     return;
86
87   /* synchronize X11 graphics at this point; if we would synchronize the
88      display immediately after the buffer switching (after the XFlush),
89      this could mean that we have to wait for the graphics to complete,
90      although we could go on doing calculations for the next frame */
91
92   XSync(display, FALSE);
93
94   /*
95 #ifdef MSDOS
96   wait_for_vsync = TRUE;
97 #endif
98   */
99
100   if (redraw_mask & REDRAW_ALL)
101   {
102     XCopyArea(display,backbuffer,window,gc,
103               0,0, WIN_XSIZE,WIN_YSIZE,
104               0,0);
105     redraw_mask = 0;
106   }
107
108   if (redraw_mask & REDRAW_FIELD)
109   {
110     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
111       XCopyArea(display,backbuffer,window,gc,
112                 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
113                 REAL_SX,REAL_SY);
114     else
115     {
116       int fx = FX, fy = FY;
117
118       if (setup.soft_scrolling)
119       {
120         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
121         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
122       }
123
124       if (setup.soft_scrolling ||
125           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
126           ABS(ScreenMovPos) == ScrollStepSize ||
127           redraw_tiles > REDRAWTILES_THRESHOLD)
128       {
129         XCopyArea(display, buffer, window, gc, fx, fy, SXSIZE, SYSIZE, SX, SY);
130
131 #ifdef DEBUG
132 #if 0
133         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
134                ScreenGfxPos,
135                (setup.soft_scrolling ?
136                 "setup.soft_scrolling" :
137                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
138                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
139                 ABS(ScreenGfxPos) == ScrollStepSize ?
140                 "ABS(ScreenGfxPos) == ScrollStepSize" :
141                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
142 #endif
143 #endif
144       }
145     }
146     redraw_mask &= ~REDRAW_MAIN;
147   }
148
149   if (redraw_mask & REDRAW_DOORS)
150   {
151     if (redraw_mask & REDRAW_DOOR_1)
152       XCopyArea(display,backbuffer,window,gc,
153                 DX,DY, DXSIZE,DYSIZE,
154                 DX,DY);
155     if (redraw_mask & REDRAW_DOOR_2)
156     {
157       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
158         XCopyArea(display,backbuffer,window,gc,
159                   VX,VY, VXSIZE,VYSIZE,
160                   VX,VY);
161       else
162       {
163         if (redraw_mask & REDRAW_VIDEO_1)
164           XCopyArea(display,backbuffer,window,gc,
165                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
166                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
167                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
168         if (redraw_mask & REDRAW_VIDEO_2)
169           XCopyArea(display,backbuffer,window,gc,
170                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
171                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
172                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
173         if (redraw_mask & REDRAW_VIDEO_3)
174           XCopyArea(display,backbuffer,window,gc,
175                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
176                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
177                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
178       }
179     }
180     if (redraw_mask & REDRAW_DOOR_3)
181       XCopyArea(display, backbuffer, window, gc,
182                 EX, EY, EXSIZE, EYSIZE,
183                 EX, EY);
184     redraw_mask &= ~REDRAW_DOORS;
185   }
186
187   if (redraw_mask & REDRAW_MICROLEV)
188   {
189     XCopyArea(display,backbuffer,window,gc,
190               MICROLEV_XPOS,MICROLEV_YPOS, MICROLEV_XSIZE,MICROLEV_YSIZE,
191               MICROLEV_XPOS,MICROLEV_YPOS);
192     XCopyArea(display,backbuffer,window,gc,
193               SX,MICROLABEL_YPOS, SXSIZE,FONT4_YSIZE,
194               SX,MICROLABEL_YPOS);
195     redraw_mask &= ~REDRAW_MICROLEV;
196   }
197
198   if (redraw_mask & REDRAW_TILES)
199   {
200     for(x=0; x<SCR_FIELDX; x++)
201       for(y=0; y<SCR_FIELDY; y++)
202         if (redraw[redraw_x1 + x][redraw_y1 + y])
203           XCopyArea(display,buffer,window,gc,
204                     FX+x*TILEX,FX+y*TILEY, TILEX,TILEY,
205                     SX+x*TILEX,SY+y*TILEY);
206   }
207
208   XFlush(display);
209
210   for(x=0; x<MAX_BUF_XSIZE; x++)
211     for(y=0; y<MAX_BUF_YSIZE; y++)
212       redraw[x][y] = 0;
213   redraw_tiles = 0;
214   redraw_mask = 0;
215 }
216
217 void FadeToFront()
218 {
219 /*
220   long fading_delay = 300;
221
222   if (setup.fading && (redraw_mask & REDRAW_FIELD))
223   {
224 */
225
226 /*
227     int x,y;
228
229     XFillRectangle(display,window,gc,
230                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
231     XFlush(display);
232
233     for(i=0;i<2*FULL_SYSIZE;i++)
234     {
235       for(y=0;y<FULL_SYSIZE;y++)
236       {
237         XCopyArea(display,backbuffer,window,gc,
238                   REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
239       }
240       XFlush(display);
241       Delay(10);
242     }
243 */
244
245 /*
246     for(i=1;i<FULL_SYSIZE;i+=2)
247       XCopyArea(display,backbuffer,window,gc,
248                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
249     XFlush(display);
250     Delay(fading_delay);
251 */
252
253 /*
254     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
255     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
256               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
257     XFlush(display);
258     Delay(fading_delay);
259
260     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
261     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
262               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
263     XFlush(display);
264     Delay(fading_delay);
265
266     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
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,0);
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     redraw_mask &= ~REDRAW_MAIN;
279   }
280 */
281
282   BackToFront();
283 }
284
285 void ClearWindow()
286 {
287   XFillRectangle(display, backbuffer, gc,
288                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
289
290   if (setup.soft_scrolling && game_status == PLAYING)
291   {
292     XFillRectangle(display, fieldbuffer, gc, 0, 0, FXSIZE, FYSIZE);
293     SetDrawtoField(DRAW_BUFFERED);
294   }
295   else
296     SetDrawtoField(DRAW_BACKBUFFER);
297
298   if (setup.direct_draw && game_status == PLAYING)
299   {
300     XFillRectangle(display, window, gc,
301                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
302     SetDrawtoField(DRAW_DIRECT);
303   }
304
305   redraw_mask |= REDRAW_FIELD;
306 }
307
308 void DrawTextFCentered(int y, int font_type, char *format, ...)
309 {
310   char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
311   int font_xsize;
312   va_list ap;
313
314   font_xsize = (font_type < FC_SPECIAL1 ? FONT2_XSIZE :
315                 font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
316
317   va_start(ap, format);
318   vsprintf(buffer, format, ap);
319   va_end(ap);
320
321   DrawText(SX + (SXSIZE - strlen(buffer) * font_xsize) / 2, SY + y,
322            buffer, FS_SMALL, font_type);
323 }
324
325 void DrawTextF(int x, int y, int font_type, char *format, ...)
326 {
327   char buffer[FULL_SXSIZE / FONT3_XSIZE + 10];
328   va_list ap;
329
330   va_start(ap, format);
331   vsprintf(buffer, format, ap);
332   va_end(ap);
333
334   DrawText(SX + x, SY + y, buffer, FS_SMALL, font_type);
335 }
336
337 void DrawText(int x, int y, char *text, int font_size, int font_type)
338 {
339   DrawTextExt(drawto, gc, x, y, text, font_size, font_type);
340
341   if (x < DX)
342     redraw_mask |= REDRAW_FIELD;
343   else if (y < VY)
344     redraw_mask |= REDRAW_DOOR_1;
345 }
346
347 void DrawTextExt(Drawable d, GC gc, int x, int y,
348                  char *text, int font_size, int font_type)
349 {
350   int font_width, font_height, font_start;
351   int font_pixmap;
352
353   if (font_size != FS_SMALL && font_size != FS_BIG)
354     font_size = FS_SMALL;
355   if (font_type < FC_RED || font_type > FC_SPECIAL2)
356     font_type = FC_RED;
357
358   font_width = (font_size == FS_BIG ? FONT1_XSIZE :
359                 font_type < FC_SPECIAL1 ? FONT2_XSIZE :
360                 font_type < FC_SPECIAL2 ? FONT3_XSIZE : FONT4_XSIZE);
361   font_height = (font_size == FS_BIG ? FONT1_XSIZE :
362                  font_type < FC_SPECIAL2 ? FONT2_XSIZE : FONT4_XSIZE);
363   font_pixmap = (font_size == FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
364   font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE : FONT2_YSIZE) *
365                 FONT_LINES_PER_FONT);
366
367   while(*text)
368   {
369     char c = *text++;
370
371     if (c >= 'a' && c <= 'z')
372       c = 'A' + (c - 'a');
373     else if (c == 'ä' || c == 'Ä')
374       c = 91;
375     else if (c == 'ö' || c == 'Ö')
376       c = 92;
377     else if (c == 'ü' || c == 'Ãœ')
378       c = 93;
379
380     if (c >= 32 && c <= 95)
381       XCopyArea(display, pix[font_pixmap], d, gc,
382                 ((c - 32) % FONT_CHARS_PER_LINE) * font_width,
383                 ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start,
384                 font_width, font_height, x, y);
385
386     x += font_width;
387   }
388 }
389
390 void DrawAllPlayers()
391 {
392   int i;
393
394   for(i=0; i<MAX_PLAYERS; i++)
395     if (stored_player[i].active)
396       DrawPlayer(&stored_player[i]);
397 }
398
399 void DrawPlayerField(int x, int y)
400 {
401   if (!IS_PLAYER(x,y))
402     return;
403
404   DrawPlayer(PLAYERINFO(x,y));
405 }
406
407 void DrawPlayer(struct PlayerInfo *player)
408 {
409   int jx = player->jx, jy = player->jy;
410   int last_jx = player->last_jx, last_jy = player->last_jy;
411   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
412   int sx = SCREENX(jx), sy = SCREENY(jy);
413   int sxx = 0, syy = 0;
414   int element = Feld[jx][jy];
415   int graphic, phase;
416
417   if (!player->active || player->gone ||
418       !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
419     return;
420
421 #if DEBUG
422   if (!IN_LEV_FIELD(jx,jy))
423   {
424     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
425     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
426     printf("DrawPlayerField(): This should never happen!\n");
427     return;
428   }
429 #endif
430
431   if (element == EL_EXPLODING)
432     return;
433
434   /* draw things in the field the player is leaving, if needed */
435
436   if (last_jx != jx || last_jy != jy)
437   {
438     if (Store[last_jx][last_jy])
439     {
440       DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
441       DrawLevelFieldThruMask(last_jx, last_jy);
442     }
443     else if (Feld[last_jx][last_jy] == EL_DYNAMIT)
444       DrawDynamite(last_jx, last_jy);
445     else
446       DrawLevelField(last_jx, last_jy);
447
448     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
449     {
450       if (player->GfxPos)
451       {
452         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
453           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER);
454         else
455           DrawLevelElement(next_jx, next_jy, EL_LEERRAUM);
456       }
457       else
458         DrawLevelField(next_jx, next_jy);
459     }
460   }
461
462   if (!IN_SCR_FIELD(sx, sy))
463     return;
464
465   if (setup.direct_draw)
466     SetDrawtoField(DRAW_BUFFERED);
467
468   /* draw things behind the player, if needed */
469
470   if (Store[jx][jy])
471     DrawLevelElement(jx, jy, Store[jx][jy]);
472   else if (element != EL_DYNAMIT && element != EL_DYNABOMB)
473     DrawLevelField(jx, jy);
474
475   /* draw player himself */
476
477   if (player->MovDir == MV_LEFT)
478     graphic = (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
479   else if (player->MovDir == MV_RIGHT)
480     graphic = (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
481   else if (player->MovDir == MV_UP)
482     graphic = GFX_SPIELER1_UP;
483   else  /* MV_DOWN || MV_NO_MOVING */
484     graphic = GFX_SPIELER1_DOWN;
485
486   graphic += player->index_nr * 3*HEROES_PER_LINE;
487   graphic += player->Frame;
488
489   if (player->GfxPos)
490   {
491     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
492       sxx = player->GfxPos;
493     else
494       syy = player->GfxPos;
495   }
496
497   if (!setup.soft_scrolling && ScreenMovPos)
498     sxx = syy = 0;
499
500   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING);
501
502   if (player->Pushing && player->GfxPos)
503   {
504     int px = SCREENX(next_jx), py = SCREENY(next_jy);
505
506     if (Feld[jx][jy] == EL_SOKOBAN_FELD_LEER ||
507         Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
508       DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT,
509                                  NO_CUTTING);
510     else
511     {
512       int element = Feld[next_jx][next_jy];
513       int graphic = el2gfx(element);
514
515       if (element == EL_FELSBROCKEN && sxx)
516       {
517         int phase = (player->GfxPos / (TILEX/4));
518
519         if (player->MovDir == MV_LEFT)
520           graphic += phase;
521         else
522           graphic += (phase+4)%4;
523       }
524
525       DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING);
526     }
527   }
528
529   /* draw things in front of player (EL_DYNAMIT || EL_DYNABOMB) */
530
531   if (element == EL_DYNAMIT || element == EL_DYNABOMB)
532   {
533     graphic = el2gfx(element);
534
535     if (element == EL_DYNAMIT)
536     {
537       if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6)
538         phase = 6;
539     }
540     else
541     {
542       if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
543         phase = 7 - phase;
544     }
545
546     if (game_emulation == EMU_SUPAPLEX)
547       DrawGraphic(sx, sy, GFX_SP_DISK_RED);
548     else
549       DrawGraphicThruMask(sx, sy, graphic + phase);
550   }
551
552   if ((last_jx != jx || last_jy != jy) &&
553       Feld[last_jx][last_jy] == EL_EXPLODING)
554   {
555     int phase = Frame[last_jx][last_jy];
556     int delay = 2;
557
558     if (phase > 2)
559       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
560                           GFX_EXPLOSION + ((phase - 1) / delay - 1));
561   }
562
563   if (setup.direct_draw)
564   {
565     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
566     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
567     int x_size = TILEX * (1 + ABS(jx - last_jx));
568     int y_size = TILEY * (1 + ABS(jy - last_jy));
569
570     XCopyArea(display, drawto_field, window, gc,
571               dest_x, dest_y, x_size, y_size, dest_x, dest_y);
572     SetDrawtoField(DRAW_DIRECT);
573   }
574
575   MarkTileDirty(sx,sy);
576 }
577
578 static int getGraphicAnimationPhase(int frames, int delay, int mode)
579 {
580   int phase;
581
582   if (mode == ANIM_OSCILLATE)
583   {
584     int max_anim_frames = 2 * frames - 2;
585     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
586     phase = (phase < frames ? phase : max_anim_frames - phase);
587   }
588   else
589     phase = (FrameCounter % (delay * frames)) / delay;
590
591   if (mode == ANIM_REVERSE)
592     phase = -phase;
593
594   return(phase);
595 }
596
597 void DrawGraphicAnimationExt(int x, int y, int graphic,
598                              int frames, int delay, int mode, int mask_mode)
599 {
600   int phase = getGraphicAnimationPhase(frames, delay, mode);
601
602   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
603   {
604     if (mask_mode == USE_MASKING)
605       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
606     else
607       DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
608   }
609 }
610
611 void DrawGraphicAnimation(int x, int y, int graphic,
612                           int frames, int delay, int mode)
613 {
614   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
615 }
616
617 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
618                                   int frames, int delay, int mode)
619 {
620   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
621 }
622
623 void DrawGraphic(int x, int y, int graphic)
624 {
625 #if DEBUG
626   if (!IN_SCR_FIELD(x,y))
627   {
628     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
629     printf("DrawGraphic(): This should never happen!\n");
630     return;
631   }
632 #endif
633
634   DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
635   MarkTileDirty(x,y);
636 }
637
638 void DrawGraphicExt(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               SX + (graphic % GFX_PER_LINE) * TILEX,
645               SY + (graphic / GFX_PER_LINE) * TILEY,
646               TILEX, TILEY, x, y);
647   }
648   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
649   {
650     graphic -= GFX_START_ROCKSMORE;
651     XCopyArea(display, pix[PIX_MORE], d, gc,
652               (graphic % MORE_PER_LINE) * TILEX,
653               (graphic / MORE_PER_LINE) * TILEY,
654               TILEX, TILEY, x, y);
655   }
656   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
657   {
658     graphic -= GFX_START_ROCKSHEROES;
659     XCopyArea(display, pix[PIX_HEROES], d, gc,
660               (graphic % HEROES_PER_LINE) * TILEX,
661               (graphic / HEROES_PER_LINE) * TILEY,
662               TILEX, TILEY, x, y);
663   }
664   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
665   {
666     graphic -= GFX_START_ROCKSFONT;
667     XCopyArea(display, pix[PIX_BIGFONT], d, gc,
668               (graphic % FONT_CHARS_PER_LINE) * TILEX,
669               (graphic / FONT_CHARS_PER_LINE) * TILEY +
670               FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY,
671               TILEX, TILEY, x, y);
672   }
673   else
674     XFillRectangle(display, d, gc, x, y, TILEX, TILEY);
675 }
676
677 void DrawGraphicThruMask(int x, int y, int graphic)
678 {
679 #if DEBUG
680   if (!IN_SCR_FIELD(x,y))
681   {
682     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
683     printf("DrawGraphicThruMask(): This should never happen!\n");
684     return;
685   }
686 #endif
687
688   DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
689   MarkTileDirty(x,y);
690 }
691
692 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
693 {
694   int src_x, src_y;
695   int tile = graphic;
696   Pixmap src_pixmap;
697   GC drawing_gc;
698
699   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
700   {
701     src_pixmap = pix[PIX_BACK];
702     drawing_gc = clip_gc[PIX_BACK];
703     graphic -= GFX_START_ROCKSSCREEN;
704     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX;
705     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY;
706   }
707   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
708   {
709     src_pixmap = pix[PIX_MORE];
710     drawing_gc = clip_gc[PIX_MORE];
711     graphic -= GFX_START_ROCKSMORE;
712     src_x  = (graphic % MORE_PER_LINE) * TILEX;
713     src_y  = (graphic / MORE_PER_LINE) * TILEY;
714   }
715   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
716   {
717     src_pixmap = pix[PIX_HEROES];
718     drawing_gc = clip_gc[PIX_HEROES];
719     graphic -= GFX_START_ROCKSHEROES;
720     src_x  = (graphic % HEROES_PER_LINE) * TILEX;
721     src_y  = (graphic / HEROES_PER_LINE) * TILEY;
722   }
723   else
724   {
725     DrawGraphicExt(d, gc, dest_x,dest_y, graphic);
726     return;
727   }
728
729   if (tile_clipmask[tile] != None)
730   {
731     XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
732     XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
733     XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
734               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
735   }
736   else
737   {
738 #if DEBUG
739     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
740 #endif
741
742     XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
743     XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
744               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
745   }
746 }
747
748 void DrawMiniGraphic(int x, int y, int graphic)
749 {
750   DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
751   MarkTileDirty(x/2, y/2);
752 }
753
754 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
755 {
756   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
757   {
758     graphic -= GFX_START_ROCKSSCREEN;
759     XCopyArea(display, pix[PIX_BACK], d, gc,
760               MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX,
761               MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY,
762               MINI_TILEX, MINI_TILEY, x, y);
763   }
764   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
765   {
766     graphic -= GFX_START_ROCKSMORE;
767     XCopyArea(display, pix[PIX_MORE], d, gc,
768               MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX,
769               MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY,
770               MINI_TILEX, MINI_TILEY, x, y);
771   }
772   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
773   {
774     graphic -= GFX_START_ROCKSFONT;
775     XCopyArea(display, pix[PIX_SMALLFONT], d, gc,
776               (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE,
777               (graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
778               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT,
779               MINI_TILEX, MINI_TILEY, x, y);
780   }
781   else
782     XFillRectangle(display, d, gc, x, y, MINI_TILEX, MINI_TILEY);
783 }
784
785 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
786                         int cut_mode, int mask_mode)
787 {
788   int width = TILEX, height = TILEY;
789   int cx = 0, cy = 0;
790   int src_x, src_y, dest_x, dest_y;
791   int tile = graphic;
792   Pixmap src_pixmap;
793   GC drawing_gc;
794
795   if (graphic < 0)
796   {
797     DrawGraphic(x, y, graphic);
798     return;
799   }
800
801   if (dx || dy)                 /* Verschiebung der Grafik? */
802   {
803     if (x < BX1)                /* Element kommt von links ins Bild */
804     {
805       x = BX1;
806       width = dx;
807       cx = TILEX - dx;
808       dx = 0;
809     }
810     else if (x > BX2)           /* Element kommt von rechts ins Bild */
811     {
812       x = BX2;
813       width = -dx;
814       dx = TILEX + dx;
815     }
816     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
817     {
818       width += dx;
819       cx = -dx;
820       dx = 0;
821     }
822     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
823       width -= dx;
824     else if (dx)                /* allg. Bewegung in x-Richtung */
825       MarkTileDirty(x + SIGN(dx), y);
826
827     if (y < BY1)                /* Element kommt von oben ins Bild */
828     {
829       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
830         return;
831
832       y = BY1;
833       height = dy;
834       cy = TILEY - dy;
835       dy = 0;
836     }
837     else if (y > BY2)           /* Element kommt von unten ins Bild */
838     {
839       y = BY2;
840       height = -dy;
841       dy = TILEY + dy;
842     }
843     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
844     {
845       height += dy;
846       cy = -dy;
847       dy = 0;
848     }
849     else if (dy > 0 && cut_mode == CUT_ABOVE)
850     {
851       if (y == BY2)             /* Element unterhalb des Bildes */
852         return;
853
854       height = dy;
855       cy = TILEY - dy;
856       dy = TILEY;
857       MarkTileDirty(x, y + 1);
858     }                           /* Element verläßt unten das Bild */
859     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
860       height -= dy;
861     else if (dy)                /* allg. Bewegung in y-Richtung */
862       MarkTileDirty(x, y + SIGN(dy));
863   }
864
865   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
866   {
867     src_pixmap = pix[PIX_BACK];
868     drawing_gc = clip_gc[PIX_BACK];
869     graphic -= GFX_START_ROCKSSCREEN;
870     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX + cx;
871     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY + cy;
872   }
873   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
874   {
875     src_pixmap = pix[PIX_MORE];
876     drawing_gc = clip_gc[PIX_MORE];
877     graphic -= GFX_START_ROCKSMORE;
878     src_x  = (graphic % MORE_PER_LINE) * TILEX + cx;
879     src_y  = (graphic / MORE_PER_LINE) * TILEY + cy;
880   }
881   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
882   {
883     src_pixmap = pix[PIX_HEROES];
884     drawing_gc = clip_gc[PIX_HEROES];
885     graphic -= GFX_START_ROCKSHEROES;
886     src_x  = (graphic % HEROES_PER_LINE) * TILEX + cx;
887     src_y  = (graphic / HEROES_PER_LINE) * TILEY + cy;
888   }
889   else  /* big font graphics currently not allowed (and not needed) */
890     return;
891
892   dest_x = FX + x * TILEX + dx;
893   dest_y = FY + y * TILEY + dy;
894
895 #if DEBUG
896   if (!IN_SCR_FIELD(x,y))
897   {
898     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
899     printf("DrawGraphicShifted(): This should never happen!\n");
900     return;
901   }
902 #endif
903
904   if (mask_mode == USE_MASKING)
905   {
906     if (tile_clipmask[tile] != None)
907     {
908       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
909       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
910       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
911                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
912     }
913     else
914     {
915 #if DEBUG
916       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
917 #endif
918
919       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
920       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
921                 src_x, src_y, width, height, dest_x, dest_y);
922     }
923   }
924   else
925     XCopyArea(display, src_pixmap, drawto_field, gc,
926               src_x, src_y, width, height, dest_x, dest_y);
927
928   MarkTileDirty(x,y);
929 }
930
931 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
932                                 int cut_mode)
933 {
934   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
935 }
936
937 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
938                           int cut_mode, int mask_mode)
939 {
940   int ux = LEVELX(x), uy = LEVELY(y);
941   int graphic = el2gfx(element);
942   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
943   int phase4 = phase8 / 2;
944   int phase2  = phase8 / 4;
945   int dir = MovDir[ux][uy];
946
947   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
948   {
949     graphic += 4 * !phase2;
950
951     if (dir == MV_UP)
952       graphic += 1;
953     else if (dir == MV_LEFT)
954       graphic += 2;
955     else if (dir == MV_DOWN)
956       graphic += 3;
957   }
958   else if (element == EL_SP_SNIKSNAK)
959   {
960     if (dir == MV_LEFT)
961       graphic = GFX_SP_SNIKSNAK_LEFT;
962     else if (dir == MV_RIGHT)
963       graphic = GFX_SP_SNIKSNAK_RIGHT;
964     else if (dir == MV_UP)
965       graphic = GFX_SP_SNIKSNAK_UP;
966     else
967       graphic = GFX_SP_SNIKSNAK_DOWN;
968
969     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
970   }
971   else if (element == EL_SP_ELECTRON)
972   {
973     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
974   }
975   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
976            element == EL_SCHWEIN || element == EL_DRACHE)
977   {
978     if (dir == MV_LEFT)
979       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
980                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
981                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
982     else if (dir == MV_RIGHT)
983       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
984                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
985                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
986     else if (dir == MV_UP)
987       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
988                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
989                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
990     else
991       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
992                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
993                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
994
995     graphic += phase4;
996   }
997   else if (element == EL_SONDE)
998   {
999     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1000   }
1001   else if (element == EL_SALZSAEURE)
1002   {
1003     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1004   }
1005   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1006   {
1007     graphic += !phase2;
1008   }
1009   else if ((element == EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
1010   {
1011     if (element != EL_SP_INFOTRON)
1012       graphic += phase2 * (element == EL_FELSBROCKEN ? 2 : 1);
1013   }
1014   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1015            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1016   {
1017     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1018   }
1019   else if (IS_AMOEBOID(element))
1020   {
1021     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1022     graphic += (x + 2 * y + 4) % 4;
1023   }
1024   else if (element == EL_MAUER_LEBT)
1025   {
1026     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1027
1028     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1029       links_massiv = TRUE;
1030     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1031       rechts_massiv = TRUE;
1032
1033     if (links_massiv && rechts_massiv)
1034       graphic = GFX_MAUERWERK;
1035     else if (links_massiv)
1036       graphic = GFX_MAUER_R;
1037     else if (rechts_massiv)
1038       graphic = GFX_MAUER_L;
1039   }
1040
1041   if (dx || dy)
1042     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1043   else if (mask_mode == USE_MASKING)
1044     DrawGraphicThruMask(x, y, graphic);
1045   else
1046     DrawGraphic(x, y, graphic);
1047 }
1048
1049 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1050                          int cut_mode, int mask_mode)
1051 {
1052   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1053     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1054                          cut_mode, mask_mode);
1055 }
1056
1057 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1058                               int cut_mode)
1059 {
1060   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1061 }
1062
1063 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1064                              int cut_mode)
1065 {
1066   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1067 }
1068
1069 void DrawScreenElementThruMask(int x, int y, int element)
1070 {
1071   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1072 }
1073
1074 void DrawLevelElementThruMask(int x, int y, int element)
1075 {
1076   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1077 }
1078
1079 void DrawLevelFieldThruMask(int x, int y)
1080 {
1081   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1082 }
1083
1084 void ErdreichAnbroeckeln(int x, int y)
1085 {
1086   int i, width, height, cx,cy;
1087   int ux = LEVELX(x), uy = LEVELY(y);
1088   int element, graphic;
1089   int snip = 4;
1090   static int xy[4][2] =
1091   {
1092     { 0, -1 },
1093     { -1, 0 },
1094     { +1, 0 },
1095     { 0, +1 }
1096   };
1097
1098   if (!IN_LEV_FIELD(ux, uy))
1099     return;
1100
1101   element = Feld[ux][uy];
1102
1103   if (element == EL_ERDREICH)
1104   {
1105     if (!IN_SCR_FIELD(x, y))
1106       return;
1107
1108     graphic = GFX_ERDENRAND;
1109
1110     for(i=0; i<4; i++)
1111     {
1112       int uxx, uyy;
1113
1114       uxx = ux + xy[i][0];
1115       uyy = uy + xy[i][1];
1116       if (!IN_LEV_FIELD(uxx, uyy))
1117         element = EL_BETON;
1118       else
1119         element = Feld[uxx][uyy];
1120
1121       if (element == EL_ERDREICH)
1122         continue;
1123
1124       if (i == 1 || i == 2)
1125       {
1126         width = snip;
1127         height = TILEY;
1128         cx = (i == 2 ? TILEX - snip : 0);
1129         cy = 0;
1130       }
1131       else
1132       {
1133         width = TILEX;
1134         height = snip;
1135         cx = 0;
1136         cy = (i == 3 ? TILEY - snip : 0);
1137       }
1138
1139       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1140                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1141                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1142                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1143     }
1144
1145     MarkTileDirty(x, y);
1146   }
1147   else
1148   {
1149     graphic = GFX_ERDENRAND;
1150
1151     for(i=0; i<4; i++)
1152     {
1153       int xx, yy, uxx, uyy;
1154
1155       xx = x + xy[i][0];
1156       yy = y + xy[i][1];
1157       uxx = ux + xy[i][0];
1158       uyy = uy + xy[i][1];
1159
1160       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1161           !IN_SCR_FIELD(xx, yy))
1162         continue;
1163
1164       if (i == 1 || i == 2)
1165       {
1166         width = snip;
1167         height = TILEY;
1168         cx = (i == 1 ? TILEX - snip : 0);
1169         cy = 0;
1170       }
1171       else
1172       {
1173         width = TILEX;
1174         height = snip;
1175         cx = 0;
1176         cy = (i==0 ? TILEY-snip : 0);
1177       }
1178
1179       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1180                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1181                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1182                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1183
1184       MarkTileDirty(xx, yy);
1185     }
1186   }
1187 }
1188
1189 void DrawScreenElement(int x, int y, int element)
1190 {
1191   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1192   ErdreichAnbroeckeln(x, y);
1193 }
1194
1195 void DrawLevelElement(int x, int y, int element)
1196 {
1197   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1198     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1199 }
1200
1201 void DrawScreenField(int x, int y)
1202 {
1203   int ux = LEVELX(x), uy = LEVELY(y);
1204   int element;
1205
1206   if (!IN_LEV_FIELD(ux, uy))
1207   {
1208     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1209       element = EL_LEERRAUM;
1210     else
1211       element = BorderElement;
1212
1213     DrawScreenElement(x, y, element);
1214     return;
1215   }
1216
1217   element = Feld[ux][uy];
1218
1219   if (IS_MOVING(ux, uy))
1220   {
1221     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1222     boolean cut_mode = NO_CUTTING;
1223
1224     if (Store[ux][uy] == EL_MORAST_LEER ||
1225         Store[ux][uy] == EL_SIEB_LEER ||
1226         Store[ux][uy] == EL_SIEB2_LEER ||
1227         Store[ux][uy] == EL_AMOEBE_NASS)
1228       cut_mode = CUT_ABOVE;
1229     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1230              Store[ux][uy] == EL_SIEB_VOLL ||
1231              Store[ux][uy] == EL_SIEB2_VOLL)
1232       cut_mode = CUT_BELOW;
1233
1234     if (cut_mode == CUT_ABOVE)
1235       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1236     else
1237       DrawScreenElement(x, y, EL_LEERRAUM);
1238
1239     if (horiz_move)
1240       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1241     else
1242       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1243
1244     if (Store[ux][uy] == EL_SALZSAEURE)
1245       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1246   }
1247   else if (IS_BLOCKED(ux, uy))
1248   {
1249     int oldx, oldy;
1250     int sx, sy;
1251     int horiz_move;
1252     boolean cut_mode = NO_CUTTING;
1253
1254     Blocked2Moving(ux, uy, &oldx, &oldy);
1255     sx = SCREENX(oldx);
1256     sy = SCREENY(oldy);
1257     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1258                   MovDir[oldx][oldy] == MV_RIGHT);
1259
1260     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1261         Store[oldx][oldy] == EL_SIEB_LEER ||
1262         Store[oldx][oldy] == EL_SIEB2_LEER ||
1263         Store[oldx][oldy] == EL_AMOEBE_NASS)
1264       cut_mode = CUT_ABOVE;
1265
1266     DrawScreenElement(x, y, EL_LEERRAUM);
1267     element = Feld[oldx][oldy];
1268
1269     if (horiz_move)
1270       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1271     else
1272       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1273   }
1274   else if (IS_DRAWABLE(element))
1275     DrawScreenElement(x, y, element);
1276   else
1277     DrawScreenElement(x, y, EL_LEERRAUM);
1278 }
1279
1280 void DrawLevelField(int x, int y)
1281 {
1282   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1283     DrawScreenField(SCREENX(x), SCREENY(y));
1284   else if (IS_MOVING(x, y))
1285   {
1286     int newx,newy;
1287
1288     Moving2Blocked(x, y, &newx, &newy);
1289     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1290       DrawScreenField(SCREENX(newx), SCREENY(newy));
1291   }
1292   else if (IS_BLOCKED(x, y))
1293   {
1294     int oldx, oldy;
1295
1296     Blocked2Moving(x, y, &oldx, &oldy);
1297     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1298       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1299   }
1300 }
1301
1302 void DrawMiniElement(int x, int y, int element)
1303 {
1304   int graphic;
1305
1306   if (!element)
1307   {
1308     DrawMiniGraphic(x, y, -1);
1309     return;
1310   }
1311
1312   graphic = el2gfx(element);
1313   DrawMiniGraphic(x, y, graphic);
1314 }
1315
1316 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1317 {
1318   int x = sx + scroll_x, y = sy + scroll_y;
1319
1320   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1321     DrawMiniElement(sx, sy, EL_LEERRAUM);
1322   else if (x == -1 || x == lev_fieldx || y == -1 || y == lev_fieldy)
1323     DrawMiniElement(sx, sy, EL_BETON);
1324   else
1325     DrawMiniElement(sx, sy, Feld[x][y]);
1326 }
1327
1328 void DrawMicroElement(int xpos, int ypos, int element)
1329 {
1330   int graphic;
1331
1332   if (element == EL_LEERRAUM)
1333     return;
1334
1335   graphic = el2gfx(element);
1336
1337   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1338   {
1339     graphic -= GFX_START_ROCKSMORE;
1340     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1341               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1342               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1343               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1344   }
1345   else
1346     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1347               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1348               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1349               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1350 }
1351
1352 void DrawLevel()
1353 {
1354   int x,y;
1355
1356   ClearWindow();
1357
1358   for(x=BX1; x<=BX2; x++)
1359     for(y=BY1; y<=BY2; y++)
1360       DrawScreenField(x, y);
1361
1362   if (setup.soft_scrolling)
1363     XCopyArea(display, fieldbuffer, backbuffer, gc,
1364               FX, FY, SXSIZE, SYSIZE, SX, SY);
1365
1366   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1367 }
1368
1369 void DrawMiniLevel(int scroll_x, int scroll_y)
1370 {
1371   int x,y;
1372
1373   ClearWindow();
1374
1375   for(x=0; x<2*SCR_FIELDX; x++)
1376     for(y=0; y<2*SCR_FIELDY; y++)
1377       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1378
1379   redraw_mask |= REDRAW_FIELD;
1380 }
1381
1382 void DrawMicroLevel(int xpos, int ypos)
1383 {
1384   int x,y;
1385
1386   /* determine border element for this level */
1387   SetBorderElement();
1388
1389   XFillRectangle(display, drawto, gc,
1390                  xpos - MICRO_TILEX, ypos - MICRO_TILEY,
1391                  MICRO_TILEX * (STD_LEV_FIELDX + 2),
1392                  MICRO_TILEY * (STD_LEV_FIELDY + 2));
1393   if (lev_fieldx < STD_LEV_FIELDX)
1394     xpos += (STD_LEV_FIELDX - lev_fieldx)/2 * MICRO_TILEX;
1395   if (lev_fieldy < STD_LEV_FIELDY)
1396     ypos += (STD_LEV_FIELDY - lev_fieldy)/2 * MICRO_TILEY;
1397
1398   for(x=-1; x<=STD_LEV_FIELDX; x++)
1399     for(y=-1; y<=STD_LEV_FIELDY; y++)
1400       if (x >= 0 && x < lev_fieldx && y >= 0 && y < lev_fieldy)
1401         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1402                          Ur[x][y]);
1403       else if (x >= -1 && x < lev_fieldx+1 && y >= -1 && y < lev_fieldy+1)
1404         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1405                          BorderElement);
1406
1407   XFillRectangle(display, drawto,gc, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1408
1409   if (level.name)
1410   {
1411     int len = strlen(level.name);
1412     int lxpos = SX + (SXSIZE - len * FONT4_XSIZE) / 2;
1413     int lypos = MICROLABEL_YPOS;
1414
1415     DrawText(lxpos, lypos, level.name, FS_SMALL, FC_SPECIAL2);
1416   }
1417
1418   redraw_mask |= REDRAW_MICROLEV;
1419 }
1420
1421 int REQ_in_range(int x, int y)
1422 {
1423   if (y > DY+249 && y < DY+278)
1424   {
1425     if (x > DX+1 && x < DX+48)
1426       return 1;
1427     else if (x > DX+51 && x < DX+98) 
1428       return 2;
1429   }
1430   return 0;
1431 }
1432
1433 boolean Request(char *text, unsigned int req_state)
1434 {
1435   int mx, my, ty, result = -1;
1436   unsigned int old_door_state;
1437
1438 #ifndef MSDOS
1439   /* pause network game while waiting for request to answer */
1440   if (options.network &&
1441       game_status == PLAYING &&
1442       req_state & REQUEST_WAIT_FOR)
1443     SendToServer_PausePlaying();
1444 #endif
1445
1446   old_door_state = GetDoorState();
1447
1448   CloseDoor(DOOR_CLOSE_1);
1449
1450   /* Alten Türinhalt sichern */
1451   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1452             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1453             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1454
1455   /* Fragetext schreiben */
1456   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1457                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1458
1459   for(ty=0; ty<13; ty++)
1460   {
1461     int tx, tl, tc;
1462     char txt[256];
1463
1464     if (!*text)
1465       break;
1466
1467     for(tl=0,tx=0; tx<7; tl++,tx++)
1468     {
1469       tc = *(text + tx);
1470       if (!tc || tc == 32)
1471         break;
1472     }
1473     if (!tl)
1474     { 
1475       text++; 
1476       ty--; 
1477       continue; 
1478     }
1479     sprintf(txt, text); 
1480     txt[tl] = 0;
1481     DrawTextExt(pix[PIX_DB_DOOR], gc,
1482                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1483                 txt, FS_SMALL, FC_YELLOW);
1484     text += tl + (tc == 32 ? 1 : 0);
1485   }
1486
1487   if (req_state & REQ_ASK)
1488   {
1489     DrawYesNoButton(BUTTON_OK, DB_INIT);
1490     DrawYesNoButton(BUTTON_NO, DB_INIT);
1491   }
1492   else if (req_state & REQ_CONFIRM)
1493   {
1494     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1495   }
1496   else if (req_state & REQ_PLAYER)
1497   {
1498     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1499     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1500     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1501     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1502   }
1503
1504   OpenDoor(DOOR_OPEN_1);
1505   ClearEventQueue();
1506
1507   if (!(req_state & REQUEST_WAIT_FOR))
1508     return(FALSE);
1509
1510   if (game_status != MAINMENU)
1511     InitAnimation();
1512
1513   button_status = MB_RELEASED;
1514
1515   while(result < 0)
1516   {
1517     if (XPending(display))
1518     {
1519       XEvent event;
1520
1521       XNextEvent(display, &event);
1522
1523       switch(event.type)
1524       {
1525         case ButtonPress:
1526         case ButtonRelease:
1527         case MotionNotify:
1528         {
1529           int choice;
1530
1531           if (event.type == MotionNotify)
1532           {
1533             motion_status = TRUE;
1534             mx = ((XMotionEvent *) &event)->x;
1535             my = ((XMotionEvent *) &event)->y;
1536           }
1537           else
1538           {
1539             motion_status = FALSE;
1540             mx = ((XButtonEvent *) &event)->x;
1541             my = ((XButtonEvent *) &event)->y;
1542             if (event.type==ButtonPress)
1543               button_status = ((XButtonEvent *) &event)->button;
1544             else
1545               button_status = MB_RELEASED;
1546           }
1547
1548           if (req_state & REQ_ASK)
1549             choice = CheckYesNoButtons(mx,my,button_status);
1550           else if (req_state & REQ_CONFIRM)
1551             choice = CheckConfirmButton(mx,my,button_status);
1552           else
1553             choice = CheckPlayerButtons(mx,my,button_status);
1554
1555           switch(choice)
1556           {
1557             case BUTTON_OK:
1558               result = TRUE;
1559               break;
1560             case BUTTON_NO:
1561               result = FALSE;
1562               break;
1563             case BUTTON_CONFIRM:
1564               result = TRUE | FALSE;
1565               break;
1566
1567             case BUTTON_PLAYER_1:
1568               result = 1;
1569               break;
1570             case BUTTON_PLAYER_2:
1571               result = 2;
1572               break;
1573             case BUTTON_PLAYER_3:
1574               result = 3;
1575               break;
1576             case BUTTON_PLAYER_4:
1577               result = 4;
1578               break;
1579
1580             default:
1581               break;
1582           }
1583           break;
1584         }
1585
1586         case KeyPress:
1587           switch(XLookupKeysym((XKeyEvent *)&event,
1588                                ((XKeyEvent *)&event)->state))
1589           {
1590             case XK_Return:
1591               result = 1;
1592               break;
1593
1594             case XK_Escape:
1595               result = 0;
1596               break;
1597
1598             default:
1599               break;
1600           }
1601           if (req_state & REQ_PLAYER)
1602             result = 0;
1603           break;
1604
1605         case KeyRelease:
1606           key_joystick_mapping = 0;
1607           break;
1608
1609         default:
1610           HandleOtherEvents(&event);
1611           break;
1612       }
1613     }
1614     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1615     {
1616       int joy = AnyJoystick();
1617
1618       if (joy & JOY_BUTTON_1)
1619         result = 1;
1620       else if (joy & JOY_BUTTON_2)
1621         result = 0;
1622     }
1623
1624     DoAnimation();
1625
1626     /* don't eat all CPU time */
1627     Delay(10);
1628   }
1629
1630   if (game_status != MAINMENU)
1631     StopAnimation();
1632
1633   if (!(req_state & REQ_STAY_OPEN))
1634   {
1635     CloseDoor(DOOR_CLOSE_1);
1636
1637     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1638     {
1639       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1640                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1641                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1642       OpenDoor(DOOR_OPEN_1);
1643     }
1644   }
1645
1646 #ifndef MSDOS
1647   /* continue network game after request */
1648   if (options.network &&
1649       game_status == PLAYING &&
1650       req_state & REQUEST_WAIT_FOR)
1651     SendToServer_ContinuePlaying();
1652 #endif
1653
1654   return(result);
1655 }
1656
1657 unsigned int OpenDoor(unsigned int door_state)
1658 {
1659   unsigned int new_door_state;
1660
1661   if (door_state & DOOR_COPY_BACK)
1662   {
1663     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1664               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1665               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1666     door_state &= ~DOOR_COPY_BACK;
1667   }
1668
1669   new_door_state = MoveDoor(door_state);
1670
1671   return(new_door_state);
1672 }
1673
1674 unsigned int CloseDoor(unsigned int door_state)
1675 {
1676   unsigned int new_door_state;
1677
1678   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1679             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1680   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1681             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1682
1683   new_door_state = MoveDoor(door_state);
1684
1685   return(new_door_state);
1686 }
1687
1688 unsigned int GetDoorState()
1689 {
1690   return(MoveDoor(DOOR_GET_STATE));
1691 }
1692
1693 unsigned int MoveDoor(unsigned int door_state)
1694 {
1695   static int door1 = DOOR_OPEN_1;
1696   static int door2 = DOOR_CLOSE_2;
1697   static unsigned long door_delay = 0;
1698   int x, start, stepsize = 2;
1699   unsigned long door_delay_value = stepsize * 5;
1700
1701   if (door_state == DOOR_GET_STATE)
1702     return(door1 | door2);
1703
1704   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1705     door_state &= ~DOOR_OPEN_1;
1706   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1707     door_state &= ~DOOR_CLOSE_1;
1708   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1709     door_state &= ~DOOR_OPEN_2;
1710   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1711     door_state &= ~DOOR_CLOSE_2;
1712
1713   if (setup.quick_doors)
1714   {
1715     stepsize = 20;
1716     door_delay_value = 0;
1717     StopSound(SND_OEFFNEN);
1718   }
1719
1720   if (door_state & DOOR_ACTION)
1721   {
1722     if (!(door_state & DOOR_NO_DELAY))
1723       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1724
1725     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1726
1727     for(x=start; x<=DXSIZE; x+=stepsize)
1728     {
1729       WaitUntilDelayReached(&door_delay, door_delay_value);
1730
1731       if (door_state & DOOR_ACTION_1)
1732       {
1733         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1734         int j = (DXSIZE - i) / 3;
1735
1736         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1737                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1738                   DXSIZE,DYSIZE - i/2, DX, DY);
1739
1740         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1741
1742         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1743                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1744         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1745                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1746         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1747                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1748                   DY + 140 + j);
1749         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1750                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1751         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1752                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1753         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1754                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1755
1756         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1757                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
1758                   DX, DY + 77 - j);
1759         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1760                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
1761                   DX, DY + 203 - j);
1762         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1763                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1764         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1765                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
1766                   DX + DXSIZE - i, DY + 77 + j);
1767         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1768                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
1769                   DX + DXSIZE - i, DY + 203 + j);
1770
1771         redraw_mask |= REDRAW_DOOR_1;
1772       }
1773
1774       if (door_state & DOOR_ACTION_2)
1775       {
1776         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
1777         int j = (VXSIZE - i) / 3;
1778
1779         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1780                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
1781                   VXSIZE, VYSIZE - i/2, VX, VY);
1782
1783         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
1784
1785         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1786                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1787         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1788                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
1789         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1790                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
1791         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1792                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
1793
1794         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1795                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
1796                   VX, VY + VYSIZE / 2 - j);
1797         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1798                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1799         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1800                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
1801                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
1802
1803         redraw_mask |= REDRAW_DOOR_2;
1804       }
1805
1806       BackToFront();
1807
1808       if (game_status == MAINMENU)
1809         DoAnimation();
1810     }
1811   }
1812
1813   if (setup.quick_doors)
1814     StopSound(SND_OEFFNEN);
1815
1816   if (door_state & DOOR_ACTION_1)
1817     door1 = door_state & DOOR_ACTION_1;
1818   if (door_state & DOOR_ACTION_2)
1819     door2 = door_state & DOOR_ACTION_2;
1820
1821   return(door1 | door2);
1822 }
1823
1824 int ReadPixel(Drawable d, int x, int y)
1825 {
1826   XImage *pixel_image;
1827   unsigned long pixel_value;
1828
1829   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
1830   pixel_value = XGetPixel(pixel_image, 0, 0);
1831
1832   XDestroyImage(pixel_image);
1833
1834   return pixel_value;
1835 }
1836
1837 int el2gfx(int element)
1838 {
1839   switch(element)
1840   {
1841     case EL_LEERRAUM:           return -1;
1842     case EL_ERDREICH:           return GFX_ERDREICH;
1843     case EL_MAUERWERK:          return GFX_MAUERWERK;
1844     case EL_FELSBODEN:          return GFX_FELSBODEN;
1845     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
1846     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
1847     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
1848     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
1849     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
1850     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
1851     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
1852     case EL_SPIELER1:           return GFX_SPIELER1;
1853     case EL_SPIELER2:           return GFX_SPIELER2;
1854     case EL_SPIELER3:           return GFX_SPIELER3;
1855     case EL_SPIELER4:           return GFX_SPIELER4;
1856     case EL_KAEFER:             return GFX_KAEFER;
1857     case EL_KAEFER_R:           return GFX_KAEFER_R;
1858     case EL_KAEFER_O:           return GFX_KAEFER_O;
1859     case EL_KAEFER_L:           return GFX_KAEFER_L;
1860     case EL_KAEFER_U:           return GFX_KAEFER_U;
1861     case EL_FLIEGER:            return GFX_FLIEGER;
1862     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
1863     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
1864     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
1865     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
1866     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
1867     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
1868     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
1869     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
1870     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
1871     case EL_FIREFLY:            return GFX_FIREFLY;
1872     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
1873     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
1874     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
1875     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
1876     case EL_MAMPFER:            return GFX_MAMPFER;
1877     case EL_ROBOT:              return GFX_ROBOT;
1878     case EL_BETON:              return GFX_BETON;
1879     case EL_DIAMANT:            return GFX_DIAMANT;
1880     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
1881     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
1882     case EL_TROPFEN:            return GFX_TROPFEN;
1883     case EL_BOMBE:              return GFX_BOMBE;
1884     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
1885     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
1886     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
1887     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
1888     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
1889     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
1890     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
1891     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
1892     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
1893     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
1894     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
1895     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
1896     case EL_LIFE:               return GFX_LIFE;
1897     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
1898     case EL_DYNAMIT:            return GFX_DYNAMIT;
1899     case EL_BADEWANNE:          return GFX_BADEWANNE;
1900     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
1901     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
1902     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
1903     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
1904     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
1905     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
1906     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
1907     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
1908     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
1909     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
1910     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
1911     case EL_PFORTE1:            return GFX_PFORTE1;
1912     case EL_PFORTE2:            return GFX_PFORTE2;
1913     case EL_PFORTE3:            return GFX_PFORTE3;
1914     case EL_PFORTE4:            return GFX_PFORTE4;
1915     case EL_PFORTE1X:           return GFX_PFORTE1X;
1916     case EL_PFORTE2X:           return GFX_PFORTE2X;
1917     case EL_PFORTE3X:           return GFX_PFORTE3X;
1918     case EL_PFORTE4X:           return GFX_PFORTE4X;
1919     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
1920     case EL_PACMAN:             return GFX_PACMAN;
1921     case EL_PACMAN_R:           return GFX_PACMAN_R;
1922     case EL_PACMAN_O:           return GFX_PACMAN_O;
1923     case EL_PACMAN_L:           return GFX_PACMAN_L;
1924     case EL_PACMAN_U:           return GFX_PACMAN_U;
1925     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
1926     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
1927     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
1928     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
1929     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
1930     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
1931     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
1932     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
1933     case EL_MAUER_X:            return GFX_MAUER_X;
1934     case EL_MAUER_Y:            return GFX_MAUER_Y;
1935     case EL_MAUER_XY:           return GFX_MAUER_XY;
1936     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
1937     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
1938     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
1939     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
1940     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
1941     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
1942     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
1943     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
1944     case EL_MAMPFER2:           return GFX_MAMPFER2;
1945     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
1946     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
1947     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
1948     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
1949     case EL_DYNABOMB:           return GFX_DYNABOMB;
1950     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
1951     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
1952     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
1953     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
1954     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
1955     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
1956     case EL_MAULWURF:           return GFX_MAULWURF;
1957     case EL_PINGUIN:            return GFX_PINGUIN;
1958     case EL_SCHWEIN:            return GFX_SCHWEIN;
1959     case EL_DRACHE:             return GFX_DRACHE;
1960     case EL_SONDE:              return GFX_SONDE;
1961     case EL_PFEIL_L:            return GFX_PFEIL_L;
1962     case EL_PFEIL_R:            return GFX_PFEIL_R;
1963     case EL_PFEIL_O:            return GFX_PFEIL_O;
1964     case EL_PFEIL_U:            return GFX_PFEIL_U;
1965     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
1966     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
1967     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
1968
1969     default:
1970     {
1971       if (IS_CHAR(element))
1972         return GFX_CHAR_START + (element - EL_CHAR_START);
1973       else if (element >= EL_SP_START && element <= EL_SP_END)
1974       {
1975         int nr_element = element - EL_SP_START;
1976         int gfx_per_line = 8;
1977         int nr_graphic =
1978           (nr_element / gfx_per_line) * MORE_PER_LINE +
1979           (nr_element % gfx_per_line);
1980
1981         return GFX_START_ROCKSMORE + nr_graphic;
1982       }
1983       else
1984         return -1;
1985     }
1986   }
1987 }